diff options
511 files changed, 18661 insertions, 29906 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk index e78fc88..b3661e4 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -54,3 +54,5 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/reboot) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/default.prop) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/default.prop) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/lmkd_intermediates/import_includes) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libsysutils_intermediates/import_includes) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/grep $(PRODUCT_OUT)/system/bin/toolbox) @@ -1,20 +0,0 @@ - -The system/ directory is intended for pieces of the world that are the -core of the embedded linux platform at the heart of Android. These -essential bits are required for basic booting, operation, and debugging. - -They should not depend on libraries outside of system/... (some of them -do currently -- they need to be updated or changed) and they should not -be required for the simulator build. - -The license for all these pieces should be clean (Apache2, BSD, or MIT). - -Currently system/bluetooth/... and system/extra/... have some pieces -with GPL/LGPL licensed code. - -Assorted Issues: - -- pppd depends on libutils for logging -- pppd depends on libcrypt/libcrypto -- init, linker, debuggerd, toolbox, usbd depend on libcutils -- should probably rename bionic to libc diff --git a/ThirdPartyProject.prop b/ThirdPartyProject.prop deleted file mode 100644 index 18b0594..0000000 --- a/ThirdPartyProject.prop +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2010 Google Inc. All Rights Reserved. -#Fri Jul 16 10:03:09 PDT 2010 -currentVersion=2.6.32 -version=2.6.32 -isNative=true -feedurl=http\://kernel.org/pub/linux/kernel/v2.6/ -name=linux -keywords=linux -onDevice=true -homepage=http\://kernel.org diff --git a/adb/.clang-format b/adb/.clang-format new file mode 100644 index 0000000..0395c8e --- /dev/null +++ b/adb/.clang-format @@ -0,0 +1,11 @@ +BasedOnStyle: Google +AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: false + +CommentPragmas: NOLINT:.* +DerivePointerAlignment: false +IndentWidth: 4 +PointerAlignment: Left +TabWidth: 4 +UseTab: Never +PenaltyExcessCharacter: 32 diff --git a/adb/Android.mk b/adb/Android.mk index b70c153..6951904 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -5,83 +5,180 @@ LOCAL_PATH:= $(call my-dir) -# adb host tool +ifeq ($(HOST_OS),windows) + adb_host_clang := false # libc++ for mingw not ready yet. +else + adb_host_clang := true +endif + +# libadb # ========================================================= + +# Much of adb is duplicated in bootable/recovery/minadb and fastboot. Changes +# made to adb rarely get ported to the other two, so the trees have diverged a +# bit. We'd like to stop this because it is a maintenance nightmare, but the +# divergence makes this difficult to do all at once. For now, we will start +# small by moving common files into a static library. Hopefully some day we can +# get enough of adb in here that we no longer need minadb. https://b/17626262 +LIBADB_SRC_FILES := \ + adb.cpp \ + adb_auth.cpp \ + adb_io.cpp \ + adb_listeners.cpp \ + adb_utils.cpp \ + sockets.cpp \ + transport.cpp \ + transport_local.cpp \ + transport_usb.cpp \ + +LIBADB_TEST_SRCS := \ + adb_io_test.cpp \ + adb_utils_test.cpp \ + transport_test.cpp \ + +LIBADB_CFLAGS := \ + -Wall -Werror \ + -Wno-unused-parameter \ + -Wno-missing-field-initializers \ + -fvisibility=hidden \ + +LIBADB_darwin_SRC_FILES := \ + fdevent.cpp \ + get_my_path_darwin.cpp \ + usb_osx.cpp \ + +LIBADB_linux_SRC_FILES := \ + fdevent.cpp \ + get_my_path_linux.cpp \ + usb_linux.cpp \ + +LIBADB_windows_SRC_FILES := \ + get_my_path_windows.cpp \ + sysdeps_win32.cpp \ + usb_windows.cpp \ + +include $(CLEAR_VARS) +LOCAL_CLANG := true +LOCAL_MODULE := libadbd +LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0 +LOCAL_SRC_FILES := \ + $(LIBADB_SRC_FILES) \ + adb_auth_client.cpp \ + fdevent.cpp \ + jdwp_service.cpp \ + qemu_tracing.cpp \ + usb_linux_client.cpp \ + +LOCAL_SHARED_LIBRARIES := libbase + +include $(BUILD_STATIC_LIBRARY) + include $(CLEAR_VARS) +LOCAL_CLANG := $(adb_host_clang) +LOCAL_MODULE := libadb +LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=1 +LOCAL_SRC_FILES := \ + $(LIBADB_SRC_FILES) \ + $(LIBADB_$(HOST_OS)_SRC_FILES) \ + adb_auth_host.cpp \ + +LOCAL_SHARED_LIBRARIES := libbase -# Default to a virtual (sockets) usb interface -USB_SRCS := -EXTRA_SRCS := +# Even though we're building a static library (and thus there's no link step for +# this to take effect), this adds the SSL includes to our path. +LOCAL_STATIC_LIBRARIES := libcrypto_static + +ifeq ($(HOST_OS),windows) + LOCAL_C_INCLUDES += development/host/windows/usb/api/ +endif + +include $(BUILD_HOST_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_CLANG := true +LOCAL_MODULE := adbd_test +LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS) +LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS) +LOCAL_STATIC_LIBRARIES := libadbd +LOCAL_SHARED_LIBRARIES := liblog libbase libcutils +include $(BUILD_NATIVE_TEST) + +include $(CLEAR_VARS) +LOCAL_CLANG := $(adb_host_clang) +LOCAL_MODULE := adb_test +LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS) +LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS) services.cpp +LOCAL_SHARED_LIBRARIES := liblog libbase +LOCAL_STATIC_LIBRARIES := \ + libadb \ + libcrypto_static \ + libcutils \ ifeq ($(HOST_OS),linux) - USB_SRCS := usb_linux.c - EXTRA_SRCS := get_my_path_linux.c LOCAL_LDLIBS += -lrt -ldl -lpthread - LOCAL_CFLAGS += -DWORKAROUND_BUG6558362 endif ifeq ($(HOST_OS),darwin) - USB_SRCS := usb_osx.c - EXTRA_SRCS := get_my_path_darwin.c - LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon + LOCAL_LDLIBS += -framework CoreFoundation -framework IOKit +endif + +include $(BUILD_HOST_NATIVE_TEST) + +# adb host tool +# ========================================================= +include $(CLEAR_VARS) + +ifeq ($(HOST_OS),linux) + LOCAL_LDLIBS += -lrt -ldl -lpthread + LOCAL_CFLAGS += -DWORKAROUND_BUG6558362 endif -ifeq ($(HOST_OS),freebsd) - USB_SRCS := usb_libusb.c - EXTRA_SRCS := get_my_path_freebsd.c - LOCAL_LDLIBS += -lpthread -lusb +ifeq ($(HOST_OS),darwin) + LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon + LOCAL_CFLAGS += -Wno-sizeof-pointer-memaccess -Wno-unused-parameter endif ifeq ($(HOST_OS),windows) - USB_SRCS := usb_windows.c - EXTRA_SRCS := get_my_path_windows.c + LOCAL_LDLIBS += -lws2_32 -lgdi32 EXTRA_STATIC_LIBS := AdbWinApi - ifneq ($(strip $(USE_CYGWIN)),) - # Pure cygwin case - LOCAL_LDLIBS += -lpthread -lgdi32 - endif - ifneq ($(strip $(USE_MINGW)),) - # MinGW under Linux case - LOCAL_LDLIBS += -lws2_32 -lgdi32 - USE_SYSDEPS_WIN32 := 1 - endif - LOCAL_C_INCLUDES += development/host/windows/usb/api/ endif +LOCAL_CLANG := $(adb_host_clang) + LOCAL_SRC_FILES := \ - adb.c \ - console.c \ - transport.c \ - transport_local.c \ - transport_usb.c \ - commandline.c \ - adb_client.c \ - adb_auth_host.c \ - sockets.c \ - services.c \ - file_sync_client.c \ - $(EXTRA_SRCS) \ - $(USB_SRCS) \ - usb_vendors.c - -LOCAL_C_INCLUDES += external/openssl/include - -ifneq ($(USE_SYSDEPS_WIN32),) - LOCAL_SRC_FILES += sysdeps_win32.c -else - LOCAL_SRC_FILES += fdevent.c -endif + adb_main.cpp \ + console.cpp \ + commandline.cpp \ + adb_client.cpp \ + services.cpp \ + file_sync_client.cpp \ + +LOCAL_CFLAGS += \ + -Wall -Werror \ + -Wno-unused-parameter \ + -D_GNU_SOURCE \ + -DADB_HOST=1 \ -LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter -Werror -LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE LOCAL_MODULE := adb LOCAL_MODULE_TAGS := debug -LOCAL_STATIC_LIBRARIES := libzipfile libunz libcrypto_static $(EXTRA_STATIC_LIBS) -ifeq ($(USE_SYSDEPS_WIN32),) - LOCAL_STATIC_LIBRARIES += libcutils +LOCAL_STATIC_LIBRARIES := \ + libadb \ + libbase \ + libcrypto_static \ + libcutils \ + $(EXTRA_STATIC_LIBS) \ + +# libc++ not available on windows yet +ifneq ($(HOST_OS),windows) + LOCAL_CXX_STL := libc++_static endif +# Don't add anything here, we don't want additional shared dependencies +# on the host adb tool, and shared libraries that link against libc++ +# will violate ODR +LOCAL_SHARED_LIBRARIES := + include $(BUILD_HOST_EXECUTABLE) $(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE)) @@ -98,30 +195,28 @@ endif include $(CLEAR_VARS) +LOCAL_CLANG := true + LOCAL_SRC_FILES := \ - adb.c \ - fdevent.c \ - transport.c \ - transport_local.c \ - transport_usb.c \ - adb_auth_client.c \ - sockets.c \ - services.c \ - file_sync_service.c \ - jdwp_service.c \ - framebuffer_service.c \ - remount_service.c \ - disable_verity_service.c \ - usb_linux_client.c - -LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter -Werror -LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE + adb_main.cpp \ + services.cpp \ + file_sync_service.cpp \ + framebuffer_service.cpp \ + remount_service.cpp \ + set_verity_enable_state_service.cpp \ + +LOCAL_CFLAGS := \ + -DADB_HOST=0 \ + -D_GNU_SOURCE \ + -Wall -Werror \ + -Wno-unused-parameter \ + -Wno-deprecated-declarations \ ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1 endif -ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT))) +ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1 endif @@ -130,57 +225,17 @@ LOCAL_MODULE := adbd LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN) LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED) -LOCAL_C_INCLUDES += system/extras/ext4_utils system/core/fs_mgr/include - -LOCAL_STATIC_LIBRARIES := liblog \ - libfs_mgr \ - libcutils \ - libc \ - libmincrypt \ - libselinux \ - libext4_utils_static +LOCAL_C_INCLUDES += system/extras/ext4_utils + +LOCAL_STATIC_LIBRARIES := \ + libadbd \ + libbase \ + libfs_mgr \ + liblog \ + libcutils \ + libc \ + libmincrypt \ + libselinux \ + libext4_utils_static \ include $(BUILD_EXECUTABLE) - - -# adb host tool for device-as-host -# ========================================================= -ifneq ($(SDK_ONLY),true) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - adb.c \ - console.c \ - transport.c \ - transport_local.c \ - transport_usb.c \ - commandline.c \ - adb_client.c \ - adb_auth_host.c \ - sockets.c \ - services.c \ - file_sync_client.c \ - get_my_path_linux.c \ - usb_linux.c \ - usb_vendors.c \ - fdevent.c - -LOCAL_CFLAGS := \ - -O2 \ - -g \ - -DADB_HOST=1 \ - -DADB_HOST_ON_TARGET=1 \ - -Wall -Wno-unused-parameter -Werror \ - -D_XOPEN_SOURCE \ - -D_GNU_SOURCE - -LOCAL_C_INCLUDES += external/openssl/include - -LOCAL_MODULE := adb - -LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils liblog - -LOCAL_SHARED_LIBRARIES := libcrypto - -include $(BUILD_EXECUTABLE) -endif diff --git a/adb/CPPLINT.cfg b/adb/CPPLINT.cfg new file mode 100644 index 0000000..9b906e8 --- /dev/null +++ b/adb/CPPLINT.cfg @@ -0,0 +1,2 @@ +set noparent +filter=-build/header_guard,-build/include,-readability/function @@ -14,35 +14,37 @@ * limitations under the License. */ -#define TRACE_TAG TRACE_ADB +#define TRACE_TAG TRACE_ADB + +#include "sysdeps.h" +#include "adb.h" -#include <stdio.h> -#include <stdlib.h> #include <ctype.h> -#include <stdarg.h> #include <errno.h> +#include <stdarg.h> #include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> #include <string.h> -#include <time.h> #include <sys/time.h> -#include <stdint.h> +#include <time.h> + +#include <string> + +#include <base/stringprintf.h> -#include "sysdeps.h" -#include "adb.h" #include "adb_auth.h" +#include "adb_io.h" +#include "adb_listeners.h" +#include "transport.h" #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #if !ADB_HOST #include <cutils/properties.h> -#include <private/android_filesystem_config.h> #include <sys/capability.h> #include <sys/mount.h> -#include <sys/prctl.h> -#include <getopt.h> -#include <selinux/selinux.h> -#else -#include "usb_vendors.h" #endif #if ADB_TRACE @@ -50,13 +52,9 @@ ADB_MUTEX_DEFINE( D_lock ); #endif int HOST = 0; -int gListenAll = 0; - -static int auth_enabled = 0; #if !ADB_HOST -static const char *adb_device_banner = "device"; -static const char *root_seclabel = NULL; +const char *adb_device_banner = "device"; #endif void fatal(const char *fmt, ...) @@ -81,17 +79,68 @@ void fatal_errno(const char *fmt, ...) exit(-1); } -int adb_trace_mask; +#if !ADB_HOST +void start_device_log(void) { + struct tm now; + time_t t; + tzset(); + time(&t); + localtime_r(&t, &now); -/* read a comma/space/colum/semi-column separated list of tags - * from the ADB_TRACE environment variable and build the trace - * mask from it. note that '1' and 'all' are special cases to - * enable all tracing - */ -void adb_trace_init(void) -{ - const char* p = getenv("ADB_TRACE"); - const char* q; + char timestamp[PATH_MAX]; + strftime(timestamp, sizeof(timestamp), "%Y-%m-%d-%H-%M-%S", &now); + + char path[PATH_MAX]; + snprintf(path, sizeof(path), "/data/adb/adb-%s-%d", timestamp, getpid()); + + int fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0640); + if (fd == -1) { + return; + } + + // redirect stdout and stderr to the log file + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid()); + adb_close(fd); +} +#endif + +int adb_trace_mask; + +std::string get_trace_setting_from_env() { + const char* setting = getenv("ADB_TRACE"); + if (setting == nullptr) { + setting = ""; + } + + return std::string(setting); +} + +#if !ADB_HOST +std::string get_trace_setting_from_prop() { + char buf[PROPERTY_VALUE_MAX]; + property_get("persist.adb.trace_mask", buf, ""); + return std::string(buf); +} +#endif + +std::string get_trace_setting() { +#if ADB_HOST + return get_trace_setting_from_env(); +#else + return get_trace_setting_from_prop(); +#endif +} + +// Split the comma/space/colum/semi-column separated list of tags from the trace +// setting and build the trace mask from it. note that '1' and 'all' are special +// cases to enable all tracing. +// +// adb's trace setting comes from the ADB_TRACE environment variable, whereas +// adbd's comes from the system property persist.adb.trace_mask. +void adb_trace_init() { + const std::string trace_setting = get_trace_setting(); static const struct { const char* tag; @@ -113,25 +162,25 @@ void adb_trace_init(void) { NULL, 0 } }; - if (p == NULL) - return; + if (trace_setting.empty()) { + return; + } - /* use a comma/column/semi-colum/space separated list */ + // Use a comma/colon/semi-colon/space separated list + const char* p = trace_setting.c_str(); while (*p) { int len, tagn; - q = strpbrk(p, " ,:;"); + const char* q = strpbrk(p, " ,:;"); if (q == NULL) { q = p + strlen(p); } len = q - p; - for (tagn = 0; tags[tagn].tag != NULL; tagn++) - { + for (tagn = 0; tags[tagn].tag != NULL; tagn++) { int taglen = strlen(tags[tagn].tag); - if (len == taglen && !memcmp(tags[tagn].tag, p, len) ) - { + if (len == taglen && !memcmp(tags[tagn].tag, p, len)) { int flag = tags[tagn].flag; if (flag == 0) { adb_trace_mask = ~0; @@ -145,65 +194,19 @@ void adb_trace_init(void) if (*p) p++; } -} #if !ADB_HOST -/* - * Implements ADB tracing inside the emulator. - */ - -#include <stdarg.h> - -/* - * Redefine open and write for qemu_pipe.h that contains inlined references - * to those routines. We will redifine them back after qemu_pipe.h inclusion. - */ - -#undef open -#undef write -#define open adb_open -#define write adb_write -#include <hardware/qemu_pipe.h> -#undef open -#undef write -#define open ___xxx_open -#define write ___xxx_write - -/* A handle to adb-debug qemud service in the emulator. */ -int adb_debug_qemu = -1; - -/* Initializes connection with the adb-debug qemud service in the emulator. */ -static int adb_qemu_trace_init(void) -{ - char con_name[32]; - - if (adb_debug_qemu >= 0) { - return 0; - } - - /* adb debugging QEMUD service connection request. */ - snprintf(con_name, sizeof(con_name), "qemud:adb-debug"); - adb_debug_qemu = qemu_pipe_open(con_name); - return (adb_debug_qemu >= 0) ? 0 : -1; + start_device_log(); +#endif } -void adb_qemu_trace(const char* fmt, ...) +apacket* get_apacket(void) { - va_list args; - va_start(args, fmt); - char msg[1024]; - - if (adb_debug_qemu >= 0) { - vsnprintf(msg, sizeof(msg), fmt, args); - adb_write(adb_debug_qemu, msg, strlen(msg)); + apacket* p = reinterpret_cast<apacket*>(malloc(sizeof(apacket))); + if (p == nullptr) { + fatal("failed to allocate an apacket"); } -} -#endif /* !ADB_HOST */ -apacket *get_apacket(void) -{ - apacket *p = malloc(sizeof(apacket)); - if(p == 0) fatal("failed to allocate an apacket"); memset(p, 0, sizeof(apacket) - MAX_PAYLOAD); return p; } @@ -324,21 +327,23 @@ static void send_msg_with_header(int fd, const char* msg, size_t msglen) { if (msglen > 0xffff) msglen = 0xffff; snprintf(header, sizeof(header), "%04x", (unsigned)msglen); - writex(fd, header, 4); - writex(fd, msg, msglen); + WriteFdExactly(fd, header, 4); + WriteFdExactly(fd, msg, msglen); } #endif +#if ADB_HOST static void send_msg_with_okay(int fd, const char* msg, size_t msglen) { char header[9]; if (msglen > 0xffff) msglen = 0xffff; snprintf(header, sizeof(header), "OKAY%04x", (unsigned)msglen); - writex(fd, header, 8); - writex(fd, msg, msglen); + WriteFdExactly(fd, header, 8); + WriteFdExactly(fd, msg, msglen); } +#endif // ADB_HOST -static void send_connect(atransport *t) +void send_connect(atransport *t) { D("Calling send_connect \n"); apacket *cp = get_apacket(); @@ -350,71 +355,8 @@ static void send_connect(atransport *t) send_packet(cp, t); } -void send_auth_request(atransport *t) -{ - D("Calling send_auth_request\n"); - apacket *p; - int ret; - - ret = adb_auth_generate_token(t->token, sizeof(t->token)); - if (ret != sizeof(t->token)) { - D("Error generating token ret=%d\n", ret); - return; - } - - p = get_apacket(); - memcpy(p->data, t->token, ret); - p->msg.command = A_AUTH; - p->msg.arg0 = ADB_AUTH_TOKEN; - p->msg.data_length = ret; - send_packet(p, t); -} - -static void send_auth_response(uint8_t *token, size_t token_size, atransport *t) -{ - D("Calling send_auth_response\n"); - apacket *p = get_apacket(); - int ret; - - ret = adb_auth_sign(t->key, token, token_size, p->data); - if (!ret) { - D("Error signing the token\n"); - put_apacket(p); - return; - } - - p->msg.command = A_AUTH; - p->msg.arg0 = ADB_AUTH_SIGNATURE; - p->msg.data_length = ret; - send_packet(p, t); -} - -static void send_auth_publickey(atransport *t) -{ - D("Calling send_auth_publickey\n"); - apacket *p = get_apacket(); - int ret; - - ret = adb_auth_get_userkey(p->data, sizeof(p->data)); - if (!ret) { - D("Failed to get user public key\n"); - put_apacket(p); - return; - } - - p->msg.command = A_AUTH; - p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY; - p->msg.data_length = ret; - send_packet(p, t); -} - -void adb_auth_verified(atransport *t) -{ - handle_online(t); - send_connect(t); -} - -static char *connection_state_name(atransport *t) +#if ADB_HOST +static const char* connection_state_name(atransport *t) { if (t == NULL) { return "unknown"; @@ -437,6 +379,7 @@ static char *connection_state_name(atransport *t) return "unknown"; } } +#endif // ADB_HOST /* qual_overwrite is used to overwrite a qualifier string. dst is a * pointer to a char pointer. It is assumed that if *dst is non-NULL, it @@ -664,409 +607,11 @@ void handle_packet(apacket *p, atransport *t) put_apacket(p); } -alistener listener_list = { - .next = &listener_list, - .prev = &listener_list, -}; - -static void ss_listener_event_func(int _fd, unsigned ev, void *_l) -{ - asocket *s; - - if(ev & FDE_READ) { - struct sockaddr addr; - socklen_t alen; - int fd; - - alen = sizeof(addr); - fd = adb_socket_accept(_fd, &addr, &alen); - if(fd < 0) return; - - adb_socket_setbufsize(fd, CHUNK_SIZE); - - s = create_local_socket(fd); - if(s) { - connect_to_smartsocket(s); - return; - } - - adb_close(fd); - } -} - -static void listener_event_func(int _fd, unsigned ev, void *_l) -{ - alistener *l = _l; - asocket *s; - - if(ev & FDE_READ) { - struct sockaddr addr; - socklen_t alen; - int fd; - - alen = sizeof(addr); - fd = adb_socket_accept(_fd, &addr, &alen); - if(fd < 0) return; - - s = create_local_socket(fd); - if(s) { - s->transport = l->transport; - connect_to_remote(s, l->connect_to); - return; - } - - adb_close(fd); - } -} - -static void free_listener(alistener* l) -{ - if (l->next) { - l->next->prev = l->prev; - l->prev->next = l->next; - l->next = l->prev = l; - } - - // closes the corresponding fd - fdevent_remove(&l->fde); - - if (l->local_name) - free((char*)l->local_name); - - if (l->connect_to) - free((char*)l->connect_to); - - if (l->transport) { - remove_transport_disconnect(l->transport, &l->disconnect); - } - free(l); -} - -static void listener_disconnect(void* _l, atransport* t) -{ - alistener* l = _l; - - free_listener(l); -} - -int local_name_to_fd(const char *name) -{ - int port; - - if(!strncmp("tcp:", name, 4)){ - int ret; - port = atoi(name + 4); - - if (gListenAll > 0) { - ret = socket_inaddr_any_server(port, SOCK_STREAM); - } else { - ret = socket_loopback_server(port, SOCK_STREAM); - } - - return ret; - } -#ifndef HAVE_WIN32_IPC /* no Unix-domain sockets on Win32 */ - // It's non-sensical to support the "reserved" space on the adb host side - if(!strncmp(name, "local:", 6)) { - return socket_local_server(name + 6, - ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); - } else if(!strncmp(name, "localabstract:", 14)) { - return socket_local_server(name + 14, - ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); - } else if(!strncmp(name, "localfilesystem:", 16)) { - return socket_local_server(name + 16, - ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); - } - -#endif - printf("unknown local portname '%s'\n", name); - return -1; -} - -// Write a single line describing a listener to a user-provided buffer. -// Appends a trailing zero, even in case of truncation, but the function -// returns the full line length. -// If |buffer| is NULL, does not write but returns required size. -static int format_listener(alistener* l, char* buffer, size_t buffer_len) { - // Format is simply: - // - // <device-serial> " " <local-name> " " <remote-name> "\n" - // - int local_len = strlen(l->local_name); - int connect_len = strlen(l->connect_to); - int serial_len = strlen(l->transport->serial); - - if (buffer != NULL) { - snprintf(buffer, buffer_len, "%s %s %s\n", - l->transport->serial, l->local_name, l->connect_to); - } - // NOTE: snprintf() on Windows returns -1 in case of truncation, so - // return the computed line length instead. - return local_len + connect_len + serial_len + 3; -} - -// Write the list of current listeners (network redirections) into a -// user-provided buffer. Appends a trailing zero, even in case of -// trunctaion, but return the full size in bytes. -// If |buffer| is NULL, does not write but returns required size. -static int format_listeners(char* buf, size_t buflen) -{ - alistener* l; - int result = 0; - for (l = listener_list.next; l != &listener_list; l = l->next) { - // Ignore special listeners like those for *smartsocket* - if (l->connect_to[0] == '*') - continue; - int len = format_listener(l, buf, buflen); - // Ensure there is space for the trailing zero. - result += len; - if (buf != NULL) { - buf += len; - buflen -= len; - if (buflen <= 0) - break; - } - } - return result; -} - -static int remove_listener(const char *local_name, atransport* transport) -{ - alistener *l; - - for (l = listener_list.next; l != &listener_list; l = l->next) { - if (!strcmp(local_name, l->local_name)) { - listener_disconnect(l, l->transport); - return 0; - } - } - return -1; -} - -static void remove_all_listeners(void) -{ - alistener *l, *l_next; - for (l = listener_list.next; l != &listener_list; l = l_next) { - l_next = l->next; - // Never remove smart sockets. - if (l->connect_to[0] == '*') - continue; - listener_disconnect(l, l->transport); - } -} - -// error/status codes for install_listener. -typedef enum { - INSTALL_STATUS_OK = 0, - INSTALL_STATUS_INTERNAL_ERROR = -1, - INSTALL_STATUS_CANNOT_BIND = -2, - INSTALL_STATUS_CANNOT_REBIND = -3, -} install_status_t; - -static install_status_t install_listener(const char *local_name, - const char *connect_to, - atransport* transport, - int no_rebind) -{ - alistener *l; - - //printf("install_listener('%s','%s')\n", local_name, connect_to); - - for(l = listener_list.next; l != &listener_list; l = l->next){ - if(strcmp(local_name, l->local_name) == 0) { - char *cto; - - /* can't repurpose a smartsocket */ - if(l->connect_to[0] == '*') { - return INSTALL_STATUS_INTERNAL_ERROR; - } - - /* can't repurpose a listener if 'no_rebind' is true */ - if (no_rebind) { - return INSTALL_STATUS_CANNOT_REBIND; - } - - cto = strdup(connect_to); - if(cto == 0) { - return INSTALL_STATUS_INTERNAL_ERROR; - } - - //printf("rebinding '%s' to '%s'\n", local_name, connect_to); - free((void*) l->connect_to); - l->connect_to = cto; - if (l->transport != transport) { - remove_transport_disconnect(l->transport, &l->disconnect); - l->transport = transport; - add_transport_disconnect(l->transport, &l->disconnect); - } - return INSTALL_STATUS_OK; - } - } - - if((l = calloc(1, sizeof(alistener))) == 0) goto nomem; - if((l->local_name = strdup(local_name)) == 0) goto nomem; - if((l->connect_to = strdup(connect_to)) == 0) goto nomem; - - - l->fd = local_name_to_fd(local_name); - if(l->fd < 0) { - free((void*) l->local_name); - free((void*) l->connect_to); - free(l); - printf("cannot bind '%s'\n", local_name); - return -2; - } - - close_on_exec(l->fd); - if(!strcmp(l->connect_to, "*smartsocket*")) { - fdevent_install(&l->fde, l->fd, ss_listener_event_func, l); - } else { - fdevent_install(&l->fde, l->fd, listener_event_func, l); - } - fdevent_set(&l->fde, FDE_READ); - - l->next = &listener_list; - l->prev = listener_list.prev; - l->next->prev = l; - l->prev->next = l; - l->transport = transport; - - if (transport) { - l->disconnect.opaque = l; - l->disconnect.func = listener_disconnect; - add_transport_disconnect(transport, &l->disconnect); - } - return INSTALL_STATUS_OK; - -nomem: - fatal("cannot allocate listener"); - return INSTALL_STATUS_INTERNAL_ERROR; -} - -#ifdef HAVE_WIN32_PROC -static BOOL WINAPI ctrlc_handler(DWORD type) -{ - exit(STATUS_CONTROL_C_EXIT); - return TRUE; -} -#endif - -static void adb_cleanup(void) -{ - usb_cleanup(); -} - -void start_logging(void) -{ -#ifdef HAVE_WIN32_PROC - char temp[ MAX_PATH ]; - FILE* fnul; - FILE* flog; - - GetTempPath( sizeof(temp) - 8, temp ); - strcat( temp, "adb.log" ); - - /* Win32 specific redirections */ - fnul = fopen( "NUL", "rt" ); - if (fnul != NULL) - stdin[0] = fnul[0]; - - flog = fopen( temp, "at" ); - if (flog == NULL) - flog = fnul; - - setvbuf( flog, NULL, _IONBF, 0 ); - - stdout[0] = flog[0]; - stderr[0] = flog[0]; - fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); -#else - int fd; - - fd = unix_open("/dev/null", O_RDONLY); - dup2(fd, 0); - adb_close(fd); - - fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640); - if(fd < 0) { - fd = unix_open("/dev/null", O_WRONLY); - } - dup2(fd, 1); - dup2(fd, 2); - adb_close(fd); - fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); -#endif -} - -#if !ADB_HOST -void start_device_log(void) -{ - int fd; - char path[PATH_MAX]; - struct tm now; - time_t t; - char value[PROPERTY_VALUE_MAX]; - - // read the trace mask from persistent property persist.adb.trace_mask - // give up if the property is not set or cannot be parsed - property_get("persist.adb.trace_mask", value, ""); - if (sscanf(value, "%x", &adb_trace_mask) != 1) - return; - - adb_mkdir("/data/adb", 0775); - tzset(); - time(&t); - localtime_r(&t, &now); - strftime(path, sizeof(path), - "/data/adb/adb-%Y-%m-%d-%H-%M-%S.txt", - &now); - fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640); - if (fd < 0) - return; - - // redirect stdout and stderr to the log file - dup2(fd, 1); - dup2(fd, 2); - fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); - adb_close(fd); - - fd = unix_open("/dev/null", O_RDONLY); - dup2(fd, 0); - adb_close(fd); -} -#endif - #if ADB_HOST -#ifdef WORKAROUND_BUG6558362 -#include <sched.h> -#define AFFINITY_ENVVAR "ADB_CPU_AFFINITY_BUG6558362" -void adb_set_affinity(void) -{ - cpu_set_t cpu_set; - const char* cpunum_str = getenv(AFFINITY_ENVVAR); - char* strtol_res; - int cpu_num; - - if (!cpunum_str || !*cpunum_str) - return; - cpu_num = strtol(cpunum_str, &strtol_res, 0); - if (*strtol_res != '\0') - fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str, AFFINITY_ENVVAR); - - sched_getaffinity(0, sizeof(cpu_set), &cpu_set); - D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]); - CPU_ZERO(&cpu_set); - CPU_SET(cpu_num, &cpu_set); - sched_setaffinity(0, sizeof(cpu_set), &cpu_set); - sched_getaffinity(0, sizeof(cpu_set), &cpu_set); - D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]); -} -#endif - int launch_server(int server_port) { -#ifdef HAVE_WIN32_PROC +#if defined(_WIN32) /* we need to start the server in the background */ /* we create a PIPE that will be used to wait for the server's "OK" */ /* message since the pipe handles must be inheritable, we use a */ @@ -1123,10 +668,11 @@ int launch_server(int server_port) /* get path of current program */ GetModuleFileName( NULL, program_path, sizeof(program_path) ); - + char args[64]; + snprintf(args, sizeof(args), "adb -P %d fork-server server", server_port); ret = CreateProcess( program_path, /* program path */ - "adb fork-server server", + args, /* the fork-server argument will set the debug = 2 in the child */ NULL, /* process handle is not inheritable */ @@ -1165,7 +711,7 @@ int launch_server(int server_port) return -1; } } -#elif defined(HAVE_FORKEXEC) +#else /* !defined(_WIN32) */ char path[PATH_MAX]; int fd[2]; @@ -1216,227 +762,10 @@ int launch_server(int server_port) setsid(); } -#else -#error "cannot implement background server start on this platform" -#endif - return 0; -} -#endif - -/* Constructs a local name of form tcp:port. - * target_str points to the target string, it's content will be overwritten. - * target_size is the capacity of the target string. - * server_port is the port number to use for the local name. - */ -void build_local_name(char* target_str, size_t target_size, int server_port) -{ - snprintf(target_str, target_size, "tcp:%d", server_port); -} - -#if !ADB_HOST - -static void drop_capabilities_bounding_set_if_needed() { -#ifdef ALLOW_ADBD_ROOT - char value[PROPERTY_VALUE_MAX]; - property_get("ro.debuggable", value, ""); - if (strcmp(value, "1") == 0) { - return; - } -#endif - int i; - for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) { - if (i == CAP_SETUID || i == CAP_SETGID) { - // CAP_SETUID CAP_SETGID needed by /system/bin/run-as - continue; - } - int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0); - - // Some kernels don't have file capabilities compiled in, and - // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically - // die when we see such misconfigured kernels. - if ((err < 0) && (errno != EINVAL)) { - exit(1); - } - } -} - -static int should_drop_privileges() { -#ifndef ALLOW_ADBD_ROOT - return 1; -#else /* ALLOW_ADBD_ROOT */ - int secure = 0; - char value[PROPERTY_VALUE_MAX]; - - /* run adbd in secure mode if ro.secure is set and - ** we are not in the emulator - */ - property_get("ro.kernel.qemu", value, ""); - if (strcmp(value, "1") != 0) { - property_get("ro.secure", value, "1"); - if (strcmp(value, "1") == 0) { - // don't run as root if ro.secure is set... - secure = 1; - - // ... except we allow running as root in userdebug builds if the - // service.adb.root property has been set by the "adb root" command - property_get("ro.debuggable", value, ""); - if (strcmp(value, "1") == 0) { - property_get("service.adb.root", value, ""); - if (strcmp(value, "1") == 0) { - secure = 0; - } - } - } - } - return secure; -#endif /* ALLOW_ADBD_ROOT */ -} -#endif /* !ADB_HOST */ - -int adb_main(int is_daemon, int server_port) -{ -#if !ADB_HOST - int port; - char value[PROPERTY_VALUE_MAX]; - - umask(000); -#endif - - atexit(adb_cleanup); -#ifdef HAVE_WIN32_PROC - SetConsoleCtrlHandler( ctrlc_handler, TRUE ); -#elif defined(HAVE_FORKEXEC) - // No SIGCHLD. Let the service subproc handle its children. - signal(SIGPIPE, SIG_IGN); -#endif - - init_transport_registration(); - -#if ADB_HOST - HOST = 1; - -#ifdef WORKAROUND_BUG6558362 - if(is_daemon) adb_set_affinity(); -#endif - usb_vendors_init(); - usb_init(); - local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); - adb_auth_init(); - - char local_name[30]; - build_local_name(local_name, sizeof(local_name), server_port); - if(install_listener(local_name, "*smartsocket*", NULL, 0)) { - exit(1); - } -#else - property_get("ro.adb.secure", value, "0"); - auth_enabled = !strcmp(value, "1"); - if (auth_enabled) - adb_auth_init(); - - // Our external storage path may be different than apps, since - // we aren't able to bind mount after dropping root. - const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE"); - if (NULL != adb_external_storage) { - setenv("EXTERNAL_STORAGE", adb_external_storage, 1); - } else { - D("Warning: ADB_EXTERNAL_STORAGE is not set. Leaving EXTERNAL_STORAGE" - " unchanged.\n"); - } - - /* add extra groups: - ** AID_ADB to access the USB driver - ** AID_LOG to read system logs (adb logcat) - ** AID_INPUT to diagnose input issues (getevent) - ** AID_INET to diagnose network issues (netcfg, ping) - ** AID_GRAPHICS to access the frame buffer - ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump) - ** AID_SDCARD_R to allow reading from the SD card - ** AID_SDCARD_RW to allow writing to the SD card - ** AID_NET_BW_STATS to read out qtaguid statistics - */ - gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS, - AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW, - AID_NET_BW_STATS }; - if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { - exit(1); - } - - /* don't listen on a port (default 5037) if running in secure mode */ - /* don't run as root if we are running in secure mode */ - if (should_drop_privileges()) { - drop_capabilities_bounding_set_if_needed(); - - /* then switch user and group to "shell" */ - if (setgid(AID_SHELL) != 0) { - exit(1); - } - if (setuid(AID_SHELL) != 0) { - exit(1); - } - - D("Local port disabled\n"); - } else { - char local_name[30]; - if ((root_seclabel != NULL) && (is_selinux_enabled() > 0)) { - // b/12587913: fix setcon to allow const pointers - if (setcon((char *)root_seclabel) < 0) { - exit(1); - } - } - build_local_name(local_name, sizeof(local_name), server_port); - if(install_listener(local_name, "*smartsocket*", NULL, 0)) { - exit(1); - } - } - - int usb = 0; - if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) { - // listen on USB - usb_init(); - usb = 1; - } - - // If one of these properties is set, also listen on that port - // If one of the properties isn't set and we couldn't listen on usb, - // listen on the default port. - property_get("service.adb.tcp.port", value, ""); - if (!value[0]) { - property_get("persist.adb.tcp.port", value, ""); - } - if (sscanf(value, "%d", &port) == 1 && port > 0) { - printf("using port=%d\n", port); - // listen on TCP port specified by service.adb.tcp.port property - local_init(port); - } else if (!usb) { - // listen on default port - local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); - } - - D("adb_main(): pre init_jdwp()\n"); - init_jdwp(); - D("adb_main(): post init_jdwp()\n"); -#endif - - if (is_daemon) - { - // inform our parent that we are up and running. -#ifdef HAVE_WIN32_PROC - DWORD count; - WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL ); -#elif defined(HAVE_FORKEXEC) - fprintf(stderr, "OK\n"); -#endif - start_logging(); - } - D("Event loop starting\n"); - - fdevent_loop(); - - usb_cleanup(); - +#endif /* !defined(_WIN32) */ return 0; } +#endif /* ADB_HOST */ // Try to handle a network forwarding request. // This returns 1 on success, 0 on failure, and -1 to indicate this is not @@ -1447,8 +776,8 @@ int handle_forward_request(const char* service, transport_type ttype, char* seri // Create the list of forward redirections. int buffer_size = format_listeners(NULL, 0); // Add one byte for the trailing zero. - char* buffer = malloc(buffer_size + 1); - if (buffer == NULL) { + char* buffer = reinterpret_cast<char*>(malloc(buffer_size + 1)); + if (buffer == nullptr) { sendfailmsg(reply_fd, "not enough memory"); return 1; } @@ -1474,8 +803,7 @@ int handle_forward_request(const char* service, transport_type ttype, char* seri if (!strncmp(service, "forward:",8) || !strncmp(service, "killforward:",12)) { - char *local, *remote, *err; - int r; + char *local, *remote; atransport *transport; int createForward = strncmp(service, "kill", 4); @@ -1511,42 +839,41 @@ int handle_forward_request(const char* service, transport_type ttype, char* seri } } - transport = acquire_one_transport(CS_ANY, ttype, serial, &err); + std::string error_msg; + transport = acquire_one_transport(CS_ANY, ttype, serial, &error_msg); if (!transport) { - sendfailmsg(reply_fd, err); + sendfailmsg(reply_fd, error_msg.c_str()); return 1; } + install_status_t r; if (createForward) { r = install_listener(local, remote, transport, no_rebind); } else { r = remove_listener(local, transport); } - if(r == 0) { + if (r == INSTALL_STATUS_OK) { #if ADB_HOST /* On the host: 1st OKAY is connect, 2nd OKAY is status */ - writex(reply_fd, "OKAY", 4); + WriteFdExactly(reply_fd, "OKAY", 4); #endif - writex(reply_fd, "OKAY", 4); + WriteFdExactly(reply_fd, "OKAY", 4); return 1; } - if (createForward) { - const char* message; - switch (r) { - case INSTALL_STATUS_CANNOT_BIND: - message = "cannot bind to socket"; - break; - case INSTALL_STATUS_CANNOT_REBIND: - message = "cannot rebind existing socket"; - break; - default: - message = "internal error"; - } - sendfailmsg(reply_fd, message); - } else { - sendfailmsg(reply_fd, "cannot remove listener"); + std::string message; + switch (r) { + case INSTALL_STATUS_OK: message = " "; break; + case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break; + case INSTALL_STATUS_CANNOT_BIND: + message = android::base::StringPrintf("cannot bind to socket: %s", strerror(errno)); + break; + case INSTALL_STATUS_CANNOT_REBIND: + message = android::base::StringPrintf("cannot rebind existing socket: %s", strerror(errno)); + break; + case INSTALL_STATUS_LISTENER_NOT_FOUND: message = "listener not found"; break; } + sendfailmsg(reply_fd, message.c_str()); return 1; } return 0; @@ -1554,8 +881,6 @@ int handle_forward_request(const char* service, transport_type ttype, char* seri int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s) { - atransport *transport = NULL; - if(!strcmp(service, "kill")) { fprintf(stderr,"adb server killed by remote request\n"); fflush(stdout); @@ -1565,12 +890,12 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r } #if ADB_HOST + atransport *transport = NULL; // "transport:" is used for switching transport with a specified serial number // "transport-usb:" is used for switching transport to the only USB transport // "transport-local:" is used for switching transport to the only local transport // "transport-any:" is used for switching transport to the only transport if (!strncmp(service, "transport", strlen("transport"))) { - char* error_string = "unknown failure"; transport_type type = kTransportAny; if (!strncmp(service, "transport-usb", strlen("transport-usb"))) { @@ -1584,13 +909,14 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r serial = service; } - transport = acquire_one_transport(CS_ANY, type, serial, &error_string); + std::string error_msg = "unknown failure"; + transport = acquire_one_transport(CS_ANY, type, serial, &error_msg); if (transport) { s->transport = transport; adb_write(reply_fd, "OKAY", 4); } else { - sendfailmsg(reply_fd, error_string); + sendfailmsg(reply_fd, error_msg.c_str()); } return 1; } @@ -1646,18 +972,18 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r } if(!strncmp(service,"get-serialno",strlen("get-serialno"))) { - char *out = "unknown"; - transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); - if (transport && transport->serial) { + const char *out = "unknown"; + transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); + if (transport && transport->serial) { out = transport->serial; } send_msg_with_okay(reply_fd, out, strlen(out)); return 0; } if(!strncmp(service,"get-devpath",strlen("get-devpath"))) { - char *out = "unknown"; - transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); - if (transport && transport->devpath) { + const char *out = "unknown"; + transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); + if (transport && transport->devpath) { out = transport->devpath; } send_msg_with_okay(reply_fd, out, strlen(out)); @@ -1673,7 +999,7 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r if(!strncmp(service,"get-state",strlen("get-state"))) { transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); - char *state = connection_state_name(transport); + const char *state = connection_state_name(transport); send_msg_with_okay(reply_fd, state, strlen(state)); return 0; } @@ -1684,42 +1010,3 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r return ret - 1; return -1; } - -int main(int argc, char **argv) -{ -#if ADB_HOST - adb_sysdeps_init(); - adb_trace_init(); - D("Handling commandline()\n"); - return adb_commandline(argc - 1, argv + 1); -#else - /* If adbd runs inside the emulator this will enable adb tracing via - * adb-debug qemud service in the emulator. */ - adb_qemu_trace_init(); - while(1) { - int c; - int option_index = 0; - static struct option opts[] = { - {"root_seclabel", required_argument, 0, 's' }, - {"device_banner", required_argument, 0, 'b' } - }; - c = getopt_long(argc, argv, "", opts, &option_index); - if (c == -1) - break; - switch (c) { - case 's': - root_seclabel = optarg; - break; - case 'b': - adb_device_banner = optarg; - break; - default: - break; - } - } - - start_device_log(); - D("Handling main()\n"); - return adb_main(0, DEFAULT_ADB_PORT); -#endif -} @@ -18,9 +18,10 @@ #define __ADB_H #include <limits.h> +#include <sys/types.h> #include "adb_trace.h" -#include "transport.h" /* readx(), writex() */ +#include "fdevent.h" #define MAX_PAYLOAD 4096 @@ -32,21 +33,18 @@ #define A_WRTE 0x45545257 #define A_AUTH 0x48545541 -#define A_VERSION 0x01000000 // ADB protocol version +// ADB protocol version. +#define A_VERSION 0x01000000 -#define ADB_VERSION_MAJOR 1 // Used for help/version information -#define ADB_VERSION_MINOR 0 // Used for help/version information +// Used for help/version information. +#define ADB_VERSION_MAJOR 1 +#define ADB_VERSION_MINOR 0 -#define ADB_SERVER_VERSION 32 // Increment this when we want to force users to start a new adb server +// Increment this when we want to force users to start a new adb server. +#define ADB_SERVER_VERSION 32 -typedef struct amessage amessage; -typedef struct apacket apacket; -typedef struct asocket asocket; -typedef struct alistener alistener; -typedef struct aservice aservice; -typedef struct atransport atransport; -typedef struct adisconnect adisconnect; -typedef struct usb_handle usb_handle; +struct atransport; +struct usb_handle; struct amessage { unsigned command; /* command identifier constant */ @@ -163,12 +161,12 @@ struct adisconnect ** object, it's a special value used to indicate that a client wants to ** connect to a service implemented within the ADB server itself. */ -typedef enum transport_type { +enum transport_type { kTransportUsb, kTransportLocal, kTransportAny, kTransportHost, -} transport_type; +}; #define TOKEN_SIZE 20 @@ -231,8 +229,8 @@ struct alistener fdevent fde; int fd; - const char *local_name; - const char *connect_to; + char *local_name; + char *connect_to; atransport *transport; adisconnect disconnect; }; @@ -258,33 +256,11 @@ void fatal(const char *fmt, ...); void fatal_errno(const char *fmt, ...); void handle_packet(apacket *p, atransport *t); -void send_packet(apacket *p, atransport *t); void get_my_path(char *s, size_t maxLen); int launch_server(int server_port); int adb_main(int is_daemon, int server_port); - -/* transports are ref-counted -** get_device_transport does an acquire on your behalf before returning -*/ -void init_transport_registration(void); -int list_transports(char *buf, size_t bufsize, int long_listing); -void update_transports(void); - -asocket* create_device_tracker(void); - -/* Obtain a transport from the available transports. -** If state is != CS_ANY, only transports in that state are considered. -** If serial is non-NULL then only the device with that serial will be chosen. -** If no suitable transport is found, error is set. -*/ -atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out); -void add_transport_disconnect( atransport* t, adisconnect* dis ); -void remove_transport_disconnect( atransport* t, adisconnect* dis ); -void run_transport_disconnects( atransport* t ); -void kick_transport( atransport* t ); - /* initialize a transport object's func pointers and state */ #if ADB_HOST int get_available_local_transport_index(); @@ -292,22 +268,6 @@ int get_available_local_transport_index(); int init_socket_transport(atransport *t, int s, int port, int local); void init_usb_transport(atransport *t, usb_handle *usb, int state); -/* for MacOS X cleanup */ -void close_usb_devices(); - -/* cause new transports to be init'd and added to the list */ -int register_socket_transport(int s, const char *serial, int port, int local); - -/* these should only be used for the "adb disconnect" command */ -void unregister_transport(atransport *t); -void unregister_all_tcp_transports(); - -void register_usb_transport(usb_handle *h, const char *serial, const char *devpath, unsigned writeable); - -/* this should only be used for transports with connection_state == CS_NOPERM */ -void unregister_usb_transport(usb_handle *usb); - -atransport *find_transport(const char *serial); #if ADB_HOST atransport* find_emulator_transport_by_adb_port(int adb_port); #endif @@ -328,16 +288,15 @@ int handle_forward_request(const char* service, transport_type ttype, char* seri #if !ADB_HOST void framebuffer_service(int fd, void *cookie); -void remount_service(int fd, void *cookie); -void disable_verity_service(int fd, void* cookie); +void set_verity_enabled_state_service(int fd, void* cookie); #endif /* packet allocator */ apacket *get_apacket(void); void put_apacket(apacket *p); -int check_header(apacket *p); -int check_data(apacket *p); +// Define it if you want to dump packets. +#define DEBUG_PACKETS 0 #if !DEBUG_PACKETS #define print_packet(tag,p) do {} while (0) @@ -376,8 +335,7 @@ void usb_kick(usb_handle *h); int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol); #endif -unsigned host_to_le32(unsigned n); -int adb_commandline(int argc, char **argv); +int adb_commandline(int argc, const char **argv); int connection_state(atransport *t); @@ -391,13 +349,14 @@ int connection_state(atransport *t); #define CS_SIDELOAD 6 #define CS_UNAUTHORIZED 7 +extern const char *adb_device_banner; extern int HOST; extern int SHELL_EXIT_NOTIFY_FD; -typedef enum { +enum subproc_mode { SUBPROC_PTY = 0, SUBPROC_RAW = 1, -} subproc_mode; +} ; #define CHUNK_SIZE (64*1024) @@ -415,4 +374,9 @@ typedef enum { int sendfailmsg(int fd, const char *reason); int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s); +void handle_online(atransport *t); +void handle_offline(atransport *t); + +void send_connect(atransport *t); + #endif diff --git a/adb/adb_auth.cpp b/adb/adb_auth.cpp new file mode 100644 index 0000000..dc01825 --- /dev/null +++ b/adb/adb_auth.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2015 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 TRACE_TAG TRACE_ADB + +#include "sysdeps.h" +#include "adb_auth.h" + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +#include "adb.h" +#include "transport.h" + +int auth_enabled = 0; + +void send_auth_request(atransport *t) +{ + D("Calling send_auth_request\n"); + apacket *p; + int ret; + + ret = adb_auth_generate_token(t->token, sizeof(t->token)); + if (ret != sizeof(t->token)) { + D("Error generating token ret=%d\n", ret); + return; + } + + p = get_apacket(); + memcpy(p->data, t->token, ret); + p->msg.command = A_AUTH; + p->msg.arg0 = ADB_AUTH_TOKEN; + p->msg.data_length = ret; + send_packet(p, t); +} + +void send_auth_response(uint8_t *token, size_t token_size, atransport *t) +{ + D("Calling send_auth_response\n"); + apacket *p = get_apacket(); + int ret; + + ret = adb_auth_sign(t->key, token, token_size, p->data); + if (!ret) { + D("Error signing the token\n"); + put_apacket(p); + return; + } + + p->msg.command = A_AUTH; + p->msg.arg0 = ADB_AUTH_SIGNATURE; + p->msg.data_length = ret; + send_packet(p, t); +} + +void send_auth_publickey(atransport *t) +{ + D("Calling send_auth_publickey\n"); + apacket *p = get_apacket(); + int ret; + + ret = adb_auth_get_userkey(p->data, sizeof(p->data)); + if (!ret) { + D("Failed to get user public key\n"); + put_apacket(p); + return; + } + + p->msg.command = A_AUTH; + p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY; + p->msg.data_length = ret; + send_packet(p, t); +} + +void adb_auth_verified(atransport *t) +{ + handle_online(t); + send_connect(t); +} diff --git a/adb/adb_auth.h b/adb/adb_auth.h index 54dd537..1e1978d 100644 --- a/adb/adb_auth.h +++ b/adb/adb_auth.h @@ -17,11 +17,16 @@ #ifndef __ADB_AUTH_H #define __ADB_AUTH_H -void adb_auth_init(void); +#include "adb.h" + +extern int auth_enabled; + int adb_auth_keygen(const char* filename); void adb_auth_verified(atransport *t); void send_auth_request(atransport *t); +void send_auth_response(uint8_t *token, size_t token_size, atransport *t); +void send_auth_publickey(atransport *t); /* AUTH packets first argument */ /* Request */ @@ -32,7 +37,9 @@ void send_auth_request(atransport *t); #if ADB_HOST -int adb_auth_sign(void *key, void *token, size_t token_size, void *sig); +void adb_auth_init(void); +int adb_auth_sign(void *key, const unsigned char* token, size_t token_size, + unsigned char* sig); void *adb_auth_nextkey(void *current); int adb_auth_get_userkey(unsigned char *data, size_t len); @@ -42,12 +49,17 @@ static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransp #else // !ADB_HOST -static inline int adb_auth_sign(void* key, void *token, size_t token_size, void *sig) { return 0; } +static inline int adb_auth_sign(void* key, const unsigned char* token, + size_t token_size, unsigned char* sig) { + return 0; +} static inline void *adb_auth_nextkey(void *current) { return NULL; } static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return 0; } +void adbd_auth_init(void); +void adbd_cloexec_auth_socket(); int adb_auth_generate_token(void *token, size_t token_size); -int adb_auth_verify(void *token, void *sig, int siglen); +int adb_auth_verify(uint8_t* token, uint8_t* sig, int siglen); void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t); #endif // ADB_HOST diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.cpp index 55e9dca..8e7d38b 100644 --- a/adb/adb_auth_client.c +++ b/adb/adb_auth_client.cpp @@ -14,28 +14,30 @@ * limitations under the License. */ -#include <stdio.h> -#include <string.h> -#include <resolv.h> -#include <cutils/list.h> -#include <cutils/sockets.h> +#define TRACE_TAG TRACE_AUTH #include "sysdeps.h" -#include "adb.h" #include "adb_auth.h" -#include "fdevent.h" + +#include <resolv.h> +#include <stdio.h> +#include <string.h> + +#include "cutils/list.h" +#include "cutils/sockets.h" #include "mincrypt/rsa.h" #include "mincrypt/sha.h" -#define TRACE_TAG TRACE_AUTH - +#include "adb.h" +#include "fdevent.h" +#include "transport.h" struct adb_public_key { struct listnode node; RSAPublicKey key; }; -static char *key_paths[] = { +static const char *key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", NULL @@ -51,7 +53,6 @@ static bool needs_retry = false; static void read_keys(const char *file, struct listnode *list) { - struct adb_public_key *key; FILE *f; char buf[MAX_PAYLOAD]; char *sep; @@ -65,8 +66,9 @@ static void read_keys(const char *file, struct listnode *list) while (fgets(buf, sizeof(buf), f)) { /* Allocate 4 extra bytes to decode the base64 data in-place */ - key = calloc(1, sizeof(*key) + 4); - if (!key) { + auto key = reinterpret_cast<adb_public_key*>( + calloc(1, sizeof(adb_public_key) + 4)); + if (key == nullptr) { D("Can't malloc key\n"); break; } @@ -107,8 +109,8 @@ static void free_keys(struct listnode *list) static void load_keys(struct listnode *list) { - char *path; - char **paths = key_paths; + const char* path; + const char** paths = key_paths; struct stat buf; list_init(list); @@ -136,10 +138,9 @@ int adb_auth_generate_token(void *token, size_t token_size) return ret * token_size; } -int adb_auth_verify(void *token, void *sig, int siglen) +int adb_auth_verify(uint8_t* token, uint8_t* sig, int siglen) { struct listnode *item; - struct adb_public_key *key; struct listnode key_list; int ret = 0; @@ -149,7 +150,7 @@ int adb_auth_verify(void *token, void *sig, int siglen) load_keys(&key_list); list_for_each(item, &key_list) { - key = node_to_item(item, struct adb_public_key, node); + adb_public_key* key = node_to_item(item, struct adb_public_key, node); ret = RSA_verify(&key->key, sig, siglen, token, SHA_DIGEST_SIZE); if (ret) break; @@ -248,19 +249,23 @@ static void adb_auth_listener(int fd, unsigned events, void *data) } } -void adb_auth_init(void) -{ - int fd, ret; - - fd = android_get_control_socket("adbd"); - if (fd < 0) { +void adbd_cloexec_auth_socket() { + int fd = android_get_control_socket("adbd"); + if (fd == -1) { D("Failed to get adbd socket\n"); return; } fcntl(fd, F_SETFD, FD_CLOEXEC); +} - ret = listen(fd, 4); - if (ret < 0) { +void adbd_auth_init(void) { + int fd = android_get_control_socket("adbd"); + if (fd == -1) { + D("Failed to get adbd socket\n"); + return; + } + + if (listen(fd, 4) == -1) { D("Failed to listen on '%d'\n", fd); return; } diff --git a/adb/adb_auth_host.c b/adb/adb_auth_host.cpp index dd83900..7c2bcfb 100644 --- a/adb/adb_auth_host.c +++ b/adb/adb_auth_host.cpp @@ -14,8 +14,14 @@ * limitations under the License. */ +#define TRACE_TAG TRACE_AUTH + +#include "sysdeps.h" +#include "adb_auth.h" + #include <stdio.h> #include <stdlib.h> +#include <string.h> #ifdef _WIN32 # ifndef WIN32_LEAN_AND_MEAN @@ -28,11 +34,8 @@ # include <sys/stat.h> # include <unistd.h> #endif -#include <string.h> -#include "sysdeps.h" #include "adb.h" -#include "adb_auth.h" /* HACK: we need the RSAPublicKey struct * but RSA_verify conflits with openssl */ @@ -48,12 +51,13 @@ #include <openssl/rsa.h> #include <openssl/sha.h> -#define TRACE_TAG TRACE_AUTH +#if defined(OPENSSL_IS_BORINGSSL) +#include <openssl/base64.h> +#endif #define ANDROID_PATH ".android" #define ADB_KEY_FILE "adbkey" - struct adb_private_key { struct listnode node; RSA *rsa; @@ -151,43 +155,67 @@ static void get_user_info(char *buf, size_t len) static int write_public_keyfile(RSA *private_key, const char *private_key_path) { RSAPublicKey pkey; - BIO *bio, *b64, *bfile; + FILE *outfile = NULL; char path[PATH_MAX], info[MAX_PAYLOAD]; - int ret; + uint8_t* encoded = nullptr; + size_t encoded_length; + int ret = 0; - ret = snprintf(path, sizeof(path), "%s.pub", private_key_path); - if (ret >= (signed)sizeof(path)) + if (snprintf(path, sizeof(path), "%s.pub", private_key_path) >= + (int)sizeof(path)) { + D("Path too long while writing public key\n"); return 0; + } - ret = RSA_to_RSAPublicKey(private_key, &pkey); - if (!ret) { + if (!RSA_to_RSAPublicKey(private_key, &pkey)) { D("Failed to convert to publickey\n"); return 0; } - bfile = BIO_new_file(path, "w"); - if (!bfile) { + outfile = fopen(path, "w"); + if (!outfile) { D("Failed to open '%s'\n", path); return 0; } D("Writing public key to '%s'\n", path); - b64 = BIO_new(BIO_f_base64()); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); +#if defined(OPENSSL_IS_BORINGSSL) + if (!EVP_EncodedLength(&encoded_length, sizeof(pkey))) { + D("Public key too large to base64 encode"); + goto out; + } +#else + /* While we switch from OpenSSL to BoringSSL we have to implement + * |EVP_EncodedLength| here. */ + encoded_length = 1 + ((sizeof(pkey) + 2) / 3 * 4); +#endif - bio = BIO_push(b64, bfile); - BIO_write(bio, &pkey, sizeof(pkey)); - (void) BIO_flush(bio); - BIO_pop(b64); - BIO_free(b64); + encoded = reinterpret_cast<uint8_t*>(malloc(encoded_length)); + if (encoded == nullptr) { + D("Allocation failure"); + goto out; + } + encoded_length = EVP_EncodeBlock(encoded, (uint8_t*) &pkey, sizeof(pkey)); get_user_info(info, sizeof(info)); - BIO_write(bfile, info, strlen(info)); - (void) BIO_flush(bfile); - BIO_free_all(bfile); - return 1; + if (fwrite(encoded, encoded_length, 1, outfile) != 1 || + fwrite(info, strlen(info), 1, outfile) != 1) { + D("Write error while writing public key"); + goto out; + } + + ret = 1; + + out: + if (outfile != NULL) { + fclose(outfile); + } + if (encoded != NULL) { + free(encoded); + } + return ret; } static int generate_key(const char *file) @@ -244,18 +272,16 @@ out: static int read_key(const char *file, struct listnode *list) { - struct adb_private_key *key; - FILE *f; - D("read_key '%s'\n", file); - f = fopen(file, "r"); + FILE* f = fopen(file, "r"); if (!f) { D("Failed to open '%s'\n", file); return 0; } - key = malloc(sizeof(*key)); + adb_private_key* key = reinterpret_cast<adb_private_key*>( + malloc(sizeof(adb_private_key))); if (!key) { D("Failed to alloc key\n"); fclose(f); @@ -362,11 +388,17 @@ static void get_vendor_keys(struct listnode *list) } } -int adb_auth_sign(void *node, void *token, size_t token_size, void *sig) +int adb_auth_sign(void *node, const unsigned char* token, size_t token_size, + unsigned char* sig) { unsigned int len; struct adb_private_key *key = node_to_item(node, struct adb_private_key, node); + if (token_size != TOKEN_SIZE) { + D("Unexpected token size %zd\n", token_size); + return 0; + } + if (!RSA_sign(NID_sha1, token, token_size, sig, &len, key->rsa)) { return 0; } @@ -400,31 +432,33 @@ void *adb_auth_nextkey(void *current) int adb_auth_get_userkey(unsigned char *data, size_t len) { char path[PATH_MAX]; - char *file; - int ret; - - ret = get_user_keyfilepath(path, sizeof(path) - 4); + int ret = get_user_keyfilepath(path, sizeof(path) - 4); if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) { D("Error getting user key filename"); return 0; } strcat(path, ".pub"); - file = load_file(path, (unsigned*)&ret); - if (!file) { + // TODO(danalbert): ReadFileToString + unsigned size; + char* file_data = reinterpret_cast<char*>(load_file(path, &size)); + if (file_data == nullptr) { D("Can't load '%s'\n", path); return 0; } - if (len < (size_t)(ret + 1)) { - D("%s: Content too large ret=%d\n", path, ret); + if (len < (size_t)(size + 1)) { + D("%s: Content too large ret=%d\n", path, size); + free(file_data); return 0; } - memcpy(data, file, ret); - data[ret] = '\0'; + memcpy(data, file_data, size); + free(file_data); + file_data = nullptr; + data[size] = '\0'; - return ret + 1; + return size + 1; } int adb_auth_keygen(const char* filename) { diff --git a/adb/adb_client.c b/adb/adb_client.cpp index eb1720d..4751bff 100644 --- a/adb/adb_client.c +++ b/adb/adb_client.cpp @@ -1,17 +1,34 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +/* + * Copyright (C) 2015 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 TRACE_TAG TRACE_ADB + +#include "sysdeps.h" +#include "adb_client.h" + #include <errno.h> #include <limits.h> #include <stdarg.h> -#include <zipfile/zipfile.h> -#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/stat.h> +#include <sys/types.h> -#include "sysdeps.h" - -#define TRACE_TAG TRACE_ADB -#include "adb_client.h" +#include "adb_io.h" static transport_type __adb_transport = kTransportAny; static const char* __adb_serial = NULL; @@ -98,7 +115,7 @@ static int switch_socket_transport(int fd) if (__adb_serial) snprintf(service, sizeof service, "host:transport:%s", __adb_serial); else { - char* transport_type = "???"; + const char* transport_type = "???"; switch (__adb_transport) { case kTransportUsb: @@ -121,7 +138,7 @@ static int switch_socket_transport(int fd) len = strlen(service); snprintf(tmp, sizeof tmp, "%04x", len); - if(writex(fd, tmp, 4) || writex(fd, service, len)) { + if(!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service, len)) { strcpy(__adb_error, "write failure during connection"); adb_close(fd); return -1; @@ -142,7 +159,7 @@ int adb_status(int fd) unsigned char buf[5]; unsigned len; - if(readx(fd, buf, 4)) { + if(!ReadFdExactly(fd, buf, 4)) { strcpy(__adb_error, "protocol fault (no status)"); return -1; } @@ -158,14 +175,14 @@ int adb_status(int fd) return -1; } - if(readx(fd, buf, 4)) { + if(!ReadFdExactly(fd, buf, 4)) { strcpy(__adb_error, "protocol fault (status len)"); return -1; } buf[4] = 0; len = strtoul((char*)buf, 0, 16); if(len > 255) len = 255; - if(readx(fd, __adb_error, len)) { + if(!ReadFdExactly(fd, __adb_error, len)) { strcpy(__adb_error, "protocol fault (status read)"); return -1; } @@ -201,7 +218,7 @@ int _adb_connect(const char *service) return -1; } - if(writex(fd, tmp, 4) || writex(fd, service, len)) { + if(!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service, len)) { strcpy(__adb_error, "write failure during connection"); adb_close(fd); return -1; @@ -246,12 +263,12 @@ int adb_connect(const char *service) // if we have a file descriptor, then parse version result if(fd >= 0) { - if(readx(fd, buf, 4)) goto error; + if(!ReadFdExactly(fd, buf, 4)) goto error; buf[4] = 0; n = strtoul(buf, 0, 16); if(n > sizeof(buf)) goto error; - if(readx(fd, buf, n)) goto error; + if(!ReadFdExactly(fd, buf, n)) goto error; adb_close(fd); if (sscanf(buf, "%04x", &version) != 1) goto error; @@ -279,7 +296,7 @@ int adb_connect(const char *service) fd = _adb_connect(service); if(fd == -1) { - D("_adb_connect error: %s\n", __adb_error); + D("_adb_connect error: %s", __adb_error); } else if(fd == -2) { fprintf(stderr,"** daemon still not running\n"); } @@ -311,8 +328,8 @@ int adb_command(const char *service) char *adb_query(const char *service) { char buf[5]; - unsigned n; - char *tmp; + unsigned long n; + char* tmp; D("adb_query: %s\n", service); int fd = adb_connect(service); @@ -321,7 +338,7 @@ char *adb_query(const char *service) return 0; } - if(readx(fd, buf, 4)) goto oops; + if(!ReadFdExactly(fd, buf, 4)) goto oops; buf[4] = 0; n = strtoul(buf, 0, 16); @@ -330,10 +347,10 @@ char *adb_query(const char *service) goto oops; } - tmp = malloc(n + 1); + tmp = reinterpret_cast<char*>(malloc(n + 1)); if(tmp == 0) goto oops; - if(readx(fd, tmp, n) == 0) { + if(!ReadFdExactly(fd, tmp, n) == 0) { tmp[n] = 0; adb_close(fd); return tmp; diff --git a/adb/adb_client.h b/adb/adb_client.h index 0ec47ca..934362a 100644 --- a/adb/adb_client.h +++ b/adb/adb_client.h @@ -43,7 +43,7 @@ int adb_get_emulator_console_port(void); * is zero, or more than one emulator connected (or if you use -s <serial> * with a <serial> that does not designate an emulator) */ -int adb_send_emulator_command(int argc, char** argv); +int adb_send_emulator_command(int argc, const char** argv); /* return verbose error string from last operation */ const char *adb_error(void); diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp new file mode 100644 index 0000000..d89f304 --- /dev/null +++ b/adb/adb_io.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2015 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 TRACE_TAG TRACE_RWX + +#include "sysdeps.h" +#include "adb_io.h" + +#include <unistd.h> + +#include "adb_trace.h" +#include "transport.h" + +bool ReadFdExactly(int fd, void* buf, size_t len) { + char* p = reinterpret_cast<char*>(buf); + +#if ADB_TRACE + size_t len0 = len; +#endif + + D("readx: fd=%d wanted=%zu\n", fd, len); + while (len > 0) { + int r = adb_read(fd, p, len); + if (r > 0) { + len -= r; + p += r; + } else if (r == -1) { + D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno)); + return false; + } else { + D("readx: fd=%d disconnected\n", fd); + errno = 0; + return false; + } + } + +#if ADB_TRACE + D("readx: fd=%d wanted=%zu got=%zu\n", fd, len0, len0 - len); + if (ADB_TRACING) { + dump_hex(reinterpret_cast<const unsigned char*>(buf), len0); + } +#endif + + return true; +} + +bool WriteFdExactly(int fd, const void* buf, size_t len) { + const char* p = reinterpret_cast<const char*>(buf); + int r; + +#if ADB_TRACE + D("writex: fd=%d len=%d: ", fd, (int)len); + if (ADB_TRACING) { + dump_hex(reinterpret_cast<const unsigned char*>(buf), len); + } +#endif + + while (len > 0) { + r = adb_write(fd, p, len); + if (r == -1) { + D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno)); + if (errno == EAGAIN) { + adb_sleep_ms(1); // just yield some cpu time + continue; + } else if (errno == EPIPE) { + D("writex: fd=%d disconnected\n", fd); + errno = 0; + return false; + } else { + return false; + } + } else { + len -= r; + p += r; + } + } + return true; +} + +bool WriteStringFully(int fd, const char* str) { + return WriteFdExactly(fd, str, strlen(str)); +} diff --git a/adb/adb_io.h b/adb/adb_io.h new file mode 100644 index 0000000..8d237ce --- /dev/null +++ b/adb/adb_io.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 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 ADB_IO_H +#define ADB_IO_H + +#include <stdbool.h> +#include <sys/types.h> + +/* + * Reads exactly len bytes from fd into buf. + * + * Returns false if there is an error or if EOF was reached before len bytes + * were read. If EOF was found, errno will be set to 0. + * + * If this function fails, the contents of buf are undefined. + */ +bool ReadFdExactly(int fd, void *buf, size_t len); + +/* + * Writes exactly len bytes from buf to fd. + * + * Returns false if there is an error or if the fd was closed before the write + * completed. If the other end of the fd (such as in a socket, pipe, or fifo), + * is closed, errno will be set to 0. + */ +bool WriteFdExactly(int fd, const void *buf, size_t len); + +/* Same as WriteFdExactly, but with an implicit len = strlen(buf). */ +bool WriteStringFully(int fd, const char* str); + +#endif /* ADB_IO_H */ diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp new file mode 100644 index 0000000..da340b2 --- /dev/null +++ b/adb/adb_io_test.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2015 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 "adb_io.h" + +#include <gtest/gtest.h> + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include <string> + +#include "base/file.h" + +class TemporaryFile { + public: + TemporaryFile() { + init("/data/local/tmp"); + if (fd == -1) { + init("/tmp"); + } + } + + ~TemporaryFile() { + close(fd); + unlink(filename); + } + + int fd; + char filename[1024]; + + private: + void init(const char* tmp_dir) { + snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir); + fd = mkstemp(filename); + } +}; + +TEST(io, ReadFdExactly_whole) { + const char expected[] = "Foobar"; + TemporaryFile tf; + ASSERT_NE(-1, tf.fd); + + ASSERT_TRUE(android::base::WriteStringToFd(expected, tf.fd)) << strerror(errno); + ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0)); + + // Test reading the whole file. + char buf[sizeof(expected)] = {}; + ASSERT_TRUE(ReadFdExactly(tf.fd, buf, sizeof(buf) - 1)) << strerror(errno); + EXPECT_STREQ(expected, buf); +} + +TEST(io, ReadFdExactly_eof) { + const char expected[] = "Foobar"; + TemporaryFile tf; + ASSERT_NE(-1, tf.fd); + + ASSERT_TRUE(android::base::WriteStringToFd(expected, tf.fd)) << strerror(errno); + ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0)); + + // Test that not having enough data will fail. + char buf[sizeof(expected) + 1] = {}; + ASSERT_FALSE(ReadFdExactly(tf.fd, buf, sizeof(buf))); + EXPECT_EQ(0, errno) << strerror(errno); +} + +TEST(io, ReadFdExactly_partial) { + const char input[] = "Foobar"; + TemporaryFile tf; + ASSERT_NE(-1, tf.fd); + + ASSERT_TRUE(android::base::WriteStringToFd(input, tf.fd)) << strerror(errno); + ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0)); + + // Test reading a partial file. + char buf[sizeof(input) - 1] = {}; + ASSERT_TRUE(ReadFdExactly(tf.fd, buf, sizeof(buf) - 1)); + + std::string expected(input); + expected.pop_back(); + EXPECT_STREQ(expected.c_str(), buf); +} + +TEST(io, WriteFdExactly_whole) { + const char expected[] = "Foobar"; + TemporaryFile tf; + ASSERT_NE(-1, tf.fd); + + // Test writing the whole string to the file. + ASSERT_TRUE(WriteFdExactly(tf.fd, expected, sizeof(expected))) + << strerror(errno); + ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0)); + + std::string s; + ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)); + EXPECT_STREQ(expected, s.c_str()); +} + +TEST(io, WriteFdExactly_partial) { + const char buf[] = "Foobar"; + TemporaryFile tf; + ASSERT_NE(-1, tf.fd); + + // Test writing a partial string to the file. + ASSERT_TRUE(WriteFdExactly(tf.fd, buf, sizeof(buf) - 2)) << strerror(errno); + ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0)); + + std::string expected(buf); + expected.pop_back(); + + std::string s; + ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)); + EXPECT_EQ(expected, s); +} + +TEST(io, WriteFdExactly_ENOSPC) { + int fd = open("/dev/full", O_WRONLY); + ASSERT_NE(-1, fd); + + char buf[] = "foo"; + ASSERT_FALSE(WriteFdExactly(fd, buf, sizeof(buf))); + ASSERT_EQ(ENOSPC, errno); +} + +TEST(io, WriteStringFully) { + const char str[] = "Foobar"; + TemporaryFile tf; + ASSERT_NE(-1, tf.fd); + + // Test writing a partial string to the file. + ASSERT_TRUE(WriteStringFully(tf.fd, str)) << strerror(errno); + ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0)); + + std::string s; + ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)); + EXPECT_STREQ(str, s.c_str()); +} diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp new file mode 100644 index 0000000..a1a5ddb --- /dev/null +++ b/adb/adb_listeners.cpp @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2015 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 "adb_listeners.h" + +#include <stdio.h> +#include <stdlib.h> + +#include "sysdeps.h" +#include "transport.h" + +int gListenAll = 0; /* Not static because it is used in commandline.c. */ + +alistener listener_list = { + .next = &listener_list, + .prev = &listener_list, +}; + +void ss_listener_event_func(int _fd, unsigned ev, void *_l) +{ + asocket *s; + + if(ev & FDE_READ) { + struct sockaddr addr; + socklen_t alen; + int fd; + + alen = sizeof(addr); + fd = adb_socket_accept(_fd, &addr, &alen); + if(fd < 0) return; + + adb_socket_setbufsize(fd, CHUNK_SIZE); + + s = create_local_socket(fd); + if(s) { + connect_to_smartsocket(s); + return; + } + + adb_close(fd); + } +} + +void listener_event_func(int _fd, unsigned ev, void* _l) +{ + alistener* listener = reinterpret_cast<alistener*>(_l); + asocket *s; + + if (ev & FDE_READ) { + struct sockaddr addr; + socklen_t alen; + int fd; + + alen = sizeof(addr); + fd = adb_socket_accept(_fd, &addr, &alen); + if (fd < 0) { + return; + } + + s = create_local_socket(fd); + if (s) { + s->transport = listener->transport; + connect_to_remote(s, listener->connect_to); + return; + } + + adb_close(fd); + } +} + +static void free_listener(alistener* l) +{ + if (l->next) { + l->next->prev = l->prev; + l->prev->next = l->next; + l->next = l->prev = l; + } + + // closes the corresponding fd + fdevent_remove(&l->fde); + + if (l->local_name) + free((char*)l->local_name); + + if (l->connect_to) + free((char*)l->connect_to); + + if (l->transport) { + remove_transport_disconnect(l->transport, &l->disconnect); + } + free(l); +} + +void listener_disconnect(void* listener, atransport* t) +{ + free_listener(reinterpret_cast<alistener*>(listener)); +} + +int local_name_to_fd(const char *name) +{ + int port; + + if(!strncmp("tcp:", name, 4)){ + int ret; + port = atoi(name + 4); + + if (gListenAll > 0) { + ret = socket_inaddr_any_server(port, SOCK_STREAM); + } else { + ret = socket_loopback_server(port, SOCK_STREAM); + } + + return ret; + } +#ifndef HAVE_WIN32_IPC /* no Unix-domain sockets on Win32 */ + // It's non-sensical to support the "reserved" space on the adb host side + if(!strncmp(name, "local:", 6)) { + return socket_local_server(name + 6, + ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); + } else if(!strncmp(name, "localabstract:", 14)) { + return socket_local_server(name + 14, + ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); + } else if(!strncmp(name, "localfilesystem:", 16)) { + return socket_local_server(name + 16, + ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); + } + +#endif + printf("unknown local portname '%s'\n", name); + return -1; +} + +// Write a single line describing a listener to a user-provided buffer. +// Appends a trailing zero, even in case of truncation, but the function +// returns the full line length. +// If |buffer| is NULL, does not write but returns required size. +static int format_listener(alistener* l, char* buffer, size_t buffer_len) { + // Format is simply: + // + // <device-serial> " " <local-name> " " <remote-name> "\n" + // + int local_len = strlen(l->local_name); + int connect_len = strlen(l->connect_to); + int serial_len = strlen(l->transport->serial); + + if (buffer != NULL) { + snprintf(buffer, buffer_len, "%s %s %s\n", + l->transport->serial, l->local_name, l->connect_to); + } + // NOTE: snprintf() on Windows returns -1 in case of truncation, so + // return the computed line length instead. + return local_len + connect_len + serial_len + 3; +} + +// Write the list of current listeners (network redirections) into a +// user-provided buffer. Appends a trailing zero, even in case of +// trunctaion, but return the full size in bytes. +// If |buffer| is NULL, does not write but returns required size. +int format_listeners(char* buf, size_t buflen) +{ + alistener* l; + int result = 0; + for (l = listener_list.next; l != &listener_list; l = l->next) { + // Ignore special listeners like those for *smartsocket* + if (l->connect_to[0] == '*') + continue; + int len = format_listener(l, buf, buflen); + // Ensure there is space for the trailing zero. + result += len; + if (buf != NULL) { + buf += len; + buflen -= len; + if (buflen <= 0) + break; + } + } + return result; +} + +install_status_t remove_listener(const char *local_name, atransport* transport) +{ + alistener *l; + + for (l = listener_list.next; l != &listener_list; l = l->next) { + if (!strcmp(local_name, l->local_name)) { + listener_disconnect(l, l->transport); + return INSTALL_STATUS_OK; + } + } + return INSTALL_STATUS_LISTENER_NOT_FOUND; +} + +void remove_all_listeners(void) +{ + alistener *l, *l_next; + for (l = listener_list.next; l != &listener_list; l = l_next) { + l_next = l->next; + // Never remove smart sockets. + if (l->connect_to[0] == '*') + continue; + listener_disconnect(l, l->transport); + } +} + +install_status_t install_listener(const char *local_name, + const char *connect_to, + atransport* transport, + int no_rebind) +{ + for (alistener* l = listener_list.next; l != &listener_list; l = l->next) { + if (strcmp(local_name, l->local_name) == 0) { + char* cto; + + /* can't repurpose a smartsocket */ + if(l->connect_to[0] == '*') { + return INSTALL_STATUS_INTERNAL_ERROR; + } + + /* can't repurpose a listener if 'no_rebind' is true */ + if (no_rebind) { + return INSTALL_STATUS_CANNOT_REBIND; + } + + cto = strdup(connect_to); + if(cto == 0) { + return INSTALL_STATUS_INTERNAL_ERROR; + } + + free((void*) l->connect_to); + l->connect_to = cto; + if (l->transport != transport) { + remove_transport_disconnect(l->transport, &l->disconnect); + l->transport = transport; + add_transport_disconnect(l->transport, &l->disconnect); + } + return INSTALL_STATUS_OK; + } + } + + alistener* listener = reinterpret_cast<alistener*>( + calloc(1, sizeof(alistener))); + if (listener == nullptr) { + goto nomem; + } + + listener->local_name = strdup(local_name); + if (listener->local_name == nullptr) { + goto nomem; + } + + listener->connect_to = strdup(connect_to); + if (listener->connect_to == nullptr) { + goto nomem; + } + + listener->fd = local_name_to_fd(local_name); + if (listener->fd < 0) { + printf("cannot bind '%s': %s\n", local_name, strerror(errno)); + free(listener->local_name); + free(listener->connect_to); + free(listener); + return INSTALL_STATUS_CANNOT_BIND; + } + + close_on_exec(listener->fd); + if (!strcmp(listener->connect_to, "*smartsocket*")) { + fdevent_install(&listener->fde, listener->fd, ss_listener_event_func, + listener); + } else { + fdevent_install(&listener->fde, listener->fd, listener_event_func, + listener); + } + fdevent_set(&listener->fde, FDE_READ); + + listener->next = &listener_list; + listener->prev = listener_list.prev; + listener->next->prev = listener; + listener->prev->next = listener; + listener->transport = transport; + + if (transport) { + listener->disconnect.opaque = listener; + listener->disconnect.func = listener_disconnect; + add_transport_disconnect(transport, &listener->disconnect); + } + return INSTALL_STATUS_OK; + +nomem: + fatal("cannot allocate listener"); + return INSTALL_STATUS_INTERNAL_ERROR; +} diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h new file mode 100644 index 0000000..f55fdee --- /dev/null +++ b/adb/adb_listeners.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 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 __ADB_LISTENERS_H +#define __ADB_LISTENERS_H + +#include "adb.h" + +// error/status codes for install_listener. +enum install_status_t { + INSTALL_STATUS_OK = 0, + INSTALL_STATUS_INTERNAL_ERROR = -1, + INSTALL_STATUS_CANNOT_BIND = -2, + INSTALL_STATUS_CANNOT_REBIND = -3, + INSTALL_STATUS_LISTENER_NOT_FOUND = -4, +}; + +extern alistener listener_list; + +void listener_disconnect(void* _l, atransport* t); +void listener_event_func(int _fd, unsigned ev, void *_l); +void ss_listener_event_func(int _fd, unsigned ev, void *_l); + +install_status_t install_listener(const char *local_name, + const char *connect_to, + atransport* transport, + int no_rebind); + +int format_listeners(char* buf, size_t buflen); + +install_status_t remove_listener(const char* local_name, atransport* transport); +void remove_all_listeners(void); + +#endif /* __ADB_LISTENERS_H */ diff --git a/adb/adb_main.cpp b/adb/adb_main.cpp new file mode 100644 index 0000000..5acaf80 --- /dev/null +++ b/adb/adb_main.cpp @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2015 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 TRACE_TAG TRACE_ADB + +#include "sysdeps.h" + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + +#include "adb.h" +#include "adb_auth.h" +#include "adb_listeners.h" +#include "transport.h" + +#if !ADB_HOST +#include <getopt.h> +#include <sys/prctl.h> + +#include "cutils/properties.h" +#include "private/android_filesystem_config.h" +#include "selinux/selinux.h" + +#include "qemu_tracing.h" +#endif + +static void adb_cleanup(void) +{ + usb_cleanup(); +} + +#if defined(_WIN32) +static BOOL WINAPI ctrlc_handler(DWORD type) +{ + exit(STATUS_CONTROL_C_EXIT); + return TRUE; +} +#endif + +#if ADB_HOST +#ifdef WORKAROUND_BUG6558362 +#include <sched.h> +#define AFFINITY_ENVVAR "ADB_CPU_AFFINITY_BUG6558362" +void adb_set_affinity(void) +{ + cpu_set_t cpu_set; + const char* cpunum_str = getenv(AFFINITY_ENVVAR); + char* strtol_res; + int cpu_num; + + if (!cpunum_str || !*cpunum_str) + return; + cpu_num = strtol(cpunum_str, &strtol_res, 0); + if (*strtol_res != '\0') + fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str, AFFINITY_ENVVAR); + + sched_getaffinity(0, sizeof(cpu_set), &cpu_set); + D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]); + CPU_ZERO(&cpu_set); + CPU_SET(cpu_num, &cpu_set); + sched_setaffinity(0, sizeof(cpu_set), &cpu_set); + sched_getaffinity(0, sizeof(cpu_set), &cpu_set); + D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]); +} +#endif +#else /* ADB_HOST */ +static const char *root_seclabel = NULL; + +static void drop_capabilities_bounding_set_if_needed() { +#ifdef ALLOW_ADBD_ROOT + char value[PROPERTY_VALUE_MAX]; + property_get("ro.debuggable", value, ""); + if (strcmp(value, "1") == 0) { + return; + } +#endif + int i; + for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) { + if (i == CAP_SETUID || i == CAP_SETGID) { + // CAP_SETUID CAP_SETGID needed by /system/bin/run-as + continue; + } + int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0); + + // Some kernels don't have file capabilities compiled in, and + // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically + // die when we see such misconfigured kernels. + if ((err < 0) && (errno != EINVAL)) { + exit(1); + } + } +} + +static bool should_drop_privileges() { +#if defined(ALLOW_ADBD_ROOT) + char value[PROPERTY_VALUE_MAX]; + + // The emulator is never secure, so don't drop privileges there. + // TODO: this seems like a bug --- shouldn't the emulator behave like a device? + property_get("ro.kernel.qemu", value, ""); + if (strcmp(value, "1") == 0) { + return false; + } + + // The properties that affect `adb root` and `adb unroot` are ro.secure and + // ro.debuggable. In this context the names don't make the expected behavior + // particularly obvious. + // + // ro.debuggable: + // Allowed to become root, but not necessarily the default. Set to 1 on + // eng and userdebug builds. + // + // ro.secure: + // Drop privileges by default. Set to 1 on userdebug and user builds. + property_get("ro.secure", value, "1"); + bool ro_secure = (strcmp(value, "1") == 0); + + property_get("ro.debuggable", value, ""); + bool ro_debuggable = (strcmp(value, "1") == 0); + + // Drop privileges if ro.secure is set... + bool drop = ro_secure; + + property_get("service.adb.root", value, ""); + bool adb_root = (strcmp(value, "1") == 0); + bool adb_unroot = (strcmp(value, "0") == 0); + + // ...except "adb root" lets you keep privileges in a debuggable build. + if (ro_debuggable && adb_root) { + drop = false; + } + + // ...and "adb unroot" lets you explicitly drop privileges. + if (adb_unroot) { + drop = true; + } + + return drop; +#else + return true; // "adb root" not allowed, always drop privileges. +#endif /* ALLOW_ADBD_ROOT */ +} +#endif /* ADB_HOST */ + +/* Constructs a local name of form tcp:port. + * target_str points to the target string, it's content will be overwritten. + * target_size is the capacity of the target string. + * server_port is the port number to use for the local name. + */ +void build_local_name(char* target_str, size_t target_size, int server_port) +{ + snprintf(target_str, target_size, "tcp:%d", server_port); +} + +void start_logging(void) +{ +#if defined(_WIN32) + char temp[ MAX_PATH ]; + FILE* fnul; + FILE* flog; + + GetTempPath( sizeof(temp) - 8, temp ); + strcat( temp, "adb.log" ); + + /* Win32 specific redirections */ + fnul = fopen( "NUL", "rt" ); + if (fnul != NULL) + stdin[0] = fnul[0]; + + flog = fopen( temp, "at" ); + if (flog == NULL) + flog = fnul; + + setvbuf( flog, NULL, _IONBF, 0 ); + + stdout[0] = flog[0]; + stderr[0] = flog[0]; + fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); +#else + int fd; + + fd = unix_open("/dev/null", O_RDONLY); + dup2(fd, 0); + adb_close(fd); + + fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640); + if(fd < 0) { + fd = unix_open("/dev/null", O_WRONLY); + } + dup2(fd, 1); + dup2(fd, 2); + adb_close(fd); + fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); +#endif +} + +int adb_main(int is_daemon, int server_port) +{ +#if !ADB_HOST + int port; + char value[PROPERTY_VALUE_MAX]; + + umask(000); +#endif + + atexit(adb_cleanup); +#if defined(_WIN32) + SetConsoleCtrlHandler( ctrlc_handler, TRUE ); +#else + // No SIGCHLD. Let the service subproc handle its children. + signal(SIGPIPE, SIG_IGN); +#endif + + init_transport_registration(); + +#if ADB_HOST + HOST = 1; + +#ifdef WORKAROUND_BUG6558362 + if(is_daemon) adb_set_affinity(); +#endif + usb_init(); + local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); + adb_auth_init(); + + char local_name[30]; + build_local_name(local_name, sizeof(local_name), server_port); + if(install_listener(local_name, "*smartsocket*", NULL, 0)) { + exit(1); + } +#else + // We need to call this even if auth isn't enabled because the file + // descriptor will always be open. + adbd_cloexec_auth_socket(); + + property_get("ro.adb.secure", value, "0"); + auth_enabled = !strcmp(value, "1"); + if (auth_enabled) + adbd_auth_init(); + + // Our external storage path may be different than apps, since + // we aren't able to bind mount after dropping root. + const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE"); + if (NULL != adb_external_storage) { + setenv("EXTERNAL_STORAGE", adb_external_storage, 1); + } else { + D("Warning: ADB_EXTERNAL_STORAGE is not set. Leaving EXTERNAL_STORAGE" + " unchanged.\n"); + } + + /* add extra groups: + ** AID_ADB to access the USB driver + ** AID_LOG to read system logs (adb logcat) + ** AID_INPUT to diagnose input issues (getevent) + ** AID_INET to diagnose network issues (ping) + ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump) + ** AID_SDCARD_R to allow reading from the SD card + ** AID_SDCARD_RW to allow writing to the SD card + ** AID_NET_BW_STATS to read out qtaguid statistics + */ + gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_NET_BT, + AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW, + AID_NET_BW_STATS }; + if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { + exit(1); + } + + /* don't listen on a port (default 5037) if running in secure mode */ + /* don't run as root if we are running in secure mode */ + if (should_drop_privileges()) { + drop_capabilities_bounding_set_if_needed(); + + /* then switch user and group to "shell" */ + if (setgid(AID_SHELL) != 0) { + exit(1); + } + if (setuid(AID_SHELL) != 0) { + exit(1); + } + + D("Local port disabled\n"); + } else { + char local_name[30]; + if ((root_seclabel != NULL) && (is_selinux_enabled() > 0)) { + // b/12587913: fix setcon to allow const pointers + if (setcon((char *)root_seclabel) < 0) { + exit(1); + } + } + build_local_name(local_name, sizeof(local_name), server_port); + if(install_listener(local_name, "*smartsocket*", NULL, 0)) { + exit(1); + } + } + + int usb = 0; + if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) { + // listen on USB + usb_init(); + usb = 1; + } + + // If one of these properties is set, also listen on that port + // If one of the properties isn't set and we couldn't listen on usb, + // listen on the default port. + property_get("service.adb.tcp.port", value, ""); + if (!value[0]) { + property_get("persist.adb.tcp.port", value, ""); + } + if (sscanf(value, "%d", &port) == 1 && port > 0) { + printf("using port=%d\n", port); + // listen on TCP port specified by service.adb.tcp.port property + local_init(port); + } else if (!usb) { + // listen on default port + local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); + } + + D("adb_main(): pre init_jdwp()\n"); + init_jdwp(); + D("adb_main(): post init_jdwp()\n"); +#endif + + if (is_daemon) + { + // inform our parent that we are up and running. +#if defined(_WIN32) + DWORD count; + WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL ); +#else + fprintf(stderr, "OK\n"); +#endif + start_logging(); + } + D("Event loop starting\n"); + + fdevent_loop(); + + usb_cleanup(); + + return 0; +} + +#if !ADB_HOST +void close_stdin() { + int fd = unix_open("/dev/null", O_RDONLY); + if (fd == -1) { + perror("failed to open /dev/null, stdin will remain open"); + return; + } + dup2(fd, 0); + adb_close(fd); +} +#endif + +int main(int argc, char **argv) { +#if ADB_HOST + adb_sysdeps_init(); +#else + close_stdin(); +#endif + adb_trace_init(); + +#if ADB_HOST + D("Handling commandline()\n"); + return adb_commandline(argc - 1, const_cast<const char**>(argv + 1)); +#else + /* If adbd runs inside the emulator this will enable adb tracing via + * adb-debug qemud service in the emulator. */ + adb_qemu_trace_init(); + while (true) { + int c; + int option_index = 0; + static struct option opts[] = { + {"root_seclabel", required_argument, 0, 's' }, + {"device_banner", required_argument, 0, 'b' } + }; + c = getopt_long(argc, argv, "", opts, &option_index); + if (c == -1) + break; + switch (c) { + case 's': + root_seclabel = optarg; + break; + case 'b': + adb_device_banner = optarg; + break; + default: + break; + } + } + + D("Handling main()\n"); + return adb_main(0, DEFAULT_ADB_PORT); +#endif +} diff --git a/adb/adb_trace.h b/adb/adb_trace.h index 8a5d9f8..32b6ae4 100644 --- a/adb/adb_trace.h +++ b/adb/adb_trace.h @@ -19,6 +19,8 @@ #if !ADB_HOST #include <android/log.h> +#else +#include <stdio.h> #endif /* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */ @@ -28,7 +30,7 @@ * forget to update the corresponding 'tags' table in * the adb_trace_init() function implemented in adb.c */ -typedef enum { +enum AdbTrace { TRACE_ADB = 0, /* 0x001 */ TRACE_SOCKETS, TRACE_PACKETS, @@ -41,7 +43,7 @@ typedef enum { TRACE_SERVICES, TRACE_AUTH, TRACE_FDEVENT, -} AdbTrace; +} ; #if ADB_TRACE @@ -73,8 +75,9 @@ void adb_trace_init(void); if (ADB_TRACING) { \ int save_errno = errno; \ adb_mutex_lock(&D_lock); \ - fprintf(stderr, "%s::%s():", \ - __FILE__, __FUNCTION__); \ + fprintf(stderr, "%16s: %5d:%5lu | ", \ + __FUNCTION__, \ + getpid(), adb_thread_id()); \ errno = save_errno; \ fprintf(stderr, __VA_ARGS__ ); \ fflush(stderr); \ @@ -96,15 +99,16 @@ void adb_trace_init(void); } while (0) # define DD(...) \ do { \ - int save_errno = errno; \ - adb_mutex_lock(&D_lock); \ - fprintf(stderr, "%s::%s():", \ - __FILE__, __FUNCTION__); \ - errno = save_errno; \ - fprintf(stderr, __VA_ARGS__ ); \ - fflush(stderr); \ - adb_mutex_unlock(&D_lock); \ - errno = save_errno; \ + int save_errno = errno; \ + adb_mutex_lock(&D_lock); \ + fprintf(stderr, "%16s: %5d:%5lu | ", \ + __FUNCTION__, \ + getpid(), adb_thread_id()); \ + errno = save_errno; \ + fprintf(stderr, __VA_ARGS__ ); \ + fflush(stderr); \ + adb_mutex_unlock(&D_lock); \ + errno = save_errno; \ } while (0) #else # define D(...) \ diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp new file mode 100644 index 0000000..f10c143 --- /dev/null +++ b/adb/adb_utils.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 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 "adb_utils.h" + +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "sysdeps.h" + +bool getcwd(std::string* s) { + char* cwd = getcwd(nullptr, 0); + if (cwd != nullptr) *s = cwd; + free(cwd); + return (cwd != nullptr); +} + +bool directory_exists(const std::string& path) { + struct stat sb; + return lstat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode); +} + +std::string escape_arg(const std::string& s) { + std::string result = s; + + // Insert a \ before any ' in the string. + for (auto it = result.begin(); it != result.end(); ++it) { + if (*it == '\'') { + it = result.insert(it, '\\') + 1; + } + } + + // Prefix and suffix the whole string with '. + result.insert(result.begin(), '\''); + result.push_back('\''); + return result; +} diff --git a/include/cutils/dir_hash.h b/adb/adb_utils.h index fbb4d02..4b64afa 100644 --- a/include/cutils/dir_hash.h +++ b/adb/adb_utils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 The Android Open Source Project + * Copyright (C) 2015 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. @@ -14,13 +14,14 @@ * limitations under the License. */ -typedef enum { - SHA_1, -} HashAlgorithm; +#ifndef _ADB_UTILS_H_ +#define _ADB_UTILS_H_ -int get_file_hash(HashAlgorithm algorithm, const char *path, - char *output_string, size_t max_output_string); +#include <string> -int get_recursive_hash_manifest(HashAlgorithm algorithm, - const char *directory_path, - char **output_string); +bool getcwd(std::string* cwd); +bool directory_exists(const std::string& path); + +std::string escape_arg(const std::string& s); + +#endif diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp new file mode 100644 index 0000000..a395079 --- /dev/null +++ b/adb/adb_utils_test.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 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 "adb_utils.h" + +#include <gtest/gtest.h> + +TEST(adb_utils, directory_exists) { + ASSERT_TRUE(directory_exists("/proc")); + ASSERT_FALSE(directory_exists("/proc/self")); // Symbolic link. + ASSERT_FALSE(directory_exists("/proc/does-not-exist")); +} + +TEST(adb_utils, escape_arg) { + ASSERT_EQ(R"('')", escape_arg("")); + + ASSERT_EQ(R"('abc')", escape_arg("abc")); + + ASSERT_EQ(R"(' abc')", escape_arg(" abc")); + ASSERT_EQ(R"('\'abc')", escape_arg("'abc")); + ASSERT_EQ(R"('"abc')", escape_arg("\"abc")); + ASSERT_EQ(R"('\abc')", escape_arg("\\abc")); + ASSERT_EQ(R"('(abc')", escape_arg("(abc")); + ASSERT_EQ(R"(')abc')", escape_arg(")abc")); + + ASSERT_EQ(R"('abc abc')", escape_arg("abc abc")); + ASSERT_EQ(R"('abc\'abc')", escape_arg("abc'abc")); + ASSERT_EQ(R"('abc"abc')", escape_arg("abc\"abc")); + ASSERT_EQ(R"('abc\abc')", escape_arg("abc\\abc")); + ASSERT_EQ(R"('abc(abc')", escape_arg("abc(abc")); + ASSERT_EQ(R"('abc)abc')", escape_arg("abc)abc")); + + ASSERT_EQ(R"('abc ')", escape_arg("abc ")); + ASSERT_EQ(R"('abc\'')", escape_arg("abc'")); + ASSERT_EQ(R"('abc"')", escape_arg("abc\"")); + ASSERT_EQ(R"('abc\')", escape_arg("abc\\")); + ASSERT_EQ(R"('abc(')", escape_arg("abc(")); + ASSERT_EQ(R"('abc)')", escape_arg("abc)")); +} diff --git a/adb/commandline.c b/adb/commandline.cpp index 7704878..e59a96a 100644 --- a/adb/commandline.c +++ b/adb/commandline.cpp @@ -14,72 +14,68 @@ * limitations under the License. */ -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> +#define TRACE_TAG TRACE_ADB + +#include "sysdeps.h" + +#include <assert.h> +#include <ctype.h> #include <errno.h> -#include <unistd.h> +#include <inttypes.h> #include <limits.h> #include <stdarg.h> -#include <sys/types.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/stat.h> -#include <ctype.h> -#include <assert.h> +#include <sys/types.h> -#include "sysdeps.h" +#include <string> -#ifdef HAVE_TERMIO_H +#include <base/stringprintf.h> + +#if !defined(_WIN32) #include <termios.h> +#include <unistd.h> #endif -#define TRACE_TAG TRACE_ADB #include "adb.h" -#include "adb_client.h" #include "adb_auth.h" +#include "adb_client.h" +#include "adb_io.h" +#include "adb_utils.h" #include "file_sync_service.h" -static int do_cmd(transport_type ttype, char* serial, char *cmd, ...); +static int do_cmd(transport_type ttype, const char* serial, const char *cmd, ...); -void get_my_path(char *s, size_t maxLen); -int find_sync_dirs(const char *srcarg, - char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out); -int install_app(transport_type transport, char* serial, int argc, char** argv); -int install_multiple_app(transport_type transport, char* serial, int argc, char** argv); -int uninstall_app(transport_type transport, char* serial, int argc, char** argv); +static int install_app(transport_type transport, const char* serial, int argc, + const char** argv); +static int install_multiple_app(transport_type transport, const char* serial, int argc, + const char** argv); +static int uninstall_app(transport_type transport, const char* serial, int argc, + const char** argv); -static const char *gProductOutPath = NULL; +static std::string gProductOutPath; extern int gListenAll; -static char *product_file(const char *extra) -{ - int n; - char *x; - - if (gProductOutPath == NULL) { +static std::string product_file(const char *extra) { + if (gProductOutPath.empty()) { fprintf(stderr, "adb: Product directory not specified; " "use -p or define ANDROID_PRODUCT_OUT\n"); exit(1); } - n = strlen(gProductOutPath) + strlen(extra) + 2; - x = malloc(n); - if (x == 0) { - fprintf(stderr, "adb: Out of memory (product_file())\n"); - exit(1); - } - - snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra); - return x; + return android::base::StringPrintf("%s%s%s", + gProductOutPath.c_str(), OS_PATH_SEPARATOR_STR, extra); } -void version(FILE * out) { +static void version(FILE* out) { fprintf(out, "Android Debug Bridge version %d.%d.%d\n", - ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION); + ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION); } -void help() -{ +static void help() { version(stderr); fprintf(stderr, @@ -191,6 +187,7 @@ void help() " adb restore <file> - restore device contents from the <file> backup archive\n" "\n" " adb disable-verity - disable dm-verity checking on USERDEBUG builds\n" + " adb enable-verity - re-enable dm-verity checking on USERDEBUG builds\n" " adb keygen <file> - generate adb public/private key. The private key is stored in <file>,\n" " and the public key is stored in <file>.pub. Any existing files\n" " are overwritten.\n" @@ -205,10 +202,15 @@ void help() " adb get-serialno - prints: <serial-number>\n" " adb get-devpath - prints: <device-path>\n" " adb status-window - continuously print device status for a specified device\n" - " adb remount - remounts the /system and /vendor (if present) partitions on the device read-write\n" - " adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n" + " adb remount - remounts the /system, /vendor (if present) and /oem (if present) partitions on the device read-write\n" + " adb reboot [bootloader|recovery]\n" + " - reboots the device, optionally into the bootloader or recovery program.\n" + " adb reboot sideload - reboots the device into the sideload mode in recovery program (adb root required).\n" + " adb reboot sideload-auto-reboot\n" + " - reboots into the sideload mode, then reboots automatically after the sideload regardless of the result.\n" " adb reboot-bootloader - reboots the device into the bootloader\n" " adb root - restarts the adbd daemon with root permissions\n" + " adb unroot - restarts the adbd daemon without root permissions\n" " adb usb - restarts the adbd daemon listening on USB\n" " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port\n" "networking:\n" @@ -220,9 +222,9 @@ void help() "adb sync notes: adb sync [ <directory> ]\n" " <localdir> can be interpreted in several ways:\n" "\n" - " - If <directory> is not specified, /system, /vendor (if present), and /data partitions will be updated.\n" + " - If <directory> is not specified, /system, /vendor (if present), /oem (if present) and /data partitions will be updated.\n" "\n" - " - If it is \"system\", \"vendor\" or \"data\", only the corresponding partition\n" + " - If it is \"system\", \"vendor\", \"oem\" or \"data\", only the corresponding partition\n" " is updated.\n" "\n" "environmental variables:\n" @@ -233,36 +235,37 @@ void help() ); } -int usage() -{ +static int usage() { help(); return 1; } -#ifdef HAVE_TERMIO_H -static struct termios tio_save; +#if defined(_WIN32) -static void stdin_raw_init(int fd) -{ - struct termios tio; +// Implemented in sysdeps_win32.cpp. +void stdin_raw_init(int fd); +void stdin_raw_restore(int fd); + +#else +static termios g_saved_terminal_state; + +static void stdin_raw_init(int fd) { + if (tcgetattr(fd, &g_saved_terminal_state)) return; - if(tcgetattr(fd, &tio)) return; - if(tcgetattr(fd, &tio_save)) return; + termios tio; + if (tcgetattr(fd, &tio)) return; - tio.c_lflag = 0; /* disable CANON, ECHO*, etc */ + cfmakeraw(&tio); - /* no timeout but request at least one character per read */ + // No timeout but request at least one character per read. tio.c_cc[VTIME] = 0; tio.c_cc[VMIN] = 1; - tcsetattr(fd, TCSANOW, &tio); - tcflush(fd, TCIFLUSH); + tcsetattr(fd, TCSAFLUSH, &tio); } -static void stdin_raw_restore(int fd) -{ - tcsetattr(fd, TCSANOW, &tio_save); - tcflush(fd, TCIFLUSH); +static void stdin_raw_restore(int fd) { + tcsetattr(fd, TCSAFLUSH, &g_saved_terminal_state); } #endif @@ -309,16 +312,17 @@ static void read_status_line(int fd, char* buf, size_t count) static void copy_to_file(int inFd, int outFd) { const size_t BUFSIZE = 32 * 1024; char* buf = (char*) malloc(BUFSIZE); + if (buf == nullptr) fatal("couldn't allocate buffer for copy_to_file"); int len; long total = 0; D("copy_to_file(%d -> %d)\n", inFd, outFd); -#ifdef HAVE_TERMIO_H + if (inFd == STDIN_FILENO) { stdin_raw_init(STDIN_FILENO); } -#endif - for (;;) { + + while (true) { if (inFd == STDIN_FILENO) { len = unix_read(inFd, buf, BUFSIZE); } else { @@ -344,11 +348,11 @@ static void copy_to_file(int inFd, int outFd) { } total += len; } -#ifdef HAVE_TERMIO_H + if (inFd == STDIN_FILENO) { stdin_raw_restore(STDIN_FILENO); } -#endif + D("copy_to_file() finished after %lu bytes\n", total); free(buf); } @@ -389,9 +393,7 @@ static void *stdin_read_thread(void *x) case '.': if(state == 2) { fprintf(stderr,"\n* disconnect *\n"); -#ifdef HAVE_TERMIO_H stdin_raw_restore(fdi); -#endif exit(0); } default: @@ -406,11 +408,9 @@ static void *stdin_read_thread(void *x) return 0; } -int interactive_shell(void) -{ +static int interactive_shell() { adb_thread_t thr; int fdi, fd; - int *fds; fd = adb_connect("shell:"); if(fd < 0) { @@ -419,18 +419,19 @@ int interactive_shell(void) } fdi = 0; //dup(0); - fds = malloc(sizeof(int) * 2); + int* fds = reinterpret_cast<int*>(malloc(sizeof(int) * 2)); + if (fds == nullptr) { + fprintf(stderr, "couldn't allocate fds array: %s\n", strerror(errno)); + return 1; + } + fds[0] = fd; fds[1] = fdi; -#ifdef HAVE_TERMIO_H stdin_raw_init(fdi); -#endif adb_thread_create(&thr, stdin_read_thread, fds); read_and_dump(fd); -#ifdef HAVE_TERMIO_H stdin_raw_restore(fdi); -#endif return 0; } @@ -450,13 +451,12 @@ static void format_host_command(char* buffer, size_t buflen, const char* comman } } -int adb_download_buffer(const char *service, const char *fn, const void* data, int sz, - unsigned progress) +static int adb_download_buffer(const char *service, const char *fn, const void* data, int sz, + unsigned progress) { char buf[4096]; unsigned total; int fd; - const unsigned char *ptr; sprintf(buf,"%s:%d", service, sz); fd = adb_connect(buf); @@ -466,10 +466,10 @@ int adb_download_buffer(const char *service, const char *fn, const void* data, i } int opt = CHUNK_SIZE; - opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt)); + opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt)); total = sz; - ptr = data; + const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data); if(progress) { char *x = strrchr(service, ':'); @@ -478,7 +478,7 @@ int adb_download_buffer(const char *service, const char *fn, const void* data, i while(sz > 0) { unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz; - if(writex(fd, ptr, xfer)) { + if(!WriteFdExactly(fd, ptr, xfer)) { adb_status(fd); fprintf(stderr,"* failed to write data '%s' *\n", adb_error()); return -1; @@ -494,7 +494,7 @@ int adb_download_buffer(const char *service, const char *fn, const void* data, i printf("\n"); } - if(readx(fd, buf, 4)){ + if(!ReadFdExactly(fd, buf, 4)){ fprintf(stderr,"* error reading response *\n"); adb_close(fd); return -1; @@ -510,23 +510,6 @@ int adb_download_buffer(const char *service, const char *fn, const void* data, i return 0; } - -int adb_download(const char *service, const char *fn, unsigned progress) -{ - void *data; - unsigned sz; - - data = load_file(fn, &sz); - if(data == 0) { - fprintf(stderr,"* cannot read '%s' *\n", fn); - return -1; - } - - int status = adb_download_buffer(service, fn, data, sz, progress); - free(data); - return status; -} - #define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE) /* @@ -548,15 +531,16 @@ int adb_download(const char *service, const char *fn, unsigned progress) * - When the other side sends "DONEDONE" instead of a block number, * we hang up. */ -int adb_sideload_host(const char* fn) { - uint8_t* data; +static int adb_sideload_host(const char* fn) { unsigned sz; size_t xfer = 0; int status; + int last_percent = -1; + int opt = SIDELOAD_HOST_BLOCK_SIZE; printf("loading: '%s'", fn); fflush(stdout); - data = load_file(fn, &sz); + uint8_t* data = reinterpret_cast<uint8_t*>(load_file(fn, &sz)); if (data == 0) { printf("\n"); fprintf(stderr, "* cannot read '%s' *\n", fn); @@ -574,12 +558,10 @@ int adb_sideload_host(const char* fn) { goto done; } - int opt = SIDELOAD_HOST_BLOCK_SIZE; - opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt)); + opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt)); - int last_percent = -1; - for (;;) { - if (readx(fd, buf, 8)) { + while (true) { + if (!ReadFdExactly(fd, buf, 8)) { fprintf(stderr, "* failed to read command: %s\n", adb_error()); status = -1; goto done; @@ -606,7 +588,7 @@ int adb_sideload_host(const char* fn) { to_write = sz - offset; } - if(writex(fd, start, to_write)) { + if(!WriteFdExactly(fd, start, to_write)) { adb_status(fd); fprintf(stderr,"* failed to write data '%s' *\n", adb_error()); status = -1; @@ -680,50 +662,6 @@ static void status_window(transport_type ttype, const char* serial) } } -static int should_escape(const char c) -{ - return (c == ' ' || c == '\'' || c == '"' || c == '\\' || c == '(' || c == ')'); -} - -/* Duplicate and escape given argument. */ -static char *escape_arg(const char *s) -{ - const char *ts; - size_t alloc_len; - char *ret; - char *dest; - - alloc_len = 0; - for (ts = s; *ts != '\0'; ts++) { - alloc_len++; - if (should_escape(*ts)) { - alloc_len++; - } - } - - if (alloc_len == 0) { - // Preserve empty arguments - ret = (char *) malloc(3); - ret[0] = '\"'; - ret[1] = '\"'; - ret[2] = '\0'; - return ret; - } - - ret = (char *) malloc(alloc_len + 1); - dest = ret; - - for (ts = s; *ts != '\0'; ts++) { - if (should_escape(*ts)) { - *dest++ = '\\'; - } - *dest++ = *ts; - } - *dest++ = '\0'; - - return ret; -} - /** * Run ppp in "notty" mode against a resource listed as the first parameter * eg: @@ -731,13 +669,11 @@ static char *escape_arg(const char *s) * ppp dev:/dev/omap_csmi_tty0 <ppp options> * */ -int ppp(int argc, char **argv) -{ -#ifdef HAVE_WIN32_PROC +static int ppp(int argc, const char** argv) { +#if defined(_WIN32) fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]); return -1; #else - char *adb_service_name; pid_t pid; int fd; @@ -748,8 +684,7 @@ int ppp(int argc, char **argv) return 1; } - adb_service_name = argv[1]; - + const char* adb_service_name = argv[1]; fd = adb_connect(adb_service_name); if(fd < 0) { @@ -796,16 +731,15 @@ int ppp(int argc, char **argv) adb_close(fd); return 0; } -#endif /* !HAVE_WIN32_PROC */ +#endif /* !defined(_WIN32) */ } -static int send_shellcommand(transport_type transport, char* serial, char* buf) -{ - int fd, ret; - - for(;;) { - fd = adb_connect(buf); - if(fd >= 0) +static int send_shell_command(transport_type transport, const char* serial, + const std::string& command) { + int fd; + while (true) { + fd = adb_connect(command.c_str()); + if (fd >= 0) break; fprintf(stderr,"- waiting for device -\n"); adb_sleep_ms(1000); @@ -813,41 +747,30 @@ static int send_shellcommand(transport_type transport, char* serial, char* buf) } read_and_dump(fd); - ret = adb_close(fd); - if (ret) + int rc = adb_close(fd); + if (rc) { perror("close"); - - return ret; + } + return rc; } -static int logcat(transport_type transport, char* serial, int argc, char **argv) -{ - char buf[4096]; - - char *log_tags; - char *quoted; +static int logcat(transport_type transport, const char* serial, int argc, const char** argv) { + char* log_tags = getenv("ANDROID_LOG_TAGS"); + std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags); - log_tags = getenv("ANDROID_LOG_TAGS"); - quoted = escape_arg(log_tags == NULL ? "" : log_tags); - snprintf(buf, sizeof(buf), - "shell:export ANDROID_LOG_TAGS=\"%s\"; exec logcat", quoted); - free(quoted); + std::string cmd = "shell:export ANDROID_LOG_TAGS=\"" + quoted + "\"; exec logcat"; if (!strcmp(argv[0], "longcat")) { - strncat(buf, " -v long", sizeof(buf) - 1); + cmd += " -v long"; } - argc -= 1; - argv += 1; - while(argc-- > 0) { - quoted = escape_arg(*argv++); - strncat(buf, " ", sizeof(buf) - 1); - strncat(buf, quoted, sizeof(buf) - 1); - free(quoted); + --argc; + ++argv; + while (argc-- > 0) { + cmd += " " + escape_arg(*argv++); } - send_shellcommand(transport, serial, buf); - return 0; + return send_shell_command(transport, serial, cmd); } static int mkdirs(const char *path) @@ -869,22 +792,18 @@ static int mkdirs(const char *path) return 0; } -static int backup(int argc, char** argv) { - char buf[4096]; - char default_name[32]; - const char* filename = strcpy(default_name, "./backup.ab"); - int fd, outFd; - int i, j; +static int backup(int argc, const char** argv) { + const char* filename = "./backup.ab"; /* find, extract, and use any -f argument */ - for (i = 1; i < argc; i++) { + for (int i = 1; i < argc; i++) { if (!strcmp("-f", argv[i])) { if (i == argc-1) { fprintf(stderr, "adb: -f passed with no filename\n"); return usage(); } filename = argv[i+1]; - for (j = i+2; j <= argc; ) { + for (int j = i+2; j <= argc; ) { argv[i++] = argv[j++]; } argc -= 2; @@ -897,20 +816,21 @@ static int backup(int argc, char** argv) { adb_unlink(filename); mkdirs(filename); - outFd = adb_creat(filename, 0640); + int outFd = adb_creat(filename, 0640); if (outFd < 0) { fprintf(stderr, "adb: unable to open file %s\n", filename); return -1; } - snprintf(buf, sizeof(buf), "backup"); - for (argc--, argv++; argc; argc--, argv++) { - strncat(buf, ":", sizeof(buf) - strlen(buf) - 1); - strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1); + std::string cmd = "backup:"; + --argc; + ++argv; + while (argc-- > 0) { + cmd += " " + escape_arg(*argv++); } - D("backup. filename=%s buf=%s\n", filename, buf); - fd = adb_connect(buf); + D("backup. filename=%s cmd=%s\n", filename, cmd.c_str()); + int fd = adb_connect(cmd.c_str()); if (fd < 0) { fprintf(stderr, "adb: unable to connect for backup\n"); adb_close(outFd); @@ -925,7 +845,7 @@ static int backup(int argc, char** argv) { return 0; } -static int restore(int argc, char** argv) { +static int restore(int argc, const char** argv) { const char* filename; int fd, tarFd; @@ -953,81 +873,9 @@ static int restore(int argc, char** argv) { return 0; } -#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make" -static int top_works(const char *top) -{ - if (top != NULL && adb_is_absolute_host_path(top)) { - char path_buf[PATH_MAX]; - snprintf(path_buf, sizeof(path_buf), - "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top); - return access(path_buf, F_OK) == 0; - } - return 0; -} - -static char *find_top_from(const char *indir, char path_buf[PATH_MAX]) -{ - strcpy(path_buf, indir); - while (1) { - if (top_works(path_buf)) { - return path_buf; - } - char *s = adb_dirstop(path_buf); - if (s != NULL) { - *s = '\0'; - } else { - path_buf[0] = '\0'; - return NULL; - } - } -} - -static char *find_top(char path_buf[PATH_MAX]) -{ - char *top = getenv("ANDROID_BUILD_TOP"); - if (top != NULL && top[0] != '\0') { - if (!top_works(top)) { - fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top); - return NULL; - } - } else { - top = getenv("TOP"); - if (top != NULL && top[0] != '\0') { - if (!top_works(top)) { - fprintf(stderr, "adb: bad TOP value \"%s\"\n", top); - return NULL; - } - } else { - top = NULL; - } - } - - if (top != NULL) { - /* The environment pointed to a top directory that works. - */ - strcpy(path_buf, top); - return path_buf; - } - - /* The environment didn't help. Walk up the tree from the CWD - * to see if we can find the top. - */ - char dir[PATH_MAX]; - top = find_top_from(getcwd(dir, sizeof(dir)), path_buf); - if (top == NULL) { - /* If the CWD isn't under a good-looking top, see if the - * executable is. - */ - get_my_path(dir, PATH_MAX); - top = find_top_from(dir, path_buf); - } - return top; -} - /* <hint> may be: * - A simple product name * e.g., "sooner" -TODO: debug? sooner-debug, sooner:debug? * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir * e.g., "out/target/product/sooner" * - An absolute path to the PRODUCT_OUT dir @@ -1036,66 +884,57 @@ TODO: debug? sooner-debug, sooner:debug? * Given <hint>, try to construct an absolute path to the * ANDROID_PRODUCT_OUT dir. */ -static const char *find_product_out_path(const char *hint) -{ - static char path_buf[PATH_MAX]; - +static std::string find_product_out_path(const char* hint) { if (hint == NULL || hint[0] == '\0') { - return NULL; + return ""; } - /* If it's already absolute, don't bother doing any work. - */ + // If it's already absolute, don't bother doing any work. if (adb_is_absolute_host_path(hint)) { - strcpy(path_buf, hint); - return path_buf; - } - - /* If there are any slashes in it, assume it's a relative path; - * make it absolute. - */ - if (adb_dirstart(hint) != NULL) { - if (getcwd(path_buf, sizeof(path_buf)) == NULL) { - fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno)); - return NULL; - } - if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) { - fprintf(stderr, "adb: Couldn't assemble path\n"); - return NULL; - } - strcat(path_buf, OS_PATH_SEPARATOR_STR); - strcat(path_buf, hint); - return path_buf; - } - - /* It's a string without any slashes. Try to do something with it. - * - * Try to find the root of the build tree, and build a PRODUCT_OUT - * path from there. - */ - char top_buf[PATH_MAX]; - const char *top = find_top(top_buf); - if (top == NULL) { - fprintf(stderr, "adb: Couldn't find top of build tree\n"); - return NULL; - } -//TODO: if we have a way to indicate debug, look in out/debug/target/... - snprintf(path_buf, sizeof(path_buf), - "%s" OS_PATH_SEPARATOR_STR - "out" OS_PATH_SEPARATOR_STR - "target" OS_PATH_SEPARATOR_STR - "product" OS_PATH_SEPARATOR_STR - "%s", top_buf, hint); - if (access(path_buf, F_OK) < 0) { - fprintf(stderr, "adb: Couldn't find a product dir " - "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf); - return NULL; - } - return path_buf; + return hint; + } + + // If there are any slashes in it, assume it's a relative path; + // make it absolute. + if (adb_dirstart(hint) != nullptr) { + std::string cwd; + if (!getcwd(&cwd)) { + fprintf(stderr, "adb: getcwd failed: %s\n", strerror(errno)); + return ""; + } + return android::base::StringPrintf("%s%s%s", cwd.c_str(), OS_PATH_SEPARATOR_STR, hint); + } + + // It's a string without any slashes. Try to do something with it. + // + // Try to find the root of the build tree, and build a PRODUCT_OUT + // path from there. + char* top = getenv("ANDROID_BUILD_TOP"); + if (top == nullptr) { + fprintf(stderr, "adb: ANDROID_BUILD_TOP not set!\n"); + return ""; + } + + std::string path = top; + path += OS_PATH_SEPARATOR_STR; + path += "out"; + path += OS_PATH_SEPARATOR_STR; + path += "target"; + path += OS_PATH_SEPARATOR_STR; + path += "product"; + path += OS_PATH_SEPARATOR_STR; + path += hint; + if (!directory_exists(path)) { + fprintf(stderr, "adb: Couldn't find a product dir based on -p %s; " + "\"%s\" doesn't exist\n", hint, path.c_str()); + return ""; + } + return path; } -static void parse_push_pull_args(char **arg, int narg, char const **path1, char const **path2, - int *show_progress, int *copy_attrs) { +static void parse_push_pull_args(const char **arg, int narg, char const **path1, + char const **path2, int *show_progress, + int *copy_attrs) { *show_progress = 0; *copy_attrs = 0; @@ -1122,7 +961,18 @@ static void parse_push_pull_args(char **arg, int narg, char const **path1, char } } -int adb_commandline(int argc, char **argv) +static int adb_connect_command(const char* command) { + int fd = adb_connect(command); + if (fd != -1) { + read_and_dump(fd); + adb_close(fd); + return 0; + } + fprintf(stderr, "Error: %s\n", adb_error()); + return 1; +} + +int adb_commandline(int argc, const char **argv) { char buf[4096]; int no_daemon = 0; @@ -1131,18 +981,17 @@ int adb_commandline(int argc, char **argv) int persist = 0; int r; transport_type ttype = kTransportAny; - char* serial = NULL; - char* server_port_str = NULL; - - /* If defined, this should be an absolute path to - * the directory containing all of the various system images - * for a particular product. If not defined, and the adb - * command requires this information, then the user must - * specify the path using "-p". - */ - gProductOutPath = getenv("ANDROID_PRODUCT_OUT"); - if (gProductOutPath == NULL || gProductOutPath[0] == '\0') { - gProductOutPath = NULL; + const char* serial = NULL; + const char* server_port_str = NULL; + + // If defined, this should be an absolute path to + // the directory containing all of the various system images + // for a particular product. If not defined, and the adb + // command requires this information, then the user must + // specify the path using "-p". + char* ANDROID_PRODUCT_OUT = getenv("ANDROID_PRODUCT_OUT"); + if (ANDROID_PRODUCT_OUT != nullptr) { + gProductOutPath = ANDROID_PRODUCT_OUT; } // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint @@ -1162,17 +1011,17 @@ int adb_commandline(int argc, char **argv) } /* modifiers and flags */ - while(argc > 0) { - if(!strcmp(argv[0],"server")) { + while (argc > 0) { + if (!strcmp(argv[0],"server")) { is_server = 1; - } else if(!strcmp(argv[0],"nodaemon")) { + } else if (!strcmp(argv[0],"nodaemon")) { no_daemon = 1; } else if (!strcmp(argv[0], "fork-server")) { /* this is a special flag used only when the ADB client launches the ADB Server */ is_daemon = 1; - } else if(!strcmp(argv[0],"persist")) { + } else if (!strcmp(argv[0],"persist")) { persist = 1; - } else if(!strncmp(argv[0], "-p", 2)) { + } else if (!strncmp(argv[0], "-p", 2)) { const char *product = NULL; if (argv[0][2] == '\0') { if (argc < 2) return usage(); @@ -1183,16 +1032,15 @@ int adb_commandline(int argc, char **argv) product = argv[0] + 2; } gProductOutPath = find_product_out_path(product); - if (gProductOutPath == NULL) { - fprintf(stderr, "adb: could not resolve \"-p %s\"\n", - product); + if (gProductOutPath.empty()) { + fprintf(stderr, "adb: could not resolve \"-p %s\"\n", product); return usage(); } } else if (argv[0][0]=='-' && argv[0][1]=='s') { if (isdigit(argv[0][2])) { serial = argv[0] + 2; } else { - if(argc < 2 || argv[0][2] != '\0') return usage(); + if (argc < 2 || argv[0][2] != '\0') return usage(); serial = argv[1]; argc--; argv++; @@ -1203,7 +1051,7 @@ int adb_commandline(int argc, char **argv) ttype = kTransportLocal; } else if (!strcmp(argv[0],"-a")) { gListenAll = 1; - } else if(!strncmp(argv[0], "-H", 2)) { + } else if (!strncmp(argv[0], "-H", 2)) { const char *hostname = NULL; if (argv[0][2] == '\0') { if (argc < 2) return usage(); @@ -1215,7 +1063,7 @@ int adb_commandline(int argc, char **argv) } adb_set_tcp_name(hostname); - } else if(!strncmp(argv[0], "-P", 2)) { + } else if (!strncmp(argv[0], "-P", 2)) { if (argv[0][2] == '\0') { if (argc < 2) return usage(); server_port_str = argv[1]; @@ -1254,22 +1102,53 @@ int adb_commandline(int argc, char **argv) } else { r = launch_server(server_port); } - if(r) { + if (r) { fprintf(stderr,"* could not start server *\n"); } return r; } -top: - if(argc == 0) { + if (argc == 0) { return usage(); } - /* adb_connect() commands */ + /* handle wait-for-* prefix */ + if (!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) { + const char* service = argv[0]; + if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) { + if (ttype == kTransportUsb) { + service = "wait-for-usb"; + } else if (ttype == kTransportLocal) { + service = "wait-for-local"; + } else { + service = "wait-for-any"; + } + } - if(!strcmp(argv[0], "devices")) { + format_host_command(buf, sizeof buf, service, ttype, serial); + + if (adb_command(buf)) { + D("failure: %s *\n",adb_error()); + fprintf(stderr,"error: %s\n", adb_error()); + return 1; + } + + /* Allow a command to be run after wait-for-device, + * e.g. 'adb wait-for-device shell'. + */ + if (argc == 1) { + return 0; + } + + /* Fall through */ + argc--; + argv++; + } + + /* adb_connect() commands */ + if (!strcmp(argv[0], "devices")) { char *tmp; - char *listopt; + const char *listopt; if (argc < 2) listopt = ""; else if (argc == 2 && !strcmp(argv[1], "-l")) @@ -1280,7 +1159,7 @@ top: } snprintf(buf, sizeof buf, "host:%s%s", argv[0], listopt); tmp = adb_query(buf); - if(tmp) { + if (tmp) { printf("List of devices attached \n"); printf("%s\n", tmp); return 0; @@ -1288,8 +1167,7 @@ top: return 1; } } - - if(!strcmp(argv[0], "connect")) { + else if (!strcmp(argv[0], "connect")) { char *tmp; if (argc != 2) { fprintf(stderr, "Usage: adb connect <host>[:<port>]\n"); @@ -1297,15 +1175,14 @@ top: } snprintf(buf, sizeof buf, "host:connect:%s", argv[1]); tmp = adb_query(buf); - if(tmp) { + if (tmp) { printf("%s\n", tmp); return 0; } else { return 1; } } - - if(!strcmp(argv[0], "disconnect")) { + else if (!strcmp(argv[0], "disconnect")) { char *tmp; if (argc > 2) { fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n"); @@ -1317,22 +1194,17 @@ top: snprintf(buf, sizeof buf, "host:disconnect:"); } tmp = adb_query(buf); - if(tmp) { + if (tmp) { printf("%s\n", tmp); return 0; } else { return 1; } } - - if (!strcmp(argv[0], "emu")) { + else if (!strcmp(argv[0], "emu")) { return adb_send_emulator_command(argc, argv); } - - if(!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) { - int r; - int fd; - + else if (!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) { char h = (argv[0][0] == 'h'); if (h) { @@ -1340,7 +1212,7 @@ top: fflush(stdout); } - if(argc < 2) { + if (argc < 2) { D("starting interactive shell\n"); r = interactive_shell(); if (h) { @@ -1350,20 +1222,19 @@ top: return r; } - snprintf(buf, sizeof(buf), "shell:%s", argv[1]); + std::string cmd = "shell:"; + cmd += argv[1]; argc -= 2; argv += 2; while (argc-- > 0) { - char *quoted = escape_arg(*argv++); - strncat(buf, " ", sizeof(buf) - 1); - strncat(buf, quoted, sizeof(buf) - 1); - free(quoted); + cmd += " " + escape_arg(*argv++); } - for(;;) { - D("interactive shell loop. buff=%s\n", buf); - fd = adb_connect(buf); - if(fd >= 0) { + while (true) { + D("interactive shell loop. cmd=%s\n", cmd.c_str()); + int fd = adb_connect(cmd.c_str()); + int r; + if (fd >= 0) { D("about to read_and_dump(fd=%d)\n", fd); read_and_dump(fd); D("read_and_dump() done.\n"); @@ -1374,7 +1245,7 @@ top: r = -1; } - if(persist) { + if (persist) { fprintf(stderr,"\n- waiting for device -\n"); adb_sleep_ms(1000); do_cmd(ttype, serial, "wait-for-device", 0); @@ -1388,22 +1259,18 @@ top: } } } - - if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) { + else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) { int exec_in = !strcmp(argv[0], "exec-in"); - int fd; - snprintf(buf, sizeof buf, "exec:%s", argv[1]); + std::string cmd = "exec:"; + cmd += argv[1]; argc -= 2; argv += 2; while (argc-- > 0) { - char *quoted = escape_arg(*argv++); - strncat(buf, " ", sizeof(buf) - 1); - strncat(buf, quoted, sizeof(buf) - 1); - free(quoted); + cmd += " " + escape_arg(*argv++); } - fd = adb_connect(buf); + int fd = adb_connect(cmd.c_str()); if (fd < 0) { fprintf(stderr, "error: %s\n", adb_error()); return -1; @@ -1418,89 +1285,49 @@ top: adb_close(fd); return 0; } - - if(!strcmp(argv[0], "kill-server")) { + else if (!strcmp(argv[0], "kill-server")) { int fd; fd = _adb_connect("host:kill"); - if(fd == -1) { + if (fd == -1) { fprintf(stderr,"* server not running *\n"); return 1; } return 0; } - - if(!strcmp(argv[0], "sideload")) { - if(argc != 2) return usage(); + else if (!strcmp(argv[0], "sideload")) { + if (argc != 2) return usage(); if (adb_sideload_host(argv[1])) { return 1; } else { return 0; } } - - if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot") - || !strcmp(argv[0], "reboot-bootloader") - || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb") - || !strcmp(argv[0], "root") || !strcmp(argv[0], "disable-verity")) { + else if (!strcmp(argv[0], "remount") || + !strcmp(argv[0], "reboot") || + !strcmp(argv[0], "reboot-bootloader") || + !strcmp(argv[0], "tcpip") || + !strcmp(argv[0], "usb") || + !strcmp(argv[0], "root") || + !strcmp(argv[0], "unroot") || + !strcmp(argv[0], "disable-verity") || + !strcmp(argv[0], "enable-verity")) { char command[100]; - if (!strcmp(argv[0], "reboot-bootloader")) + if (!strcmp(argv[0], "reboot-bootloader")) { snprintf(command, sizeof(command), "reboot:bootloader"); - else if (argc > 1) + } else if (argc > 1) { snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]); - else + } else { snprintf(command, sizeof(command), "%s:", argv[0]); - int fd = adb_connect(command); - if(fd >= 0) { - read_and_dump(fd); - adb_close(fd); - return 0; } - fprintf(stderr,"error: %s\n", adb_error()); - return 1; + return adb_connect_command(command); } - - if(!strcmp(argv[0], "bugreport")) { + else if (!strcmp(argv[0], "bugreport")) { if (argc != 1) return usage(); do_cmd(ttype, serial, "shell", "bugreport", 0); return 0; } - /* adb_command() wrapper commands */ - - if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) { - char* service = argv[0]; - if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) { - if (ttype == kTransportUsb) { - service = "wait-for-usb"; - } else if (ttype == kTransportLocal) { - service = "wait-for-local"; - } else { - service = "wait-for-any"; - } - } - - format_host_command(buf, sizeof buf, service, ttype, serial); - - if (adb_command(buf)) { - D("failure: %s *\n",adb_error()); - fprintf(stderr,"error: %s\n", adb_error()); - return 1; - } - - /* Allow a command to be run after wait-for-device, - * e.g. 'adb wait-for-device shell'. - */ - if(argc > 1) { - argc--; - argv++; - goto top; - } - return 0; - } - - if(!strcmp(argv[0], "forward") || - !strcmp(argv[0], "reverse")) - { + else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) { char host_prefix[64]; char reverse = (char) !strcmp(argv[0], "reverse"); char remove = 0; @@ -1581,25 +1408,22 @@ top: { if (argc != 3) return usage(); - const char* command = no_rebind ? "forward:norebind:" : "forward"; + const char* command = no_rebind ? "forward:norebind" : "forward"; snprintf(buf, sizeof buf, "%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]); } - if(adb_command(buf)) { + if (adb_command(buf)) { fprintf(stderr,"error: %s\n", adb_error()); return 1; } return 0; } - /* do_sync_*() commands */ - - if(!strcmp(argv[0], "ls")) { - if(argc != 2) return usage(); + else if (!strcmp(argv[0], "ls")) { + if (argc != 2) return usage(); return do_sync_ls(argv[1]); } - - if(!strcmp(argv[0], "push")) { + else if (!strcmp(argv[0], "push")) { int show_progress = 0; int copy_attrs = 0; // unused const char* lpath = NULL, *rpath = NULL; @@ -1612,8 +1436,7 @@ top: return usage(); } - - if(!strcmp(argv[0], "pull")) { + else if (!strcmp(argv[0], "pull")) { int show_progress = 0; int copy_attrs = 0; const char* rpath = NULL, *lpath = "."; @@ -1626,62 +1449,65 @@ top: return usage(); } - - if (!strcmp(argv[0], "install")) { + else if (!strcmp(argv[0], "install")) { if (argc < 2) return usage(); return install_app(ttype, serial, argc, argv); } - - if (!strcmp(argv[0], "install-multiple")) { + else if (!strcmp(argv[0], "install-multiple")) { if (argc < 2) return usage(); return install_multiple_app(ttype, serial, argc, argv); } - - if (!strcmp(argv[0], "uninstall")) { + else if (!strcmp(argv[0], "uninstall")) { if (argc < 2) return usage(); return uninstall_app(ttype, serial, argc, argv); } - - if(!strcmp(argv[0], "sync")) { - char *srcarg, *android_srcpath, *data_srcpath, *vendor_srcpath; - int listonly = 0; - - int ret; - if(argc < 2) { - /* No local path was specified. */ - srcarg = NULL; + else if (!strcmp(argv[0], "sync")) { + std::string src; + bool list_only = false; + if (argc < 2) { + // No local path was specified. + src = ""; } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) { - listonly = 1; + list_only = true; if (argc == 3) { - srcarg = argv[2]; + src = argv[2]; } else { - srcarg = NULL; + src = ""; } - } else if(argc == 2) { - /* A local path or "android"/"data" arg was specified. */ - srcarg = argv[1]; + } else if (argc == 2) { + // A local path or "android"/"data" arg was specified. + src = argv[1]; } else { return usage(); } - ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath, &vendor_srcpath); - if(ret != 0) return usage(); - if(android_srcpath != NULL) - ret = do_sync_sync(android_srcpath, "/system", listonly); - if(ret == 0 && vendor_srcpath != NULL) - ret = do_sync_sync(vendor_srcpath, "/vendor", listonly); - if(ret == 0 && data_srcpath != NULL) - ret = do_sync_sync(data_srcpath, "/data", listonly); + if (src != "" && + src != "system" && src != "data" && src != "vendor" && src != "oem") { + return usage(); + } - free(android_srcpath); - free(vendor_srcpath); - free(data_srcpath); - return ret; - } + std::string system_src_path = product_file("system"); + std::string data_src_path = product_file("data"); + std::string vendor_src_path = product_file("vendor"); + std::string oem_src_path = product_file("oem"); + int rc = 0; + if (rc == 0 && (src.empty() || src == "system")) { + rc = do_sync_sync(system_src_path, "/system", list_only); + } + if (rc == 0 && (src.empty() || src == "vendor") && directory_exists(vendor_src_path)) { + rc = do_sync_sync(vendor_src_path, "/vendor", list_only); + } + if (rc == 0 && (src.empty() || src == "oem") && directory_exists(oem_src_path)) { + rc = do_sync_sync(oem_src_path, "/oem", list_only); + } + if (rc == 0 && (src.empty() || src == "data")) { + rc = do_sync_sync(data_src_path, "/data", list_only); + } + return rc; + } /* passthrough commands */ - - if(!strcmp(argv[0],"get-state") || + else if (!strcmp(argv[0],"get-state") || !strcmp(argv[0],"get-serialno") || !strcmp(argv[0],"get-devpath")) { @@ -1689,65 +1515,46 @@ top: format_host_command(buf, sizeof buf, argv[0], ttype, serial); tmp = adb_query(buf); - if(tmp) { + if (tmp) { printf("%s\n", tmp); return 0; } else { return 1; } } - /* other commands */ - - if(!strcmp(argv[0],"status-window")) { + else if (!strcmp(argv[0],"status-window")) { status_window(ttype, serial); return 0; } - - if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) { + else if (!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) { return logcat(ttype, serial, argc, argv); } - - if(!strcmp(argv[0],"ppp")) { + else if (!strcmp(argv[0],"ppp")) { return ppp(argc, argv); } - - if (!strcmp(argv[0], "start-server")) { + else if (!strcmp(argv[0], "start-server")) { return adb_connect("host:start-server"); } - - if (!strcmp(argv[0], "backup")) { + else if (!strcmp(argv[0], "backup")) { return backup(argc, argv); } - - if (!strcmp(argv[0], "restore")) { + else if (!strcmp(argv[0], "restore")) { return restore(argc, argv); } - - if (!strcmp(argv[0], "keygen")) { + else if (!strcmp(argv[0], "keygen")) { if (argc < 2) return usage(); return adb_auth_keygen(argv[1]); } - - if (!strcmp(argv[0], "jdwp")) { - int fd = adb_connect("jdwp"); - if (fd >= 0) { - read_and_dump(fd); - adb_close(fd); - return 0; - } else { - fprintf(stderr, "error: %s\n", adb_error()); - return -1; - } + else if (!strcmp(argv[0], "jdwp")) { + return adb_connect_command("jdwp"); } - /* "adb /?" is a common idiom under Windows */ - if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) { + else if (!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) { help(); return 0; } - - if(!strcmp(argv[0], "version")) { + else if (!strcmp(argv[0], "version")) { version(stdout); return 0; } @@ -1757,9 +1564,9 @@ top: } #define MAX_ARGV_LENGTH 16 -static int do_cmd(transport_type ttype, char* serial, char *cmd, ...) +static int do_cmd(transport_type ttype, const char* serial, const char *cmd, ...) { - char *argv[MAX_ARGV_LENGTH]; + const char *argv[MAX_ARGV_LENGTH]; int argc; va_list ap; @@ -1792,72 +1599,20 @@ static int do_cmd(transport_type ttype, char* serial, char *cmd, ...) return adb_commandline(argc, argv); } -int find_sync_dirs(const char *srcarg, - char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out) -{ - char *android_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL; - struct stat st; - - if(srcarg == NULL) { - android_srcdir = product_file("system"); - data_srcdir = product_file("data"); - vendor_srcdir = product_file("vendor"); - /* Check if vendor partition exists */ - if (lstat(vendor_srcdir, &st) || !S_ISDIR(st.st_mode)) - vendor_srcdir = NULL; - } else { - /* srcarg may be "data", "system" or NULL. - * if srcarg is NULL, then both data and system are synced - */ - if(strcmp(srcarg, "system") == 0) { - android_srcdir = product_file("system"); - } else if(strcmp(srcarg, "data") == 0) { - data_srcdir = product_file("data"); - } else if(strcmp(srcarg, "vendor") == 0) { - vendor_srcdir = product_file("vendor"); - } else { - /* It's not "system", "vendor", or "data". - */ - return 1; - } - } - - if(android_srcdir_out != NULL) - *android_srcdir_out = android_srcdir; - else - free(android_srcdir); - - if(vendor_srcdir_out != NULL) - *vendor_srcdir_out = vendor_srcdir; - else - free(vendor_srcdir); - - if(data_srcdir_out != NULL) - *data_srcdir_out = data_srcdir; - else - free(data_srcdir); - return 0; -} - -static int pm_command(transport_type transport, char* serial, - int argc, char** argv) +static int pm_command(transport_type transport, const char* serial, + int argc, const char** argv) { - char buf[4096]; - - snprintf(buf, sizeof(buf), "shell:pm"); + std::string cmd = "shell:pm"; - while(argc-- > 0) { - char *quoted = escape_arg(*argv++); - strncat(buf, " ", sizeof(buf) - 1); - strncat(buf, quoted, sizeof(buf) - 1); - free(quoted); + while (argc-- > 0) { + cmd += " " + escape_arg(*argv++); } - send_shellcommand(transport, serial, buf); - return 0; + return send_shell_command(transport, serial, cmd); } -int uninstall_app(transport_type transport, char* serial, int argc, char** argv) +static int uninstall_app(transport_type transport, const char* serial, int argc, + const char** argv) { /* if the user choose the -k option, we refuse to do it until devices are out with the option to uninstall the remaining data somehow (adb/ui) */ @@ -1875,18 +1630,10 @@ int uninstall_app(transport_type transport, char* serial, int argc, char** argv) return pm_command(transport, serial, argc, argv); } -static int delete_file(transport_type transport, char* serial, char* filename) +static int delete_file(transport_type transport, const char* serial, char* filename) { - char buf[4096]; - char* quoted; - - snprintf(buf, sizeof(buf), "shell:rm -f "); - quoted = escape_arg(filename); - strncat(buf, quoted, sizeof(buf)-1); - free(quoted); - - send_shellcommand(transport, serial, buf); - return 0; + std::string cmd = "shell:rm -f " + escape_arg(filename); + return send_shell_command(transport, serial, cmd); } static const char* get_basename(const char* filename) @@ -1900,7 +1647,8 @@ static const char* get_basename(const char* filename) } } -int install_app(transport_type transport, char* serial, int argc, char** argv) +static int install_app(transport_type transport, const char* serial, int argc, + const char** argv) { static const char *const DATA_DEST = "/data/local/tmp/%s"; static const char *const SD_DEST = "/sdcard/tmp/%s"; @@ -1918,7 +1666,7 @@ int install_app(transport_type transport, char* serial, int argc, char** argv) // All other arguments passed through verbatim. int last_apk = -1; for (i = argc - 1; i >= 0; i--) { - char* file = argv[i]; + const char* file = argv[i]; char* dot = strrchr(file, '.'); if (dot && !strcasecmp(dot, ".apk")) { if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) { @@ -1936,7 +1684,7 @@ int install_app(transport_type transport, char* serial, int argc, char** argv) return -1; } - char* apk_file = argv[last_apk]; + const char* apk_file = argv[last_apk]; char apk_dest[PATH_MAX]; snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file)); int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */); @@ -1946,25 +1694,25 @@ int install_app(transport_type transport, char* serial, int argc, char** argv) argv[last_apk] = apk_dest; /* destination name, not source location */ } - pm_command(transport, serial, argc, argv); + err = pm_command(transport, serial, argc, argv); cleanup_apk: delete_file(transport, serial, apk_dest); return err; } -int install_multiple_app(transport_type transport, char* serial, int argc, char** argv) +static int install_multiple_app(transport_type transport, const char* serial, int argc, + const char** argv) { - char buf[1024]; int i; struct stat sb; - unsigned long long total_size = 0; + uint64_t total_size = 0; // Find all APK arguments starting at end. // All other arguments passed through verbatim. int first_apk = -1; for (i = argc - 1; i >= 0; i--) { - char* file = argv[i]; + const char* file = argv[i]; char* dot = strrchr(file, '.'); if (dot && !strcasecmp(dot, ".apk")) { if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) { @@ -1984,20 +1732,22 @@ int install_multiple_app(transport_type transport, char* serial, int argc, char* return 1; } - snprintf(buf, sizeof(buf), "exec:pm install-create -S %lld", total_size); +#if defined(_WIN32) // Remove when we're using clang for Win32. + std::string cmd = android::base::StringPrintf("exec:pm install-create -S %u", (unsigned) total_size); +#else + std::string cmd = android::base::StringPrintf("exec:pm install-create -S %" PRIu64, total_size); +#endif for (i = 1; i < first_apk; i++) { - char *quoted = escape_arg(argv[i]); - strncat(buf, " ", sizeof(buf) - 1); - strncat(buf, quoted, sizeof(buf) - 1); - free(quoted); + cmd += " " + escape_arg(argv[i]); } // Create install session - int fd = adb_connect(buf); + int fd = adb_connect(cmd.c_str()); if (fd < 0) { fprintf(stderr, "Connect error for create: %s\n", adb_error()); return -1; } + char buf[BUFSIZ]; read_status_line(fd, buf, sizeof(buf)); adb_close(fd); @@ -2019,15 +1769,22 @@ int install_multiple_app(transport_type transport, char* serial, int argc, char* // Valid session, now stream the APKs int success = 1; for (i = first_apk; i < argc; i++) { - char* file = argv[i]; + const char* file = argv[i]; if (stat(file, &sb) == -1) { fprintf(stderr, "Failed to stat %s\n", file); success = 0; goto finalize_session; } - snprintf(buf, sizeof(buf), "exec:pm install-write -S %lld %d %d_%s -", - (long long int) sb.st_size, session_id, i, get_basename(file)); +#if defined(_WIN32) // Remove when we're using clang for Win32. + std::string cmd = android::base::StringPrintf( + "exec:pm install-write -S %u %d %d_%s -", + (unsigned) sb.st_size, session_id, i, get_basename(file)); +#else + std::string cmd = android::base::StringPrintf( + "exec:pm install-write -S %" PRIu64 " %d %d_%s -", + static_cast<uint64_t>(sb.st_size), session_id, i, get_basename(file)); +#endif int localFd = adb_open(file, O_RDONLY); if (localFd < 0) { @@ -2036,7 +1793,7 @@ int install_multiple_app(transport_type transport, char* serial, int argc, char* goto finalize_session; } - int remoteFd = adb_connect(buf); + int remoteFd = adb_connect(cmd.c_str()); if (remoteFd < 0) { fprintf(stderr, "Connect error for write: %s\n", adb_error()); adb_close(localFd); diff --git a/adb/console.c b/adb/console.cpp index b813d33..452ee41 100644 --- a/adb/console.c +++ b/adb/console.cpp @@ -24,7 +24,7 @@ static int connect_to_console(void) } -int adb_send_emulator_command(int argc, char** argv) +int adb_send_emulator_command(int argc, const char** argv) { int fd, nn; diff --git a/adb/fdevent.c b/adb/fdevent.cpp index 43e600c..0c43c5e 100644 --- a/adb/fdevent.c +++ b/adb/fdevent.cpp @@ -15,25 +15,23 @@ ** limitations under the License. */ -#include <sys/ioctl.h> +#define TRACE_TAG TRACE_FDEVENT -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> +#include "sysdeps.h" +#include "fdevent.h" +#include <errno.h> #include <fcntl.h> - #include <stdarg.h> #include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include "adb_io.h" #include "adb_trace.h" -#include "fdevent.h" -#include "transport.h" -#include "sysdeps.h" - -#define TRACE_TAG TRACE_FDEVENT /* !!! Do not enable DEBUG for the adb that will run as the server: ** both stdout and stderr are used to communicate between the client @@ -88,6 +86,12 @@ static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata); static fdevent list_pending = { .next = &list_pending, .prev = &list_pending, + .fd = -1, + .force_eof = 0, + .state = 0, + .events = 0, + .func = nullptr, + .arg = nullptr, }; static fdevent **fd_table = 0; @@ -312,7 +316,7 @@ static int fdevent_fd_check(fd_set *fds) } #if !DEBUG -static inline void dump_all_fds(const char *extra_msg) {} +static inline void dump_all_fds(const char* /* extra_msg */) {} #else static void dump_all_fds(const char *extra_msg) { @@ -434,7 +438,8 @@ static void fdevent_register(fdevent *fde) while(fd_table_max <= fde->fd) { fd_table_max *= 2; } - fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max); + fd_table = reinterpret_cast<fdevent**>( + realloc(fd_table, sizeof(fdevent*) * fd_table_max)); if(fd_table == 0) { FATAL("could not expand fd_table to %d entries\n", fd_table_max); } @@ -505,7 +510,8 @@ static void fdevent_call_fdfunc(fdevent* fde) fde->func(fde->fd, events, fde->arg); } -static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata) +static void fdevent_subproc_event_func(int fd, unsigned ev, + void* /* userdata */) { D("subproc handling on fd=%d ev=%04x\n", fd, ev); @@ -520,7 +526,7 @@ static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata) if(ev & FDE_READ){ int subproc_fd; - if(readx(fd, &subproc_fd, sizeof(subproc_fd))) { + if(!ReadFdExactly(fd, &subproc_fd, sizeof(subproc_fd))) { FATAL("Failed to read the subproc's fd from fd=%d\n", fd); } if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) { @@ -579,6 +585,7 @@ void fdevent_destroy(fdevent *fde) FATAL("fde %p not created by fdevent_create()\n", fde); } fdevent_remove(fde); + free(fde); } void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg) @@ -661,6 +668,8 @@ void fdevent_subproc_setup() if(adb_socketpair(s)) { FATAL("cannot create shell-exit socket-pair\n"); } + D("socketpair: (%d,%d)", s[0], s[1]); + SHELL_EXIT_NOTIFY_FD = s[0]; fdevent *fde; fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL); diff --git a/adb/fdevent.h b/adb/fdevent.h index a0ebe2a..8d84b29 100644 --- a/adb/fdevent.h +++ b/adb/fdevent.h @@ -28,7 +28,7 @@ /* features that may be set (via the events set/add/del interface) */ #define FDE_DONT_CLOSE 0x0080 -typedef struct fdevent fdevent; +struct fdevent; typedef void (*fd_func)(int fd, unsigned events, void *userdata); @@ -64,20 +64,18 @@ void fdevent_set_timeout(fdevent *fde, int64_t timeout_ms); */ void fdevent_loop(); -struct fdevent -{ +struct fdevent { fdevent *next; fdevent *prev; int fd; int force_eof; - unsigned short state; - unsigned short events; + uint16_t state; + uint16_t events; fd_func func; void *arg; }; - #endif diff --git a/adb/file_sync_client.c b/adb/file_sync_client.cpp index ad59e81..49d8783 100644 --- a/adb/file_sync_client.c +++ b/adb/file_sync_client.cpp @@ -14,25 +14,25 @@ * limitations under the License. */ +#include <dirent.h> +#include <errno.h> +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <errno.h> #include <sys/stat.h> #include <sys/time.h> -#include <time.h> -#include <dirent.h> -#include <limits.h> #include <sys/types.h> -#include <zipfile/zipfile.h> +#include <time.h> #include <utime.h> #include "sysdeps.h" + #include "adb.h" #include "adb_client.h" +#include "adb_io.h" #include "file_sync_service.h" - static unsigned long long total_bytes; static long long start_time; @@ -86,7 +86,7 @@ void sync_quit(int fd) msg.req.id = ID_QUIT; msg.req.namelen = 0; - writex(fd, &msg.req, sizeof(msg.req)); + WriteFdExactly(fd, &msg.req, sizeof(msg.req)); } typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie); @@ -103,20 +103,20 @@ int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie) msg.req.id = ID_LIST; msg.req.namelen = htoll(len); - if(writex(fd, &msg.req, sizeof(msg.req)) || - writex(fd, path, len)) { + if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || + !WriteFdExactly(fd, path, len)) { goto fail; } for(;;) { - if(readx(fd, &msg.dent, sizeof(msg.dent))) break; + if(!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break; if(msg.dent.id == ID_DONE) return 0; if(msg.dent.id != ID_DENT) break; len = ltohl(msg.dent.namelen); if(len > 256) break; - if(readx(fd, buf, len)) break; + if(!ReadFdExactly(fd, buf, len)) break; buf[len] = 0; func(ltohl(msg.dent.mode), @@ -130,8 +130,6 @@ fail: return -1; } -typedef struct syncsendbuf syncsendbuf; - struct syncsendbuf { unsigned id; unsigned size; @@ -149,12 +147,12 @@ int sync_readtime(int fd, const char *path, unsigned int *timestamp, msg.req.id = ID_STAT; msg.req.namelen = htoll(len); - if(writex(fd, &msg.req, sizeof(msg.req)) || - writex(fd, path, len)) { + if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || + !WriteFdExactly(fd, path, len)) { return -1; } - if(readx(fd, &msg.stat, sizeof(msg.stat))) { + if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) { return -1; } @@ -175,8 +173,8 @@ static int sync_start_readtime(int fd, const char *path) msg.req.id = ID_STAT; msg.req.namelen = htoll(len); - if(writex(fd, &msg.req, sizeof(msg.req)) || - writex(fd, path, len)) { + if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || + !WriteFdExactly(fd, path, len)) { return -1; } @@ -188,7 +186,7 @@ static int sync_finish_readtime(int fd, unsigned int *timestamp, { syncmsg msg; - if(readx(fd, &msg.stat, sizeof(msg.stat))) + if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) return -1; if(msg.stat.id != ID_STAT) @@ -209,12 +207,12 @@ int sync_readmode(int fd, const char *path, unsigned *mode) msg.req.id = ID_STAT; msg.req.namelen = htoll(len); - if(writex(fd, &msg.req, sizeof(msg.req)) || - writex(fd, path, len)) { + if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || + !WriteFdExactly(fd, path, len)) { return -1; } - if(readx(fd, &msg.stat, sizeof(msg.stat))) { + if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) { return -1; } @@ -240,7 +238,7 @@ static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show if (show_progress) { // Determine local file size. struct stat st; - if (fstat(lfd, &st)) { + if (stat(path, &st)) { fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno)); return -1; } @@ -264,7 +262,7 @@ static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show } sbuf->size = htoll(ret); - if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){ + if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + ret)){ err = -1; break; } @@ -294,7 +292,7 @@ static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *s memcpy(sbuf->data, &file_buffer[total], count); sbuf->size = htoll(count); - if(writex(fd, sbuf, sizeof(unsigned) * 2 + count)){ + if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + count)){ err = -1; break; } @@ -309,7 +307,9 @@ static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *s return err; } -#ifdef HAVE_SYMLINKS +#if defined(_WIN32) +extern int write_data_link(int fd, const char *path, syncsendbuf *sbuf) __attribute__((error("no symlinks on Windows"))); +#else static int write_data_link(int fd, const char *path, syncsendbuf *sbuf) { int len, ret; @@ -324,7 +324,7 @@ static int write_data_link(int fd, const char *path, syncsendbuf *sbuf) sbuf->size = htoll(len + 1); sbuf->id = ID_DATA; - ret = writex(fd, sbuf, sizeof(unsigned) * 2 + len + 1); + ret = !WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1); if(ret) return -1; @@ -353,8 +353,8 @@ static int sync_send(int fd, const char *lpath, const char *rpath, msg.req.id = ID_SEND; msg.req.namelen = htoll(len + r); - if(writex(fd, &msg.req, sizeof(msg.req)) || - writex(fd, rpath, len) || writex(fd, tmp, r)) { + if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || + !WriteFdExactly(fd, rpath, len) || !WriteFdExactly(fd, tmp, r)) { free(file_buffer); goto fail; } @@ -364,26 +364,24 @@ static int sync_send(int fd, const char *lpath, const char *rpath, free(file_buffer); } else if (S_ISREG(mode)) write_data_file(fd, lpath, sbuf, show_progress); -#ifdef HAVE_SYMLINKS else if (S_ISLNK(mode)) write_data_link(fd, lpath, sbuf); -#endif else goto fail; msg.data.id = ID_DONE; msg.data.size = htoll(mtime); - if(writex(fd, &msg.data, sizeof(msg.data))) + if(!WriteFdExactly(fd, &msg.data, sizeof(msg.data))) goto fail; - if(readx(fd, &msg.status, sizeof(msg.status))) + if(!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) return -1; if(msg.status.id != ID_OKAY) { if(msg.status.id == ID_FAIL) { len = ltohl(msg.status.msglen); if(len > 256) len = 256; - if(readx(fd, sbuf->data, len)) { + if(!ReadFdExactly(fd, sbuf->data, len)) { return -1; } sbuf->data[len] = 0; @@ -439,12 +437,12 @@ int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress) stat_msg.req.id = ID_STAT; stat_msg.req.namelen = htoll(len); - if (writex(fd, &stat_msg.req, sizeof(stat_msg.req)) || - writex(fd, rpath, len)) { + if (!WriteFdExactly(fd, &stat_msg.req, sizeof(stat_msg.req)) || + !WriteFdExactly(fd, rpath, len)) { return -1; } - if (readx(fd, &stat_msg.stat, sizeof(stat_msg.stat))) { + if (!ReadFdExactly(fd, &stat_msg.stat, sizeof(stat_msg.stat))) { return -1; } @@ -455,12 +453,12 @@ int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress) msg.req.id = ID_RECV; msg.req.namelen = htoll(len); - if(writex(fd, &msg.req, sizeof(msg.req)) || - writex(fd, rpath, len)) { + if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || + !WriteFdExactly(fd, rpath, len)) { return -1; } - if(readx(fd, &msg.data, sizeof(msg.data))) { + if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) { return -1; } id = msg.data.id; @@ -479,7 +477,7 @@ int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress) } for(;;) { - if(readx(fd, &msg.data, sizeof(msg.data))) { + if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) { return -1; } id = msg.data.id; @@ -494,12 +492,12 @@ int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress) return -1; } - if(readx(fd, buffer, len)) { + if(!ReadFdExactly(fd, buffer, len)) { adb_close(lfd); return -1; } - if(writex(lfd, buffer, len)) { + if(!WriteFdExactly(lfd, buffer, len)) { fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno)); adb_close(lfd); return -1; @@ -522,24 +520,19 @@ remote_error: if(id == ID_FAIL) { len = ltohl(msg.data.size); if(len > 256) len = 256; - if(readx(fd, buffer, len)) { + if(!ReadFdExactly(fd, buffer, len)) { return -1; } buffer[len] = 0; } else { memcpy(buffer, &id, 4); buffer[4] = 0; -// strcpy(buffer,"unknown reason"); } fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer); return 0; } - - /* --- */ - - static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie) { @@ -562,8 +555,6 @@ int do_sync_ls(const char *path) } } -typedef struct copyinfo copyinfo; - struct copyinfo { copyinfo *next; @@ -573,7 +564,6 @@ struct copyinfo unsigned int mode; unsigned int size; int flag; - //char data[0]; }; copyinfo *mkcopyinfo(const char *spath, const char *dpath, @@ -585,7 +575,8 @@ copyinfo *mkcopyinfo(const char *spath, const char *dpath, int ssize = slen + nlen + 2; int dsize = dlen + nlen + 2; - copyinfo *ci = malloc(sizeof(copyinfo) + ssize + dsize); + copyinfo *ci = reinterpret_cast<copyinfo*>( + malloc(sizeof(copyinfo) + ssize + dsize)); if(ci == 0) { fprintf(stderr,"out of memory\n"); abort(); @@ -601,7 +592,6 @@ copyinfo *mkcopyinfo(const char *spath, const char *dpath, snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name); snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name); -// fprintf(stderr,"mkcopyinfo('%s','%s')\n", ci->src, ci->dst); return ci; } @@ -615,8 +605,6 @@ static int local_build_list(copyinfo **filelist, copyinfo *dirlist = 0; copyinfo *ci, *next; -// fprintf(stderr,"local_build_list('%s','%s')\n", lpath, rpath); - d = opendir(lpath); if(d == 0) { fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno)); @@ -692,14 +680,14 @@ static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, i if((lpath[0] == 0) || (rpath[0] == 0)) return -1; if(lpath[strlen(lpath) - 1] != '/') { int tmplen = strlen(lpath)+2; - char *tmp = malloc(tmplen); + char *tmp = reinterpret_cast<char*>(malloc(tmplen)); if(tmp == 0) return -1; snprintf(tmp, tmplen, "%s/",lpath); lpath = tmp; } if(rpath[strlen(rpath) - 1] != '/') { int tmplen = strlen(rpath)+2; - char *tmp = malloc(tmplen); + char *tmp = reinterpret_cast<char*>(malloc(tmplen)); if(tmp == 0) return -1; snprintf(tmp, tmplen, "%s/",rpath); rpath = tmp; @@ -792,7 +780,8 @@ int do_sync_push(const char *lpath, const char *rpath, int show_progress) name++; } int tmplen = strlen(name) + strlen(rpath) + 2; - char *tmp = malloc(strlen(name) + strlen(rpath) + 2); + char *tmp = reinterpret_cast<char*>( + malloc(strlen(name) + strlen(rpath) + 2)); if(tmp == 0) return 1; snprintf(tmp, tmplen, "%s/%s", rpath, name); rpath = tmp; @@ -811,12 +800,12 @@ int do_sync_push(const char *lpath, const char *rpath, int show_progress) } -typedef struct { +struct sync_ls_build_list_cb_args { copyinfo **filelist; copyinfo **dirlist; const char *rpath; const char *lpath; -} sync_ls_build_list_cb_args; +}; void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time, @@ -880,7 +869,7 @@ static int remote_build_list(int syncfd, copyinfo **filelist, return 0; } -static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int mode) +static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode) { struct utimbuf times = { time, time }; int r1 = utime(lpath, ×); @@ -893,6 +882,21 @@ static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int return r1 ? : r2; } +/* Return a copy of the path string with / appended if needed */ +static char *add_slash_to_path(const char *path) +{ + if (path[strlen(path) - 1] != '/') { + size_t len = strlen(path) + 2; + char *path_with_slash = reinterpret_cast<char*>(malloc(len)); + if (path_with_slash == NULL) + return NULL; + snprintf(path_with_slash, len, "%s/", path); + return path_with_slash; + } else { + return strdup(path); + } +} + static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, int copy_attrs) { @@ -900,28 +904,32 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, copyinfo *ci, *next; int pulled = 0; int skipped = 0; + char *rpath_clean = NULL; + char *lpath_clean = NULL; + int ret = 0; + + if (rpath[0] == '\0' || lpath[0] == '\0') { + ret = -1; + goto finish; + } /* Make sure that both directory paths end in a slash. */ - if (rpath[0] == 0 || lpath[0] == 0) return -1; - if (rpath[strlen(rpath) - 1] != '/') { - int tmplen = strlen(rpath) + 2; - char *tmp = malloc(tmplen); - if (tmp == 0) return -1; - snprintf(tmp, tmplen, "%s/", rpath); - rpath = tmp; + rpath_clean = add_slash_to_path(rpath); + if (!rpath_clean) { + ret = -1; + goto finish; } - if (lpath[strlen(lpath) - 1] != '/') { - int tmplen = strlen(lpath) + 2; - char *tmp = malloc(tmplen); - if (tmp == 0) return -1; - snprintf(tmp, tmplen, "%s/", lpath); - lpath = tmp; + lpath_clean = add_slash_to_path(lpath); + if (!lpath_clean) { + ret = -1; + goto finish; } - fprintf(stderr, "pull: building file list...\n"); /* Recursively build the list of files to copy. */ - if (remote_build_list(fd, &filelist, rpath, lpath)) { - return -1; + fprintf(stderr, "pull: building file list...\n"); + if (remote_build_list(fd, &filelist, rpath_clean, lpath_clean)) { + ret = -1; + goto finish; } for (ci = filelist; ci != 0; ci = next) { @@ -929,11 +937,13 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, if (ci->flag == 0) { fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst); if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) { - return 1; + ret = -1; + goto finish; } if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) { - return 1; + ret = -1; + goto finish; } pulled++; } else { @@ -946,7 +956,10 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, pulled, (pulled == 1) ? "" : "s", skipped, (skipped == 1) ? "" : "s"); - return 0; +finish: + free(lpath_clean); + free(rpath_clean); + return ret; } int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs) @@ -983,7 +996,7 @@ int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int co name++; } int tmplen = strlen(name) + strlen(lpath) + 2; - char *tmp = malloc(tmplen); + char *tmp = reinterpret_cast<char*>(malloc(tmplen)); if(tmp == 0) return 1; snprintf(tmp, tmplen, "%s/%s", lpath, name); lpath = tmp; @@ -1014,18 +1027,18 @@ int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int co } } -int do_sync_sync(const char *lpath, const char *rpath, int listonly) +int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) { - fprintf(stderr,"syncing %s...\n",rpath); + fprintf(stderr, "syncing %s...\n", rpath.c_str()); int fd = adb_connect("sync:"); - if(fd < 0) { - fprintf(stderr,"error: %s\n", adb_error()); + if (fd < 0) { + fprintf(stderr, "error: %s\n", adb_error()); return 1; } BEGIN(); - if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){ + if (copy_local_dir_remote(fd, lpath.c_str(), rpath.c_str(), 1, list_only)) { return 1; } else { END(); diff --git a/adb/file_sync_service.c b/adb/file_sync_service.cpp index 7933858..e8e9a0f 100644 --- a/adb/file_sync_service.c +++ b/adb/file_sync_service.cpp @@ -14,34 +14,31 @@ * limitations under the License. */ -#include <stdlib.h> +#define TRACE_TAG TRACE_SYNC + +#include "sysdeps.h" +#include "file_sync_service.h" + +#include <dirent.h> +#include <errno.h> +#include <selinux/android.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> - #include <sys/stat.h> #include <sys/types.h> -#include <dirent.h> -#include <utime.h> #include <unistd.h> +#include <utime.h> -#include <errno.h> -#include <private/android_filesystem_config.h> -#include <selinux/android.h> -#include "sysdeps.h" - -#define TRACE_TAG TRACE_SYNC #include "adb.h" -#include "file_sync_service.h" - -/* TODO: use fs_config to configure permissions on /data */ -static bool is_on_system(const char *name) { - const char *SYSTEM = "/system/"; - return (strncmp(SYSTEM, name, strlen(SYSTEM)) == 0); -} - -static bool is_on_vendor(const char *name) { - const char *VENDOR = "/vendor/"; - return (strncmp(VENDOR, name, strlen(VENDOR)) == 0); +#include "adb_io.h" +#include "private/android_filesystem_config.h" + +static bool should_use_fs_config(const char* path) { + // TODO: use fs_config to configure permissions on /data. + return strncmp("/system/", path, strlen("/system/")) == 0 || + strncmp("/vendor/", path, strlen("/vendor/")) == 0 || + strncmp("/oem/", path, strlen("/oem/")) == 0; } static int mkdirs(char *name) @@ -59,7 +56,7 @@ static int mkdirs(char *name) x = adb_dirstart(x); if(x == 0) return 0; *x = 0; - if (is_on_system(name) || is_on_vendor(name)) { + if (should_use_fs_config(name)) { fs_config(name, 1, &uid, &gid, &mode, &cap); } ret = adb_mkdir(name, mode); @@ -97,7 +94,7 @@ static int do_stat(int s, const char *path) msg.stat.time = htoll(st.st_mtime); } - return writex(s, &msg.stat, sizeof(msg.stat)); + return WriteFdExactly(s, &msg.stat, sizeof(msg.stat)) ? 0 : -1; } static int do_list(int s, const char *path) @@ -135,8 +132,8 @@ static int do_list(int s, const char *path) msg.dent.time = htoll(st.st_mtime); msg.dent.namelen = htoll(len); - if(writex(s, &msg.dent, sizeof(msg.dent)) || - writex(s, de->d_name, len)) { + if(!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) || + !WriteFdExactly(s, de->d_name, len)) { closedir(d); return -1; } @@ -151,7 +148,7 @@ done: msg.dent.size = 0; msg.dent.time = 0; msg.dent.namelen = 0; - return writex(s, &msg.dent, sizeof(msg.dent)); + return WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ? 0 : -1; } static int fail_message(int s, const char *reason) @@ -163,8 +160,8 @@ static int fail_message(int s, const char *reason) msg.data.id = ID_FAIL; msg.data.size = htoll(len); - if(writex(s, &msg.data, sizeof(msg.data)) || - writex(s, reason, len)) { + if(!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || + !WriteFdExactly(s, reason, len)) { return -1; } else { return 0; @@ -217,7 +214,7 @@ static int handle_send_file(int s, char *path, uid_t uid, for(;;) { unsigned int len; - if(readx(s, &msg.data, sizeof(msg.data))) + if(!ReadFdExactly(s, &msg.data, sizeof(msg.data))) goto fail; if(msg.data.id != ID_DATA) { @@ -233,12 +230,12 @@ static int handle_send_file(int s, char *path, uid_t uid, fail_message(s, "oversize data message"); goto fail; } - if(readx(s, buffer, len)) + if(!ReadFdExactly(s, buffer, len)) goto fail; if(fd < 0) continue; - if(writex(fd, buffer, len)) { + if(!WriteFdExactly(fd, buffer, len)) { int saved_errno = errno; adb_close(fd); if (do_unlink) adb_unlink(path); @@ -258,7 +255,7 @@ static int handle_send_file(int s, char *path, uid_t uid, msg.status.id = ID_OKAY; msg.status.msglen = 0; - if(writex(s, &msg.status, sizeof(msg.status))) + if(!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return -1; } return 0; @@ -270,14 +267,16 @@ fail: return -1; } -#ifdef HAVE_SYMLINKS +#if defined(_WIN32) +extern int handle_send_link(int s, char *path, char *buffer) __attribute__((error("no symlinks on Windows"))); +#else static int handle_send_link(int s, char *path, char *buffer) { syncmsg msg; unsigned int len; int ret; - if(readx(s, &msg.data, sizeof(msg.data))) + if(!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return -1; if(msg.data.id != ID_DATA) { @@ -290,7 +289,7 @@ static int handle_send_link(int s, char *path, char *buffer) fail_message(s, "oversize data message"); return -1; } - if(readx(s, buffer, len)) + if(!ReadFdExactly(s, buffer, len)) return -1; ret = symlink(buffer, path); @@ -306,13 +305,13 @@ static int handle_send_link(int s, char *path, char *buffer) return -1; } - if(readx(s, &msg.data, sizeof(msg.data))) + if(!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return -1; if(msg.data.id == ID_DONE) { msg.status.id = ID_OKAY; msg.status.msglen = 0; - if(writex(s, &msg.status, sizeof(msg.status))) + if(!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return -1; } else { fail_message(s, "invalid data message: expected ID_DONE"); @@ -321,25 +320,20 @@ static int handle_send_link(int s, char *path, char *buffer) return 0; } -#endif /* HAVE_SYMLINKS */ +#endif static int do_send(int s, char *path, char *buffer) { - char *tmp; unsigned int mode; - int is_link, ret; + bool is_link = false; bool do_unlink; - tmp = strrchr(path,','); + char* tmp = strrchr(path,','); if(tmp) { *tmp = 0; errno = 0; mode = strtoul(tmp + 1, NULL, 0); -#ifndef HAVE_SYMLINKS - is_link = 0; -#else is_link = S_ISLNK((mode_t) mode); -#endif mode &= 0777; } if(!tmp || errno) { @@ -355,32 +349,26 @@ static int do_send(int s, char *path, char *buffer) } } -#ifdef HAVE_SYMLINKS - if(is_link) - ret = handle_send_link(s, path, buffer); - else { -#else - { -#endif - uid_t uid = -1; - gid_t gid = -1; - uint64_t cap = 0; + if (is_link) { + return handle_send_link(s, path, buffer); + } - /* copy user permission bits to "group" and "other" permissions */ - mode |= ((mode >> 3) & 0070); - mode |= ((mode >> 3) & 0007); + uid_t uid = -1; + gid_t gid = -1; + uint64_t cap = 0; - tmp = path; - if(*tmp == '/') { - tmp++; - } - if (is_on_system(path) || is_on_vendor(path)) { - fs_config(tmp, 0, &uid, &gid, &mode, &cap); - } - ret = handle_send_file(s, path, uid, gid, mode, buffer, do_unlink); - } + /* copy user permission bits to "group" and "other" permissions */ + mode |= ((mode >> 3) & 0070); + mode |= ((mode >> 3) & 0007); - return ret; + tmp = path; + if(*tmp == '/') { + tmp++; + } + if (should_use_fs_config(path)) { + fs_config(tmp, 0, &uid, &gid, &mode, &cap); + } + return handle_send_file(s, path, uid, gid, mode, buffer, do_unlink); } static int do_recv(int s, const char *path, char *buffer) @@ -405,8 +393,8 @@ static int do_recv(int s, const char *path, char *buffer) return r; } msg.data.size = htoll(r); - if(writex(s, &msg.data, sizeof(msg.data)) || - writex(s, buffer, r)) { + if(!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || + !WriteFdExactly(s, buffer, r)) { adb_close(fd); return -1; } @@ -416,7 +404,7 @@ static int do_recv(int s, const char *path, char *buffer) msg.data.id = ID_DONE; msg.data.size = 0; - if(writex(s, &msg.data, sizeof(msg.data))) { + if(!WriteFdExactly(s, &msg.data, sizeof(msg.data))) { return -1; } @@ -429,13 +417,13 @@ void file_sync_service(int fd, void *cookie) char name[1025]; unsigned namelen; - char *buffer = malloc(SYNC_DATA_MAX); + char *buffer = reinterpret_cast<char*>(malloc(SYNC_DATA_MAX)); if(buffer == 0) goto fail; for(;;) { D("sync: waiting for command\n"); - if(readx(fd, &msg.req, sizeof(msg.req))) { + if(!ReadFdExactly(fd, &msg.req, sizeof(msg.req))) { fail_message(fd, "command read failure"); break; } @@ -444,7 +432,7 @@ void file_sync_service(int fd, void *cookie) fail_message(fd, "invalid namelen"); break; } - if(readx(fd, name, namelen)) { + if(!ReadFdExactly(fd, name, namelen)) { fail_message(fd, "filename read failure"); break; } diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h index 5dd2e80..344eb98 100644 --- a/adb/file_sync_service.h +++ b/adb/file_sync_service.h @@ -17,22 +17,12 @@ #ifndef _FILE_SYNC_SERVICE_H_ #define _FILE_SYNC_SERVICE_H_ -#ifdef HAVE_BIG_ENDIAN -static inline unsigned __swap_uint32(unsigned x) -{ - return (((x) & 0xFF000000) >> 24) - | (((x) & 0x00FF0000) >> 8) - | (((x) & 0x0000FF00) << 8) - | (((x) & 0x000000FF) << 24); -} -#define htoll(x) __swap_uint32(x) -#define ltohl(x) __swap_uint32(x) -#define MKID(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24)) -#else +#include <string> + #define htoll(x) (x) #define ltohl(x) (x) + #define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) -#endif #define ID_STAT MKID('S','T','A','T') #define ID_LIST MKID('L','I','S','T') @@ -46,7 +36,7 @@ static inline unsigned __swap_uint32(unsigned x) #define ID_FAIL MKID('F','A','I','L') #define ID_QUIT MKID('Q','U','I','T') -typedef union { +union syncmsg { unsigned id; struct { unsigned id; @@ -73,13 +63,13 @@ typedef union { unsigned id; unsigned msglen; } status; -} syncmsg; +} ; void file_sync_service(int fd, void *cookie); int do_sync_ls(const char *path); int do_sync_push(const char *lpath, const char *rpath, int show_progress); -int do_sync_sync(const char *lpath, const char *rpath, int listonly); +int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only); int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime); #define SYNC_DATA_MAX (64*1024) diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.cpp index 8cbe840..7baad8b 100644 --- a/adb/framebuffer_service.c +++ b/adb/framebuffer_service.cpp @@ -14,21 +14,23 @@ * limitations under the License. */ -#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> +#include <linux/fb.h> #include <stdio.h> -#include <unistd.h> +#include <stdlib.h> #include <string.h> -#include <fcntl.h> -#include <errno.h> +#include <sys/ioctl.h> +#include <sys/mman.h> #include <sys/types.h> #include <sys/wait.h> +#include <unistd.h> -#include "fdevent.h" -#include "adb.h" +#include "sysdeps.h" -#include <linux/fb.h> -#include <sys/ioctl.h> -#include <sys/mman.h> +#include "adb.h" +#include "adb_io.h" +#include "fdevent.h" /* TODO: ** - sync with vsync to avoid tearing @@ -60,28 +62,30 @@ void framebuffer_service(int fd, void *cookie) int fd_screencap; int w, h, f; int fds[2]; + pid_t pid; if (pipe2(fds, O_CLOEXEC) < 0) goto pipefail; - pid_t pid = fork(); + pid = fork(); if (pid < 0) goto done; if (pid == 0) { dup2(fds[1], STDOUT_FILENO); - close(fds[0]); - close(fds[1]); + adb_close(fds[0]); + adb_close(fds[1]); const char* command = "screencap"; const char *args[2] = {command, NULL}; execvp(command, (char**)args); exit(1); } + adb_close(fds[1]); fd_screencap = fds[0]; /* read w, h & format */ - if(readx(fd_screencap, &w, 4)) goto done; - if(readx(fd_screencap, &h, 4)) goto done; - if(readx(fd_screencap, &f, 4)) goto done; + if(!ReadFdExactly(fd_screencap, &w, 4)) goto done; + if(!ReadFdExactly(fd_screencap, &h, 4)) goto done; + if(!ReadFdExactly(fd_screencap, &f, 4)) goto done; fbinfo.version = DDMS_RAWIMAGE_VERSION; /* see hardware/hardware.h */ @@ -161,22 +165,21 @@ void framebuffer_service(int fd, void *cookie) } /* write header */ - if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done; + if(!WriteFdExactly(fd, &fbinfo, sizeof(fbinfo))) goto done; /* write data */ for(i = 0; i < fbinfo.size; i += bsize) { bsize = sizeof(buf); if (i + bsize > fbinfo.size) bsize = fbinfo.size - i; - if(readx(fd_screencap, buf, bsize)) goto done; - if(writex(fd, buf, bsize)) goto done; + if(!ReadFdExactly(fd_screencap, buf, bsize)) goto done; + if(!WriteFdExactly(fd, buf, bsize)) goto done; } done: - TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0)); + adb_close(fds[0]); - close(fds[0]); - close(fds[1]); + TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0)); pipefail: - close(fd); + adb_close(fd); } diff --git a/adb/get_my_path_darwin.c b/adb/get_my_path_darwin.cpp index ff1396c..b0c962e 100644 --- a/adb/get_my_path_darwin.c +++ b/adb/get_my_path_darwin.cpp @@ -17,6 +17,8 @@ #import <Carbon/Carbon.h> #include <unistd.h> +#include "adb.h" + void get_my_path(char *s, size_t maxLen) { CFBundleRef mainBundle = CFBundleGetMainBundle(); diff --git a/adb/get_my_path_linux.c b/adb/get_my_path_linux.cpp index 179c3dd..11c0b21 100644 --- a/adb/get_my_path_linux.c +++ b/adb/get_my_path_linux.cpp @@ -14,10 +14,12 @@ * limitations under the License. */ -#include <sys/types.h> -#include <unistd.h> #include <limits.h> #include <stdio.h> +#include <sys/types.h> +#include <unistd.h> + +#include "adb.h" void get_my_path(char *exe, size_t maxLen) { diff --git a/adb/get_my_path_windows.c b/adb/get_my_path_windows.cpp index ddf2816..9d23e1c 100644 --- a/adb/get_my_path_windows.c +++ b/adb/get_my_path_windows.cpp @@ -14,10 +14,12 @@ * limitations under the License. */ -#include <limits.h> #include <assert.h> +#include <limits.h> #include <windows.h> +#include "adb.h" + void get_my_path(char *exe, size_t maxLen) { char *r; diff --git a/adb/jdwp_service.c b/adb/jdwp_service.cpp index cd62b55..c0f7ec2 100644 --- a/adb/jdwp_service.c +++ b/adb/jdwp_service.cpp @@ -1,12 +1,32 @@ +/* + * Copyright (C) 2015 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. + */ + /* implement the "debug-ports" and "track-debug-ports" device services */ + +#define TRACE_TAG TRACE_JDWP + #include "sysdeps.h" -#define TRACE_TAG TRACE_JDWP -#include "adb.h" + #include <errno.h> #include <stdio.h> #include <string.h> #include <unistd.h> +#include "adb.h" + /* here's how these things work. when adbd starts, it creates a unix server socket @@ -101,7 +121,6 @@ #include <sys/socket.h> #include <sys/un.h> -typedef struct JdwpProcess JdwpProcess; struct JdwpProcess { JdwpProcess* next; JdwpProcess* prev; @@ -194,7 +213,8 @@ static void jdwp_process_event(int, unsigned, void*); /* forward */ static JdwpProcess* jdwp_process_alloc( int socket ) { - JdwpProcess* proc = calloc(1,sizeof(*proc)); + JdwpProcess* proc = reinterpret_cast<JdwpProcess*>( + calloc(1, sizeof(*proc))); if (proc == NULL) { D("not enough memory to create new JDWP process\n"); @@ -234,7 +254,7 @@ jdwp_process_alloc( int socket ) static void jdwp_process_event( int socket, unsigned events, void* _proc ) { - JdwpProcess* proc = _proc; + JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc); if (events & FDE_READ) { if (proc->pid < 0) { @@ -415,6 +435,7 @@ FoundIt: __FUNCTION__, strerror(errno)); return -1; } + D("socketpair: (%d,%d)", fds[0], fds[1]); proc->out_fds[ proc->out_count ] = fds[1]; if (++proc->out_count == 1) @@ -433,11 +454,10 @@ FoundIt: #define JDWP_CONTROL_NAME "\0jdwp-control" #define JDWP_CONTROL_NAME_LEN (sizeof(JDWP_CONTROL_NAME)-1) -typedef struct { +struct JdwpControl { int listen_socket; fdevent* fde; - -} JdwpControl; +}; static void @@ -548,10 +568,10 @@ static JdwpControl _jdwp_control; ** this simply returns the list of known JDWP process pids **/ -typedef struct { +struct JdwpSocket { asocket socket; int pass; -} JdwpSocket; +}; static void jdwp_socket_close( asocket* s ) @@ -600,7 +620,7 @@ jdwp_socket_ready( asocket* s ) asocket* create_jdwp_service_socket( void ) { - JdwpSocket* s = calloc(sizeof(*s),1); + JdwpSocket* s = reinterpret_cast<JdwpSocket*>(calloc(sizeof(*s), 1)); if (s == NULL) return NULL; @@ -620,8 +640,6 @@ create_jdwp_service_socket( void ) ** to the client... **/ -typedef struct JdwpTracker JdwpTracker; - struct JdwpTracker { asocket socket; JdwpTracker* next; @@ -695,7 +713,7 @@ jdwp_tracker_enqueue( asocket* s, apacket* p ) asocket* create_jdwp_tracker_service_socket( void ) { - JdwpTracker* t = calloc(sizeof(*t),1); + JdwpTracker* t = reinterpret_cast<JdwpTracker*>(calloc(sizeof(*t), 1)); if (t == NULL) return NULL; @@ -732,4 +750,3 @@ init_jdwp(void) } #endif /* !ADB_HOST */ - diff --git a/adb/qemu_tracing.cpp b/adb/qemu_tracing.cpp new file mode 100644 index 0000000..f31eae8 --- /dev/null +++ b/adb/qemu_tracing.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015 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. + */ + +/* + * Implements ADB tracing inside the emulator. + */ + +#include <stdarg.h> + +#include "sysdeps.h" +#include "qemu_tracing.h" + +/* + * Redefine open and write for qemu_pipe.h that contains inlined references + * to those routines. We will redifine them back after qemu_pipe.h inclusion. + */ + +#undef open +#undef write +#define open adb_open +#define write adb_write +#include <hardware/qemu_pipe.h> +#undef open +#undef write +#define open ___xxx_open +#define write ___xxx_write + +/* A handle to adb-debug qemud service in the emulator. */ +int adb_debug_qemu = -1; + +/* Initializes connection with the adb-debug qemud service in the emulator. */ +int adb_qemu_trace_init(void) +{ + char con_name[32]; + + if (adb_debug_qemu >= 0) { + return 0; + } + + /* adb debugging QEMUD service connection request. */ + snprintf(con_name, sizeof(con_name), "qemud:adb-debug"); + adb_debug_qemu = qemu_pipe_open(con_name); + return (adb_debug_qemu >= 0) ? 0 : -1; +} + +void adb_qemu_trace(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + char msg[1024]; + + if (adb_debug_qemu >= 0) { + vsnprintf(msg, sizeof(msg), fmt, args); + adb_write(adb_debug_qemu, msg, strlen(msg)); + } +} diff --git a/adb/qemu_tracing.h b/adb/qemu_tracing.h new file mode 100644 index 0000000..ff42d4f --- /dev/null +++ b/adb/qemu_tracing.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2015 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. + */ + +/* + * Implements ADB tracing inside the emulator. + */ + +#ifndef __QEMU_TRACING_H +#define __QEMU_TRACING_H + +/* Initializes connection with the adb-debug qemud service in the emulator. */ +int adb_qemu_trace_init(void); +void adb_qemu_trace(const char* fmt, ...); + +#endif /* __QEMU_TRACING_H */ diff --git a/adb/remount_service.c b/adb/remount_service.c deleted file mode 100644 index 36367a7..0000000 --- a/adb/remount_service.c +++ /dev/null @@ -1,170 +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 "sysdeps.h" - -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/mount.h> -#include <unistd.h> - -#include "cutils/properties.h" - -#define TRACE_TAG TRACE_ADB -#include "adb.h" - - -static int system_ro = 1; -static int vendor_ro = 1; - -/* Returns the device used to mount a directory in /proc/mounts */ -static char *find_mount(const char *dir) -{ - int fd; - int res; - char *token = NULL; - const char delims[] = "\n"; - char buf[4096]; - - fd = unix_open("/proc/mounts", O_RDONLY | O_CLOEXEC); - if (fd < 0) - return NULL; - - buf[sizeof(buf) - 1] = '\0'; - adb_read(fd, buf, sizeof(buf) - 1); - adb_close(fd); - - token = strtok(buf, delims); - - while (token) { - char mount_dev[256]; - char mount_dir[256]; - int mount_freq; - int mount_passno; - - res = sscanf(token, "%255s %255s %*s %*s %d %d\n", - mount_dev, mount_dir, &mount_freq, &mount_passno); - mount_dev[255] = 0; - mount_dir[255] = 0; - if (res == 4 && (strcmp(dir, mount_dir) == 0)) - return strdup(mount_dev); - - token = strtok(NULL, delims); - } - return NULL; -} - -static int hasVendorPartition() -{ - struct stat info; - if (!lstat("/vendor", &info)) - if ((info.st_mode & S_IFMT) == S_IFDIR) - return true; - return false; -} - -/* Init mounts /system as read only, remount to enable writes. */ -static int remount(const char* dir, int* dir_ro) -{ - char *dev; - int fd; - int OFF = 0; - - if (dir_ro == 0) { - return 0; - } - - dev = find_mount(dir); - - if (!dev) - return -1; - - fd = unix_open(dev, O_RDONLY | O_CLOEXEC); - if (fd < 0) - return -1; - - ioctl(fd, BLKROSET, &OFF); - adb_close(fd); - - *dir_ro = mount(dev, dir, "none", MS_REMOUNT, NULL); - - free(dev); - - return *dir_ro; -} - -static void write_string(int fd, const char* str) -{ - writex(fd, str, strlen(str)); -} - -void remount_service(int fd, void *cookie) -{ - char buffer[200]; - char prop_buf[PROPERTY_VALUE_MAX]; - - bool system_verified = false, vendor_verified = false; - property_get("partition.system.verified", prop_buf, "0"); - if (!strcmp(prop_buf, "1")) { - system_verified = true; - } - - property_get("partition.vendor.verified", prop_buf, "0"); - if (!strcmp(prop_buf, "1")) { - vendor_verified = true; - } - - if (system_verified || vendor_verified) { - // Allow remount but warn of likely bad effects - bool both = system_verified && vendor_verified; - snprintf(buffer, sizeof(buffer), - "dm_verity is enabled on the %s%s%s partition%s.\n", - system_verified ? "system" : "", - both ? " and " : "", - vendor_verified ? "vendor" : "", - both ? "s" : ""); - write_string(fd, buffer); - snprintf(buffer, sizeof(buffer), - "Use \"adb disable-verity\" to disable verity.\n" - "If you do not, remount may succeed, however, you will still " - "not be able to write to these volumes.\n"); - write_string(fd, buffer); - } - - if (remount("/system", &system_ro)) { - snprintf(buffer, sizeof(buffer), "remount of system failed: %s\n",strerror(errno)); - write_string(fd, buffer); - } - - if (hasVendorPartition()) { - if (remount("/vendor", &vendor_ro)) { - snprintf(buffer, sizeof(buffer), "remount of vendor failed: %s\n",strerror(errno)); - write_string(fd, buffer); - } - } - - if (!system_ro && (!vendor_ro || !hasVendorPartition())) - write_string(fd, "remount succeeded\n"); - else { - write_string(fd, "remount failed\n"); - } - - adb_close(fd); -} - diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp new file mode 100644 index 0000000..1eaee73 --- /dev/null +++ b/adb/remount_service.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define TRACE_TAG TRACE_ADB + +#include "sysdeps.h" + +#include <errno.h> +#include <fcntl.h> +#include <mntent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mount.h> +#include <unistd.h> + +#include <string> + +#include "adb.h" +#include "adb_io.h" +#include "adb_utils.h" +#include "cutils/properties.h" + +static int system_ro = 1; +static int vendor_ro = 1; +static int oem_ro = 1; + +/* Returns the device used to mount a directory in /proc/mounts */ +static std::string find_mount(const char *dir) { + FILE* fp; + struct mntent* mentry; + char* device = NULL; + + if ((fp = setmntent("/proc/mounts", "r")) == NULL) { + return NULL; + } + while ((mentry = getmntent(fp)) != NULL) { + if (strcmp(dir, mentry->mnt_dir) == 0) { + device = mentry->mnt_fsname; + break; + } + } + endmntent(fp); + return device; +} + +int make_block_device_writable(const std::string& dev) { + int fd = unix_open(dev.c_str(), O_RDONLY | O_CLOEXEC); + if (fd == -1) { + return -1; + } + + int result = -1; + int OFF = 0; + if (!ioctl(fd, BLKROSET, &OFF)) { + result = 0; + } + adb_close(fd); + + return result; +} + +// Init mounts /system as read only, remount to enable writes. +static int remount(const char* dir, int* dir_ro) { + std::string dev(find_mount(dir)); + if (dev.empty() || make_block_device_writable(dev)) { + return -1; + } + + int rc = mount(dev.c_str(), dir, "none", MS_REMOUNT, NULL); + *dir_ro = rc; + return rc; +} + +static bool remount_partition(int fd, const char* partition, int* ro) { + if (!directory_exists(partition)) { + return true; + } + if (remount(partition, ro)) { + char buf[200]; + snprintf(buf, sizeof(buf), "remount of %s failed: %s\n", partition, strerror(errno)); + WriteStringFully(fd, buf); + return false; + } + return true; +} + +void remount_service(int fd, void* cookie) { + char prop_buf[PROPERTY_VALUE_MAX]; + + if (getuid() != 0) { + WriteStringFully(fd, "Not running as root. Try \"adb root\" first.\n"); + adb_close(fd); + return; + } + + bool system_verified = false, vendor_verified = false; + property_get("partition.system.verified", prop_buf, ""); + if (strlen(prop_buf) > 0) { + system_verified = true; + } + + property_get("partition.vendor.verified", prop_buf, ""); + if (strlen(prop_buf) > 0) { + vendor_verified = true; + } + + if (system_verified || vendor_verified) { + // Allow remount but warn of likely bad effects + bool both = system_verified && vendor_verified; + char buffer[200]; + snprintf(buffer, sizeof(buffer), + "dm_verity is enabled on the %s%s%s partition%s.\n", + system_verified ? "system" : "", + both ? " and " : "", + vendor_verified ? "vendor" : "", + both ? "s" : ""); + WriteStringFully(fd, buffer); + snprintf(buffer, sizeof(buffer), + "Use \"adb disable-verity\" to disable verity.\n" + "If you do not, remount may succeed, however, you will still " + "not be able to write to these volumes.\n"); + WriteStringFully(fd, buffer); + } + + bool success = true; + success &= remount_partition(fd, "/system", &system_ro); + success &= remount_partition(fd, "/vendor", &vendor_ro); + success &= remount_partition(fd, "/oem", &oem_ro); + + WriteStringFully(fd, success ? "remount succeeded\n" : "remount failed\n"); + + adb_close(fd); +} diff --git a/adb/usb_vendors.h b/adb/remount_service.h index cee23a1..e1763cf 100644 --- a/adb/usb_vendors.h +++ b/adb/remount_service.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2015 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. @@ -14,12 +14,12 @@ * limitations under the License. */ -#ifndef __USB_VENDORS_H -#define __USB_VENDORS_H +#ifndef _REMOUNT_SERVICE_H_ +#define _REMOUNT_SERVICE_H_ -extern int vendorIds[]; -extern unsigned vendorIdCount; +#include <string> -void usb_vendors_init(void); +int make_block_device_writable(const std::string&); +void remount_service(int, void*); #endif diff --git a/adb/services.c b/adb/services.cpp index 21b08dc..e6c84a4 100644 --- a/adb/services.c +++ b/adb/services.cpp @@ -14,31 +14,36 @@ * limitations under the License. */ +#define TRACE_TAG TRACE_SERVICES + +#include "sysdeps.h" + +#include <errno.h> #include <stddef.h> -#include <stdlib.h> #include <stdio.h> -#include <unistd.h> +#include <stdlib.h> #include <string.h> -#include <errno.h> -#include "sysdeps.h" +#ifndef _WIN32 +#include <netdb.h> +#include <netinet/in.h> +#include <sys/ioctl.h> +#include <unistd.h> +#endif -#define TRACE_TAG TRACE_SERVICES -#include "adb.h" -#include "file_sync_service.h" +#include <base/stringprintf.h> -#if ADB_HOST -# ifndef HAVE_WINSOCK -# include <netinet/in.h> -# include <netdb.h> -# include <sys/ioctl.h> -# endif -#else -# include <cutils/android_reboot.h> -# include <cutils/properties.h> +#if !ADB_HOST +#include "base/file.h" +#include "cutils/android_reboot.h" +#include "cutils/properties.h" #endif -typedef struct stinfo stinfo; +#include "adb.h" +#include "adb_io.h" +#include "file_sync_service.h" +#include "remount_service.h" +#include "transport.h" struct stinfo { void (*func)(int fd, void *cookie); @@ -49,7 +54,7 @@ struct stinfo { void *service_bootstrap_func(void *x) { - stinfo *sti = x; + stinfo* sti = reinterpret_cast<stinfo*>(x); sti->func(sti->fd, sti->cookie); free(sti); return 0; @@ -64,20 +69,36 @@ void restart_root_service(int fd, void *cookie) if (getuid() == 0) { snprintf(buf, sizeof(buf), "adbd is already running as root\n"); - writex(fd, buf, strlen(buf)); + WriteFdExactly(fd, buf, strlen(buf)); adb_close(fd); } else { property_get("ro.debuggable", value, ""); if (strcmp(value, "1") != 0) { snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n"); - writex(fd, buf, strlen(buf)); + WriteFdExactly(fd, buf, strlen(buf)); adb_close(fd); return; } property_set("service.adb.root", "1"); snprintf(buf, sizeof(buf), "restarting adbd as root\n"); - writex(fd, buf, strlen(buf)); + WriteFdExactly(fd, buf, strlen(buf)); + adb_close(fd); + } +} + +void restart_unroot_service(int fd, void *cookie) +{ + char buf[100]; + + if (getuid() != 0) { + snprintf(buf, sizeof(buf), "adbd not running as root\n"); + WriteFdExactly(fd, buf, strlen(buf)); + adb_close(fd); + } else { + property_set("service.adb.root", "0"); + snprintf(buf, sizeof(buf), "restarting adbd as non root\n"); + WriteFdExactly(fd, buf, strlen(buf)); adb_close(fd); } } @@ -90,7 +111,7 @@ void restart_tcp_service(int fd, void *cookie) if (port <= 0) { snprintf(buf, sizeof(buf), "invalid port\n"); - writex(fd, buf, strlen(buf)); + WriteFdExactly(fd, buf, strlen(buf)); adb_close(fd); return; } @@ -98,7 +119,7 @@ void restart_tcp_service(int fd, void *cookie) snprintf(value, sizeof(value), "%d", port); property_set("service.adb.tcp.port", value); snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port); - writex(fd, buf, strlen(buf)); + WriteFdExactly(fd, buf, strlen(buf)); adb_close(fd); } @@ -108,42 +129,83 @@ void restart_usb_service(int fd, void *cookie) property_set("service.adb.tcp.port", "0"); snprintf(buf, sizeof(buf), "restarting in USB mode\n"); - writex(fd, buf, strlen(buf)); + WriteFdExactly(fd, buf, strlen(buf)); adb_close(fd); } -void reboot_service(int fd, void *arg) -{ +static bool reboot_service_impl(int fd, const char* arg) { + const char* reboot_arg = arg; + bool auto_reboot = false; + + if (strcmp(reboot_arg, "sideload-auto-reboot") == 0) { + auto_reboot = true; + reboot_arg = "sideload"; + } + char buf[100]; - char property_val[PROPERTY_VALUE_MAX]; - int ret; + // It reboots into sideload mode by setting "--sideload" or "--sideload_auto_reboot" + // in the command file. + if (strcmp(reboot_arg, "sideload") == 0) { + if (getuid() != 0) { + snprintf(buf, sizeof(buf), "'adb root' is required for 'adb reboot sideload'.\n"); + WriteStringFully(fd, buf); + return false; + } + + const char* const recovery_dir = "/cache/recovery"; + const char* const command_file = "/cache/recovery/command"; + // Ensure /cache/recovery exists. + if (adb_mkdir(recovery_dir, 0770) == -1 && errno != EEXIST) { + D("Failed to create directory '%s': %s\n", recovery_dir, strerror(errno)); + return false; + } + + bool write_status = android::base::WriteStringToFile( + auto_reboot ? "--sideload_auto_reboot" : "--sideload", command_file); + if (!write_status) { + return false; + } + + reboot_arg = "recovery"; + } sync(); - ret = snprintf(property_val, sizeof(property_val), "reboot,%s", (char *) arg); - if (ret >= (int) sizeof(property_val)) { + char property_val[PROPERTY_VALUE_MAX]; + int ret = snprintf(property_val, sizeof(property_val), "reboot,%s", reboot_arg); + if (ret >= static_cast<int>(sizeof(property_val))) { snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret); - writex(fd, buf, strlen(buf)); - goto cleanup; + WriteStringFully(fd, buf); + return false; } ret = property_set(ANDROID_RB_PROPERTY, property_val); if (ret < 0) { snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret); - writex(fd, buf, strlen(buf)); - goto cleanup; + WriteStringFully(fd, buf); + return false; + } + + return true; +} + +void reboot_service(int fd, void* arg) +{ + if (reboot_service_impl(fd, static_cast<const char*>(arg))) { + // Don't return early. Give the reboot command time to take effect + // to avoid messing up scripts which do "adb reboot && adb wait-for-device" + while (true) { + pause(); + } } - // Don't return early. Give the reboot command time to take effect - // to avoid messing up scripts which do "adb reboot && adb wait-for-device" - while(1) { pause(); } -cleanup: + free(arg); adb_close(fd); } void reverse_service(int fd, void* arg) { - const char* command = arg; + const char* command = reinterpret_cast<const char*>(arg); if (handle_forward_request(command, kTransportAny, NULL, fd) < 0) { sendfailmsg(fd, "not a reverse forwarding command"); @@ -156,22 +218,23 @@ void reverse_service(int fd, void* arg) static int create_service_thread(void (*func)(int, void *), void *cookie) { - stinfo *sti; - adb_thread_t t; int s[2]; - - if(adb_socketpair(s)) { + if (adb_socketpair(s)) { printf("cannot create service socket pair\n"); return -1; } + D("socketpair: (%d,%d)", s[0], s[1]); - sti = malloc(sizeof(stinfo)); - if(sti == 0) fatal("cannot allocate stinfo"); + stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo))); + if (sti == nullptr) { + fatal("cannot allocate stinfo"); + } sti->func = func; sti->cookie = cookie; sti->fd = s[1]; - if(adb_thread_create( &t, service_bootstrap_func, sti)){ + adb_thread_t t; + if (adb_thread_create(&t, service_bootstrap_func, sti)) { free(sti); adb_close(s[0]); adb_close(s[1]); @@ -202,10 +265,10 @@ static void init_subproc_child() static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg1, pid_t *pid) { D("create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1); -#ifdef HAVE_WIN32_PROC +#if defined(_WIN32) fprintf(stderr, "error: create_subproc_pty not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1); return -1; -#else /* !HAVE_WIN32_PROC */ +#else int ptm; ptm = unix_open("/dev/ptmx", O_RDWR | O_CLOEXEC); // | O_NOCTTY); @@ -251,23 +314,24 @@ static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg } else { return ptm; } -#endif /* !HAVE_WIN32_PROC */ +#endif /* !defined(_WIN32) */ } static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1, pid_t *pid) { D("create_subproc_raw(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1); -#ifdef HAVE_WIN32_PROC +#if defined(_WIN32) fprintf(stderr, "error: create_subproc_raw not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1); return -1; -#else /* !HAVE_WIN32_PROC */ +#else // 0 is parent socket, 1 is child socket int sv[2]; - if (unix_socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) { + if (adb_socketpair(sv) < 0) { printf("[ cannot create socket pair - %s ]\n", strerror(errno)); return -1; } + D("socketpair: (%d,%d)", sv[0], sv[1]); *pid = fork(); if (*pid < 0) { @@ -295,7 +359,7 @@ static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg adb_close(sv[1]); return sv[0]; } -#endif /* !HAVE_WIN32_PROC */ +#endif /* !defined(_WIN32) */ } #endif /* !ABD_HOST */ @@ -311,7 +375,7 @@ static void subproc_waiter_service(int fd, void *cookie) pid_t pid = (pid_t) (uintptr_t) cookie; D("entered. fd=%d of pid=%d\n", fd, pid); - for (;;) { + while (true) { int status; pid_t p = waitpid(pid, &status, 0); if (p == pid) { @@ -331,7 +395,7 @@ static void subproc_waiter_service(int fd, void *cookie) D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno); if (SHELL_EXIT_NOTIFY_FD >=0) { int res; - res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd)); + res = WriteFdExactly(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd)) ? 0 : -1; D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n", SHELL_EXIT_NOTIFY_FD, pid, res, errno); } @@ -339,7 +403,6 @@ static void subproc_waiter_service(int fd, void *cookie) static int create_subproc_thread(const char *name, const subproc_mode mode) { - stinfo *sti; adb_thread_t t; int ret_fd; pid_t pid = -1; @@ -364,7 +427,7 @@ static int create_subproc_thread(const char *name, const subproc_mode mode) } D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid); - sti = malloc(sizeof(stinfo)); + stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo))); if(sti == 0) fatal("cannot allocate stinfo"); sti->func = subproc_waiter_service; sti->cookie = (void*) (uintptr_t) pid; @@ -435,25 +498,16 @@ int service_to_fd(const char *name) ret = create_service_thread(reboot_service, arg); } else if(!strncmp(name, "root:", 5)) { ret = create_service_thread(restart_root_service, NULL); + } else if(!strncmp(name, "unroot:", 7)) { + ret = create_service_thread(restart_unroot_service, NULL); } else if(!strncmp(name, "backup:", 7)) { - char* arg = strdup(name + 7); - if (arg == NULL) return -1; - char* c = arg; - for (; *c != '\0'; c++) { - if (*c == ':') - *c = ' '; - } - char* cmd; - if (asprintf(&cmd, "/system/bin/bu backup %s", arg) != -1) { - ret = create_subproc_thread(cmd, SUBPROC_RAW); - free(cmd); - } - free(arg); + ret = create_subproc_thread(android::base::StringPrintf("/system/bin/bu backup %s", + (name + 7)).c_str(), SUBPROC_RAW); } else if(!strncmp(name, "restore:", 8)) { ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW); } else if(!strncmp(name, "tcpip:", 6)) { int port; - if (sscanf(name + 6, "%d", &port) == 0) { + if (sscanf(name + 6, "%d", &port) != 1) { port = 0; } ret = create_service_thread(restart_tcp_service, (void *) (uintptr_t) port); @@ -470,7 +524,9 @@ int service_to_fd(const char *name) } } } else if(!strncmp(name, "disable-verity:", 15)) { - ret = create_service_thread(disable_verity_service, NULL); + ret = create_service_thread(set_verity_enabled_state_service, (void*)0); + } else if(!strncmp(name, "enable-verity:", 15)) { + ret = create_service_thread(set_verity_enabled_state_service, (void*)1); #endif } if (ret >= 0) { @@ -488,16 +544,16 @@ struct state_info { static void wait_for_state(int fd, void* cookie) { - struct state_info* sinfo = cookie; - char* err = "unknown error"; + state_info* sinfo = reinterpret_cast<state_info*>(cookie); D("wait_for_state %d\n", sinfo->state); - atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err); - if(t != 0) { - writex(fd, "OKAY", 4); + std::string error_msg = "unknown error"; + atransport* t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &error_msg); + if (t != 0) { + WriteFdExactly(fd, "OKAY", 4); } else { - sendfailmsg(fd, err); + sendfailmsg(fd, error_msg.c_str()); } if (sinfo->serial) @@ -523,7 +579,7 @@ static void connect_device(char* host, char* buffer, int buffer_size) } // zero terminate the host at the point we found the colon hostbuf[portstr - host] = 0; - if (sscanf(portstr + 1, "%d", &port) == 0) { + if (sscanf(portstr + 1, "%d", &port) != 1) { snprintf(buffer, buffer_size, "bad port number %s", portstr); return; } @@ -611,7 +667,7 @@ static void connect_service(int fd, void* cookie) { char buf[4096]; char resp[4096]; - char *host = cookie; + char *host = reinterpret_cast<char*>(cookie); if (!strncmp(host, "emu:", 4)) { connect_emulator(host + 4, buf, sizeof(buf)); @@ -621,7 +677,7 @@ static void connect_service(int fd, void* cookie) // Send response for emulator and device snprintf(resp, sizeof(resp), "%04x%s",(unsigned)strlen(buf), buf); - writex(fd, resp, strlen(resp)); + WriteFdExactly(fd, resp, strlen(resp)); adb_close(fd); } #endif @@ -632,7 +688,11 @@ asocket* host_service_to_socket(const char* name, const char *serial) if (!strcmp(name,"track-devices")) { return create_device_tracker(); } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) { - struct state_info* sinfo = malloc(sizeof(struct state_info)); + auto sinfo = reinterpret_cast<state_info*>(malloc(sizeof(state_info))); + if (sinfo == nullptr) { + fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno)); + return NULL; + } if (serial) sinfo->serial = strdup(serial); diff --git a/adb/disable_verity_service.c b/adb/set_verity_enable_state_service.cpp index ed3da52..b75ed4c 100644 --- a/adb/disable_verity_service.c +++ b/adb/set_verity_enable_state_service.cpp @@ -14,24 +14,33 @@ * limitations under the License. */ -#include "sysdeps.h" +#define TRACE_TAG TRACE_ADB -#define TRACE_TAG TRACE_ADB -#include "adb.h" +#include "sysdeps.h" -#include <stdio.h> -#include <stdarg.h> -#include <sys/stat.h> #include <fcntl.h> #include <inttypes.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <sys/stat.h> #include "cutils/properties.h" + +#include "adb.h" #include "ext4_sb.h" -#include <fs_mgr.h> +#include "fs_mgr.h" +#include "remount_service.h" #define FSTAB_PREFIX "/fstab." struct fstab *fstab; +#ifdef ALLOW_ADBD_DISABLE_VERITY +static const bool kAllowDisableVerity = true; +#else +static const bool kAllowDisableVerity = false; +#endif + __attribute__((__format__(printf, 2, 3))) __nonnull((2)) static void write_console(int fd, const char* format, ...) { @@ -78,15 +87,23 @@ static int get_target_device_size(int fd, const char *blk_device, return 0; } -static int disable_verity(int fd, const char *block_device, - const char* mount_point) +/* Turn verity on/off */ +static int set_verity_enabled_state(int fd, const char *block_device, + const char* mount_point, bool enable) { uint32_t magic_number; - const uint32_t voff = VERITY_METADATA_MAGIC_DISABLE; - uint64_t device_length; - int device; + const uint32_t new_magic = enable ? VERITY_METADATA_MAGIC_NUMBER + : VERITY_METADATA_MAGIC_DISABLE; + uint64_t device_length = 0; + int device = -1; int retval = -1; + if (make_block_device_writable(block_device)) { + write_console(fd, "Could not make block device %s writable (%s).\n", + block_device, strerror(errno)); + goto errout; + } + device = adb_open(block_device, O_RDWR | O_CLOEXEC); if (device == -1) { write_console(fd, "Could not open block device %s (%s).\n", @@ -114,14 +131,20 @@ static int disable_verity(int fd, const char *block_device, goto errout; } - if (magic_number == VERITY_METADATA_MAGIC_DISABLE) { + if (!enable && magic_number == VERITY_METADATA_MAGIC_DISABLE) { write_console(fd, "Verity already disabled on %s\n", mount_point); goto errout; } - if (magic_number != VERITY_METADATA_MAGIC_NUMBER) { + if (enable && magic_number == VERITY_METADATA_MAGIC_NUMBER) { + write_console(fd, "Verity already enabled on %s\n", mount_point); + goto errout; + } + + if (magic_number != VERITY_METADATA_MAGIC_NUMBER + && magic_number != VERITY_METADATA_MAGIC_DISABLE) { write_console(fd, - "Couldn't find verity metadata at offset %"PRIu64"!\n", + "Couldn't find verity metadata at offset %" PRIu64 "!\n", device_length); goto errout; } @@ -132,13 +155,17 @@ static int disable_verity(int fd, const char *block_device, goto errout; } - if (adb_write(device, &voff, sizeof(voff)) != sizeof(voff)) { - write_console(fd, "Could not set verity disabled flag on device %s\n", - block_device); + if (adb_write(device, &new_magic, sizeof(new_magic)) != sizeof(new_magic)) { + write_console( + fd, "Could not set verity %s flag on device %s with error %s\n", + enable ? "enabled" : "disabled", + block_device, strerror(errno)); goto errout; } - write_console(fd, "Verity disabled on %s\n", mount_point); + write_console(fd, "Verity %s on %s\n", + enable ? "enabled" : "disabled", + mount_point); retval = 0; errout: if (device != -1) @@ -146,54 +173,59 @@ errout: return retval; } -void disable_verity_service(int fd, void* cookie) +void set_verity_enabled_state_service(int fd, void* cookie) { -#ifdef ALLOW_ADBD_DISABLE_VERITY - char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; - char propbuf[PROPERTY_VALUE_MAX]; - int i; - bool any_disabled = false; - - property_get("ro.secure", propbuf, "0"); - if (strcmp(propbuf, "1")) { - write_console(fd, "verity not enabled - ENG build\n"); - goto errout; + bool enable = (cookie != NULL); + if (kAllowDisableVerity) { + char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; + char propbuf[PROPERTY_VALUE_MAX]; + int i; + bool any_changed = false; + + property_get("ro.secure", propbuf, "0"); + if (strcmp(propbuf, "1")) { + write_console(fd, "verity not enabled - ENG build\n"); + goto errout; + } + + property_get("ro.debuggable", propbuf, "0"); + if (strcmp(propbuf, "1")) { + write_console( + fd, "verity cannot be disabled/enabled - USER build\n"); + goto errout; + } + + property_get("ro.hardware", propbuf, ""); + snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", + propbuf); + + fstab = fs_mgr_read_fstab(fstab_filename); + if (!fstab) { + write_console(fd, "Failed to open %s\nMaybe run adb root?\n", + fstab_filename); + goto errout; + } + + /* Loop through entries looking for ones that vold manages */ + for (i = 0; i < fstab->num_entries; i++) { + if(fs_mgr_is_verified(&fstab->recs[i])) { + if (!set_verity_enabled_state(fd, fstab->recs[i].blk_device, + fstab->recs[i].mount_point, + enable)) { + any_changed = true; + } + } + } + + if (any_changed) { + write_console( + fd, "Now reboot your device for settings to take effect\n"); + } + } else { + write_console(fd, "%s-verity only works for userdebug builds\n", + enable ? "enable" : "disable"); } - property_get("ro.debuggable", propbuf, "0"); - if (strcmp(propbuf, "1")) { - write_console(fd, "verity cannot be disabled - USER build\n"); - goto errout; - } - - property_get("ro.hardware", propbuf, ""); - snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf); - - fstab = fs_mgr_read_fstab(fstab_filename); - if (!fstab) { - write_console(fd, "Failed to open %s\nMaybe run adb root?\n", - fstab_filename); - goto errout; - } - - /* Loop through entries looking for ones that vold manages */ - for (i = 0; i < fstab->num_entries; i++) { - if(fs_mgr_is_verified(&fstab->recs[i])) { - if (!disable_verity(fd, fstab->recs[i].blk_device, - fstab->recs[i].mount_point)) { - any_disabled = true; - } - } - } - - if (any_disabled) { - write_console(fd, - "Now reboot your device for settings to take effect\n"); - } -#else - write_console(fd, "disable-verity only works for userdebug builds\n"); -#endif - errout: adb_close(fd); } diff --git a/adb/sockets.c b/adb/sockets.cpp index faa9564..f468029 100644 --- a/adb/sockets.c +++ b/adb/sockets.cpp @@ -14,21 +14,24 @@ * limitations under the License. */ +#define TRACE_TAG TRACE_SOCKETS + +#include "sysdeps.h" + +#include <ctype.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> -#include <unistd.h> -#include <errno.h> #include <string.h> -#include <ctype.h> - -#include "sysdeps.h" +#include <unistd.h> #if !ADB_HOST -#include <cutils/properties.h> +#include "cutils/properties.h" #endif -#define TRACE_TAG TRACE_SOCKETS #include "adb.h" +#include "adb_io.h" +#include "transport.h" ADB_MUTEX_DEFINE( socket_list_lock ); @@ -39,13 +42,17 @@ int sendfailmsg(int fd, const char *reason) char buf[9]; int len; len = strlen(reason); - if(len > 0xffff) len = 0xffff; + if (len > 0xffff) { + len = 0xffff; + } + snprintf(buf, sizeof buf, "FAIL%04x", len); - if(writex(fd, buf, 8)) return -1; - return writex(fd, reason, len); -} + if (!WriteFdExactly(fd, buf, 8)) { + return -1; + } -//extern int online; + return WriteFdExactly(fd, reason, len) ? 0 : -1; +} static unsigned local_socket_next_id = 1; @@ -196,10 +203,9 @@ enqueue: static void local_socket_ready(asocket *s) { - /* far side is ready for data, pay attention to - readable events */ + /* far side is ready for data, pay attention to + readable events */ fdevent_add(&s->fde, FDE_READ); -// D("LS(%d): ready()\n", s->id); } static void local_socket_close(asocket *s) @@ -240,7 +246,7 @@ static void local_socket_destroy(asocket *s) static void local_socket_close_locked(asocket *s) { - D("entered. LS(%d) fd=%d\n", s->id, s->fd); + D("entered local_socket_close_locked. LS(%d) fd=%d\n", s->id, s->fd); if(s->peer) { D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n", s->id, s->peer->id, s->peer->fd); @@ -280,98 +286,101 @@ static void local_socket_close_locked(asocket *s) insert_local_socket(s, &local_socket_closing_list); } -static void local_socket_event_func(int fd, unsigned ev, void *_s) +static void local_socket_event_func(int fd, unsigned ev, void* _s) { - asocket *s = _s; - + asocket* s = reinterpret_cast<asocket*>(_s); D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev); /* put the FDE_WRITE processing before the FDE_READ ** in order to simplify the code. */ - if(ev & FDE_WRITE){ - apacket *p; - - while((p = s->pkt_first) != 0) { - while(p->len > 0) { + if (ev & FDE_WRITE) { + apacket* p; + while ((p = s->pkt_first) != nullptr) { + while (p->len > 0) { int r = adb_write(fd, p->ptr, p->len); - if(r > 0) { - p->ptr += r; - p->len -= r; - continue; - } - if(r < 0) { + if (r == -1) { /* returning here is ok because FDE_READ will ** be processed in the next iteration loop */ - if(errno == EAGAIN) return; - if(errno == EINTR) continue; + if (errno == EAGAIN) { + return; + } + } else if (r > 0) { + p->ptr += r; + p->len -= r; + continue; } + D(" closing after write because r=%d and errno is %d\n", r, errno); s->close(s); return; } - if(p->len == 0) { + if (p->len == 0) { s->pkt_first = p->next; - if(s->pkt_first == 0) s->pkt_last = 0; + if (s->pkt_first == 0) { + s->pkt_last = 0; + } put_apacket(p); } } - /* if we sent the last packet of a closing socket, - ** we can now destroy it. - */ + /* if we sent the last packet of a closing socket, + ** we can now destroy it. + */ if (s->closing) { D(" closing because 'closing' is set after write\n"); s->close(s); return; } - /* no more packets queued, so we can ignore - ** writable events again and tell our peer - ** to resume writing - */ + /* no more packets queued, so we can ignore + ** writable events again and tell our peer + ** to resume writing + */ fdevent_del(&s->fde, FDE_WRITE); s->peer->ready(s->peer); } - if(ev & FDE_READ){ + if (ev & FDE_READ) { apacket *p = get_apacket(); unsigned char *x = p->data; size_t avail = MAX_PAYLOAD; int r; int is_eof = 0; - while(avail > 0) { + while (avail > 0) { r = adb_read(fd, x, avail); - D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu\n", s->id, s->fd, r, r<0?errno:0, avail); - if(r > 0) { + D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu\n", + s->id, s->fd, r, r < 0 ? errno : 0, avail); + if (r == -1) { + if (errno == EAGAIN) { + break; + } + } else if (r > 0) { avail -= r; x += r; continue; } - if(r < 0) { - if(errno == EAGAIN) break; - if(errno == EINTR) continue; - } - /* r = 0 or unhandled error */ + /* r = 0 or unhandled error */ is_eof = 1; break; } D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n", s->id, s->fd, r, is_eof, s->fde.force_eof); - if((avail == MAX_PAYLOAD) || (s->peer == 0)) { + if ((avail == MAX_PAYLOAD) || (s->peer == 0)) { put_apacket(p); } else { p->len = MAX_PAYLOAD - avail; r = s->peer->enqueue(s->peer, p); - D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r); + D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, + r); - if(r < 0) { + if (r < 0) { /* error return means they closed us as a side-effect ** and we must return immediately. ** @@ -383,7 +392,7 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s) return; } - if(r > 0) { + if (r > 0) { /* if the remote cannot accept further events, ** we disable notification of READs. They'll ** be enabled again when we get a call to ready() @@ -392,18 +401,18 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s) } } /* Don't allow a forced eof if data is still there */ - if((s->fde.force_eof && !r) || is_eof) { - D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof); + if ((s->fde.force_eof && !r) || is_eof) { + D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", + is_eof, r, s->fde.force_eof); s->close(s); } } - if(ev & FDE_ERROR){ + if (ev & FDE_ERROR){ /* this should be caught be the next read or write ** catching it here means we may skip the last few ** bytes of readable data. */ -// s->close(s); D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd); return; @@ -412,7 +421,7 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s) asocket *create_local_socket(int fd) { - asocket *s = calloc(1, sizeof(asocket)); + asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket))); if (s == NULL) fatal("cannot allocate socket"); s->fd = fd; s->enqueue = local_socket_enqueue; @@ -422,20 +431,12 @@ asocket *create_local_socket(int fd) install_local_socket(s); fdevent_install(&s->fde, fd, local_socket_event_func, s); -/* fdevent_add(&s->fde, FDE_ERROR); */ - //fprintf(stderr, "Created local socket in create_local_socket \n"); D("LS(%d): created (fd=%d)\n", s->id, s->fd); return s; } asocket *create_local_service_socket(const char *name) { - asocket *s; - int fd; -#if !ADB_HOST - char debug[PROPERTY_VALUE_MAX]; -#endif - #if !ADB_HOST if (!strcmp(name,"jdwp")) { return create_jdwp_service_socket(); @@ -444,18 +445,19 @@ asocket *create_local_service_socket(const char *name) return create_jdwp_tracker_service_socket(); } #endif - fd = service_to_fd(name); + int fd = service_to_fd(name); if(fd < 0) return 0; - s = create_local_socket(fd); + asocket* s = create_local_socket(fd); D("LS(%d): bound to '%s' via %d\n", s->id, name, fd); #if !ADB_HOST + char debug[PROPERTY_VALUE_MAX]; if (!strncmp(name, "root:", 5)) property_get("ro.debuggable", debug, ""); - if ((!strncmp(name, "root:", 5) && getuid() != 0 - && strcmp(debug, "1") == 0) + if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0) + || (!strncmp(name, "unroot:", 7) && getuid() == 0) || !strncmp(name, "usb:", 4) || !strncmp(name, "tcpip:", 6)) { D("LS(%d): enabling exit_on_close\n", s->id); @@ -485,10 +487,10 @@ static asocket *create_host_service_socket(const char *name, const char* serial) /* a Remote socket is used to send/receive data to/from a given transport object ** it needs to be closed when the transport is forcibly destroyed by the user */ -typedef struct aremotesocket { +struct aremotesocket { asocket socket; adisconnect disconnect; -} aremotesocket; +}; static int remote_socket_enqueue(asocket *s, apacket *p) { @@ -543,8 +545,8 @@ static void remote_socket_close(asocket *s) static void remote_socket_disconnect(void* _s, atransport* t) { - asocket* s = _s; - asocket* peer = s->peer; + asocket* s = reinterpret_cast<asocket*>(_s); + asocket* peer = s->peer; D("remote_socket_disconnect RS(%d)\n", s->id); if (peer) { @@ -561,12 +563,9 @@ static void remote_socket_disconnect(void* _s, atransport* t) Returns a new non-NULL asocket handle. */ asocket *create_remote_socket(unsigned id, atransport *t) { - asocket* s; - adisconnect* dis; - if (id == 0) fatal("invalid remote socket id (0)"); - s = calloc(1, sizeof(aremotesocket)); - dis = &((aremotesocket*)s)->disconnect; + asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(aremotesocket))); + adisconnect* dis = &reinterpret_cast<aremotesocket*>(s)->disconnect; if (s == NULL) fatal("cannot allocate socket"); s->id = id; @@ -828,12 +827,11 @@ static int smart_socket_enqueue(asocket *s, apacket *p) } #else /* !ADB_HOST */ if (s->transport == NULL) { - char* error_string = "unknown failure"; - s->transport = acquire_one_transport (CS_ANY, - kTransportAny, NULL, &error_string); + std::string error_msg = "unknown failure"; + s->transport = acquire_one_transport(CS_ANY, kTransportAny, NULL, &error_msg); if (s->transport == NULL) { - sendfailmsg(s->peer->fd, error_string); + sendfailmsg(s->peer->fd, error_msg.c_str()); goto fail; } } @@ -896,7 +894,7 @@ static void smart_socket_close(asocket *s) static asocket *create_smart_socket(void) { D("Creating smart socket \n"); - asocket *s = calloc(1, sizeof(asocket)); + asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket))); if (s == NULL) fatal("cannot allocate socket"); s->enqueue = smart_socket_enqueue; s->ready = smart_socket_ready; diff --git a/adb/sysdeps.h b/adb/sysdeps.h index cc1f839..d9a1518 100644 --- a/adb/sysdeps.h +++ b/adb/sysdeps.h @@ -24,18 +24,35 @@ # undef _WIN32 #endif +/* + * TEMP_FAILURE_RETRY is defined by some, but not all, versions of + * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's + * not already defined, then define it here. + */ +#ifndef TEMP_FAILURE_RETRY +/* Used to retry syscalls that can return EINTR. */ +#define TEMP_FAILURE_RETRY(exp) ({ \ + typeof (exp) _rc; \ + do { \ + _rc = (exp); \ + } while (_rc == -1 && errno == EINTR); \ + _rc; }) +#endif + #ifdef _WIN32 -#include <winsock2.h> -#include <windows.h> -#include <ws2tcpip.h> -#include <process.h> +#include <ctype.h> +#include <direct.h> +#include <errno.h> #include <fcntl.h> #include <io.h> +#include <process.h> #include <sys/stat.h> -#include <errno.h> -#include <ctype.h> -#include <direct.h> +#include <winsock2.h> +#include <windows.h> +#include <ws2tcpip.h> + +#include "fdevent.h" #define OS_PATH_SEPARATOR '\\' #define OS_PATH_SEPARATOR_STR "\\" @@ -77,13 +94,16 @@ static __inline__ int adb_thread_create( adb_thread_t *thread, adb_thread_func return 0; } +static __inline__ unsigned long adb_thread_id() +{ + return GetCurrentThreadId(); +} + static __inline__ void close_on_exec(int fd) { /* nothing really */ } -extern void disable_tcp_nagle(int fd); - #define lstat stat /* no symlinks on Win32 */ #define S_ISLNK(m) 0 /* no symlinks on Win32 */ @@ -126,10 +146,8 @@ static __inline__ int unix_close(int fd) #undef close #define close ____xxx_close -static __inline__ int unix_read(int fd, void* buf, size_t len) -{ - return read(fd, buf, len); -} +extern int unix_read(int fd, void* buf, size_t len); + #undef read #define read ___xxx_read @@ -182,8 +200,6 @@ extern int socket_inaddr_any_server(int port, int type); #define FDE_ERROR 0x0004 #define FDE_DONT_CLOSE 0x0080 -typedef struct fdevent fdevent; - typedef void (*fd_func)(int fd, unsigned events, void *userdata); fdevent *fdevent_create(int fd, fd_func func, void *arg); @@ -195,20 +211,6 @@ void fdevent_add(fdevent *fde, unsigned events); void fdevent_del(fdevent *fde, unsigned events); void fdevent_loop(); -struct fdevent { - fdevent *next; - fdevent *prev; - - int fd; - int force_eof; - - unsigned short state; - unsigned short events; - - fd_func func; - void *arg; -}; - static __inline__ void adb_sleep_ms( int mseconds ) { Sleep( mseconds ); @@ -219,10 +221,21 @@ extern int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t #undef accept #define accept ___xxx_accept +extern int adb_setsockopt(int fd, int level, int optname, const void* optval, socklen_t optlen); + +#undef setsockopt +#define setsockopt ___xxx_setsockopt + static __inline__ int adb_socket_setbufsize( int fd, int bufsize ) { int opt = bufsize; - return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt)); + return adb_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const void*)&opt, sizeof(opt)); +} + +static __inline__ void disable_tcp_nagle( int fd ) +{ + int on = 1; + adb_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void*)&on, sizeof(on)); } extern int adb_socketpair( int sv[2] ); @@ -279,21 +292,6 @@ extern char* adb_strtok_r(char *str, const char *delim, char **saveptr); #include <string.h> #include <unistd.h> -/* - * TEMP_FAILURE_RETRY is defined by some, but not all, versions of - * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's - * not already defined, then define it here. - */ -#ifndef TEMP_FAILURE_RETRY -/* Used to retry syscalls that can return EINTR. */ -#define TEMP_FAILURE_RETRY(exp) ({ \ - typeof (exp) _rc; \ - do { \ - _rc = (exp); \ - } while (_rc == -1 && errno == EINTR); \ - _rc; }) -#endif - #define OS_PATH_SEPARATOR '/' #define OS_PATH_SEPARATOR_STR "/" #define ENV_PATH_SEPARATOR_STR ":" @@ -459,6 +457,13 @@ static __inline__ void disable_tcp_nagle(int fd) setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) ); } +static __inline__ int adb_setsockopt( int fd, int level, int optname, const void* optval, socklen_t optlen ) +{ + return setsockopt( fd, level, optname, optval, optlen ); +} + +#undef setsockopt +#define setsockopt ___xxx_setsockopt static __inline__ int unix_socketpair( int d, int type, int protocol, int sv[2] ) { @@ -516,6 +521,12 @@ static __inline__ char* adb_strtok_r(char *str, const char *delim, char **savep { return strtok_r(str, delim, saveptr); } + +static __inline__ unsigned long adb_thread_id() +{ + return (unsigned long)pthread_self(); +} + #undef strtok_r #define strtok_r ___xxx_strtok_r diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.cpp index e69ec2b..de47638 100644 --- a/adb/sysdeps_win32.c +++ b/adb/sysdeps_win32.cpp @@ -1,14 +1,82 @@ +/* + * Copyright (C) 2015 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 TRACE_TAG TRACE_SYSDEPS + #include "sysdeps.h" -#include <winsock2.h> + +#include <winsock2.h> /* winsock.h *must* be included before windows.h. */ #include <windows.h> + +#include <errno.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> -#include <errno.h> -#define TRACE_TAG TRACE_SYSDEPS + #include "adb.h" extern void fatal(const char *fmt, ...); +/* forward declarations */ + +typedef const struct FHClassRec_* FHClass; +typedef struct FHRec_* FH; +typedef struct EventHookRec_* EventHook; + +typedef struct FHClassRec_ { + void (*_fh_init)(FH); + int (*_fh_close)(FH); + int (*_fh_lseek)(FH, int, int); + int (*_fh_read)(FH, void*, int); + int (*_fh_write)(FH, const void*, int); + void (*_fh_hook)(FH, int, EventHook); +} FHClassRec; + +static void _fh_file_init(FH); +static int _fh_file_close(FH); +static int _fh_file_lseek(FH, int, int); +static int _fh_file_read(FH, void*, int); +static int _fh_file_write(FH, const void*, int); +static void _fh_file_hook(FH, int, EventHook); + +static const FHClassRec _fh_file_class = { + _fh_file_init, + _fh_file_close, + _fh_file_lseek, + _fh_file_read, + _fh_file_write, + _fh_file_hook +}; + +static void _fh_socket_init(FH); +static int _fh_socket_close(FH); +static int _fh_socket_lseek(FH, int, int); +static int _fh_socket_read(FH, void*, int); +static int _fh_socket_write(FH, const void*, int); +static void _fh_socket_hook(FH, int, EventHook); + +static const FHClassRec _fh_socket_class = { + _fh_socket_init, + _fh_socket_close, + _fh_socket_lseek, + _fh_socket_read, + _fh_socket_write, + _fh_socket_hook +}; + #define assert(cond) do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0) /**************************************************************************/ @@ -71,23 +139,6 @@ void *load_file(const char *fn, unsigned *_sz) /**************************************************************************/ /**************************************************************************/ -typedef const struct FHClassRec_* FHClass; - -typedef struct FHRec_* FH; - -typedef struct EventHookRec_* EventHook; - -typedef struct FHClassRec_ -{ - void (*_fh_init) ( FH f ); - int (*_fh_close)( FH f ); - int (*_fh_lseek)( FH f, int pos, int origin ); - int (*_fh_read) ( FH f, void* buf, int len ); - int (*_fh_write)( FH f, const void* buf, int len ); - void (*_fh_hook) ( FH f, int events, EventHook hook ); - -} FHClassRec; - /* used to emulate unix-domain socket pairs */ typedef struct SocketPairRec_* SocketPair; @@ -199,10 +250,6 @@ _fh_close( FH f ) return 0; } -/* forward definitions */ -static const FHClassRec _fh_file_class; -static const FHClassRec _fh_socket_class; - /**************************************************************************/ /**************************************************************************/ /***** *****/ @@ -211,23 +258,17 @@ static const FHClassRec _fh_socket_class; /**************************************************************************/ /**************************************************************************/ -static void -_fh_file_init( FH f ) -{ +static void _fh_file_init( FH f ) { f->fh_handle = INVALID_HANDLE_VALUE; } -static int -_fh_file_close( FH f ) -{ +static int _fh_file_close( FH f ) { CloseHandle( f->fh_handle ); f->fh_handle = INVALID_HANDLE_VALUE; return 0; } -static int -_fh_file_read( FH f, void* buf, int len ) -{ +static int _fh_file_read( FH f, void* buf, int len ) { DWORD read_bytes; if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) { @@ -240,9 +281,7 @@ _fh_file_read( FH f, void* buf, int len ) return (int)read_bytes; } -static int -_fh_file_write( FH f, const void* buf, int len ) -{ +static int _fh_file_write( FH f, const void* buf, int len ) { DWORD wrote_bytes; if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) { @@ -255,9 +294,7 @@ _fh_file_write( FH f, const void* buf, int len ) return (int)wrote_bytes; } -static int -_fh_file_lseek( FH f, int pos, int origin ) -{ +static int _fh_file_lseek( FH f, int pos, int origin ) { DWORD method; DWORD result; @@ -281,17 +318,6 @@ _fh_file_lseek( FH f, int pos, int origin ) return (int)result; } -static void _fh_file_hook( FH f, int event, EventHook eventhook ); /* forward */ - -static const FHClassRec _fh_file_class = -{ - _fh_file_init, - _fh_file_close, - _fh_file_lseek, - _fh_file_read, - _fh_file_write, - _fh_file_hook -}; /**************************************************************************/ /**************************************************************************/ @@ -440,7 +466,8 @@ int adb_shutdown(int fd) { FH f = _fh_from_int(fd); - if (!f) { + if (!f || f->clazz != &_fh_socket_class) { + D("adb_shutdown: invalid fd %d\n", fd); return -1; } @@ -471,9 +498,9 @@ int adb_close(int fd) /**************************************************************************/ /**************************************************************************/ -static void -_socket_set_errno( void ) -{ +#undef setsockopt + +static void _socket_set_errno( void ) { switch (WSAGetLastError()) { case 0: errno = 0; break; case WSAEWOULDBLOCK: errno = EAGAIN; break; @@ -484,17 +511,13 @@ _socket_set_errno( void ) } } -static void -_fh_socket_init( FH f ) -{ +static void _fh_socket_init( FH f ) { f->fh_socket = INVALID_SOCKET; f->event = WSACreateEvent(); f->mask = 0; } -static int -_fh_socket_close( FH f ) -{ +static int _fh_socket_close( FH f ) { /* gently tell any peer that we're closing the socket */ shutdown( f->fh_socket, SD_BOTH ); closesocket( f->fh_socket ); @@ -504,17 +527,13 @@ _fh_socket_close( FH f ) return 0; } -static int -_fh_socket_lseek( FH f, int pos, int origin ) -{ +static int _fh_socket_lseek( FH f, int pos, int origin ) { errno = EPIPE; return -1; } -static int -_fh_socket_read( FH f, void* buf, int len ) -{ - int result = recv( f->fh_socket, buf, len, 0 ); +static int _fh_socket_read(FH f, void* buf, int len) { + int result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0); if (result == SOCKET_ERROR) { _socket_set_errno(); result = -1; @@ -522,10 +541,8 @@ _fh_socket_read( FH f, void* buf, int len ) return result; } -static int -_fh_socket_write( FH f, const void* buf, int len ) -{ - int result = send( f->fh_socket, buf, len, 0 ); +static int _fh_socket_write(FH f, const void* buf, int len) { + int result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0); if (result == SOCKET_ERROR) { _socket_set_errno(); result = -1; @@ -533,18 +550,6 @@ _fh_socket_write( FH f, const void* buf, int len ) return result; } -static void _fh_socket_hook( FH f, int event, EventHook hook ); /* forward */ - -static const FHClassRec _fh_socket_class = -{ - _fh_socket_init, - _fh_socket_close, - _fh_socket_lseek, - _fh_socket_read, - _fh_socket_write, - _fh_socket_hook -}; - /**************************************************************************/ /**************************************************************************/ /***** *****/ @@ -786,15 +791,16 @@ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrle } -void disable_tcp_nagle(int fd) +int adb_setsockopt( int fd, int level, int optname, const void* optval, socklen_t optlen ) { FH fh = _fh_from_int(fd); - int on = 1; - if ( !fh || fh->clazz != &_fh_socket_class ) - return; + if ( !fh || fh->clazz != &_fh_socket_class ) { + D("adb_setsockopt: invalid fd %d\n", fd); + return -1; + } - setsockopt( fh->fh_socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on) ); + return setsockopt( fh->fh_socket, level, optname, reinterpret_cast<const char*>(optval), optlen ); } /**************************************************************************/ @@ -1194,18 +1200,16 @@ static const FHClassRec _fh_socketpair_class = }; -int adb_socketpair( int sv[2] ) -{ - FH fa, fb; - SocketPair pair; +int adb_socketpair(int sv[2]) { + SocketPair pair; - fa = _fh_alloc( &_fh_socketpair_class ); - fb = _fh_alloc( &_fh_socketpair_class ); + FH fa = _fh_alloc(&_fh_socketpair_class); + FH fb = _fh_alloc(&_fh_socketpair_class); if (!fa || !fb) goto Fail; - pair = malloc( sizeof(*pair) ); + pair = reinterpret_cast<SocketPair>(malloc(sizeof(*pair))); if (pair == NULL) { D("adb_socketpair: not enough memory to allocate pipes\n" ); goto Fail; @@ -1303,13 +1307,12 @@ typedef struct EventHookRec_ static EventHook _free_hooks; static EventHook -event_hook_alloc( FH fh ) -{ - EventHook hook = _free_hooks; - if (hook != NULL) +event_hook_alloc(FH fh) { + EventHook hook = _free_hooks; + if (hook != NULL) { _free_hooks = hook->next; - else { - hook = malloc( sizeof(*hook) ); + } else { + hook = reinterpret_cast<EventHook>(malloc(sizeof(*hook))); if (hook == NULL) fatal( "could not allocate event hook\n" ); } @@ -1771,7 +1774,7 @@ static void fdevent_register(fdevent *fde) while(fd_table_max <= fd) { fd_table_max *= 2; } - fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max); + fd_table = reinterpret_cast<fdevent**>(realloc(fd_table, sizeof(fdevent*) * fd_table_max)); if(fd_table == 0) { FATAL("could not expand fd_table to %d entries\n", fd_table_max); } @@ -2226,3 +2229,905 @@ cont: } /* NOTREACHED */ } + +/**************************************************************************/ +/**************************************************************************/ +/***** *****/ +/***** Console Window Terminal Emulation *****/ +/***** *****/ +/**************************************************************************/ +/**************************************************************************/ + +// This reads input from a Win32 console window and translates it into Unix +// terminal-style sequences. This emulates mostly Gnome Terminal (in Normal +// mode, not Application mode), which itself emulates xterm. Gnome Terminal +// is emulated instead of xterm because it is probably more popular than xterm: +// Ubuntu's default Ctrl-Alt-T shortcut opens Gnome Terminal, Gnome Terminal +// supports modern fonts, etc. It seems best to emulate the terminal that most +// Android developers use because they'll fix apps (the shell, etc.) to keep +// working with that terminal's emulation. +// +// The point of this emulation is not to be perfect or to solve all issues with +// console windows on Windows, but to be better than the original code which +// just called read() (which called ReadFile(), which called ReadConsoleA()) +// which did not support Ctrl-C, tab completion, shell input line editing +// keys, server echo, and more. +// +// This implementation reconfigures the console with SetConsoleMode(), then +// calls ReadConsoleInput() to get raw input which it remaps to Unix +// terminal-style sequences which is returned via unix_read() which is used +// by the 'adb shell' command. +// +// Code organization: +// +// * stdin_raw_init() and stdin_raw_restore() reconfigure the console. +// * unix_read() detects console windows (as opposed to pipes, files, etc.). +// * _console_read() is the main code of the emulation. + + +// Read an input record from the console; one that should be processed. +static bool _get_interesting_input_record_uncached(const HANDLE console, + INPUT_RECORD* const input_record) { + for (;;) { + DWORD read_count = 0; + memset(input_record, 0, sizeof(*input_record)); + if (!ReadConsoleInputA(console, input_record, 1, &read_count)) { + D("_get_interesting_input_record_uncached: ReadConsoleInputA() " + "failure, error %ld\n", GetLastError()); + errno = EIO; + return false; + } + + if (read_count == 0) { // should be impossible + fatal("ReadConsoleInputA returned 0"); + } + + if (read_count != 1) { // should be impossible + fatal("ReadConsoleInputA did not return one input record"); + } + + if ((input_record->EventType == KEY_EVENT) && + (input_record->Event.KeyEvent.bKeyDown)) { + if (input_record->Event.KeyEvent.wRepeatCount == 0) { + fatal("ReadConsoleInputA returned a key event with zero repeat" + " count"); + } + + // Got an interesting INPUT_RECORD, so return + return true; + } + } +} + +// Cached input record (in case _console_read() is passed a buffer that doesn't +// have enough space to fit wRepeatCount number of key sequences). A non-zero +// wRepeatCount indicates that a record is cached. +static INPUT_RECORD _win32_input_record; + +// Get the next KEY_EVENT_RECORD that should be processed. +static KEY_EVENT_RECORD* _get_key_event_record(const HANDLE console) { + // If nothing cached, read directly from the console until we get an + // interesting record. + if (_win32_input_record.Event.KeyEvent.wRepeatCount == 0) { + if (!_get_interesting_input_record_uncached(console, + &_win32_input_record)) { + // There was an error, so make sure wRepeatCount is zero because + // that signifies no cached input record. + _win32_input_record.Event.KeyEvent.wRepeatCount = 0; + return NULL; + } + } + + return &_win32_input_record.Event.KeyEvent; +} + +static __inline__ bool _is_shift_pressed(const DWORD control_key_state) { + return (control_key_state & SHIFT_PRESSED) != 0; +} + +static __inline__ bool _is_ctrl_pressed(const DWORD control_key_state) { + return (control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0; +} + +static __inline__ bool _is_alt_pressed(const DWORD control_key_state) { + return (control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) != 0; +} + +static __inline__ bool _is_numlock_on(const DWORD control_key_state) { + return (control_key_state & NUMLOCK_ON) != 0; +} + +static __inline__ bool _is_capslock_on(const DWORD control_key_state) { + return (control_key_state & CAPSLOCK_ON) != 0; +} + +static __inline__ bool _is_enhanced_key(const DWORD control_key_state) { + return (control_key_state & ENHANCED_KEY) != 0; +} + +// Constants from MSDN for ToAscii(). +static const BYTE TOASCII_KEY_OFF = 0x00; +static const BYTE TOASCII_KEY_DOWN = 0x80; +static const BYTE TOASCII_KEY_TOGGLED_ON = 0x01; // for CapsLock + +// Given a key event, ignore a modifier key and return the character that was +// entered without the modifier. Writes to *ch and returns the number of bytes +// written. +static size_t _get_char_ignoring_modifier(char* const ch, + const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state, + const WORD modifier) { + // If there is no character from Windows, try ignoring the specified + // modifier and look for a character. Note that if AltGr is being used, + // there will be a character from Windows. + if (key_event->uChar.AsciiChar == '\0') { + // Note that we read the control key state from the passed in argument + // instead of from key_event since the argument has been normalized. + if (((modifier == VK_SHIFT) && + _is_shift_pressed(control_key_state)) || + ((modifier == VK_CONTROL) && + _is_ctrl_pressed(control_key_state)) || + ((modifier == VK_MENU) && _is_alt_pressed(control_key_state))) { + + BYTE key_state[256] = {0}; + key_state[VK_SHIFT] = _is_shift_pressed(control_key_state) ? + TOASCII_KEY_DOWN : TOASCII_KEY_OFF; + key_state[VK_CONTROL] = _is_ctrl_pressed(control_key_state) ? + TOASCII_KEY_DOWN : TOASCII_KEY_OFF; + key_state[VK_MENU] = _is_alt_pressed(control_key_state) ? + TOASCII_KEY_DOWN : TOASCII_KEY_OFF; + key_state[VK_CAPITAL] = _is_capslock_on(control_key_state) ? + TOASCII_KEY_TOGGLED_ON : TOASCII_KEY_OFF; + + // cause this modifier to be ignored + key_state[modifier] = TOASCII_KEY_OFF; + + WORD translated = 0; + if (ToAscii(key_event->wVirtualKeyCode, + key_event->wVirtualScanCode, key_state, &translated, 0) == 1) { + // Ignoring the modifier, we found a character. + *ch = (CHAR)translated; + return 1; + } + } + } + + // Just use whatever Windows told us originally. + *ch = key_event->uChar.AsciiChar; + + // If the character from Windows is NULL, return a size of zero. + return (*ch == '\0') ? 0 : 1; +} + +// If a Ctrl key is pressed, lookup the character, ignoring the Ctrl key, +// but taking into account the shift key. This is because for a sequence like +// Ctrl-Alt-0, we want to find the character '0' and for Ctrl-Alt-Shift-0, +// we want to find the character ')'. +// +// Note that Windows doesn't seem to pass bKeyDown for Ctrl-Shift-NoAlt-0 +// because it is the default key-sequence to switch the input language. +// This is configurable in the Region and Language control panel. +static __inline__ size_t _get_non_control_char(char* const ch, + const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) { + return _get_char_ignoring_modifier(ch, key_event, control_key_state, + VK_CONTROL); +} + +// Get without Alt. +static __inline__ size_t _get_non_alt_char(char* const ch, + const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) { + return _get_char_ignoring_modifier(ch, key_event, control_key_state, + VK_MENU); +} + +// Ignore the control key, find the character from Windows, and apply any +// Control key mappings (for example, Ctrl-2 is a NULL character). Writes to +// *pch and returns number of bytes written. +static size_t _get_control_character(char* const pch, + const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) { + const size_t len = _get_non_control_char(pch, key_event, + control_key_state); + + if ((len == 1) && _is_ctrl_pressed(control_key_state)) { + char ch = *pch; + switch (ch) { + case '2': + case '@': + case '`': + ch = '\0'; + break; + case '3': + case '[': + case '{': + ch = '\x1b'; + break; + case '4': + case '\\': + case '|': + ch = '\x1c'; + break; + case '5': + case ']': + case '}': + ch = '\x1d'; + break; + case '6': + case '^': + case '~': + ch = '\x1e'; + break; + case '7': + case '-': + case '_': + ch = '\x1f'; + break; + case '8': + ch = '\x7f'; + break; + case '/': + if (!_is_alt_pressed(control_key_state)) { + ch = '\x1f'; + } + break; + case '?': + if (!_is_alt_pressed(control_key_state)) { + ch = '\x7f'; + } + break; + } + *pch = ch; + } + + return len; +} + +static DWORD _normalize_altgr_control_key_state( + const KEY_EVENT_RECORD* const key_event) { + DWORD control_key_state = key_event->dwControlKeyState; + + // If we're in an AltGr situation where the AltGr key is down (depending on + // the keyboard layout, that might be the physical right alt key which + // produces a control_key_state where Right-Alt and Left-Ctrl are down) or + // AltGr-equivalent keys are down (any Ctrl key + any Alt key), and we have + // a character (which indicates that there was an AltGr mapping), then act + // as if alt and control are not really down for the purposes of modifiers. + // This makes it so that if the user with, say, a German keyboard layout + // presses AltGr-] (which we see as Right-Alt + Left-Ctrl + key), we just + // output the key and we don't see the Alt and Ctrl keys. + if (_is_ctrl_pressed(control_key_state) && + _is_alt_pressed(control_key_state) + && (key_event->uChar.AsciiChar != '\0')) { + // Try to remove as few bits as possible to improve our chances of + // detecting combinations like Left-Alt + AltGr, Right-Ctrl + AltGr, or + // Left-Alt + Right-Ctrl + AltGr. + if ((control_key_state & RIGHT_ALT_PRESSED) != 0) { + // Remove Right-Alt. + control_key_state &= ~RIGHT_ALT_PRESSED; + // If uChar is set, a Ctrl key is pressed, and Right-Alt is + // pressed, Left-Ctrl is almost always set, except if the user + // presses Right-Ctrl, then AltGr (in that specific order) for + // whatever reason. At any rate, make sure the bit is not set. + control_key_state &= ~LEFT_CTRL_PRESSED; + } else if ((control_key_state & LEFT_ALT_PRESSED) != 0) { + // Remove Left-Alt. + control_key_state &= ~LEFT_ALT_PRESSED; + // Whichever Ctrl key is down, remove it from the state. We only + // remove one key, to improve our chances of detecting the + // corner-case of Left-Ctrl + Left-Alt + Right-Ctrl. + if ((control_key_state & LEFT_CTRL_PRESSED) != 0) { + // Remove Left-Ctrl. + control_key_state &= ~LEFT_CTRL_PRESSED; + } else if ((control_key_state & RIGHT_CTRL_PRESSED) != 0) { + // Remove Right-Ctrl. + control_key_state &= ~RIGHT_CTRL_PRESSED; + } + } + + // Note that this logic isn't 100% perfect because Windows doesn't + // allow us to detect all combinations because a physical AltGr key + // press shows up as two bits, plus some combinations are ambiguous + // about what is actually physically pressed. + } + + return control_key_state; +} + +// If NumLock is on and Shift is pressed, SHIFT_PRESSED is not set in +// dwControlKeyState for the following keypad keys: period, 0-9. If we detect +// this scenario, set the SHIFT_PRESSED bit so we can add modifiers +// appropriately. +static DWORD _normalize_keypad_control_key_state(const WORD vk, + const DWORD control_key_state) { + if (!_is_numlock_on(control_key_state)) { + return control_key_state; + } + if (!_is_enhanced_key(control_key_state)) { + switch (vk) { + case VK_INSERT: // 0 + case VK_DELETE: // . + case VK_END: // 1 + case VK_DOWN: // 2 + case VK_NEXT: // 3 + case VK_LEFT: // 4 + case VK_CLEAR: // 5 + case VK_RIGHT: // 6 + case VK_HOME: // 7 + case VK_UP: // 8 + case VK_PRIOR: // 9 + return control_key_state | SHIFT_PRESSED; + } + } + + return control_key_state; +} + +static const char* _get_keypad_sequence(const DWORD control_key_state, + const char* const normal, const char* const shifted) { + if (_is_shift_pressed(control_key_state)) { + // Shift is pressed and NumLock is off + return shifted; + } else { + // Shift is not pressed and NumLock is off, or, + // Shift is pressed and NumLock is on, in which case we want the + // NumLock and Shift to neutralize each other, thus, we want the normal + // sequence. + return normal; + } + // If Shift is not pressed and NumLock is on, a different virtual key code + // is returned by Windows, which can be taken care of by a different case + // statement in _console_read(). +} + +// Write sequence to buf and return the number of bytes written. +static size_t _get_modifier_sequence(char* const buf, const WORD vk, + DWORD control_key_state, const char* const normal) { + // Copy the base sequence into buf. + const size_t len = strlen(normal); + memcpy(buf, normal, len); + + int code = 0; + + control_key_state = _normalize_keypad_control_key_state(vk, + control_key_state); + + if (_is_shift_pressed(control_key_state)) { + code |= 0x1; + } + if (_is_alt_pressed(control_key_state)) { // any alt key pressed + code |= 0x2; + } + if (_is_ctrl_pressed(control_key_state)) { // any control key pressed + code |= 0x4; + } + // If some modifier was held down, then we need to insert the modifier code + if (code != 0) { + if (len == 0) { + // Should be impossible because caller should pass a string of + // non-zero length. + return 0; + } + size_t index = len - 1; + const char lastChar = buf[index]; + if (lastChar != '~') { + buf[index++] = '1'; + } + buf[index++] = ';'; // modifier separator + // 2 = shift, 3 = alt, 4 = shift & alt, 5 = control, + // 6 = shift & control, 7 = alt & control, 8 = shift & alt & control + buf[index++] = '1' + code; + buf[index++] = lastChar; // move ~ (or other last char) to the end + return index; + } + return len; +} + +// Write sequence to buf and return the number of bytes written. +static size_t _get_modifier_keypad_sequence(char* const buf, const WORD vk, + const DWORD control_key_state, const char* const normal, + const char shifted) { + if (_is_shift_pressed(control_key_state)) { + // Shift is pressed and NumLock is off + if (shifted != '\0') { + buf[0] = shifted; + return sizeof(buf[0]); + } else { + return 0; + } + } else { + // Shift is not pressed and NumLock is off, or, + // Shift is pressed and NumLock is on, in which case we want the + // NumLock and Shift to neutralize each other, thus, we want the normal + // sequence. + return _get_modifier_sequence(buf, vk, control_key_state, normal); + } + // If Shift is not pressed and NumLock is on, a different virtual key code + // is returned by Windows, which can be taken care of by a different case + // statement in _console_read(). +} + +// The decimal key on the keypad produces a '.' for U.S. English and a ',' for +// Standard German. Figure this out at runtime so we know what to output for +// Shift-VK_DELETE. +static char _get_decimal_char() { + return (char)MapVirtualKeyA(VK_DECIMAL, MAPVK_VK_TO_CHAR); +} + +// Prefix the len bytes in buf with the escape character, and then return the +// new buffer length. +size_t _escape_prefix(char* const buf, const size_t len) { + // If nothing to prefix, don't do anything. We might be called with + // len == 0, if alt was held down with a dead key which produced nothing. + if (len == 0) { + return 0; + } + + memmove(&buf[1], buf, len); + buf[0] = '\x1b'; + return len + 1; +} + +// Writes to buffer buf (of length len), returning number of bytes written or +// -1 on error. Never returns zero because Win32 consoles are never 'closed' +// (as far as I can tell). +static int _console_read(const HANDLE console, void* buf, size_t len) { + for (;;) { + KEY_EVENT_RECORD* const key_event = _get_key_event_record(console); + if (key_event == NULL) { + return -1; + } + + const WORD vk = key_event->wVirtualKeyCode; + const CHAR ch = key_event->uChar.AsciiChar; + const DWORD control_key_state = _normalize_altgr_control_key_state( + key_event); + + // The following emulation code should write the output sequence to + // either seqstr or to seqbuf and seqbuflen. + const char* seqstr = NULL; // NULL terminated C-string + // Enough space for max sequence string below, plus modifiers and/or + // escape prefix. + char seqbuf[16]; + size_t seqbuflen = 0; // Space used in seqbuf. + +#define MATCH(vk, normal) \ + case (vk): \ + { \ + seqstr = (normal); \ + } \ + break; + + // Modifier keys should affect the output sequence. +#define MATCH_MODIFIER(vk, normal) \ + case (vk): \ + { \ + seqbuflen = _get_modifier_sequence(seqbuf, (vk), \ + control_key_state, (normal)); \ + } \ + break; + + // The shift key should affect the output sequence. +#define MATCH_KEYPAD(vk, normal, shifted) \ + case (vk): \ + { \ + seqstr = _get_keypad_sequence(control_key_state, (normal), \ + (shifted)); \ + } \ + break; + + // The shift key and other modifier keys should affect the output + // sequence. +#define MATCH_MODIFIER_KEYPAD(vk, normal, shifted) \ + case (vk): \ + { \ + seqbuflen = _get_modifier_keypad_sequence(seqbuf, (vk), \ + control_key_state, (normal), (shifted)); \ + } \ + break; + +#define ESC "\x1b" +#define CSI ESC "[" +#define SS3 ESC "O" + + // Only support normal mode, not application mode. + + // Enhanced keys: + // * 6-pack: insert, delete, home, end, page up, page down + // * cursor keys: up, down, right, left + // * keypad: divide, enter + // * Undocumented: VK_PAUSE (Ctrl-NumLock), VK_SNAPSHOT, + // VK_CANCEL (Ctrl-Pause/Break), VK_NUMLOCK + if (_is_enhanced_key(control_key_state)) { + switch (vk) { + case VK_RETURN: // Enter key on keypad + if (_is_ctrl_pressed(control_key_state)) { + seqstr = "\n"; + } else { + seqstr = "\r"; + } + break; + + MATCH_MODIFIER(VK_PRIOR, CSI "5~"); // Page Up + MATCH_MODIFIER(VK_NEXT, CSI "6~"); // Page Down + + // gnome-terminal currently sends SS3 "F" and SS3 "H", but that + // will be fixed soon to match xterm which sends CSI "F" and + // CSI "H". https://bugzilla.redhat.com/show_bug.cgi?id=1119764 + MATCH(VK_END, CSI "F"); + MATCH(VK_HOME, CSI "H"); + + MATCH_MODIFIER(VK_LEFT, CSI "D"); + MATCH_MODIFIER(VK_UP, CSI "A"); + MATCH_MODIFIER(VK_RIGHT, CSI "C"); + MATCH_MODIFIER(VK_DOWN, CSI "B"); + + MATCH_MODIFIER(VK_INSERT, CSI "2~"); + MATCH_MODIFIER(VK_DELETE, CSI "3~"); + + MATCH(VK_DIVIDE, "/"); + } + } else { // Non-enhanced keys: + switch (vk) { + case VK_BACK: // backspace + if (_is_alt_pressed(control_key_state)) { + seqstr = ESC "\x7f"; + } else { + seqstr = "\x7f"; + } + break; + + case VK_TAB: + if (_is_shift_pressed(control_key_state)) { + seqstr = CSI "Z"; + } else { + seqstr = "\t"; + } + break; + + // Number 5 key in keypad when NumLock is off, or if NumLock is + // on and Shift is down. + MATCH_KEYPAD(VK_CLEAR, CSI "E", "5"); + + case VK_RETURN: // Enter key on main keyboard + if (_is_alt_pressed(control_key_state)) { + seqstr = ESC "\n"; + } else if (_is_ctrl_pressed(control_key_state)) { + seqstr = "\n"; + } else { + seqstr = "\r"; + } + break; + + // VK_ESCAPE: Don't do any special handling. The OS uses many + // of the sequences with Escape and many of the remaining + // sequences don't produce bKeyDown messages, only !bKeyDown + // for whatever reason. + + case VK_SPACE: + if (_is_alt_pressed(control_key_state)) { + seqstr = ESC " "; + } else if (_is_ctrl_pressed(control_key_state)) { + seqbuf[0] = '\0'; // NULL char + seqbuflen = 1; + } else { + seqstr = " "; + } + break; + + MATCH_MODIFIER_KEYPAD(VK_PRIOR, CSI "5~", '9'); // Page Up + MATCH_MODIFIER_KEYPAD(VK_NEXT, CSI "6~", '3'); // Page Down + + MATCH_KEYPAD(VK_END, CSI "4~", "1"); + MATCH_KEYPAD(VK_HOME, CSI "1~", "7"); + + MATCH_MODIFIER_KEYPAD(VK_LEFT, CSI "D", '4'); + MATCH_MODIFIER_KEYPAD(VK_UP, CSI "A", '8'); + MATCH_MODIFIER_KEYPAD(VK_RIGHT, CSI "C", '6'); + MATCH_MODIFIER_KEYPAD(VK_DOWN, CSI "B", '2'); + + MATCH_MODIFIER_KEYPAD(VK_INSERT, CSI "2~", '0'); + MATCH_MODIFIER_KEYPAD(VK_DELETE, CSI "3~", + _get_decimal_char()); + + case 0x30: // 0 + case 0x31: // 1 + case 0x39: // 9 + case VK_OEM_1: // ;: + case VK_OEM_PLUS: // =+ + case VK_OEM_COMMA: // ,< + case VK_OEM_PERIOD: // .> + case VK_OEM_7: // '" + case VK_OEM_102: // depends on keyboard, could be <> or \| + case VK_OEM_2: // /? + case VK_OEM_3: // `~ + case VK_OEM_4: // [{ + case VK_OEM_5: // \| + case VK_OEM_6: // ]} + { + seqbuflen = _get_control_character(seqbuf, key_event, + control_key_state); + + if (_is_alt_pressed(control_key_state)) { + seqbuflen = _escape_prefix(seqbuf, seqbuflen); + } + } + break; + + case 0x32: // 2 + case 0x36: // 6 + case VK_OEM_MINUS: // -_ + { + seqbuflen = _get_control_character(seqbuf, key_event, + control_key_state); + + // If Alt is pressed and it isn't Ctrl-Alt-ShiftUp, then + // prefix with escape. + if (_is_alt_pressed(control_key_state) && + !(_is_ctrl_pressed(control_key_state) && + !_is_shift_pressed(control_key_state))) { + seqbuflen = _escape_prefix(seqbuf, seqbuflen); + } + } + break; + + case 0x33: // 3 + case 0x34: // 4 + case 0x35: // 5 + case 0x37: // 7 + case 0x38: // 8 + { + seqbuflen = _get_control_character(seqbuf, key_event, + control_key_state); + + // If Alt is pressed and it isn't Ctrl-Alt-ShiftUp, then + // prefix with escape. + if (_is_alt_pressed(control_key_state) && + !(_is_ctrl_pressed(control_key_state) && + !_is_shift_pressed(control_key_state))) { + seqbuflen = _escape_prefix(seqbuf, seqbuflen); + } + } + break; + + case 0x41: // a + case 0x42: // b + case 0x43: // c + case 0x44: // d + case 0x45: // e + case 0x46: // f + case 0x47: // g + case 0x48: // h + case 0x49: // i + case 0x4a: // j + case 0x4b: // k + case 0x4c: // l + case 0x4d: // m + case 0x4e: // n + case 0x4f: // o + case 0x50: // p + case 0x51: // q + case 0x52: // r + case 0x53: // s + case 0x54: // t + case 0x55: // u + case 0x56: // v + case 0x57: // w + case 0x58: // x + case 0x59: // y + case 0x5a: // z + { + seqbuflen = _get_non_alt_char(seqbuf, key_event, + control_key_state); + + // If Alt is pressed, then prefix with escape. + if (_is_alt_pressed(control_key_state)) { + seqbuflen = _escape_prefix(seqbuf, seqbuflen); + } + } + break; + + // These virtual key codes are generated by the keys on the + // keypad *when NumLock is on* and *Shift is up*. + MATCH(VK_NUMPAD0, "0"); + MATCH(VK_NUMPAD1, "1"); + MATCH(VK_NUMPAD2, "2"); + MATCH(VK_NUMPAD3, "3"); + MATCH(VK_NUMPAD4, "4"); + MATCH(VK_NUMPAD5, "5"); + MATCH(VK_NUMPAD6, "6"); + MATCH(VK_NUMPAD7, "7"); + MATCH(VK_NUMPAD8, "8"); + MATCH(VK_NUMPAD9, "9"); + + MATCH(VK_MULTIPLY, "*"); + MATCH(VK_ADD, "+"); + MATCH(VK_SUBTRACT, "-"); + // VK_DECIMAL is generated by the . key on the keypad *when + // NumLock is on* and *Shift is up* and the sequence is not + // Ctrl-Alt-NoShift-. (which causes Ctrl-Alt-Del and the + // Windows Security screen to come up). + case VK_DECIMAL: + // U.S. English uses '.', Germany German uses ','. + seqbuflen = _get_non_control_char(seqbuf, key_event, + control_key_state); + break; + + MATCH_MODIFIER(VK_F1, SS3 "P"); + MATCH_MODIFIER(VK_F2, SS3 "Q"); + MATCH_MODIFIER(VK_F3, SS3 "R"); + MATCH_MODIFIER(VK_F4, SS3 "S"); + MATCH_MODIFIER(VK_F5, CSI "15~"); + MATCH_MODIFIER(VK_F6, CSI "17~"); + MATCH_MODIFIER(VK_F7, CSI "18~"); + MATCH_MODIFIER(VK_F8, CSI "19~"); + MATCH_MODIFIER(VK_F9, CSI "20~"); + MATCH_MODIFIER(VK_F10, CSI "21~"); + MATCH_MODIFIER(VK_F11, CSI "23~"); + MATCH_MODIFIER(VK_F12, CSI "24~"); + + MATCH_MODIFIER(VK_F13, CSI "25~"); + MATCH_MODIFIER(VK_F14, CSI "26~"); + MATCH_MODIFIER(VK_F15, CSI "28~"); + MATCH_MODIFIER(VK_F16, CSI "29~"); + MATCH_MODIFIER(VK_F17, CSI "31~"); + MATCH_MODIFIER(VK_F18, CSI "32~"); + MATCH_MODIFIER(VK_F19, CSI "33~"); + MATCH_MODIFIER(VK_F20, CSI "34~"); + + // MATCH_MODIFIER(VK_F21, ???); + // MATCH_MODIFIER(VK_F22, ???); + // MATCH_MODIFIER(VK_F23, ???); + // MATCH_MODIFIER(VK_F24, ???); + } + } + +#undef MATCH +#undef MATCH_MODIFIER +#undef MATCH_KEYPAD +#undef MATCH_MODIFIER_KEYPAD +#undef ESC +#undef CSI +#undef SS3 + + const char* out; + size_t outlen; + + // Check for output in any of: + // * seqstr is set (and strlen can be used to determine the length). + // * seqbuf and seqbuflen are set + // Fallback to ch from Windows. + if (seqstr != NULL) { + out = seqstr; + outlen = strlen(seqstr); + } else if (seqbuflen > 0) { + out = seqbuf; + outlen = seqbuflen; + } else if (ch != '\0') { + // Use whatever Windows told us it is. + seqbuf[0] = ch; + seqbuflen = 1; + out = seqbuf; + outlen = seqbuflen; + } else { + // No special handling for the virtual key code and Windows isn't + // telling us a character code, then we don't know how to translate + // the key press. + // + // Consume the input and 'continue' to cause us to get a new key + // event. + D("_console_read: unknown virtual key code: %d, enhanced: %s\n", + vk, _is_enhanced_key(control_key_state) ? "true" : "false"); + key_event->wRepeatCount = 0; + continue; + } + + int bytesRead = 0; + + // put output wRepeatCount times into buf/len + while (key_event->wRepeatCount > 0) { + if (len >= outlen) { + // Write to buf/len + memcpy(buf, out, outlen); + buf = (void*)((char*)buf + outlen); + len -= outlen; + bytesRead += outlen; + + // consume the input + --key_event->wRepeatCount; + } else { + // Not enough space, so just leave it in _win32_input_record + // for a subsequent retrieval. + if (bytesRead == 0) { + // We didn't write anything because there wasn't enough + // space to even write one sequence. This should never + // happen if the caller uses sensible buffer sizes + // (i.e. >= maximum sequence length which is probably a + // few bytes long). + D("_console_read: no buffer space to write one sequence; " + "buffer: %ld, sequence: %ld\n", (long)len, + (long)outlen); + errno = ENOMEM; + return -1; + } else { + // Stop trying to write to buf/len, just return whatever + // we wrote so far. + break; + } + } + } + + return bytesRead; + } +} + +static DWORD _old_console_mode; // previous GetConsoleMode() result +static HANDLE _console_handle; // when set, console mode should be restored + +void stdin_raw_init(const int fd) { + if (STDIN_FILENO == fd) { + const HANDLE in = GetStdHandle(STD_INPUT_HANDLE); + if ((in == INVALID_HANDLE_VALUE) || (in == NULL)) { + return; + } + + if (GetFileType(in) != FILE_TYPE_CHAR) { + // stdin might be a file or pipe. + return; + } + + if (!GetConsoleMode(in, &_old_console_mode)) { + // If GetConsoleMode() fails, stdin is probably is not a console. + return; + } + + // Disable ENABLE_PROCESSED_INPUT so that Ctrl-C is read instead of + // calling the process Ctrl-C routine (configured by + // SetConsoleCtrlHandler()). + // Disable ENABLE_LINE_INPUT so that input is immediately sent. + // Disable ENABLE_ECHO_INPUT to disable local echo. Disabling this + // flag also seems necessary to have proper line-ending processing. + if (!SetConsoleMode(in, _old_console_mode & ~(ENABLE_PROCESSED_INPUT | + ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))) { + // This really should not fail. + D("stdin_raw_init: SetConsoleMode() failure, error %ld\n", + GetLastError()); + } + + // Once this is set, it means that stdin has been configured for + // reading from and that the old console mode should be restored later. + _console_handle = in; + + // Note that we don't need to configure C Runtime line-ending + // translation because _console_read() does not call the C Runtime to + // read from the console. + } +} + +void stdin_raw_restore(const int fd) { + if (STDIN_FILENO == fd) { + if (_console_handle != NULL) { + const HANDLE in = _console_handle; + _console_handle = NULL; // clear state + + if (!SetConsoleMode(in, _old_console_mode)) { + // This really should not fail. + D("stdin_raw_restore: SetConsoleMode() failure, error %ld\n", + GetLastError()); + } + } + } +} + +// Called by 'adb shell' command to read from stdin. +int unix_read(int fd, void* buf, size_t len) { + if ((fd == STDIN_FILENO) && (_console_handle != NULL)) { + // If it is a request to read from stdin, and stdin_raw_init() has been + // called, and it successfully configured the console, then read from + // the console using Win32 console APIs and partially emulate a unix + // terminal. + return _console_read(_console_handle, buf, len); + } else { + // Just call into C Runtime which can read from pipes/files and which + // can do LF/CR translation. +#undef read + return read(fd, buf, len); + } +} diff --git a/adb/test_track_devices.c b/adb/test_track_devices.cpp index 77b3ad9..77b3ad9 100644 --- a/adb/test_track_devices.c +++ b/adb/test_track_devices.cpp diff --git a/adb/test_track_jdwp.c b/adb/test_track_jdwp.cpp index 8ecc6b8..8ecc6b8 100644 --- a/adb/test_track_jdwp.c +++ b/adb/test_track_jdwp.cpp diff --git a/adb/tests/test_adb.py b/adb/tests/test_adb.py new file mode 100755 index 0000000..52d8056 --- /dev/null +++ b/adb/tests/test_adb.py @@ -0,0 +1,412 @@ +#!/usr/bin/env python2 +"""Simple conformance test for adb. + +This script will use the available adb in path and run simple +tests that attempt to touch all accessible attached devices. +""" +import hashlib +import os +import random +import re +import shlex +import subprocess +import sys +import tempfile +import unittest + + +def trace(cmd): + """Print debug message if tracing enabled.""" + if False: + print >> sys.stderr, cmd + + +def call(cmd_str): + """Run process and return output tuple (stdout, stderr, ret code).""" + trace(cmd_str) + process = subprocess.Popen(shlex.split(cmd_str), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = process.communicate() + return stdout, stderr, process.returncode + + +def call_combined(cmd_str): + """Run process and return output tuple (stdout+stderr, ret code).""" + trace(cmd_str) + process = subprocess.Popen(shlex.split(cmd_str), + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + stdout, _ = process.communicate() + return stdout, process.returncode + + +def call_checked(cmd_str): + """Run process and get stdout+stderr, raise an exception on trouble.""" + trace(cmd_str) + return subprocess.check_output(shlex.split(cmd_str), + stderr=subprocess.STDOUT) + + +def call_checked_list(cmd_str): + return call_checked(cmd_str).split('\n') + + +def call_checked_list_skip(cmd_str): + out_list = call_checked_list(cmd_str) + + def is_init_line(line): + if (len(line) >= 3) and (line[0] == "*") and (line[-2] == "*"): + return True + else: + return False + + return [line for line in out_list if not is_init_line(line)] + + +def get_device_list(): + output = call_checked_list_skip("adb devices") + dev_list = [] + for line in output[1:]: + if line.strip() == "": + continue + device, _ = line.split() + dev_list.append(device) + return dev_list + + +def get_attached_device_count(): + return len(get_device_list()) + + +def compute_md5(string): + hsh = hashlib.md5() + hsh.update(string) + return hsh.hexdigest() + + +class HostFile(object): + def __init__(self, handle, md5): + self.handle = handle + self.md5 = md5 + self.full_path = handle.name + self.base_name = os.path.basename(self.full_path) + + +class DeviceFile(object): + def __init__(self, md5, full_path): + self.md5 = md5 + self.full_path = full_path + self.base_name = os.path.basename(self.full_path) + + +def make_random_host_files(in_dir, num_files, rand_size=True): + files = {} + min_size = 1 * (1 << 10) + max_size = 16 * (1 << 10) + fixed_size = min_size + + for _ in range(num_files): + file_handle = tempfile.NamedTemporaryFile(dir=in_dir) + + if rand_size: + size = random.randrange(min_size, max_size, 1024) + else: + size = fixed_size + rand_str = os.urandom(size) + file_handle.write(rand_str) + file_handle.flush() + + md5 = compute_md5(rand_str) + files[file_handle.name] = HostFile(file_handle, md5) + return files + + +def make_random_device_files(adb, in_dir, num_files, rand_size=True): + files = {} + min_size = 1 * (1 << 10) + max_size = 16 * (1 << 10) + fixed_size = min_size + + for i in range(num_files): + if rand_size: + size = random.randrange(min_size, max_size, 1024) + else: + size = fixed_size + + base_name = "device_tmpfile" + str(i) + full_path = in_dir + "/" + base_name + + adb.shell("dd if=/dev/urandom of={} bs={} count=1".format(full_path, + size)) + dev_md5, _ = adb.shell("md5sum {}".format(full_path)).split() + + files[full_path] = DeviceFile(dev_md5, full_path) + return files + + +class AdbWrapper(object): + """Convenience wrapper object for the adb command.""" + def __init__(self, device=None, out_dir=None): + self.device = device + self.out_dir = out_dir + self.adb_cmd = "adb " + if self.device: + self.adb_cmd += "-s {} ".format(device) + if self.out_dir: + self.adb_cmd += "-p {} ".format(out_dir) + + def shell(self, cmd): + return call_checked(self.adb_cmd + "shell " + cmd) + + def shell_nocheck(self, cmd): + return call_combined(self.adb_cmd + "shell " + cmd) + + def push(self, local, remote): + return call_checked(self.adb_cmd + "push {} {}".format(local, remote)) + + def pull(self, remote, local): + return call_checked(self.adb_cmd + "pull {} {}".format(remote, local)) + + def sync(self, directory=""): + return call_checked(self.adb_cmd + "sync {}".format(directory)) + + def forward(self, local, remote): + return call_checked(self.adb_cmd + "forward {} {}".format(local, + remote)) + + def tcpip(self, port): + return call_checked(self.adb_cmd + "tcpip {}".format(port)) + + def usb(self): + return call_checked(self.adb_cmd + "usb") + + def root(self): + return call_checked(self.adb_cmd + "root") + + def unroot(self): + return call_checked(self.adb_cmd + "unroot") + + def forward_remove(self, local): + return call_checked(self.adb_cmd + "forward --remove {}".format(local)) + + def forward_remove_all(self): + return call_checked(self.adb_cmd + "forward --remove-all") + + def connect(self, host): + return call_checked(self.adb_cmd + "connect {}".format(host)) + + def disconnect(self, host): + return call_checked(self.adb_cmd + "disconnect {}".format(host)) + + def reverse(self, remote, local): + return call_checked(self.adb_cmd + "reverse {} {}".format(remote, + local)) + + def reverse_remove_all(self): + return call_checked(self.adb_cmd + "reverse --remove-all") + + def reverse_remove(self, remote): + return call_checked( + self.adb_cmd + "reverse --remove {}".format(remote)) + + def wait(self): + return call_checked(self.adb_cmd + "wait-for-device") + + +class AdbBasic(unittest.TestCase): + def test_shell(self): + """Check that we can at least cat a file.""" + adb = AdbWrapper() + out = adb.shell("cat /proc/uptime") + self.assertEqual(len(out.split()), 2) + self.assertGreater(float(out.split()[0]), 0.0) + self.assertGreater(float(out.split()[1]), 0.0) + + def test_help(self): + """Make sure we get _something_ out of help.""" + out = call_checked("adb help") + self.assertTrue(len(out) > 0) + + def test_version(self): + """Get a version number out of the output of adb.""" + out = call_checked("adb version").split() + version_num = False + for item in out: + if re.match(r"[\d+\.]*\d", item): + version_num = True + self.assertTrue(version_num) + + def _test_root(self): + adb = AdbWrapper() + adb.root() + adb.wait() + self.assertEqual("root", adb.shell("id -un").strip()) + + def _test_unroot(self): + adb = AdbWrapper() + adb.unroot() + adb.wait() + self.assertEqual("shell", adb.shell("id -un").strip()) + + def test_root_unroot(self): + """Make sure that adb root and adb unroot work, using id(1).""" + adb = AdbWrapper() + original_user = adb.shell("id -un").strip() + try: + if original_user == "root": + self._test_unroot() + self._test_root() + elif original_user == "shell": + self._test_root() + self._test_unroot() + finally: + if original_user == "root": + adb.root() + else: + adb.unroot() + adb.wait() + + def test_argument_escaping(self): + """Make sure that argument escaping is somewhat sane.""" + adb = AdbWrapper() + + # http://b/19734868 + result = adb.shell("sh -c 'echo hello; echo world'").splitlines() + self.assertEqual(["hello", "world"], result) + + # http://b/15479704 + self.assertEqual('t', adb.shell("'true && echo t'").strip()) + self.assertEqual('t', adb.shell("sh -c 'true && echo t'").strip()) + + +class AdbFile(unittest.TestCase): + SCRATCH_DIR = "/data/local/tmp" + DEVICE_TEMP_FILE = SCRATCH_DIR + "/adb_test_file" + DEVICE_TEMP_DIR = SCRATCH_DIR + "/adb_test_dir" + + def test_push(self): + """Push a randomly generated file to specified device.""" + kbytes = 512 + adb = AdbWrapper() + with tempfile.NamedTemporaryFile(mode="w") as tmp: + rand_str = os.urandom(1024 * kbytes) + tmp.write(rand_str) + tmp.flush() + + host_md5 = compute_md5(rand_str) + adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_FILE)) + try: + adb.push(local=tmp.name, remote=AdbFile.DEVICE_TEMP_FILE) + dev_md5, _ = adb.shell( + "md5sum {}".format(AdbFile.DEVICE_TEMP_FILE)).split() + self.assertEqual(host_md5, dev_md5) + finally: + adb.shell_nocheck("rm {}".format(AdbFile.DEVICE_TEMP_FILE)) + + # TODO: write push directory test. + + def test_pull(self): + """Pull a randomly generated file from specified device.""" + kbytes = 512 + adb = AdbWrapper() + adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_FILE)) + try: + adb.shell("dd if=/dev/urandom of={} bs=1024 count={}".format( + AdbFile.DEVICE_TEMP_FILE, kbytes)) + dev_md5, _ = adb.shell( + "md5sum {}".format(AdbFile.DEVICE_TEMP_FILE)).split() + + with tempfile.NamedTemporaryFile(mode="w") as tmp_write: + adb.pull(remote=AdbFile.DEVICE_TEMP_FILE, local=tmp_write.name) + with open(tmp_write.name) as tmp_read: + host_contents = tmp_read.read() + host_md5 = compute_md5(host_contents) + self.assertEqual(dev_md5, host_md5) + finally: + adb.shell_nocheck("rm {}".format(AdbFile.DEVICE_TEMP_FILE)) + + def test_pull_dir(self): + """Pull a randomly generated directory of files from the device.""" + adb = AdbWrapper() + temp_files = {} + host_dir = None + try: + # create temporary host directory + host_dir = tempfile.mkdtemp() + + # create temporary dir on device + adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_DIR)) + adb.shell("mkdir -p {}".format(AdbFile.DEVICE_TEMP_DIR)) + + # populate device dir with random files + temp_files = make_random_device_files( + adb, in_dir=AdbFile.DEVICE_TEMP_DIR, num_files=32) + + adb.pull(remote=AdbFile.DEVICE_TEMP_DIR, local=host_dir) + + for device_full_path in temp_files: + host_path = os.path.join( + host_dir, temp_files[device_full_path].base_name) + with open(host_path) as host_file: + host_md5 = compute_md5(host_file.read()) + self.assertEqual(host_md5, + temp_files[device_full_path].md5) + finally: + for dev_file in temp_files.values(): + host_path = os.path.join(host_dir, dev_file.base_name) + os.remove(host_path) + adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_DIR)) + if host_dir: + os.removedirs(host_dir) + + def test_sync(self): + """Sync a randomly generated directory of files to specified device.""" + try: + adb = AdbWrapper() + temp_files = {} + + # create temporary host directory + base_dir = tempfile.mkdtemp() + + # create mirror device directory hierarchy within base_dir + full_dir_path = base_dir + AdbFile.DEVICE_TEMP_DIR + os.makedirs(full_dir_path) + + # create 32 random files within the host mirror + temp_files = make_random_host_files(in_dir=full_dir_path, + num_files=32) + + # clean up any trash on the device + adb = AdbWrapper(out_dir=base_dir) + adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_DIR)) + + # issue the sync + adb.sync("data") + + # confirm that every file on the device mirrors that on the host + for host_full_path in temp_files.keys(): + device_full_path = os.path.join( + AdbFile.DEVICE_TEMP_DIR, + temp_files[host_full_path].base_name) + dev_md5, _ = adb.shell( + "md5sum {}".format(device_full_path)).split() + self.assertEqual(temp_files[host_full_path].md5, dev_md5) + + finally: + adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_DIR)) + if temp_files: + for tf in temp_files.values(): + tf.handle.close() + if base_dir: + os.removedirs(base_dir + AdbFile.DEVICE_TEMP_DIR) + + +if __name__ == '__main__': + random.seed(0) + dev_count = get_attached_device_count() + if dev_count: + suite = unittest.TestLoader().loadTestsFromName(__name__) + unittest.TextTestRunner(verbosity=3).run(suite) + else: + print "Test suite must be run with attached devices" diff --git a/adb/transport.c b/adb/transport.cpp index f35880c..d395a80 100644 --- a/adb/transport.c +++ b/adb/transport.cpp @@ -14,15 +14,18 @@ * limitations under the License. */ +#define TRACE_TAG TRACE_TRANSPORT + +#include "sysdeps.h" +#include "transport.h" + +#include <ctype.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> -#include <unistd.h> #include <string.h> -#include <errno.h> - -#include "sysdeps.h" +#include <unistd.h> -#define TRACE_TAG TRACE_TRANSPORT #include "adb.h" static void transport_unref(atransport *t); @@ -41,7 +44,7 @@ ADB_MUTEX_DEFINE( transport_lock ); #if ADB_TRACE #define MAX_DUMP_HEX_LEN 16 -static void dump_hex( const unsigned char* ptr, size_t len ) +void dump_hex(const unsigned char* ptr, size_t len) { int nn, len2 = len; // Build a string instead of logging each character. @@ -67,8 +70,7 @@ static void dump_hex( const unsigned char* ptr, size_t len ) } #endif -void -kick_transport(atransport* t) +void kick_transport(atransport* t) { if (t && !t->kicked) { @@ -85,8 +87,25 @@ kick_transport(atransport* t) } } -void -run_transport_disconnects(atransport* t) +// Each atransport contains a list of adisconnects (t->disconnects). +// An adisconnect contains a link to the next/prev adisconnect, a function +// pointer to a disconnect callback which takes a void* piece of user data and +// the atransport, and some user data for the callback (helpfully named +// "opaque"). +// +// The list is circular. New items are added to the entry member of the list +// (t->disconnects) by add_transport_disconnect. +// +// run_transport_disconnects invokes each function in the list. +// +// Gotchas: +// * run_transport_disconnects assumes that t->disconnects is non-null, so +// this can't be run on a zeroed atransport. +// * The callbacks in this list are not removed when called, and this function +// is not guarded against running more than once. As such, ensure that this +// function is not called multiple times on the same atransport. +// TODO(danalbert): Just fix this so that it is guarded once you have tests. +void run_transport_disconnects(atransport* t) { adisconnect* dis = t->disconnects.next; @@ -202,7 +221,7 @@ write_packet(int fd, const char* name, apacket** ppacket) static void transport_socket_events(int fd, unsigned events, void *_t) { - atransport *t = _t; + atransport *t = reinterpret_cast<atransport*>(_t); D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events); if(events & FDE_READ){ apacket *p = 0; @@ -259,7 +278,7 @@ void send_packet(apacket *p, atransport *t) static void *output_thread(void *_t) { - atransport *t = _t; + atransport *t = reinterpret_cast<atransport*>(_t); apacket *p; D("%s: starting transport output thread on fd %d, SYNC online (%d)\n", @@ -314,7 +333,7 @@ oops: static void *input_thread(void *_t) { - atransport *t = _t; + atransport *t = reinterpret_cast<atransport*>(_t); apacket *p; int active = 0; @@ -387,7 +406,6 @@ static int list_transports_msg(char* buffer, size_t bufferlen) * number of client connections that want it through a single * live TCP connection */ -typedef struct device_tracker device_tracker; struct device_tracker { asocket socket; int update_needed; @@ -475,9 +493,8 @@ device_tracker_ready( asocket* socket ) asocket* create_device_tracker(void) { - device_tracker* tracker = calloc(1,sizeof(*tracker)); - - if(tracker == 0) fatal("cannot allocate device tracker"); + device_tracker* tracker = reinterpret_cast<device_tracker*>(calloc(1, sizeof(*tracker))); + if (tracker == nullptr) fatal("cannot allocate device tracker"); D( "device tracker %p created\n", tracker); @@ -494,8 +511,7 @@ create_device_tracker(void) /* call this function each time the transport list has changed */ -void update_transports(void) -{ +void update_transports(void) { char buffer[1024]; int len; device_tracker* tracker; @@ -517,7 +533,6 @@ void update_transports(void) } #endif // ADB_HOST -typedef struct tmsg tmsg; struct tmsg { atransport *transport; @@ -629,7 +644,7 @@ static void transport_registration_func(int _fd, unsigned ev, void *data) fatal_errno("cannot open transport socketpair"); } - D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]); + D("transport: %s socketpair: (%d,%d) starting", t->serial, s[0], s[1]); t->transport_socket = s[0]; t->fd = s[1]; @@ -673,6 +688,7 @@ void init_transport_registration(void) if(adb_socketpair(s)){ fatal_errno("cannot open transport registration socketpair"); } + D("socketpair: (%d,%d)", s[0], s[1]); transport_registration_send = s[0]; transport_registration_recv = s[1]; @@ -751,19 +767,8 @@ void remove_transport_disconnect(atransport* t, adisconnect* dis) dis->next = dis->prev = dis; } -static int qual_char_is_invalid(char ch) -{ - if ('A' <= ch && ch <= 'Z') - return 0; - if ('a' <= ch && ch <= 'z') - return 0; - if ('0' <= ch && ch <= '9') - return 0; - return 1; -} - static int qual_match(const char *to_test, - const char *prefix, const char *qual, int sanitize_qual) + const char *prefix, const char *qual, bool sanitize_qual) { if (!to_test || !*to_test) /* Return true if both the qual and to_test are null strings. */ @@ -781,7 +786,7 @@ static int qual_match(const char *to_test, while (*qual) { char ch = *qual++; - if (sanitize_qual && qual_char_is_invalid(ch)) + if (sanitize_qual && !isalnum(ch)) ch = '_'; if (ch != *to_test++) return 0; @@ -791,21 +796,20 @@ static int qual_match(const char *to_test, return !*to_test; } -atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out) +atransport* acquire_one_transport(int state, transport_type ttype, + const char* serial, std::string* error_out) { atransport *t; atransport *result = NULL; int ambiguous = 0; retry: - if (error_out) - *error_out = "device not found"; + if (error_out) *error_out = "device not found"; adb_mutex_lock(&transport_lock); for (t = transport_list.next; t != &transport_list; t = t->next) { if (t->connection_state == CS_NOPERM) { - if (error_out) - *error_out = "insufficient permissions for device"; + if (error_out) *error_out = "insufficient permissions for device"; continue; } @@ -813,12 +817,11 @@ retry: if (serial) { if ((t->serial && !strcmp(serial, t->serial)) || (t->devpath && !strcmp(serial, t->devpath)) || - qual_match(serial, "product:", t->product, 0) || - qual_match(serial, "model:", t->model, 1) || - qual_match(serial, "device:", t->device, 0)) { + qual_match(serial, "product:", t->product, false) || + qual_match(serial, "model:", t->model, true) || + qual_match(serial, "device:", t->device, false)) { if (result) { - if (error_out) - *error_out = "more than one device"; + if (error_out) *error_out = "more than one device"; ambiguous = 1; result = NULL; break; @@ -828,8 +831,7 @@ retry: } else { if (ttype == kTransportUsb && t->type == kTransportUsb) { if (result) { - if (error_out) - *error_out = "more than one device"; + if (error_out) *error_out = "more than one device"; ambiguous = 1; result = NULL; break; @@ -837,8 +839,7 @@ retry: result = t; } else if (ttype == kTransportLocal && t->type == kTransportLocal) { if (result) { - if (error_out) - *error_out = "more than one emulator"; + if (error_out) *error_out = "more than one emulator"; ambiguous = 1; result = NULL; break; @@ -846,8 +847,7 @@ retry: result = t; } else if (ttype == kTransportAny) { if (result) { - if (error_out) - *error_out = "more than one device and emulator"; + if (error_out) *error_out = "more than one device and emulator"; ambiguous = 1; result = NULL; break; @@ -860,29 +860,33 @@ retry: if (result) { if (result->connection_state == CS_UNAUTHORIZED) { - if (error_out) - *error_out = "device unauthorized. Please check the confirmation dialog on your device."; + if (error_out) { + *error_out = "device unauthorized.\n"; + char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS"); + *error_out += "This adbd's $ADB_VENDOR_KEYS is "; + *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set"; + *error_out += "; try 'adb kill-server' if that seems wrong.\n"; + *error_out += "Otherwise check for a confirmation dialog on your device."; + } result = NULL; } - /* offline devices are ignored -- they are either being born or dying */ + /* offline devices are ignored -- they are either being born or dying */ if (result && result->connection_state == CS_OFFLINE) { - if (error_out) - *error_out = "device offline"; + if (error_out) *error_out = "device offline"; result = NULL; } - /* check for required connection state */ + + /* check for required connection state */ if (result && state != CS_ANY && result->connection_state != state) { - if (error_out) - *error_out = "invalid device state"; + if (error_out) *error_out = "invalid device state"; result = NULL; } } if (result) { /* found one that we can take */ - if (error_out) - *error_out = NULL; + if (error_out) *error_out = "success"; } else if (state != CS_ANY && (serial || !ambiguous)) { adb_sleep_ms(1000); goto retry; @@ -908,20 +912,17 @@ static const char *statename(atransport *t) } static void add_qual(char **buf, size_t *buf_size, - const char *prefix, const char *qual, int sanitize_qual) + const char *prefix, const char *qual, bool sanitize_qual) { - size_t len; - int prefix_len; - if (!buf || !*buf || !buf_size || !*buf_size || !qual || !*qual) return; - len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual); + int prefix_len; + size_t len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual); if (sanitize_qual) { - char *cp; - for (cp = *buf + prefix_len; cp < *buf + len; cp++) { - if (qual_char_is_invalid(*cp)) + for (char* cp = *buf + prefix_len; cp < *buf + len; cp++) { + if (!isalnum(*cp)) *cp = '_'; } } @@ -946,10 +947,10 @@ static size_t format_transport(atransport *t, char *buf, size_t bufsize, remaining -= len; buf += len; - add_qual(&buf, &remaining, " ", t->devpath, 0); - add_qual(&buf, &remaining, " product:", t->product, 0); - add_qual(&buf, &remaining, " model:", t->model, 1); - add_qual(&buf, &remaining, " device:", t->device, 0); + add_qual(&buf, &remaining, " ", t->devpath, false); + add_qual(&buf, &remaining, " product:", t->product, false); + add_qual(&buf, &remaining, " model:", t->model, true); + add_qual(&buf, &remaining, " device:", t->device, false); len = snprintf(buf, remaining, "\n"); remaining -= len; @@ -999,7 +1000,11 @@ void close_usb_devices() int register_socket_transport(int s, const char *serial, int port, int local) { - atransport *t = calloc(1, sizeof(atransport)); + atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport))); + if (t == nullptr) { + return -1; + } + atransport *n; char buff[32]; @@ -1098,7 +1103,8 @@ void unregister_all_tcp_transports() void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable) { - atransport *t = calloc(1, sizeof(atransport)); + atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport))); + if (t == nullptr) fatal("cannot allocate USB atransport"); D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb, serial ? serial : ""); init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM)); @@ -1137,70 +1143,6 @@ void unregister_usb_transport(usb_handle *usb) #undef TRACE_TAG #define TRACE_TAG TRACE_RWX -int readx(int fd, void *ptr, size_t len) -{ - char *p = ptr; - int r; -#if ADB_TRACE - size_t len0 = len; -#endif - D("readx: fd=%d wanted=%zu\n", fd, len); - while(len > 0) { - r = adb_read(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if (r < 0) { - D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno)); - if (errno == EINTR) - continue; - } else { - D("readx: fd=%d disconnected\n", fd); - } - return -1; - } - } - -#if ADB_TRACE - D("readx: fd=%d wanted=%zu got=%zu\n", fd, len0, len0 - len); - dump_hex( ptr, len0 ); -#endif - return 0; -} - -int writex(int fd, const void *ptr, size_t len) -{ - char *p = (char*) ptr; - int r; - -#if ADB_TRACE - D("writex: fd=%d len=%d: ", fd, (int)len); - dump_hex( ptr, len ); -#endif - while(len > 0) { - r = adb_write(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if (r < 0) { - D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno)); - if (errno == EINTR) - continue; - if (errno == EAGAIN) { - adb_sleep_ms(1); // just yield some cpu time - continue; - } - } else { - D("writex: fd=%d disconnected\n", fd); - } - return -1; - } - } - return 0; -} - int check_header(apacket *p) { if(p->msg.magic != (p->msg.command ^ 0xffffffff)) { diff --git a/adb/transport.h b/adb/transport.h index 992e052..a2077e8 100644 --- a/adb/transport.h +++ b/adb/transport.h @@ -17,10 +17,58 @@ #ifndef __TRANSPORT_H #define __TRANSPORT_H -/* convenience wrappers around read/write that will retry on -** EINTR and/or short read/write. Returns 0 on success, -1 -** on error or EOF. +#include <sys/types.h> + +#include <string> + +#include "adb.h" + +#if ADB_TRACE +void dump_hex(const unsigned char* ptr, size_t len); +#endif + +/* + * Obtain a transport from the available transports. + * If state is != CS_ANY, only transports in that state are considered. + * If serial is non-NULL then only the device with that serial will be chosen. + * If no suitable transport is found, error is set. + */ +atransport* acquire_one_transport(int state, transport_type ttype, + const char* serial, std::string* error_out); +void add_transport_disconnect(atransport* t, adisconnect* dis); +void remove_transport_disconnect(atransport* t, adisconnect* dis); +void kick_transport(atransport* t); +void run_transport_disconnects(atransport* t); +void update_transports(void); + +/* transports are ref-counted +** get_device_transport does an acquire on your behalf before returning */ -int readx(int fd, void *ptr, size_t len); -int writex(int fd, const void *ptr, size_t len); +void init_transport_registration(void); +int list_transports(char* buf, size_t bufsize, int long_listing); +atransport* find_transport(const char* serial); + +void register_usb_transport(usb_handle* h, const char* serial, + const char* devpath, unsigned writeable); + +/* cause new transports to be init'd and added to the list */ +int register_socket_transport(int s, const char* serial, int port, int local); + +/* this should only be used for transports with connection_state == CS_NOPERM */ +void unregister_usb_transport(usb_handle* usb); + +/* these should only be used for the "adb disconnect" command */ +void unregister_transport(atransport* t); +void unregister_all_tcp_transports(); + +int check_header(apacket* p); +int check_data(apacket* p); + +/* for MacOS X cleanup */ +void close_usb_devices(); + +void send_packet(apacket* p, atransport* t); + +asocket* create_device_tracker(void); + #endif /* __TRANSPORT_H */ diff --git a/adb/transport_local.c b/adb/transport_local.cpp index 948cc15..30e6bf5 100644 --- a/adb/transport_local.c +++ b/adb/transport_local.cpp @@ -14,34 +14,23 @@ * limitations under the License. */ +#define TRACE_TAG TRACE_TRANSPORT + +#include "sysdeps.h" +#include "transport.h" + +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <errno.h> - -#include "sysdeps.h" #include <sys/types.h> + #if !ADB_HOST -#include <cutils/properties.h> +#include "cutils/properties.h" #endif -#define TRACE_TAG TRACE_TRANSPORT #include "adb.h" - -#ifdef HAVE_BIG_ENDIAN -#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) -static inline void fix_endians(apacket *p) -{ - p->msg.command = H4(p->msg.command); - p->msg.arg0 = H4(p->msg.arg0); - p->msg.arg1 = H4(p->msg.arg1); - p->msg.data_length = H4(p->msg.data_length); - p->msg.data_check = H4(p->msg.data_check); - p->msg.magic = H4(p->msg.magic); -} -#else -#define fix_endians(p) do {} while (0) -#endif +#include "adb_io.h" #if ADB_HOST /* we keep a list of opened transports. The atransport struct knows to which @@ -57,23 +46,17 @@ static atransport* local_transports[ ADB_LOCAL_TRANSPORT_MAX ]; static int remote_read(apacket *p, atransport *t) { - if(readx(t->sfd, &p->msg, sizeof(amessage))){ + if(!ReadFdExactly(t->sfd, &p->msg, sizeof(amessage))){ D("remote local: read terminated (message)\n"); return -1; } - fix_endians(p); - -#if 0 && defined HAVE_BIG_ENDIAN - D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", - p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic); -#endif if(check_header(p)) { D("bad header: terminated (data)\n"); return -1; } - if(readx(t->sfd, p->data, p->msg.data_length)){ + if(!ReadFdExactly(t->sfd, p->data, p->msg.data_length)){ D("remote local: terminated (data)\n"); return -1; } @@ -90,13 +73,7 @@ static int remote_write(apacket *p, atransport *t) { int length = p->msg.data_length; - fix_endians(p); - -#if 0 && defined HAVE_BIG_ENDIAN - D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", - p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic); -#endif - if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) { + if(!WriteFdExactly(t->sfd, &p->msg, sizeof(amessage) + length)) { D("remote local: write terminated\n"); return -1; } @@ -167,7 +144,7 @@ static void *server_socket_thread(void * arg) if(serverfd == -1) { serverfd = socket_inaddr_any_server(port, SOCK_STREAM); if(serverfd < 0) { - D("server: cannot bind socket yet\n"); + D("server: cannot bind socket yet: %s\n", strerror(errno)); adb_sleep_ms(1000); continue; } diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp new file mode 100644 index 0000000..2b3fe3c --- /dev/null +++ b/adb/transport_test.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 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 "transport.h" + +#include <gtest/gtest.h> + +#include "adb.h" + +TEST(transport, kick_transport) { + atransport t = {}; + // Mutate some member so we can test that the function is run. + t.kick = [](atransport* trans) { trans->fd = 42; }; + atransport expected = t; + expected.fd = 42; + expected.kicked = 1; + kick_transport(&t); + ASSERT_EQ(42, t.fd); + ASSERT_EQ(1, t.kicked); + ASSERT_EQ(0, memcmp(&expected, &t, sizeof(atransport))); +} + +TEST(transport, kick_transport_already_kicked) { + // Ensure that the transport is not modified if the transport has already been + // kicked. + atransport t = {}; + t.kicked = 1; + t.kick = [](atransport*) { FAIL() << "Kick should not have been called"; }; + atransport expected = t; + kick_transport(&t); + ASSERT_EQ(0, memcmp(&expected, &t, sizeof(atransport))); +} + +// Disabled because the function currently segfaults for a zeroed atransport. I +// want to make sure I understand how this is working at all before I try fixing +// that. +TEST(transport, DISABLED_run_transport_disconnects_zeroed_atransport) { + atransport t = {}; + run_transport_disconnects(&t); +} diff --git a/adb/transport_usb.c b/adb/transport_usb.cpp index ee6b637..cdabffe 100644 --- a/adb/transport_usb.c +++ b/adb/transport_usb.cpp @@ -14,42 +14,17 @@ * limitations under the License. */ +#define TRACE_TAG TRACE_TRANSPORT + +#include "sysdeps.h" +#include "transport.h" + #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sysdeps.h> - -#define TRACE_TAG TRACE_TRANSPORT #include "adb.h" -#if ADB_HOST -#include "usb_vendors.h" -#endif - -#ifdef HAVE_BIG_ENDIAN -#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) -static inline void fix_endians(apacket *p) -{ - p->msg.command = H4(p->msg.command); - p->msg.arg0 = H4(p->msg.arg0); - p->msg.arg1 = H4(p->msg.arg1); - p->msg.data_length = H4(p->msg.data_length); - p->msg.data_check = H4(p->msg.data_check); - p->msg.magic = H4(p->msg.magic); -} -unsigned host_to_le32(unsigned n) -{ - return H4(n); -} -#else -#define fix_endians(p) do {} while (0) -unsigned host_to_le32(unsigned n) -{ - return n; -} -#endif - static int remote_read(apacket *p, atransport *t) { if(usb_read(t->usb, &p->msg, sizeof(amessage))){ @@ -57,8 +32,6 @@ static int remote_read(apacket *p, atransport *t) return -1; } - fix_endians(p); - if(check_header(p)) { D("remote usb: check_header failed\n"); return -1; @@ -83,8 +56,6 @@ static int remote_write(apacket *p, atransport *t) { unsigned size = p->msg.data_length; - fix_endians(p); - if(usb_write(t->usb, &p->msg, sizeof(amessage))) { D("remote usb: 1 - write terminated\n"); return -1; @@ -131,18 +102,6 @@ void init_usb_transport(atransport *t, usb_handle *h, int state) #if ADB_HOST int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol) { - unsigned i; - for (i = 0; i < vendorIdCount; i++) { - if (vid == vendorIds[i]) { - if (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && - usb_protocol == ADB_PROTOCOL) { - return 1; - } - - return 0; - } - } - - return 0; + return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL); } #endif diff --git a/adb/usb_libusb.c b/adb/usb_libusb.c deleted file mode 100644 index 06ff5dc..0000000 --- a/adb/usb_libusb.c +++ /dev/null @@ -1,657 +0,0 @@ -/* - * Copyright (C) 2009 bsdroid project - * Alexey Tarasov <tarasov@dodologics.com> - * - * 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. - */ - -#include <sys/endian.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/uio.h> - -#include <err.h> -#include <errno.h> -#include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> -#include <string.h> -#include <sysexits.h> -#include <unistd.h> -#include <libusb.h> -#include "sysdeps.h" - -#define TRACE_TAG TRACE_USB -#include "adb.h" - -static adb_mutex_t usb_lock = ADB_MUTEX_INITIALIZER; -static libusb_context *ctx = NULL; - -struct usb_handle -{ - usb_handle *prev; - usb_handle *next; - - libusb_device *dev; - libusb_device_handle *devh; - int interface; - uint8_t dev_bus; - uint8_t dev_addr; - - int zero_mask; - unsigned char end_point_address[2]; - char serial[128]; - - adb_cond_t notify; - adb_mutex_t lock; -}; - -static struct usb_handle handle_list = { - .prev = &handle_list, - .next = &handle_list, -}; - -void -usb_cleanup() -{ - libusb_exit(ctx); -} - -void -report_bulk_libusb_error(int r) -{ - switch (r) { - case LIBUSB_ERROR_TIMEOUT: - D("Transfer timeout\n"); - break; - - case LIBUSB_ERROR_PIPE: - D("Control request is not supported\n"); - break; - - case LIBUSB_ERROR_OVERFLOW: - D("Device offered more data\n"); - break; - - case LIBUSB_ERROR_NO_DEVICE : - D("Device was disconnected\n"); - break; - - default: - D("Error %d during transfer\n", r); - break; - }; -} - -static int -usb_bulk_write(usb_handle *uh, const void *data, int len) -{ - int r = 0; - int transferred = 0; - - r = libusb_bulk_transfer(uh->devh, uh->end_point_address[1], (void *)data, len, - &transferred, 0); - - if (r != 0) { - D("usb_bulk_write(): "); - report_bulk_libusb_error(r); - return r; - } - - return (transferred); -} - -static int -usb_bulk_read(usb_handle *uh, void *data, int len) -{ - int r = 0; - int transferred = 0; - - r = libusb_bulk_transfer(uh->devh, uh->end_point_address[0], data, len, - &transferred, 0); - - if (r != 0) { - D("usb_bulk_read(): "); - report_bulk_libusb_error(r); - return r; - } - - return (transferred); -} - -int -usb_write(struct usb_handle *uh, const void *_data, int len) -{ - unsigned char *data = (unsigned char*) _data; - int n; - int need_zero = 0; - - if (uh->zero_mask == 1) { - if (!(len & uh->zero_mask)) { - need_zero = 1; - } - } - - D("usb_write(): %p:%d -> transport %p\n", _data, len, uh); - - while (len > 0) { - int xfer = (len > 4096) ? 4096 : len; - - n = usb_bulk_write(uh, data, xfer); - - if (n != xfer) { - D("usb_write(): failed for transport %p (%d bytes left)\n", uh, len); - return -1; - } - - len -= xfer; - data += xfer; - } - - if (need_zero){ - n = usb_bulk_write(uh, _data, 0); - - if (n < 0) { - D("usb_write(): failed to finish operation for transport %p\n", uh); - } - return n; - } - - return 0; -} - -int -usb_read(struct usb_handle *uh, void *_data, int len) -{ - unsigned char *data = (unsigned char*) _data; - int n; - - D("usb_read(): %p:%d <- transport %p\n", _data, len, uh); - - while (len > 0) { - int xfer = (len > 4096) ? 4096 : len; - - n = usb_bulk_read(uh, data, xfer); - - if (n != xfer) { - if (n > 0) { - data += n; - len -= n; - continue; - } - - D("usb_read(): failed for transport %p (%d bytes left)\n", uh, len); - return -1; - } - - len -= xfer; - data += xfer; - } - - return 0; - } - -int -usb_close(struct usb_handle *h) -{ - D("usb_close(): closing transport %p\n", h); - adb_mutex_lock(&usb_lock); - - h->next->prev = h->prev; - h->prev->next = h->next; - h->prev = NULL; - h->next = NULL; - - libusb_release_interface(h->devh, h->interface); - libusb_close(h->devh); - libusb_unref_device(h->dev); - - adb_mutex_unlock(&usb_lock); - - free(h); - - return (0); -} - -void usb_kick(struct usb_handle *h) -{ - D("usb_cick(): kicking transport %p\n", h); - - adb_mutex_lock(&h->lock); - unregister_usb_transport(h); - adb_mutex_unlock(&h->lock); - - h->next->prev = h->prev; - h->prev->next = h->next; - h->prev = NULL; - h->next = NULL; - - libusb_release_interface(h->devh, h->interface); - libusb_close(h->devh); - libusb_unref_device(h->dev); - free(h); -} - -int -check_usb_interface(libusb_interface *interface, - libusb_device_descriptor *desc, - struct usb_handle *uh) -{ - int e; - - if (interface->num_altsetting == 0) { - D("check_usb_interface(): No interface settings\n"); - return -1; - } - - libusb_interface_descriptor *idesc = &interface->altsetting[0]; - - if (idesc->bNumEndpoints != 2) { - D("check_usb_interface(): Interface have not 2 endpoints, ignoring\n"); - return -1; - } - - for (e = 0; e < idesc->bNumEndpoints; e++) { - libusb_endpoint_descriptor *edesc = &idesc->endpoint[e]; - - if (edesc->bmAttributes != LIBUSB_TRANSFER_TYPE_BULK) { - D("check_usb_interface(): Endpoint (%u) is not bulk (%u), ignoring\n", - edesc->bmAttributes, LIBUSB_TRANSFER_TYPE_BULK); - return -1; - } - - if (edesc->bEndpointAddress & LIBUSB_ENDPOINT_IN) - uh->end_point_address[0] = edesc->bEndpointAddress; - else - uh->end_point_address[1] = edesc->bEndpointAddress; - - /* aproto 01 needs 0 termination */ - if (idesc->bInterfaceProtocol == 0x01) { - uh->zero_mask = edesc->wMaxPacketSize - 1; - D("check_usb_interface(): Forced Android interface protocol v.1\n"); - } - } - - D("check_usb_interface(): Device: %04x:%04x " - "iclass: %x, isclass: %x, iproto: %x ep: %x/%x-> ", - desc->idVendor, desc->idProduct, idesc->bInterfaceClass, - idesc->bInterfaceSubClass, idesc->bInterfaceProtocol, - uh->end_point_address[0], uh->end_point_address[1]); - - if (!is_adb_interface(desc->idVendor, desc->idProduct, - idesc->bInterfaceClass, idesc->bInterfaceSubClass, - idesc->bInterfaceProtocol)) - { - D("not matches\n"); - return -1; - } - - D("matches\n"); - return 1; -} - -int -check_usb_interfaces(libusb_config_descriptor *config, - libusb_device_descriptor *desc, struct usb_handle *uh) -{ - int i; - - for (i = 0; i < config->bNumInterfaces; ++i) { - if (check_usb_interface(&config->interface[i], desc, uh) != -1) { - /* found some interface and saved information about it */ - D("check_usb_interfaces(): Interface %d of %04x:%04x " - "matches Android device\n", i, desc->idVendor, - desc->idProduct); - - return i; - } - } - - return -1; -} - -int -register_device(struct usb_handle *uh, const char *serial) -{ - D("register_device(): Registering %p [%s] as USB transport\n", - uh, serial); - - struct usb_handle *usb= NULL; - - usb = calloc(1, sizeof(struct usb_handle)); - memcpy(usb, uh, sizeof(struct usb_handle)); - strcpy(usb->serial, uh->serial); - - adb_cond_init(&usb->notify, 0); - adb_mutex_init(&usb->lock, 0); - - adb_mutex_lock(&usb_lock); - - usb->next = &handle_list; - usb->prev = handle_list.prev; - usb->prev->next = usb; - usb->next->prev = usb; - - adb_mutex_unlock(&usb_lock); - - register_usb_transport(usb, serial, NULL, 1); - - return (1); -} - -int -already_registered(usb_handle *uh) -{ - struct usb_handle *usb= NULL; - int exists = 0; - - adb_mutex_lock(&usb_lock); - - for (usb = handle_list.next; usb != &handle_list; usb = usb->next) { - if ((usb->dev_bus == uh->dev_bus) && - (usb->dev_addr == uh->dev_addr)) - { - exists = 1; - break; - } - } - - adb_mutex_unlock(&usb_lock); - - return exists; -} - -void -check_device(libusb_device *dev) -{ - struct usb_handle uh; - int i = 0; - int found = -1; - char serial[256] = {0}; - - libusb_device_descriptor desc; - libusb_config_descriptor *config = NULL; - - int r = libusb_get_device_descriptor(dev, &desc); - - if (r != LIBUSB_SUCCESS) { - D("check_device(): Failed to get device descriptor\n"); - return; - } - - if ((desc.idVendor == 0) && (desc.idProduct == 0)) - return; - - D("check_device(): Probing usb device %04x:%04x\n", - desc.idVendor, desc.idProduct); - - if (!is_adb_interface (desc.idVendor, desc.idProduct, - ADB_CLASS, ADB_SUBCLASS, ADB_PROTOCOL)) - { - D("check_device(): Ignored due unknown vendor id\n"); - return; - } - - uh.dev_bus = libusb_get_bus_number(dev); - uh.dev_addr = libusb_get_device_address(dev); - - if (already_registered(&uh)) { - D("check_device(): Device (bus: %d, address: %d) " - "is already registered\n", uh.dev_bus, uh.dev_addr); - return; - } - - D("check_device(): Device bus: %d, address: %d\n", - uh.dev_bus, uh.dev_addr); - - r = libusb_get_active_config_descriptor(dev, &config); - - if (r != 0) { - if (r == LIBUSB_ERROR_NOT_FOUND) { - D("check_device(): Device %4x:%4x is unconfigured\n", - desc.idVendor, desc.idProduct); - return; - } - - D("check_device(): Failed to get configuration for %4x:%4x\n", - desc.idVendor, desc.idProduct); - return; - } - - if (config == NULL) { - D("check_device(): Sanity check failed after " - "getting active config\n"); - return; - } - - if (config->interface != NULL) { - found = check_usb_interfaces(config, &desc, &uh); - } - - /* not needed anymore */ - libusb_free_config_descriptor(config); - - r = libusb_open(dev, &uh.devh); - uh.dev = dev; - - if (r != 0) { - switch (r) { - case LIBUSB_ERROR_NO_MEM: - D("check_device(): Memory allocation problem\n"); - break; - - case LIBUSB_ERROR_ACCESS: - D("check_device(): Permissions problem, " - "current user priveleges are messed up?\n"); - break; - - case LIBUSB_ERROR_NO_DEVICE: - D("check_device(): Device disconected, bad cable?\n"); - break; - - default: - D("check_device(): libusb triggered error %d\n", r); - } - // skip rest - found = -1; - } - - if (found >= 0) { - D("check_device(): Device matches Android interface\n"); - // read the device's serial number - memset(serial, 0, sizeof(serial)); - uh.interface = found; - - r = libusb_claim_interface(uh.devh, uh.interface); - - if (r < 0) { - D("check_device(): Failed to claim interface %d\n", - uh.interface); - - goto fail; - } - - if (desc.iSerialNumber) { - // reading serial - uint16_t buffer[128] = {0}; - uint16_t languages[128] = {0}; - int languageCount = 0; - - memset(languages, 0, sizeof(languages)); - r = libusb_control_transfer(uh.devh, - LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, - LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_DT_STRING << 8, - 0, (uint8_t *)languages, sizeof(languages), 0); - - if (r <= 0) { - D("check_device(): Failed to get languages count\n"); - goto fail; - } - - languageCount = (r - 2) / 2; - - for (i = 1; i <= languageCount; ++i) { - memset(buffer, 0, sizeof(buffer)); - - r = libusb_control_transfer(uh.devh, - LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, - LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc.iSerialNumber, - languages[i], (uint8_t *)buffer, sizeof(buffer), 0); - - if (r > 0) { /* converting serial */ - int j = 0; - r /= 2; - - for (j = 1; j < r; ++j) - serial[j - 1] = buffer[j]; - - serial[j - 1] = '\0'; - break; /* languagesCount cycle */ - } - } - - if (register_device(&uh, serial) == 0) { - D("check_device(): Failed to register device\n"); - goto fail_interface; - } - - libusb_ref_device(dev); - } - } - - return; - -fail_interface: - libusb_release_interface(uh.devh, uh.interface); - -fail: - libusb_close(uh.devh); - uh.devh = NULL; -} - -int -check_device_connected(struct usb_handle *uh) -{ - int r = libusb_kernel_driver_active(uh->devh, uh->interface); - - if (r == LIBUSB_ERROR_NO_DEVICE) - return 0; - - if (r < 0) - return -1; - - return 1; -} - -void -kick_disconnected() -{ - struct usb_handle *usb= NULL; - - adb_mutex_lock(&usb_lock); - - for (usb = handle_list.next; usb != &handle_list; usb = usb->next) { - - if (check_device_connected(usb) == 0) { - D("kick_disconnected(): Transport %p is not online anymore\n", - usb); - - usb_kick(usb); - } - } - - adb_mutex_unlock(&usb_lock); -} - -void -scan_usb_devices() -{ - D("scan_usb_devices(): started\n"); - - libusb_device **devs= NULL; - libusb_device *dev= NULL; - ssize_t cnt = libusb_get_device_list(ctx, &devs); - - if (cnt < 0) { - D("scan_usb_devices(): Failed to get device list (error: %d)\n", - cnt); - - return; - } - - int i = 0; - - while ((dev = devs[i++]) != NULL) { - check_device(dev); - } - - libusb_free_device_list(devs, 1); -} - -void * -device_poll_thread(void* unused) -{ - D("device_poll_thread(): Created USB scan thread\n"); - - for (;;) { - sleep(5); - kick_disconnected(); - scan_usb_devices(); - } - - /* never reaching this point */ - return (NULL); -} - -static void -sigalrm_handler(int signo) -{ - /* nothing */ -} - -void -usb_init() -{ - D("usb_init(): started\n"); - adb_thread_t tid; - struct sigaction actions; - - int r = libusb_init(&ctx); - - if (r != LIBUSB_SUCCESS) { - err(EX_IOERR, "Failed to init libusb\n"); - } - - memset(&actions, 0, sizeof(actions)); - - sigemptyset(&actions.sa_mask); - - actions.sa_flags = 0; - actions.sa_handler = sigalrm_handler; - - sigaction(SIGALRM, &actions, NULL); - - /* initial device scan */ - scan_usb_devices(); - - /* starting USB event polling thread */ - if (adb_thread_create(&tid, device_poll_thread, NULL)) { - err(EX_IOERR, "cannot create USB scan thread\n"); - } - - D("usb_init(): finished\n"); -} - diff --git a/adb/usb_linux.c b/adb/usb_linux.cpp index f16bdd0..31fd167 100644 --- a/adb/usb_linux.c +++ b/adb/usb_linux.cpp @@ -14,33 +14,31 @@ * limitations under the License. */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> +#define TRACE_TAG TRACE_USB -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/time.h> +#include "sysdeps.h" + +#include <ctype.h> #include <dirent.h> -#include <fcntl.h> #include <errno.h> -#include <ctype.h> - +#include <fcntl.h> #include <linux/usbdevice_fs.h> #include <linux/version.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) #include <linux/usb/ch9.h> #else #include <linux/usb_ch9.h> #endif -#include <asm/byteorder.h> -#include "sysdeps.h" - -#define TRACE_TAG TRACE_USB #include "adb.h" - +#include "transport.h" /* usb scan debugging is waaaay too verbose */ #define DBGX(x...) @@ -116,10 +114,6 @@ static void kick_disconnected_devices() } -static void register_device(const char *dev_name, const char *devpath, - unsigned char ep_in, unsigned char ep_out, - int ifc, int serial_index, unsigned zero_mask); - static inline int badname(const char *name) { while(*name) { @@ -237,8 +231,20 @@ static void find_usb_device(const char *base, // looks like ADB... ep1 = (struct usb_endpoint_descriptor *)bufptr; bufptr += USB_DT_ENDPOINT_SIZE; + // For USB 3.0 SuperSpeed devices, skip potential + // USB 3.0 SuperSpeed Endpoint Companion descriptor + if (bufptr+2 <= devdesc + desclength && + bufptr[0] == USB_DT_SS_EP_COMP_SIZE && + bufptr[1] == USB_DT_SS_ENDPOINT_COMP) { + bufptr += USB_DT_SS_EP_COMP_SIZE; + } ep2 = (struct usb_endpoint_descriptor *)bufptr; bufptr += USB_DT_ENDPOINT_SIZE; + if (bufptr+2 <= devdesc + desclength && + bufptr[0] == USB_DT_SS_EP_COMP_SIZE && + bufptr[1] == USB_DT_SS_ENDPOINT_COMP) { + bufptr += USB_DT_SS_EP_COMP_SIZE; + } if (bufptr > devdesc + desclength || ep1->bLength != USB_DT_ENDPOINT_SIZE || @@ -367,6 +373,7 @@ static int usb_bulk_read(usb_handle *h, void *data, int len) struct usbdevfs_urb *out = NULL; int res; + D("++ usb_bulk_read ++\n"); memset(urb, 0, sizeof(*urb)); urb->type = USBDEVFS_URB_TYPE_BULK; urb->endpoint = h->ep_in; @@ -429,6 +436,7 @@ static int usb_bulk_read(usb_handle *h, void *data, int len) } fail: adb_mutex_unlock(&h->lock); + D("-- usb_bulk_read --\n"); return res; } @@ -439,6 +447,7 @@ int usb_write(usb_handle *h, const void *_data, int len) int n; int need_zero = 0; + D("++ usb_write ++\n"); if(h->zero_mask) { /* if we need 0-markers and our transfer ** is an even multiple of the packet size, @@ -468,6 +477,7 @@ int usb_write(usb_handle *h, const void *_data, int len) return n; } + D("-- usb_write --\n"); return 0; } @@ -542,7 +552,7 @@ void usb_kick(usb_handle *h) int usb_close(usb_handle *h) { - D("[ usb close ... ]\n"); + D("++ usb close ++\n"); adb_mutex_lock(&usb_lock); h->next->prev = h->prev; h->prev->next = h->next; @@ -550,7 +560,7 @@ int usb_close(usb_handle *h) h->next = 0; adb_close(h->desc); - D("[ usb closed %p (fd = %d) ]\n", h, h->desc); + D("-- usb closed %p (fd = %d) --\n", h, h->desc); adb_mutex_unlock(&usb_lock); free(h); @@ -561,7 +571,6 @@ static void register_device(const char *dev_name, const char *devpath, unsigned char ep_in, unsigned char ep_out, int interface, int serial_index, unsigned zero_mask) { - usb_handle* usb = 0; int n = 0; char serial[256]; @@ -574,17 +583,17 @@ static void register_device(const char *dev_name, const char *devpath, ** name, we have no further work to do. */ adb_mutex_lock(&usb_lock); - for(usb = handle_list.next; usb != &handle_list; usb = usb->next){ - if(!strcmp(usb->fname, dev_name)) { + for (usb_handle* usb = handle_list.next; usb != &handle_list; usb = usb->next) { + if (!strcmp(usb->fname, dev_name)) { adb_mutex_unlock(&usb_lock); return; } } adb_mutex_unlock(&usb_lock); - D("[ usb located new device %s (%d/%d/%d) ]\n", - dev_name, ep_in, ep_out, interface); - usb = calloc(1, sizeof(usb_handle)); + D("[ usb located new device %s (%d/%d/%d) ]\n", dev_name, ep_in, ep_out, interface); + usb_handle* usb = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle))); + if (usb == nullptr) fatal("couldn't allocate usb_handle"); strcpy(usb->fname, dev_name); usb->ep_in = ep_in; usb->ep_out = ep_out; @@ -598,16 +607,27 @@ static void register_device(const char *dev_name, const char *devpath, usb->reaper_thread = 0; usb->desc = unix_open(usb->fname, O_RDWR | O_CLOEXEC); - if(usb->desc < 0) { - /* if we fail, see if have read-only access */ + if (usb->desc == -1) { + // Opening RW failed, so see if we have RO access. usb->desc = unix_open(usb->fname, O_RDONLY | O_CLOEXEC); - if(usb->desc < 0) goto fail; + if (usb->desc == -1) { + D("[ usb open %s failed: %s]\n", usb->fname, strerror(errno)); + free(usb); + return; + } usb->writeable = 0; - D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc); - } else { - D("[ usb open %s fd = %d]\n", usb->fname, usb->desc); + } + + D("[ usb opened %s%s, fd=%d]\n", usb->fname, (usb->writeable ? "" : " (read-only)"), usb->desc); + + if (usb->writeable) { n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface); - if(n != 0) goto fail; + if (n != 0) { + D("[ usb ioctl(%d, USBDEVFS_CLAIMINTERFACE) failed: %s]\n", usb->desc, strerror(errno)); + adb_close(usb->desc); + free(usb); + return; + } } /* read the device's serial number */ @@ -670,15 +690,6 @@ static void register_device(const char *dev_name, const char *devpath, adb_mutex_unlock(&usb_lock); register_usb_transport(usb, serial, devpath, usb->writeable); - return; - -fail: - D("[ usb open %s error=%d, err_str = %s]\n", - usb->fname, errno, strerror(errno)); - if(usb->desc >= 0) { - adb_close(usb->desc); - } - free(usb); } void* device_poll_thread(void* unused) diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.cpp index 8426e0e..18289e2 100644 --- a/adb/usb_linux_client.c +++ b/adb/usb_linux_client.cpp @@ -14,25 +14,28 @@ * limitations under the License. */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> +#define TRACE_TAG TRACE_USB + +#include "sysdeps.h" +#include <cutils/properties.h> +#include <dirent.h> +#include <errno.h> #include <linux/usb/ch9.h> #include <linux/usb/functionfs.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/ioctl.h> #include <sys/types.h> -#include <dirent.h> -#include <errno.h> - -#include "sysdeps.h" +#include <unistd.h> -#define TRACE_TAG TRACE_USB #include "adb.h" +#include "transport.h" #define MAX_PACKET_SIZE_FS 64 #define MAX_PACKET_SIZE_HS 512 +#define MAX_PACKET_SIZE_SS 1024 #define cpu_to_le16(x) htole16(x) #define cpu_to_le32(x) htole32(x) @@ -55,71 +58,81 @@ struct usb_handle int bulk_in; /* "in" from the host's perspective => sink for adbd */ }; -static const struct { - struct usb_functionfs_descs_head header; - struct { - struct usb_interface_descriptor intf; - struct usb_endpoint_descriptor_no_audio source; - struct usb_endpoint_descriptor_no_audio sink; - } __attribute__((packed)) fs_descs, hs_descs; -} __attribute__((packed)) descriptors = { - .header = { - .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC), - .length = cpu_to_le32(sizeof(descriptors)), - .fs_count = 3, - .hs_count = 3, +struct func_desc { + struct usb_interface_descriptor intf; + struct usb_endpoint_descriptor_no_audio source; + struct usb_endpoint_descriptor_no_audio sink; +} __attribute__((packed)); + +struct desc_v1 { + struct usb_functionfs_descs_head_v1 { + __le32 magic; + __le32 length; + __le32 fs_count; + __le32 hs_count; + } __attribute__((packed)) header; + struct func_desc fs_descs, hs_descs; +} __attribute__((packed)); + +struct desc_v2 { + struct usb_functionfs_descs_head_v2 header; + // The rest of the structure depends on the flags in the header. + __le32 fs_count; + __le32 hs_count; + struct func_desc fs_descs, hs_descs; +} __attribute__((packed)); + +struct func_desc fs_descriptors = { + .intf = { + .bLength = sizeof(fs_descriptors.intf), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bNumEndpoints = 2, + .bInterfaceClass = ADB_CLASS, + .bInterfaceSubClass = ADB_SUBCLASS, + .bInterfaceProtocol = ADB_PROTOCOL, + .iInterface = 1, /* first string from the provided table */ }, - .fs_descs = { - .intf = { - .bLength = sizeof(descriptors.fs_descs.intf), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bNumEndpoints = 2, - .bInterfaceClass = ADB_CLASS, - .bInterfaceSubClass = ADB_SUBCLASS, - .bInterfaceProtocol = ADB_PROTOCOL, - .iInterface = 1, /* first string from the provided table */ - }, - .source = { - .bLength = sizeof(descriptors.fs_descs.source), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 1 | USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_FS, - }, - .sink = { - .bLength = sizeof(descriptors.fs_descs.sink), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 2 | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_FS, - }, + .source = { + .bLength = sizeof(fs_descriptors.source), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = MAX_PACKET_SIZE_FS, }, - .hs_descs = { - .intf = { - .bLength = sizeof(descriptors.hs_descs.intf), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bNumEndpoints = 2, - .bInterfaceClass = ADB_CLASS, - .bInterfaceSubClass = ADB_SUBCLASS, - .bInterfaceProtocol = ADB_PROTOCOL, - .iInterface = 1, /* first string from the provided table */ - }, - .source = { - .bLength = sizeof(descriptors.hs_descs.source), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 1 | USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_HS, - }, - .sink = { - .bLength = sizeof(descriptors.hs_descs.sink), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 2 | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_HS, - }, + .sink = { + .bLength = sizeof(fs_descriptors.sink), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 2 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = MAX_PACKET_SIZE_FS, + }, +}; + +struct func_desc hs_descriptors = { + .intf = { + .bLength = sizeof(hs_descriptors.intf), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bNumEndpoints = 2, + .bInterfaceClass = ADB_CLASS, + .bInterfaceSubClass = ADB_SUBCLASS, + .bInterfaceProtocol = ADB_PROTOCOL, + .iInterface = 1, /* first string from the provided table */ + }, + .source = { + .bLength = sizeof(hs_descriptors.source), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = MAX_PACKET_SIZE_HS, + }, + .sink = { + .bLength = sizeof(hs_descriptors.sink), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 2 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = MAX_PACKET_SIZE_HS, }, }; @@ -151,7 +164,7 @@ static void *usb_adb_open_thread(void *x) struct usb_handle *usb = (struct usb_handle *)x; int fd; - while (1) { + while (true) { // wait until the USB device needs opening adb_mutex_lock(&usb->lock); while (usb->fd != -1) @@ -227,11 +240,8 @@ static void usb_adb_kick(usb_handle *h) static void usb_adb_init() { - usb_handle *h; - adb_thread_t tid; - int fd; - - h = calloc(1, sizeof(usb_handle)); + usb_handle* h = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle))); + if (h == nullptr) fatal("couldn't allocate usb_handle"); h->write = usb_adb_write; h->read = usb_adb_read; @@ -241,12 +251,12 @@ static void usb_adb_init() adb_cond_init(&h->notify, 0); adb_mutex_init(&h->lock, 0); - // Open the file /dev/android_adb_enable to trigger + // Open the file /dev/android_adb_enable to trigger // the enabling of the adb USB function in the kernel. // We never touch this file again - just leave it open // indefinitely so the kernel will know when we are running // and when we are not. - fd = unix_open("/dev/android_adb_enable", O_RDWR); + int fd = unix_open("/dev/android_adb_enable", O_RDWR); if (fd < 0) { D("failed to open /dev/android_adb_enable\n"); } else { @@ -254,6 +264,7 @@ static void usb_adb_init() } D("[ usb_init - starting thread ]\n"); + adb_thread_t tid; if(adb_thread_create(&tid, usb_adb_open_thread, h)){ fatal_errno("cannot create usb thread"); } @@ -263,6 +274,16 @@ static void usb_adb_init() static void init_functionfs(struct usb_handle *h) { ssize_t ret; + struct desc_v1 v1_descriptor; + struct desc_v2 v2_descriptor; + + v2_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2); + v2_descriptor.header.length = cpu_to_le32(sizeof(v2_descriptor)); + v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC; + v2_descriptor.fs_count = 3; + v2_descriptor.hs_count = 3; + v2_descriptor.fs_descs = fs_descriptors; + v2_descriptor.hs_descs = hs_descriptors; if (h->control < 0) { // might have already done this before D("OPENING %s\n", USB_FFS_ADB_EP0); @@ -272,10 +293,20 @@ static void init_functionfs(struct usb_handle *h) goto err; } - ret = adb_write(h->control, &descriptors, sizeof(descriptors)); + ret = adb_write(h->control, &v2_descriptor, sizeof(v2_descriptor)); if (ret < 0) { - D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno); - goto err; + v1_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC); + v1_descriptor.header.length = cpu_to_le32(sizeof(v1_descriptor)); + v1_descriptor.header.fs_count = 3; + v1_descriptor.header.hs_count = 3; + v1_descriptor.fs_descs = fs_descriptors; + v1_descriptor.hs_descs = hs_descriptors; + D("[ %s: Switching to V1_descriptor format errno=%d ]\n", USB_FFS_ADB_EP0, errno); + ret = adb_write(h->control, &v1_descriptor, sizeof(v1_descriptor)); + if (ret < 0) { + D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno); + goto err; + } } ret = adb_write(h->control, &strings, sizeof(strings)); @@ -319,14 +350,14 @@ static void *usb_ffs_open_thread(void *x) { struct usb_handle *usb = (struct usb_handle *)x; - while (1) { + while (true) { // wait until the USB device needs opening adb_mutex_lock(&usb->lock); while (usb->control != -1 && usb->bulk_in != -1 && usb->bulk_out != -1) adb_cond_wait(&usb->notify, &usb->lock); adb_mutex_unlock(&usb->lock); - while (1) { + while (true) { init_functionfs(usb); if (usb->control >= 0 && usb->bulk_in >= 0 && usb->bulk_out >= 0) @@ -334,6 +365,7 @@ static void *usb_ffs_open_thread(void *x) adb_sleep_ms(1000); } + property_set("sys.usb.ffs.ready", "1"); D("[ usb_thread - registering device ]\n"); register_usb_transport(usb, 0, 0, 1); @@ -343,7 +375,7 @@ static void *usb_ffs_open_thread(void *x) return 0; } -static int bulk_write(int bulk_in, const char *buf, size_t length) +static int bulk_write(int bulk_in, const uint8_t* buf, size_t length) { size_t count = 0; int ret; @@ -362,22 +394,19 @@ static int bulk_write(int bulk_in, const char *buf, size_t length) return count; } -static int usb_ffs_write(usb_handle *h, const void *data, int len) +static int usb_ffs_write(usb_handle* h, const void* data, int len) { - int n; - D("about to write (fd=%d, len=%d)\n", h->bulk_in, len); - n = bulk_write(h->bulk_in, data, len); + int n = bulk_write(h->bulk_in, reinterpret_cast<const uint8_t*>(data), len); if (n != len) { - D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", - h->bulk_in, n, errno, strerror(errno)); + D("ERROR: fd = %d, n = %d: %s\n", h->bulk_in, n, strerror(errno)); return -1; } D("[ done fd=%d ]\n", h->bulk_in); return 0; } -static int bulk_read(int bulk_out, char *buf, size_t length) +static int bulk_read(int bulk_out, uint8_t* buf, size_t length) { size_t count = 0; int ret; @@ -398,15 +427,12 @@ static int bulk_read(int bulk_out, char *buf, size_t length) return count; } -static int usb_ffs_read(usb_handle *h, void *data, int len) +static int usb_ffs_read(usb_handle* h, void* data, int len) { - int n; - D("about to read (fd=%d, len=%d)\n", h->bulk_out, len); - n = bulk_read(h->bulk_out, data, len); + int n = bulk_read(h->bulk_out, reinterpret_cast<uint8_t*>(data), len); if (n != len) { - D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", - h->bulk_out, n, errno, strerror(errno)); + D("ERROR: fd = %d, n = %d: %s\n", h->bulk_out, n, strerror(errno)); return -1; } D("[ done fd=%d ]\n", h->bulk_out); @@ -441,18 +467,15 @@ static void usb_ffs_kick(usb_handle *h) static void usb_ffs_init() { - usb_handle *h; - adb_thread_t tid; - D("[ usb_init - using FunctionFS ]\n"); - h = calloc(1, sizeof(usb_handle)); + usb_handle* h = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle))); + if (h == nullptr) fatal("couldn't allocate usb_handle"); h->write = usb_ffs_write; h->read = usb_ffs_read; h->kick = usb_ffs_kick; - - h->control = -1; + h->control = -1; h->bulk_out = -1; h->bulk_out = -1; @@ -460,6 +483,7 @@ static void usb_ffs_init() adb_mutex_init(&h->lock, 0); D("[ usb_init - starting thread ]\n"); + adb_thread_t tid; if (adb_thread_create(&tid, usb_ffs_open_thread, h)){ fatal_errno("[ cannot create usb thread ]\n"); } diff --git a/adb/usb_osx.c b/adb/usb_osx.cpp index ca4f2af..a795ce3 100644 --- a/adb/usb_osx.c +++ b/adb/usb_osx.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +#define TRACE_TAG TRACE_USB + +#include "sysdeps.h" + #include <CoreFoundation/CoreFoundation.h> #include <IOKit/IOKitLib.h> @@ -22,18 +26,16 @@ #include <IOKit/IOMessage.h> #include <mach/mach_port.h> -#include "sysdeps.h" - +#include <inttypes.h> #include <stdio.h> -#define TRACE_TAG TRACE_USB #include "adb.h" -#include "usb_vendors.h" +#include "transport.h" #define DBG D static IONotificationPortRef notificationPort = 0; -static io_iterator_t* notificationIterators; +static io_iterator_t notificationIterator; struct usb_handle { @@ -61,8 +63,6 @@ InitUSB() { CFMutableDictionaryRef matchingDict; CFRunLoopSourceRef runLoopSource; - SInt32 vendor, if_subclass, if_protocol; - unsigned i; //* To set up asynchronous notifications, create a notification port and //* add its run loop event source to the program's run loop @@ -70,47 +70,33 @@ InitUSB() runLoopSource = IONotificationPortGetRunLoopSource(notificationPort); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode); - memset(notificationIterators, 0, sizeof(notificationIterators)); - - //* loop through all supported vendors - for (i = 0; i < vendorIdCount; i++) { - //* Create our matching dictionary to find the Android device's - //* adb interface - //* IOServiceAddMatchingNotification consumes the reference, so we do - //* not need to release this - matchingDict = IOServiceMatching(kIOUSBInterfaceClassName); + //* Create our matching dictionary to find the Android device's + //* adb interface + //* IOServiceAddMatchingNotification consumes the reference, so we do + //* not need to release this + matchingDict = IOServiceMatching(kIOUSBInterfaceClassName); - if (!matchingDict) { - DBG("ERR: Couldn't create USB matching dictionary.\n"); - return -1; - } - - //* Match based on vendor id, interface subclass and protocol - vendor = vendorIds[i]; - if_subclass = ADB_SUBCLASS; - if_protocol = ADB_PROTOCOL; - CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), - CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt32Type, &vendor)); - CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass), - CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt32Type, &if_subclass)); - CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol), - CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt32Type, &if_protocol)); - IOServiceAddMatchingNotification( - notificationPort, - kIOFirstMatchNotification, - matchingDict, - AndroidInterfaceAdded, - NULL, - ¬ificationIterators[i]); - - //* Iterate over set of matching interfaces to access already-present - //* devices and to arm the notification - AndroidInterfaceAdded(NULL, notificationIterators[i]); + if (!matchingDict) { + DBG("ERR: Couldn't create USB matching dictionary.\n"); + return -1; } + //* We have to get notifications for all potential candidates and test them + //* at connection time because the matching rules don't allow for a + //* USB interface class of 0xff for class+subclass+protocol matches + //* See https://developer.apple.com/library/mac/qa/qa1076/_index.html + IOServiceAddMatchingNotification( + notificationPort, + kIOFirstMatchNotification, + matchingDict, + AndroidInterfaceAdded, + NULL, + ¬ificationIterator); + + //* Iterate over set of matching interfaces to access already-present + //* devices and to arm the notification + AndroidInterfaceAdded(NULL, notificationIterator); + return 0; } @@ -126,6 +112,7 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) HRESULT result; SInt32 score; UInt32 locationId; + UInt8 if_class, subclass, protocol; UInt16 vendor; UInt16 product; UInt8 serialIndex; @@ -146,9 +133,9 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) } //* This gets us the interface object - result = (*plugInInterface)->QueryInterface(plugInInterface, - CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID) - &iface); + result = (*plugInInterface)->QueryInterface( + plugInInterface, + CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID*)&iface); //* We only needed the plugin to get the interface, so discard it (*plugInInterface)->Release(plugInInterface); if (result || !iface) { @@ -156,6 +143,16 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) continue; } + kr = (*iface)->GetInterfaceClass(iface, &if_class); + kr = (*iface)->GetInterfaceSubClass(iface, &subclass); + kr = (*iface)->GetInterfaceProtocol(iface, &protocol); + if(if_class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) { + // Ignore non-ADB devices. + DBG("Ignoring interface with incorrect class/subclass/protocol - %d, %d, %d\n", if_class, subclass, protocol); + (*iface)->Release(iface); + continue; + } + //* this gets us an ioservice, with which we will find the actual //* device; after getting a plugin, and querying the interface, of //* course. @@ -181,7 +178,7 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) } result = (*plugInInterface)->QueryInterface(plugInInterface, - CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev); + CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*)&dev); //* only needed this to query the plugin (*plugInInterface)->Release(plugInInterface); if (result || !dev) { @@ -192,12 +189,12 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) //* Now after all that, we actually have a ref to the device and //* the interface that matched our criteria - kr = (*dev)->GetDeviceVendor(dev, &vendor); kr = (*dev)->GetDeviceProduct(dev, &product); kr = (*dev)->GetLocationID(dev, &locationId); if (kr == 0) { - snprintf(devpathBuf, sizeof(devpathBuf), "usb:%lX", locationId); + snprintf(devpathBuf, sizeof(devpathBuf), "usb:%" PRIu32 "X", + (unsigned int)locationId); devpath = devpathBuf; } kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex); @@ -338,7 +335,8 @@ CheckInterface(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 produc interfaceSubClass, interfaceProtocol)) goto err_bad_adb_interface; - handle = calloc(1, sizeof(usb_handle)); + handle = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle))); + if (handle == nullptr) goto err_bad_adb_interface; //* Iterate over the endpoints for this interface and find the first //* bulk in/out pipes available. These will be our read/write pipes. @@ -384,8 +382,6 @@ err_get_num_ep: void* RunLoopThread(void* unused) { - unsigned i; - InitUSB(); currentRunLoop = CFRunLoopGetCurrent(); @@ -398,9 +394,7 @@ void* RunLoopThread(void* unused) CFRunLoopRun(); currentRunLoop = 0; - for (i = 0; i < vendorIdCount; i++) { - IOObjectRelease(notificationIterators[i]); - } + IOObjectRelease(notificationIterator); IONotificationPortDestroy(notificationPort); DBG("RunLoopThread done\n"); @@ -415,9 +409,6 @@ void usb_init() { adb_thread_t tid; - notificationIterators = (io_iterator_t*)malloc( - vendorIdCount * sizeof(io_iterator_t)); - adb_mutex_init(&start_lock, NULL); adb_cond_init(&start_cond, NULL); @@ -442,11 +433,6 @@ void usb_cleanup() close_usb_devices(); if (currentRunLoop) CFRunLoopStop(currentRunLoop); - - if (notificationIterators != NULL) { - free(notificationIterators); - notificationIterators = NULL; - } } int usb_write(usb_handle *handle, const void *buf, int len) diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c deleted file mode 100755 index 19bcae4..0000000 --- a/adb/usb_vendors.c +++ /dev/null @@ -1,370 +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 "usb_vendors.h" - -#include <stdio.h> -#include <stdlib.h> - -#ifdef _WIN32 -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include "windows.h" -# include "shlobj.h" -#else -# include <unistd.h> -# include <sys/stat.h> -#endif - -#include "sysdeps.h" -#include "adb.h" - -#define ANDROID_PATH ".android" -#define ANDROID_ADB_INI "adb_usb.ini" - -#define TRACE_TAG TRACE_USB - -/* Keep the list below sorted alphabetically by #define name */ -// Acer's USB Vendor ID -#define VENDOR_ID_ACER 0x0502 -// Allwinner's USB Vendor ID -#define VENDOR_ID_ALLWINNER 0x1F3A -// Amlogic's USB Vendor ID -#define VENDOR_ID_AMLOGIC 0x1b8e -// AnyDATA's USB Vendor ID -#define VENDOR_ID_ANYDATA 0x16D5 -// Archos's USB Vendor ID -#define VENDOR_ID_ARCHOS 0x0E79 -// Asus's USB Vendor ID -#define VENDOR_ID_ASUS 0x0b05 -// BYD's USB Vendor ID -#define VENDOR_ID_BYD 0x1D91 -// Compal's USB Vendor ID -#define VENDOR_ID_COMPAL 0x04B7 -// Compalcomm's USB Vendor ID -#define VENDOR_ID_COMPALCOMM 0x1219 -// Dell's USB Vendor ID -#define VENDOR_ID_DELL 0x413c -// ECS's USB Vendor ID -#define VENDOR_ID_ECS 0x03fc -// EMERGING_TECH's USB Vendor ID -#define VENDOR_ID_EMERGING_TECH 0x297F -// Emerson's USB Vendor ID -#define VENDOR_ID_EMERSON 0x2207 -// Foxconn's USB Vendor ID -#define VENDOR_ID_FOXCONN 0x0489 -// Fujitsu's USB Vendor ID -#define VENDOR_ID_FUJITSU 0x04C5 -// Funai's USB Vendor ID -#define VENDOR_ID_FUNAI 0x0F1C -// Garmin-Asus's USB Vendor ID -#define VENDOR_ID_GARMIN_ASUS 0x091E -// Gigabyte's USB Vendor ID -#define VENDOR_ID_GIGABYTE 0x0414 -// Gigaset's USB Vendor ID -#define VENDOR_ID_GIGASET 0x1E85 -// GIONEE's USB Vendor ID -#define VENDOR_ID_GIONEE 0x271D -// Google's USB Vendor ID -#define VENDOR_ID_GOOGLE 0x18d1 -// Haier's USB Vendor ID -#define VENDOR_ID_HAIER 0x201E -// Harris's USB Vendor ID -#define VENDOR_ID_HARRIS 0x19A5 -// Hisense's USB Vendor ID -#define VENDOR_ID_HISENSE 0x109b -// Honeywell's USB Vendor ID -#define VENDOR_ID_HONEYWELL 0x0c2e -// HP's USB Vendor ID -#define VENDOR_ID_HP 0x03f0 -// HTC's USB Vendor ID -#define VENDOR_ID_HTC 0x0bb4 -// Huawei's USB Vendor ID -#define VENDOR_ID_HUAWEI 0x12D1 -// INQ Mobile's USB Vendor ID -#define VENDOR_ID_INQ_MOBILE 0x2314 -// Intel's USB Vendor ID -#define VENDOR_ID_INTEL 0x8087 -// Intermec's USB Vendor ID -#define VENDOR_ID_INTERMEC 0x067e -// IRiver's USB Vendor ID -#define VENDOR_ID_IRIVER 0x2420 -// K-Touch's USB Vendor ID -#define VENDOR_ID_K_TOUCH 0x24E3 -// KT Tech's USB Vendor ID -#define VENDOR_ID_KT_TECH 0x2116 -// Kobo's USB Vendor ID -#define VENDOR_ID_KOBO 0x2237 -// Kyocera's USB Vendor ID -#define VENDOR_ID_KYOCERA 0x0482 -// Lab126's USB Vendor ID -#define VENDOR_ID_LAB126 0x1949 -// Lenovo's USB Vendor ID -#define VENDOR_ID_LENOVO 0x17EF -// LenovoMobile's USB Vendor ID -#define VENDOR_ID_LENOVOMOBILE 0x2006 -// LG's USB Vendor ID -#define VENDOR_ID_LGE 0x1004 -// Lumigon's USB Vendor ID -#define VENDOR_ID_LUMIGON 0x25E3 -// Motorola's USB Vendor ID -#define VENDOR_ID_MOTOROLA 0x22b8 -// MSI's USB Vendor ID -#define VENDOR_ID_MSI 0x0DB0 -// MTK's USB Vendor ID -#define VENDOR_ID_MTK 0x0e8d -// NEC's USB Vendor ID -#define VENDOR_ID_NEC 0x0409 -// B&N Nook's USB Vendor ID -#define VENDOR_ID_NOOK 0x2080 -// Nvidia's USB Vendor ID -#define VENDOR_ID_NVIDIA 0x0955 -// OPPO's USB Vendor ID -#define VENDOR_ID_OPPO 0x22D9 -// On-The-Go-Video's USB Vendor ID -#define VENDOR_ID_OTGV 0x2257 -// OUYA's USB Vendor ID -#define VENDOR_ID_OUYA 0x2836 -// Pantech's USB Vendor ID -#define VENDOR_ID_PANTECH 0x10A9 -// Pegatron's USB Vendor ID -#define VENDOR_ID_PEGATRON 0x1D4D -// Philips's USB Vendor ID -#define VENDOR_ID_PHILIPS 0x0471 -// Panasonic Mobile Communication's USB Vendor ID -#define VENDOR_ID_PMC 0x04DA -// Positivo's USB Vendor ID -#define VENDOR_ID_POSITIVO 0x1662 -// Prestigio's USB Vendor ID -#define VENDOR_ID_PRESTIGIO 0x29e4 -// Qisda's USB Vendor ID -#define VENDOR_ID_QISDA 0x1D45 -// Qualcomm's USB Vendor ID -#define VENDOR_ID_QUALCOMM 0x05c6 -// Quanta's USB Vendor ID -#define VENDOR_ID_QUANTA 0x0408 -// Rockchip's USB Vendor ID -#define VENDOR_ID_ROCKCHIP 0x2207 -// Samsung's USB Vendor ID -#define VENDOR_ID_SAMSUNG 0x04e8 -// Sharp's USB Vendor ID -#define VENDOR_ID_SHARP 0x04dd -// SK Telesys's USB Vendor ID -#define VENDOR_ID_SK_TELESYS 0x1F53 -// Smartisan's USB Vendor ID -#define VENDOR_ID_SMARTISAN 0x29a9 -// Sony's USB Vendor ID -#define VENDOR_ID_SONY 0x054C -// Sony Ericsson's USB Vendor ID -#define VENDOR_ID_SONY_ERICSSON 0x0FCE -// T & A Mobile Phones' USB Vendor ID -#define VENDOR_ID_T_AND_A 0x1BBB -// TechFaith's USB Vendor ID -#define VENDOR_ID_TECHFAITH 0x1d09 -// Teleepoch's USB Vendor ID -#define VENDOR_ID_TELEEPOCH 0x2340 -// Texas Instruments's USB Vendor ID -#define VENDOR_ID_TI 0x0451 -// Toshiba's USB Vendor ID -#define VENDOR_ID_TOSHIBA 0x0930 -// Unowhy's USB Vendor ID -#define VENDOR_ID_UNOWHY 0x2A49 -// Vizio's USB Vendor ID -#define VENDOR_ID_VIZIO 0xE040 -// Wacom's USB Vendor ID -#define VENDOR_ID_WACOM 0x0531 -// Xiaomi's USB Vendor ID -#define VENDOR_ID_XIAOMI 0x2717 -// YotaDevices's USB Vendor ID -#define VENDOR_ID_YOTADEVICES 0x2916 -// Yulong Coolpad's USB Vendor ID -#define VENDOR_ID_YULONG_COOLPAD 0x1EBF -// ZTE's USB Vendor ID -#define VENDOR_ID_ZTE 0x19D2 -/* Keep the list above sorted alphabetically by #define name */ - -/** built-in vendor list */ -/* Keep the list below sorted alphabetically */ -int builtInVendorIds[] = { - VENDOR_ID_ACER, - VENDOR_ID_ALLWINNER, - VENDOR_ID_AMLOGIC, - VENDOR_ID_ANYDATA, - VENDOR_ID_ARCHOS, - VENDOR_ID_ASUS, - VENDOR_ID_BYD, - VENDOR_ID_COMPAL, - VENDOR_ID_COMPALCOMM, - VENDOR_ID_DELL, - VENDOR_ID_ECS, - VENDOR_ID_EMERGING_TECH, - VENDOR_ID_EMERSON, - VENDOR_ID_FOXCONN, - VENDOR_ID_FUJITSU, - VENDOR_ID_FUNAI, - VENDOR_ID_GARMIN_ASUS, - VENDOR_ID_GIGABYTE, - VENDOR_ID_GIGASET, - VENDOR_ID_GIONEE, - VENDOR_ID_GOOGLE, - VENDOR_ID_HAIER, - VENDOR_ID_HARRIS, - VENDOR_ID_HISENSE, - VENDOR_ID_HONEYWELL, - VENDOR_ID_HP, - VENDOR_ID_HTC, - VENDOR_ID_HUAWEI, - VENDOR_ID_INQ_MOBILE, - VENDOR_ID_INTEL, - VENDOR_ID_INTERMEC, - VENDOR_ID_IRIVER, - VENDOR_ID_KOBO, - VENDOR_ID_K_TOUCH, - VENDOR_ID_KT_TECH, - VENDOR_ID_KYOCERA, - VENDOR_ID_LAB126, - VENDOR_ID_LENOVO, - VENDOR_ID_LENOVOMOBILE, - VENDOR_ID_LGE, - VENDOR_ID_LUMIGON, - VENDOR_ID_MOTOROLA, - VENDOR_ID_MSI, - VENDOR_ID_MTK, - VENDOR_ID_NEC, - VENDOR_ID_NOOK, - VENDOR_ID_NVIDIA, - VENDOR_ID_OPPO, - VENDOR_ID_OTGV, - VENDOR_ID_OUYA, - VENDOR_ID_PANTECH, - VENDOR_ID_PEGATRON, - VENDOR_ID_PHILIPS, - VENDOR_ID_PMC, - VENDOR_ID_POSITIVO, - VENDOR_ID_PRESTIGIO, - VENDOR_ID_QISDA, - VENDOR_ID_QUALCOMM, - VENDOR_ID_QUANTA, - VENDOR_ID_ROCKCHIP, - VENDOR_ID_SAMSUNG, - VENDOR_ID_SHARP, - VENDOR_ID_SK_TELESYS, - VENDOR_ID_SMARTISAN, - VENDOR_ID_SONY, - VENDOR_ID_SONY_ERICSSON, - VENDOR_ID_T_AND_A, - VENDOR_ID_TECHFAITH, - VENDOR_ID_TELEEPOCH, - VENDOR_ID_TI, - VENDOR_ID_TOSHIBA, - VENDOR_ID_UNOWHY, - VENDOR_ID_VIZIO, - VENDOR_ID_WACOM, - VENDOR_ID_XIAOMI, - VENDOR_ID_YOTADEVICES, - VENDOR_ID_YULONG_COOLPAD, - VENDOR_ID_ZTE, -}; -/* Keep the list above sorted alphabetically */ - -#define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0])) - -/* max number of supported vendor ids (built-in + 3rd party). increase as needed */ -#define VENDOR_COUNT_MAX 128 - -int vendorIds[VENDOR_COUNT_MAX]; -unsigned vendorIdCount = 0; - -int get_adb_usb_ini(char* buff, size_t len); - -void usb_vendors_init(void) -{ - if (VENDOR_COUNT_MAX < BUILT_IN_VENDOR_COUNT) { - fprintf(stderr, "VENDOR_COUNT_MAX not big enough for built-in vendor list.\n"); - exit(2); - } - - /* add the built-in vendors at the beginning of the array */ - memcpy(vendorIds, builtInVendorIds, sizeof(builtInVendorIds)); - - /* default array size is the number of built-in vendors */ - vendorIdCount = BUILT_IN_VENDOR_COUNT; - - if (VENDOR_COUNT_MAX == BUILT_IN_VENDOR_COUNT) - return; - - char temp[PATH_MAX]; - if (get_adb_usb_ini(temp, sizeof(temp)) == 0) { - FILE * f = fopen(temp, "rt"); - - if (f != NULL) { - /* The vendor id file is pretty basic. 1 vendor id per line. - Lines starting with # are comments */ - while (fgets(temp, sizeof(temp), f) != NULL) { - if (temp[0] == '#') - continue; - - long value = strtol(temp, NULL, 0); - if (errno == EINVAL || errno == ERANGE || value > INT_MAX || value < 0) { - fprintf(stderr, "Invalid content in %s. Quitting.\n", ANDROID_ADB_INI); - exit(2); - } - - vendorIds[vendorIdCount++] = (int)value; - - /* make sure we don't go beyond the array */ - if (vendorIdCount == VENDOR_COUNT_MAX) { - break; - } - } - fclose(f); - } - } -} - -/* Utils methods */ - -/* builds the path to the adb vendor id file. returns 0 if success */ -int build_path(char* buff, size_t len, const char* format, const char* home) -{ - if (snprintf(buff, len, format, home, ANDROID_PATH, ANDROID_ADB_INI) >= (signed)len) { - return 1; - } - - return 0; -} - -/* fills buff with the path to the adb vendor id file. returns 0 if success */ -int get_adb_usb_ini(char* buff, size_t len) -{ -#ifdef _WIN32 - const char* home = getenv("ANDROID_SDK_HOME"); - if (home != NULL) { - return build_path(buff, len, "%s\\%s\\%s", home); - } else { - char path[MAX_PATH]; - SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, path); - return build_path(buff, len, "%s\\%s\\%s", path); - } -#else - const char* home = getenv("HOME"); - if (home == NULL) - home = "/tmp"; - - return build_path(buff, len, "%s/%s/%s", home); -#endif -} diff --git a/adb/usb_windows.c b/adb/usb_windows.cpp index a2d7226..d2bd58c 100644 --- a/adb/usb_windows.c +++ b/adb/usb_windows.cpp @@ -14,19 +14,21 @@ * limitations under the License. */ -#include <winsock2.h> -#include <windows.h> -#include <winerror.h> -#include <errno.h> -#include <usb100.h> +#define TRACE_TAG TRACE_USB + +#include "sysdeps.h" + +#include <winsock2.h> // winsock.h *must* be included before windows.h. #include <adb_api.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> +#include <usb100.h> +#include <windows.h> +#include <winerror.h> -#include "sysdeps.h" - -#define TRACE_TAG TRACE_USB #include "adb.h" +#include "transport.h" /** Structure usb_handle describes our connection to the usb device via AdbWinApi.dll. This structure is returned from usb_open() routine and diff --git a/adf/libadf/Android.mk b/adf/libadf/Android.mk index 908aa6c..7df354b 100644 --- a/adf/libadf/Android.mk +++ b/adf/libadf/Android.mk @@ -18,6 +18,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := adf.c LOCAL_MODULE := libadf LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS += -Werror LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS) include $(BUILD_STATIC_LIBRARY) diff --git a/adf/libadf/adf.c b/adf/libadf/adf.c index 1d19152..66c329c 100644 --- a/adf/libadf/adf.c +++ b/adf/libadf/adf.c @@ -17,9 +17,11 @@ #include <dirent.h> #include <errno.h> #include <fcntl.h> +#include <malloc.h> #include <stdint.h> #include <stdio.h> #include <string.h> +#include <unistd.h> #include <linux/limits.h> diff --git a/adf/libadf/tests/Android.mk b/adf/libadf/tests/Android.mk new file mode 100644 index 0000000..68e5817 --- /dev/null +++ b/adf/libadf/tests/Android.mk @@ -0,0 +1,23 @@ +# +# Copyright (C) 2013 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. +# +LOCAL_PATH := $(my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := adf_test.cpp +LOCAL_MODULE := adf-unit-tests +LOCAL_STATIC_LIBRARIES := libadf +LOCAL_CFLAGS += -Werror +include $(BUILD_NATIVE_TEST) diff --git a/adf/libadf/tests/adf_test.cpp b/adf/libadf/tests/adf_test.cpp new file mode 100644 index 0000000..01b2785 --- /dev/null +++ b/adf/libadf/tests/adf_test.cpp @@ -0,0 +1,342 @@ +/* + * Copyright (C) 2013 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 <adf/adf.h> +#include <gtest/gtest.h> +#include <sys/mman.h> + +class AdfTest : public testing::Test { +public: + AdfTest() : intf_id(0), intf(-1), eng_id(0), eng(-1) { } + + virtual void SetUp() { + int err = adf_device_open(dev_id, O_RDWR, &dev); + ASSERT_GE(err, 0) << "opening ADF device " << dev_id << + " failed: " << strerror(-err); + + err = adf_find_simple_post_configuration(&dev, fmt8888, n_fmt8888, + &intf_id, &eng_id); + ASSERT_GE(err, 0) << "finding ADF configuration failed: " << + strerror(-err); + + intf = adf_interface_open(&dev, intf_id, O_RDWR); + ASSERT_GE(intf, 0) << "opening ADF interface " << dev_id << "." << + intf_id << " failed: " << strerror(-intf); + + eng = adf_overlay_engine_open(&dev, eng_id, O_RDWR); + ASSERT_GE(eng, 0) << "opening ADF overlay engine " << dev_id << "." << + eng_id << " failed: " << strerror(-eng); + } + + virtual void TearDown() { + if (eng >= 0) + close(eng); + if (intf >= 0) + close(intf); + adf_device_close(&dev); + } + + void get8888Format(uint32_t &fmt, char fmt_str[ADF_FORMAT_STR_SIZE]) { + adf_overlay_engine_data data; + int err = adf_get_overlay_engine_data(eng, &data); + ASSERT_GE(err, 0) << "getting ADF overlay engine data failed: " << + strerror(-err); + + for (size_t i = 0; i < data.n_supported_formats; i++) { + for (size_t j = 0; j < n_fmt8888; j++) { + if (data.supported_formats[i] == fmt8888[j]) { + fmt = data.supported_formats[i]; + adf_format_str(fmt, fmt_str); + adf_free_overlay_engine_data(&data); + return; + } + } + } + + adf_free_overlay_engine_data(&data); + FAIL(); /* this should never happen */ + } + + void drawCheckerboard(void *buf, uint32_t w, uint32_t h, uint32_t pitch) { + uint8_t *buf8 = reinterpret_cast<uint8_t *>(buf); + for (uint32_t y = 0; y < h / 2; y++) { + uint32_t *scanline = reinterpret_cast<uint32_t *>(buf8 + y * pitch); + for (uint32_t x = 0; x < w / 2; x++) + scanline[x] = 0xFF0000FF; + for (uint32_t x = w / 2; x < w; x++) + scanline[x] = 0xFF00FFFF; + } + for (uint32_t y = h / 2; y < h; y++) { + uint32_t *scanline = reinterpret_cast<uint32_t *>(buf8 + y * pitch); + for (uint32_t x = 0; x < w / 2; x++) + scanline[x] = 0xFFFF00FF; + for (uint32_t x = w / 2; x < w; x++) + scanline[x] = 0xFFFFFFFF; + } + } + + /* various helpers to call ADF and die on failure */ + + void getInterfaceData(adf_interface_data &data) { + int err = adf_get_interface_data(intf, &data); + ASSERT_GE(err, 0) << "getting ADF interface data failed: " << + strerror(-err); + } + + void getCurrentMode(uint32_t &w, uint32_t &h) { + adf_interface_data data; + ASSERT_NO_FATAL_FAILURE(getInterfaceData(data)); + w = data.current_mode.hdisplay; + h = data.current_mode.vdisplay; + adf_free_interface_data(&data); + } + + void blank(uint8_t mode) { + int err = adf_interface_blank(intf, mode); + ASSERT_FALSE(err < 0 && err != -EBUSY) << + "unblanking interface failed: " << strerror(-err); + } + + void attach() { + int err = adf_device_attach(&dev, eng_id, intf_id); + ASSERT_FALSE(err < 0 && err != -EALREADY) << + "attaching overlay engine " << eng_id << " to interface " << + intf_id << " failed: " << strerror(-err); + } + + void detach() { + int err = adf_device_detach(&dev, eng_id, intf_id); + ASSERT_FALSE(err < 0 && err != -EINVAL) << + "detaching overlay engine " << eng_id << " from interface " << + intf_id << " failed: " << strerror(-err); + } + + void readVsyncTimestamp(uint64_t ×tamp) { + adf_event *event; + int err = adf_read_event(intf, &event); + ASSERT_GE(err, 0) << "reading ADF event failed: " << strerror(-err); + + ASSERT_EQ(ADF_EVENT_VSYNC, event->type); + ASSERT_EQ(sizeof(adf_vsync_event), event->length); + + adf_vsync_event *vsync_event = + reinterpret_cast<adf_vsync_event *>(event); + timestamp = vsync_event->timestamp; + free(event); + } + +protected: + adf_device dev; + adf_id_t intf_id; + int intf; + adf_id_t eng_id; + int eng; + +private: + const static adf_id_t dev_id = 0; + const static __u32 fmt8888[]; + const static size_t n_fmt8888; +}; + +const __u32 AdfTest::fmt8888[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_RGBX8888, + DRM_FORMAT_BGRX8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGBA8888, + DRM_FORMAT_BGRA8888 +}; +const size_t AdfTest::n_fmt8888 = sizeof(fmt8888) / sizeof(fmt8888[0]); + +TEST(adf, devices) { + adf_id_t *devs; + ssize_t n_devs = adf_devices(&devs); + free(devs); + + ASSERT_GE(n_devs, 0) << "enumerating ADF devices failed: " << + strerror(-n_devs); + ASSERT_TRUE(devs != NULL); +} + +TEST_F(AdfTest, device_data) { + adf_device_data data; + int err = adf_get_device_data(&dev, &data); + ASSERT_GE(err, 0) << "getting ADF device data failed: " << strerror(-err); + + EXPECT_LT(data.n_attachments, ADF_MAX_ATTACHMENTS); + EXPECT_GT(data.n_allowed_attachments, 0U); + EXPECT_LT(data.n_allowed_attachments, ADF_MAX_ATTACHMENTS); + EXPECT_LT(data.custom_data_size, (size_t)ADF_MAX_CUSTOM_DATA_SIZE); + adf_free_device_data(&data); +} + +TEST_F(AdfTest, interface_data) { + adf_interface_data data; + ASSERT_NO_FATAL_FAILURE(getInterfaceData(data)); + + EXPECT_LT(data.type, ADF_INTF_TYPE_MAX); + EXPECT_LE(data.dpms_state, DRM_MODE_DPMS_OFF); + EXPECT_EQ(1, data.hotplug_detect); + EXPECT_GT(data.n_available_modes, 0U); + EXPECT_LT(data.custom_data_size, (size_t)ADF_MAX_CUSTOM_DATA_SIZE); + adf_free_interface_data(&data); +} + +TEST_F(AdfTest, overlay_engine_data) { + adf_overlay_engine_data data; + int err = adf_get_overlay_engine_data(eng, &data); + ASSERT_GE(err, 0) << "getting ADF overlay engine failed: " << + strerror(-err); + + EXPECT_GT(data.n_supported_formats, 0U); + EXPECT_LT(data.n_supported_formats, ADF_MAX_SUPPORTED_FORMATS); + EXPECT_LT(data.custom_data_size, (size_t)ADF_MAX_CUSTOM_DATA_SIZE); + adf_free_overlay_engine_data(&data); +} + +TEST_F(AdfTest, blank) { + int err = adf_interface_blank(intf, (uint8_t)-1); + EXPECT_EQ(-EINVAL, err) << "setting bogus DPMS mode should have failed"; + + err = adf_interface_blank(eng, DRM_MODE_DPMS_OFF); + EXPECT_EQ(-EINVAL, err) << "blanking overlay engine should have failed"; + + ASSERT_NO_FATAL_FAILURE(blank(DRM_MODE_DPMS_OFF)); + err = adf_interface_blank(intf, DRM_MODE_DPMS_OFF); + EXPECT_EQ(-EBUSY, err) << "blanking interface twice should have failed"; + + ASSERT_NO_FATAL_FAILURE(blank(DRM_MODE_DPMS_ON)); + err = adf_interface_blank(intf, DRM_MODE_DPMS_ON); + EXPECT_EQ(-EBUSY, err) << "unblanking interface twice should have failed"; + + adf_interface_data data; + ASSERT_NO_FATAL_FAILURE(getInterfaceData(data)); + EXPECT_EQ(DRM_MODE_DPMS_ON, data.dpms_state); + adf_free_interface_data(&data); +} + +TEST_F(AdfTest, event) { + int err = adf_set_event(intf, ADF_EVENT_TYPE_MAX, true); + EXPECT_EQ(-EINVAL, err) << "enabling bogus ADF event should have failed"; + + err = adf_set_event(intf, ADF_EVENT_TYPE_MAX, false); + EXPECT_EQ(-EINVAL, err) << "disabling bogus ADF event should have failed"; + + err = adf_set_event(intf, ADF_EVENT_VSYNC, true); + ASSERT_GE(err, 0) << "enabling vsync event failed: " << strerror(-err); + + err = adf_set_event(intf, ADF_EVENT_VSYNC, true); + EXPECT_EQ(-EALREADY, err) << + "enabling vsync event twice should have failed"; + + ASSERT_NO_FATAL_FAILURE(blank(DRM_MODE_DPMS_ON)); + + uint64_t timestamp1, timestamp2; + ASSERT_NO_FATAL_FAILURE(readVsyncTimestamp(timestamp1)); + ASSERT_NO_FATAL_FAILURE(readVsyncTimestamp(timestamp2)); + EXPECT_GT(timestamp2, timestamp1); + + err = adf_set_event(intf, ADF_EVENT_VSYNC, false); + EXPECT_GE(err, 0) << "disabling vsync event failed: " << strerror(-err); + + err = adf_set_event(intf, ADF_EVENT_VSYNC, false); + EXPECT_EQ(-EALREADY, err) << + "disabling vsync event twice should have failed"; +} + +TEST_F(AdfTest, attach) { + ASSERT_NO_FATAL_FAILURE(attach()); + int err = adf_device_attach(&dev, eng_id, intf_id); + EXPECT_EQ(-EALREADY, err) << "attaching overlay engine " << eng_id << + " to interface " << intf_id << " twice should have failed"; + + ASSERT_NO_FATAL_FAILURE(detach()); + err = adf_device_detach(&dev, eng_id, intf_id); + EXPECT_EQ(-EINVAL, err) << "detaching overlay engine " << eng_id << + " from interface " << intf_id << " twice should have failed"; + + err = adf_device_attach(&dev, eng_id, ADF_MAX_INTERFACES); + EXPECT_EQ(-EINVAL, err) << "attaching overlay engine " << eng_id << + " to bogus interface should have failed"; + + err = adf_device_detach(&dev, eng_id, ADF_MAX_INTERFACES); + EXPECT_EQ(-EINVAL, err) << "detaching overlay engine " << eng_id << + " from bogus interface should have failed"; +} + +TEST_F(AdfTest, simple_buffer_alloc) { + uint32_t w = 0, h = 0; + ASSERT_NO_FATAL_FAILURE(getCurrentMode(w, h)); + + uint32_t format; + char format_str[ADF_FORMAT_STR_SIZE]; + ASSERT_NO_FATAL_FAILURE(get8888Format(format, format_str)); + + uint32_t offset; + uint32_t pitch; + int buf_fd = adf_interface_simple_buffer_alloc(intf, w, h, format, &offset, + &pitch); + EXPECT_GE(buf_fd, 0) << "allocating " << w << "x" << h << " " << + format_str << " buffer failed: " << strerror(-buf_fd); + EXPECT_GE(pitch, w * 4); + close(buf_fd); + + buf_fd = adf_interface_simple_buffer_alloc(intf, w, h, 0xDEADBEEF, &offset, + &pitch); + /* n.b.: ADF only allows simple buffers with built-in RGB formats, + so this should fail even if a driver supports custom format 0xDEADBEEF */ + EXPECT_EQ(-EINVAL, buf_fd) << + "allocating buffer with bogus format should have failed"; +} + +TEST_F(AdfTest, simple_buffer) { + uint32_t w = 0, h = 0; + ASSERT_NO_FATAL_FAILURE(getCurrentMode(w, h)); + + uint32_t format = 0; + char format_str[ADF_FORMAT_STR_SIZE]; + ASSERT_NO_FATAL_FAILURE(get8888Format(format, format_str)); + + uint32_t offset; + uint32_t pitch; + int buf_fd = adf_interface_simple_buffer_alloc(intf, w, h, format, &offset, + &pitch); + ASSERT_GE(buf_fd, 0) << "allocating " << w << "x" << h << " " << + format_str << " buffer failed: " << strerror(-buf_fd); + EXPECT_GE(pitch, w * 4); + + void *mapped = mmap(NULL, pitch * h, PROT_WRITE, MAP_SHARED, buf_fd, + offset); + ASSERT_NE(mapped, MAP_FAILED) << "mapping " << w << "x" << h << " " << + format_str << " buffer failed: " << strerror(-errno); + drawCheckerboard(mapped, w, h, pitch); + munmap(mapped, pitch * h); + + ASSERT_NO_FATAL_FAILURE(attach()); + ASSERT_NO_FATAL_FAILURE(blank(DRM_MODE_DPMS_ON)); + + int release_fence = adf_interface_simple_post(intf, eng_id, w, h, format, + buf_fd, offset, pitch, -1); + close(buf_fd); + ASSERT_GE(release_fence, 0) << "posting " << w << "x" << h << " " << + format_str << " buffer failed: " << strerror(-release_fence); + close(release_fence); +} diff --git a/adf/libadfhwc/Android.mk b/adf/libadfhwc/Android.mk index acea322..898f9c9 100644 --- a/adf/libadfhwc/Android.mk +++ b/adf/libadfhwc/Android.mk @@ -19,7 +19,7 @@ LOCAL_SRC_FILES := adfhwc.cpp LOCAL_MODULE := libadfhwc LOCAL_MODULE_TAGS := optional LOCAL_STATIC_LIBRARIES := libadf liblog libutils -LOCAL_CFLAGS += -DLOG_TAG=\"adfhwc\" +LOCAL_CFLAGS += -DLOG_TAG=\"adfhwc\" -Werror LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS) include $(BUILD_STATIC_LIBRARY) diff --git a/adf/libadfhwc/adfhwc.cpp b/adf/libadfhwc/adfhwc.cpp index 57e09eb..21f245e 100644 --- a/adf/libadfhwc/adfhwc.cpp +++ b/adf/libadfhwc/adfhwc.cpp @@ -15,6 +15,7 @@ */ #include <fcntl.h> +#include <malloc.h> #include <poll.h> #include <pthread.h> #include <sys/resource.h> diff --git a/base/.clang-format b/base/.clang-format new file mode 100644 index 0000000..2b83a1f --- /dev/null +++ b/base/.clang-format @@ -0,0 +1,11 @@ +BasedOnStyle: Google +AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: false + +CommentPragmas: NOLINT:.* +DerivePointerAlignment: false +IndentWidth: 2 +PointerAlignment: Left +TabWidth: 2 +UseTab: Never +PenaltyExcessCharacter: 32 diff --git a/base/Android.mk b/base/Android.mk new file mode 100644 index 0000000..ad85c6b --- /dev/null +++ b/base/Android.mk @@ -0,0 +1,109 @@ +# +# Copyright (C) 2015 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. +# + +LOCAL_PATH := $(call my-dir) + +libbase_src_files := \ + file.cpp \ + stringprintf.cpp \ + strings.cpp \ + +libbase_test_src_files := \ + file_test.cpp \ + stringprintf_test.cpp \ + strings_test.cpp \ + test_main.cpp \ + test_utils.cpp \ + +libbase_cppflags := \ + -Wall \ + -Wextra \ + -Werror \ + +# Device +# ------------------------------------------------------------------------------ +include $(CLEAR_VARS) +LOCAL_MODULE := libbase +LOCAL_CLANG := true +LOCAL_SRC_FILES := $(libbase_src_files) logging.cpp +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include +LOCAL_CPPFLAGS := $(libbase_cppflags) +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +LOCAL_STATIC_LIBRARIES := libcutils +LOCAL_MULTILIB := both +include $(BUILD_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := libbase +LOCAL_CLANG := true +LOCAL_WHOLE_STATIC_LIBRARIES := libbase +LOCAL_SHARED_LIBRARIES := liblog +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +LOCAL_SHARED_LIBRARIES := libcutils +LOCAL_MULTILIB := both +include $(BUILD_SHARED_LIBRARY) + +# Host +# ------------------------------------------------------------------------------ +include $(CLEAR_VARS) +LOCAL_MODULE := libbase +LOCAL_SRC_FILES := $(libbase_src_files) +ifneq ($(HOST_OS),windows) + LOCAL_SRC_FILES += logging.cpp +endif +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include +LOCAL_CPPFLAGS := $(libbase_cppflags) +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +LOCAL_STATIC_LIBRARIES := libcutils +LOCAL_MULTILIB := both +include $(BUILD_HOST_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := libbase +LOCAL_WHOLE_STATIC_LIBRARIES := libbase +LOCAL_SHARED_LIBRARIES := liblog +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +LOCAL_STATIC_LIBRARIES := libcutils +LOCAL_MULTILIB := both +include $(BUILD_HOST_SHARED_LIBRARY) + +# Tests +# ------------------------------------------------------------------------------ +include $(CLEAR_VARS) +LOCAL_MODULE := libbase_test +LOCAL_CLANG := true +LOCAL_SRC_FILES := $(libbase_test_src_files) logging_test.cpp +LOCAL_C_INCLUDES := $(LOCAL_PATH) +LOCAL_CPPFLAGS := $(libbase_cppflags) +LOCAL_SHARED_LIBRARIES := libbase +LOCAL_MULTILIB := both +LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 +LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 +include $(BUILD_NATIVE_TEST) + +include $(CLEAR_VARS) +LOCAL_MODULE := libbase_test +LOCAL_SRC_FILES := $(libbase_test_src_files) +ifneq ($(HOST_OS),windows) + LOCAL_SRC_FILES += logging_test.cpp +endif +LOCAL_C_INCLUDES := $(LOCAL_PATH) +LOCAL_CPPFLAGS := $(libbase_cppflags) +LOCAL_SHARED_LIBRARIES := libbase +LOCAL_MULTILIB := both +LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 +LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 +include $(BUILD_HOST_NATIVE_TEST) diff --git a/base/CPPLINT.cfg b/base/CPPLINT.cfg new file mode 100644 index 0000000..d94a89c --- /dev/null +++ b/base/CPPLINT.cfg @@ -0,0 +1,2 @@ +set noparent +filter=-build/header_guard,-build/include,-build/c++11,-whitespace/operators diff --git a/base/file.cpp b/base/file.cpp new file mode 100644 index 0000000..6b19818 --- /dev/null +++ b/base/file.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2015 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 "base/file.h" + +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <string> + +#include "base/macros.h" // For TEMP_FAILURE_RETRY on Darwin. +#define LOG_TAG "base.file" +#include "cutils/log.h" +#include "utils/Compat.h" + +namespace android { +namespace base { + +bool ReadFdToString(int fd, std::string* content) { + content->clear(); + + char buf[BUFSIZ]; + ssize_t n; + while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) { + content->append(buf, n); + } + return (n == 0) ? true : false; +} + +bool ReadFileToString(const std::string& path, std::string* content) { + content->clear(); + + int fd = + TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); + if (fd == -1) { + return false; + } + bool result = ReadFdToString(fd, content); + TEMP_FAILURE_RETRY(close(fd)); + return result; +} + +bool WriteStringToFd(const std::string& content, int fd) { + const char* p = content.data(); + size_t left = content.size(); + while (left > 0) { + ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, left)); + if (n == -1) { + return false; + } + p += n; + left -= n; + } + return true; +} + +static bool CleanUpAfterFailedWrite(const std::string& path) { + // Something went wrong. Let's not leave a corrupt file lying around. + int saved_errno = errno; + unlink(path.c_str()); + errno = saved_errno; + return false; +} + +#if !defined(_WIN32) +bool WriteStringToFile(const std::string& content, const std::string& path, + mode_t mode, uid_t owner, gid_t group) { + int fd = TEMP_FAILURE_RETRY( + open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, + mode)); + if (fd == -1) { + ALOGE("android::WriteStringToFile open failed: %s", strerror(errno)); + return false; + } + + // We do an explicit fchmod here because we assume that the caller really + // meant what they said and doesn't want the umask-influenced mode. + if (fchmod(fd, mode) == -1) { + ALOGE("android::WriteStringToFile fchmod failed: %s", strerror(errno)); + return CleanUpAfterFailedWrite(path); + } + if (fchown(fd, owner, group) == -1) { + ALOGE("android::WriteStringToFile fchown failed: %s", strerror(errno)); + return CleanUpAfterFailedWrite(path); + } + if (!WriteStringToFd(content, fd)) { + ALOGE("android::WriteStringToFile write failed: %s", strerror(errno)); + return CleanUpAfterFailedWrite(path); + } + TEMP_FAILURE_RETRY(close(fd)); + return true; +} +#endif + +bool WriteStringToFile(const std::string& content, const std::string& path) { + int fd = TEMP_FAILURE_RETRY( + open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, + DEFFILEMODE)); + if (fd == -1) { + return false; + } + + bool result = WriteStringToFd(content, fd); + TEMP_FAILURE_RETRY(close(fd)); + return result || CleanUpAfterFailedWrite(path); +} + +bool ReadFully(int fd, void* data, size_t byte_count) { + uint8_t* p = reinterpret_cast<uint8_t*>(data); + size_t remaining = byte_count; + while (remaining > 0) { + ssize_t n = TEMP_FAILURE_RETRY(read(fd, p, remaining)); + if (n <= 0) return false; + p += n; + remaining -= n; + } + return true; +} + +bool WriteFully(int fd, const void* data, size_t byte_count) { + const uint8_t* p = reinterpret_cast<const uint8_t*>(data); + size_t remaining = byte_count; + while (remaining > 0) { + ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, remaining)); + if (n == -1) return false; + p += n; + remaining -= n; + } + return true; +} + +} // namespace base +} // namespace android diff --git a/base/file_test.cpp b/base/file_test.cpp new file mode 100644 index 0000000..e5cf696 --- /dev/null +++ b/base/file_test.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2013 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 "base/file.h" + +#include <gtest/gtest.h> + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include <string> + +#include "test_utils.h" + +TEST(file, ReadFileToString_ENOENT) { + std::string s("hello"); + errno = 0; + ASSERT_FALSE(android::base::ReadFileToString("/proc/does-not-exist", &s)); + EXPECT_EQ(ENOENT, errno); + EXPECT_EQ("", s); // s was cleared. +} + +TEST(file, ReadFileToString_success) { + std::string s("hello"); + ASSERT_TRUE(android::base::ReadFileToString("/proc/version", &s)) << errno; + EXPECT_GT(s.length(), 6U); + EXPECT_EQ('\n', s[s.length() - 1]); + s[5] = 0; + EXPECT_STREQ("Linux", s.c_str()); +} + +TEST(file, WriteStringToFile) { + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.filename)) << errno; + std::string s; + ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s)) << errno; + EXPECT_EQ("abc", s); +} + +TEST(file, WriteStringToFile2) { + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.filename, 0660, + getuid(), getgid())) + << errno; + struct stat sb; + ASSERT_EQ(0, stat(tf.filename, &sb)); + ASSERT_EQ(0660U, (sb.st_mode & ~S_IFMT)); + ASSERT_EQ(getuid(), sb.st_uid); + ASSERT_EQ(getgid(), sb.st_gid); + std::string s; + ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s)) << errno; + EXPECT_EQ("abc", s); +} + +TEST(file, WriteStringToFd) { + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd)); + + ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << errno; + + std::string s; + ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << errno; + EXPECT_EQ("abc", s); +} + +TEST(file, ReadFully) { + int fd = open("/proc/version", O_RDONLY); + ASSERT_NE(-1, fd) << strerror(errno); + + char buf[1024]; + memset(buf, 0, sizeof(buf)); + ASSERT_TRUE(android::base::ReadFully(fd, buf, 5)); + ASSERT_STREQ("Linux", buf); + + ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno); + + ASSERT_FALSE(android::base::ReadFully(fd, buf, sizeof(buf))); + + close(fd); +} + +TEST(file, WriteFully) { + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3)); + std::string s; + ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s)) << errno; + EXPECT_EQ("abc", s); +} diff --git a/base/include/base/file.h b/base/include/base/file.h new file mode 100644 index 0000000..acd29b3 --- /dev/null +++ b/base/include/base/file.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 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 BASE_FILE_H +#define BASE_FILE_H + +#include <sys/stat.h> +#include <string> + +namespace android { +namespace base { + +bool ReadFdToString(int fd, std::string* content); +bool ReadFileToString(const std::string& path, std::string* content); + +bool WriteStringToFile(const std::string& content, const std::string& path); +bool WriteStringToFd(const std::string& content, int fd); + +#if !defined(_WIN32) +bool WriteStringToFile(const std::string& content, const std::string& path, + mode_t mode, uid_t owner, gid_t group); +#endif + +bool ReadFully(int fd, void* data, size_t byte_count); +bool WriteFully(int fd, const void* data, size_t byte_count); + +} // namespace base +} // namespace android + +#endif // BASE_FILE_H diff --git a/base/include/base/logging.h b/base/include/base/logging.h new file mode 100644 index 0000000..230adb8 --- /dev/null +++ b/base/include/base/logging.h @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2015 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 BASE_LOGGING_H +#define BASE_LOGGING_H + +#include <functional> +#include <memory> +#include <ostream> + +#include "base/macros.h" + +namespace android { +namespace base { + +enum LogSeverity { + VERBOSE, + DEBUG, + INFO, + WARNING, + ERROR, + FATAL, +}; + +enum LogId { + DEFAULT, + MAIN, + SYSTEM, +}; + +typedef std::function<void(LogId, LogSeverity, const char*, const char*, + unsigned int, const char*)> LogFunction; + +extern void StderrLogger(LogId, LogSeverity, const char*, const char*, + unsigned int, const char*); + +#ifdef __ANDROID__ +// We expose this even though it is the default because a user that wants to +// override the default log buffer will have to construct this themselves. +class LogdLogger { + public: + explicit LogdLogger(LogId default_log_id = android::base::MAIN); + + void operator()(LogId, LogSeverity, const char* tag, const char* file, + unsigned int line, const char* message); + + private: + LogId default_log_id_; +}; +#endif + +// Configure logging based on ANDROID_LOG_TAGS environment variable. +// We need to parse a string that looks like +// +// *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i +// +// The tag (or '*' for the global level) comes first, followed by a colon and a +// letter indicating the minimum priority level we're expected to log. This can +// be used to reveal or conceal logs with specific tags. +extern void InitLogging(char* argv[], LogFunction&& logger); + +// Configures logging using the default logger (logd for the device, stderr for +// the host). +extern void InitLogging(char* argv[]); + +// Replace the current logger. +extern void SetLogger(LogFunction&& logger); + +// Logs a message to logcat on Android otherwise to stderr. If the severity is +// FATAL it also causes an abort. For example: +// +// LOG(FATAL) << "We didn't expect to reach here"; +#define LOG(severity) \ + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \ + ::android::base::severity, -1).stream() + +// Logs a message to logcat with the specified log ID on Android otherwise to +// stderr. If the severity is FATAL it also causes an abort. +#define LOG_TO(dest, severity) \ + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest, \ + ::android::base::severity, -1).stream() + +// A variant of LOG that also logs the current errno value. To be used when +// library calls fail. +#define PLOG(severity) \ + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \ + ::android::base::severity, errno).stream() + +// Behaves like PLOG, but logs to the specified log ID. +#define PLOG_TO(dest, severity) \ + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest, \ + ::android::base::severity, errno).stream() + +// Marker that code is yet to be implemented. +#define UNIMPLEMENTED(level) \ + LOG(level) << __PRETTY_FUNCTION__ << " unimplemented " + +// Check whether condition x holds and LOG(FATAL) if not. The value of the +// expression x is only evaluated once. Extra logging can be appended using << +// after. For example: +// +// CHECK(false == true) results in a log message of +// "Check failed: false == true". +#define CHECK(x) \ + if (UNLIKELY(!(x))) \ + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \ + ::android::base::FATAL, -1).stream() \ + << "Check failed: " #x << " " + +// Helper for CHECK_xx(x,y) macros. +#define CHECK_OP(LHS, RHS, OP) \ + for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS); \ + UNLIKELY(!(_values.lhs OP _values.rhs)); \ + /* empty */) \ + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \ + ::android::base::FATAL, -1).stream() \ + << "Check failed: " << #LHS << " " << #OP << " " << #RHS \ + << " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") " + +// Check whether a condition holds between x and y, LOG(FATAL) if not. The value +// of the expressions x and y is evaluated once. Extra logging can be appended +// using << after. For example: +// +// CHECK_NE(0 == 1, false) results in +// "Check failed: false != false (0==1=false, false=false) ". +#define CHECK_EQ(x, y) CHECK_OP(x, y, == ) +#define CHECK_NE(x, y) CHECK_OP(x, y, != ) +#define CHECK_LE(x, y) CHECK_OP(x, y, <= ) +#define CHECK_LT(x, y) CHECK_OP(x, y, < ) +#define CHECK_GE(x, y) CHECK_OP(x, y, >= ) +#define CHECK_GT(x, y) CHECK_OP(x, y, > ) + +// Helper for CHECK_STRxx(s1,s2) macros. +#define CHECK_STROP(s1, s2, sense) \ + if (UNLIKELY((strcmp(s1, s2) == 0) != sense)) \ + LOG(FATAL) << "Check failed: " \ + << "\"" << s1 << "\"" \ + << (sense ? " == " : " != ") << "\"" << s2 << "\"" + +// Check for string (const char*) equality between s1 and s2, LOG(FATAL) if not. +#define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true) +#define CHECK_STRNE(s1, s2) CHECK_STROP(s1, s2, false) + +// Perform the pthread function call(args), LOG(FATAL) on error. +#define CHECK_PTHREAD_CALL(call, args, what) \ + do { \ + int rc = call args; \ + if (rc != 0) { \ + errno = rc; \ + PLOG(FATAL) << #call << " failed for " << what; \ + } \ + } while (false) + +// CHECK that can be used in a constexpr function. For example: +// +// constexpr int half(int n) { +// return +// DCHECK_CONSTEXPR(n >= 0, , 0) +// CHECK_CONSTEXPR((n & 1) == 0), +// << "Extra debugging output: n = " << n, 0) +// n / 2; +// } +#define CHECK_CONSTEXPR(x, out, dummy) \ + (UNLIKELY(!(x))) \ + ? (LOG(FATAL) << "Check failed: " << #x out, dummy) \ + : + +// DCHECKs are debug variants of CHECKs only enabled in debug builds. Generally +// CHECK should be used unless profiling identifies a CHECK as being in +// performance critical code. +#if defined(NDEBUG) +static constexpr bool kEnableDChecks = false; +#else +static constexpr bool kEnableDChecks = true; +#endif + +#define DCHECK(x) \ + if (::android::base::kEnableDChecks) CHECK(x) +#define DCHECK_EQ(x, y) \ + if (::android::base::kEnableDChecks) CHECK_EQ(x, y) +#define DCHECK_NE(x, y) \ + if (::android::base::kEnableDChecks) CHECK_NE(x, y) +#define DCHECK_LE(x, y) \ + if (::android::base::kEnableDChecks) CHECK_LE(x, y) +#define DCHECK_LT(x, y) \ + if (::android::base::kEnableDChecks) CHECK_LT(x, y) +#define DCHECK_GE(x, y) \ + if (::android::base::kEnableDChecks) CHECK_GE(x, y) +#define DCHECK_GT(x, y) \ + if (::android::base::kEnableDChecks) CHECK_GT(x, y) +#define DCHECK_STREQ(s1, s2) \ + if (::android::base::kEnableDChecks) CHECK_STREQ(s1, s2) +#define DCHECK_STRNE(s1, s2) \ + if (::android::base::kEnableDChecks) CHECK_STRNE(s1, s2) +#if defined(NDEBUG) +#define DCHECK_CONSTEXPR(x, out, dummy) +#else +#define DCHECK_CONSTEXPR(x, out, dummy) CHECK_CONSTEXPR(x, out, dummy) +#endif + +// Temporary class created to evaluate the LHS and RHS, used with +// MakeEagerEvaluator to infer the types of LHS and RHS. +template <typename LHS, typename RHS> +struct EagerEvaluator { + EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) { + } + LHS lhs; + RHS rhs; +}; + +// Helper function for CHECK_xx. +template <typename LHS, typename RHS> +static inline EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) { + return EagerEvaluator<LHS, RHS>(lhs, rhs); +} + +// Explicitly instantiate EagerEvalue for pointers so that char*s aren't treated +// as strings. To compare strings use CHECK_STREQ and CHECK_STRNE. We rely on +// signed/unsigned warnings to protect you against combinations not explicitly +// listed below. +#define EAGER_PTR_EVALUATOR(T1, T2) \ + template <> \ + struct EagerEvaluator<T1, T2> { \ + EagerEvaluator(T1 l, T2 r) \ + : lhs(reinterpret_cast<const void*>(l)), \ + rhs(reinterpret_cast<const void*>(r)) { \ + } \ + const void* lhs; \ + const void* rhs; \ + } +EAGER_PTR_EVALUATOR(const char*, const char*); +EAGER_PTR_EVALUATOR(const char*, char*); +EAGER_PTR_EVALUATOR(char*, const char*); +EAGER_PTR_EVALUATOR(char*, char*); +EAGER_PTR_EVALUATOR(const unsigned char*, const unsigned char*); +EAGER_PTR_EVALUATOR(const unsigned char*, unsigned char*); +EAGER_PTR_EVALUATOR(unsigned char*, const unsigned char*); +EAGER_PTR_EVALUATOR(unsigned char*, unsigned char*); +EAGER_PTR_EVALUATOR(const signed char*, const signed char*); +EAGER_PTR_EVALUATOR(const signed char*, signed char*); +EAGER_PTR_EVALUATOR(signed char*, const signed char*); +EAGER_PTR_EVALUATOR(signed char*, signed char*); + +// Data for the log message, not stored in LogMessage to avoid increasing the +// stack size. +class LogMessageData; + +// A LogMessage is a temporarily scoped object used by LOG and the unlikely part +// of a CHECK. The destructor will abort if the severity is FATAL. +class LogMessage { + public: + LogMessage(const char* file, unsigned int line, LogId id, + LogSeverity severity, int error); + + ~LogMessage(); + + // Returns the stream associated with the message, the LogMessage performs + // output when it goes out of scope. + std::ostream& stream(); + + // The routine that performs the actual logging. + static void LogLine(const char* file, unsigned int line, LogId id, + LogSeverity severity, const char* msg); + + private: + const std::unique_ptr<LogMessageData> data_; + + DISALLOW_COPY_AND_ASSIGN(LogMessage); +}; + +// Allows to temporarily change the minimum severity level for logging. +class ScopedLogSeverity { + public: + explicit ScopedLogSeverity(LogSeverity level); + ~ScopedLogSeverity(); + + private: + LogSeverity old_; +}; + +} // namespace base +} // namespace android + +#endif // BASE_LOGGING_H diff --git a/base/include/base/macros.h b/base/include/base/macros.h new file mode 100644 index 0000000..b1ce7c6 --- /dev/null +++ b/base/include/base/macros.h @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2015 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 UTILS_MACROS_H +#define UTILS_MACROS_H + +#include <stddef.h> // for size_t +#include <unistd.h> // for TEMP_FAILURE_RETRY + +// bionic and glibc both have TEMP_FAILURE_RETRY, but eg Mac OS' libc doesn't. +#ifndef TEMP_FAILURE_RETRY +#define TEMP_FAILURE_RETRY(exp) \ + ({ \ + decltype(exp) _rc; \ + do { \ + _rc = (exp); \ + } while (_rc == -1 && errno == EINTR); \ + _rc; \ + }) +#endif + +// A macro to disallow the copy constructor and operator= functions +// This must be placed in the private: declarations for a class. +// +// For disallowing only assign or copy, delete the relevant operator or +// constructor, for example: +// void operator=(const TypeName&) = delete; +// Note, that most uses of DISALLOW_ASSIGN and DISALLOW_COPY are broken +// semantically, one should either use disallow both or neither. Try to +// avoid these in new code. +// +// When building with C++11 toolchains, just use the language support +// for explicitly deleted methods. +#if __cplusplus >= 201103L +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&) = delete; \ + void operator=(const TypeName&) = delete +#else +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) +#endif + +// A macro to disallow all the implicit constructors, namely the +// default constructor, copy constructor and operator= functions. +// +// This should be used in the private: declarations for a class +// that wants to prevent anyone from instantiating it. This is +// especially useful for classes containing only static methods. +#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ + TypeName(); \ + DISALLOW_COPY_AND_ASSIGN(TypeName) + +// The arraysize(arr) macro returns the # of elements in an array arr. +// The expression is a compile-time constant, and therefore can be +// used in defining new arrays, for example. If you use arraysize on +// a pointer by mistake, you will get a compile-time error. +// +// One caveat is that arraysize() doesn't accept any array of an +// anonymous type or a type defined inside a function. In these rare +// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is +// due to a limitation in C++'s template system. The limitation might +// eventually be removed, but it hasn't happened yet. + +// This template function declaration is used in defining arraysize. +// Note that the function doesn't need an implementation, as we only +// use its type. +template <typename T, size_t N> +char(&ArraySizeHelper(T(&array)[N]))[N]; // NOLINT(readability/casting) + +#define arraysize(array) (sizeof(ArraySizeHelper(array))) + +// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize, +// but can be used on anonymous types or types defined inside +// functions. It's less safe than arraysize as it accepts some +// (although not all) pointers. Therefore, you should use arraysize +// whenever possible. +// +// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type +// size_t. +// +// ARRAYSIZE_UNSAFE catches a few type errors. If you see a compiler error +// +// "warning: division by zero in ..." +// +// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer. +// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays. +// +// The following comments are on the implementation details, and can +// be ignored by the users. +// +// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in +// the array) and sizeof(*(arr)) (the # of bytes in one array +// element). If the former is divisible by the latter, perhaps arr is +// indeed an array, in which case the division result is the # of +// elements in the array. Otherwise, arr cannot possibly be an array, +// and we generate a compiler error to prevent the code from +// compiling. +// +// Since the size of bool is implementation-defined, we need to cast +// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final +// result has type size_t. +// +// This macro is not perfect as it wrongfully accepts certain +// pointers, namely where the pointer size is divisible by the pointee +// size. Since all our code has to go through a 32-bit compiler, +// where a pointer is 4 bytes, this means all pointers to a type whose +// size is 3 or greater than 4 will be (righteously) rejected. +#define ARRAYSIZE_UNSAFE(a) \ + ((sizeof(a) / sizeof(*(a))) / \ + static_cast<size_t>(!(sizeof(a) % sizeof(*(a))))) + +#define LIKELY(x) __builtin_expect((x), true) +#define UNLIKELY(x) __builtin_expect((x), false) + +#define WARN_UNUSED __attribute__((warn_unused_result)) + +// A deprecated function to call to create a false use of the parameter, for +// example: +// int foo(int x) { UNUSED(x); return 10; } +// to avoid compiler warnings. Going forward we prefer ATTRIBUTE_UNUSED. +template <typename... T> +void UNUSED(const T&...) { +} + +// An attribute to place on a parameter to a function, for example: +// int foo(int x ATTRIBUTE_UNUSED) { return 10; } +// to avoid compiler warnings. +#define ATTRIBUTE_UNUSED __attribute__((__unused__)) + +// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through +// between switch labels: +// switch (x) { +// case 40: +// case 41: +// if (truth_is_out_there) { +// ++x; +// FALLTHROUGH_INTENDED; // Use instead of/along with annotations in +// // comments. +// } else { +// return x; +// } +// case 42: +// ... +// +// As shown in the example above, the FALLTHROUGH_INTENDED macro should be +// followed by a semicolon. It is designed to mimic control-flow statements +// like 'break;', so it can be placed in most places where 'break;' can, but +// only if there are no statements on the execution path between it and the +// next switch label. +// +// When compiled with clang in C++11 mode, the FALLTHROUGH_INTENDED macro is +// expanded to [[clang::fallthrough]] attribute, which is analysed when +// performing switch labels fall-through diagnostic ('-Wimplicit-fallthrough'). +// See clang documentation on language extensions for details: +// http://clang.llvm.org/docs/LanguageExtensions.html#clang__fallthrough +// +// When used with unsupported compilers, the FALLTHROUGH_INTENDED macro has no +// effect on diagnostics. +// +// In either case this macro has no effect on runtime behavior and performance +// of code. +#if defined(__clang__) && __cplusplus >= 201103L && defined(__has_warning) +#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough") +#define FALLTHROUGH_INTENDED [[clang::fallthrough]] // NOLINT +#endif +#endif + +#ifndef FALLTHROUGH_INTENDED +#define FALLTHROUGH_INTENDED \ + do { \ + } while (0) +#endif + +#endif // UTILS_MACROS_H diff --git a/base/include/base/memory.h b/base/include/base/memory.h new file mode 100644 index 0000000..882582f --- /dev/null +++ b/base/include/base/memory.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 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 BASE_MEMORY_H +#define BASE_MEMORY_H + +namespace android { +namespace base { + +// Use packed structures for access to unaligned data on targets with alignment +// restrictions. The compiler will generate appropriate code to access these +// structures without generating alignment exceptions. +template <typename T> +static inline T get_unaligned(const T* address) { + struct unaligned { + T v; + } __attribute__((packed)); + const unaligned* p = reinterpret_cast<const unaligned*>(address); + return p->v; +} + +template <typename T> +static inline void put_unaligned(T* address, T v) { + struct unaligned { + T v; + } __attribute__((packed)); + unaligned* p = reinterpret_cast<unaligned*>(address); + p->v = v; +} + +} // namespace base +} // namespace android + +#endif // BASE_MEMORY_H diff --git a/base/include/base/stringprintf.h b/base/include/base/stringprintf.h new file mode 100644 index 0000000..195c1de --- /dev/null +++ b/base/include/base/stringprintf.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2011 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 BASE_STRINGPRINTF_H +#define BASE_STRINGPRINTF_H + +#include <stdarg.h> +#include <string> + +namespace android { +namespace base { + +// Returns a string corresponding to printf-like formatting of the arguments. +std::string StringPrintf(const char* fmt, ...) + __attribute__((__format__(__printf__, 1, 2))); + +// Appends a printf-like formatting of the arguments to 'dst'. +void StringAppendF(std::string* dst, const char* fmt, ...) + __attribute__((__format__(__printf__, 2, 3))); + +// Appends a printf-like formatting of the arguments to 'dst'. +void StringAppendV(std::string* dst, const char* format, va_list ap); + +} // namespace base +} // namespace android + +#endif // BASE_STRINGPRINTF_H diff --git a/base/include/base/strings.h b/base/include/base/strings.h new file mode 100644 index 0000000..3559342 --- /dev/null +++ b/base/include/base/strings.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 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 BASE_STRINGS_H +#define BASE_STRINGS_H + +#include <string> +#include <vector> + +namespace android { +namespace base { + +// Splits a string into a vector of strings. +// +// The string is split at each occurrence of a character in delimiters. +// +// Empty splits will be omitted. I.e. Split("a,,b", ",") -> {"a", "b"} +// +// The empty string is not a valid delimiter list. +std::vector<std::string> Split(const std::string& s, + const std::string& delimiters); + +// Trims whitespace off both ends of the given string. +std::string Trim(const std::string& s); + +// Joins a vector of strings into a single string, using the given separator. +template <typename StringT> +std::string Join(const std::vector<StringT>& strings, char separator); + +// Tests whether 's' starts with 'prefix'. +bool StartsWith(const std::string& s, const char* prefix); + +// Tests whether 's' ends with 'suffix'. +bool EndsWith(const std::string& s, const char* suffix); + +} // namespace base +} // namespace android + +#endif // BASE_STRINGS_H diff --git a/base/logging.cpp b/base/logging.cpp new file mode 100644 index 0000000..0142b70 --- /dev/null +++ b/base/logging.cpp @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2015 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 "base/logging.h" + +#include <libgen.h> + +// For getprogname(3) or program_invocation_short_name. +#if defined(__ANDROID__) || defined(__APPLE__) +#include <stdlib.h> +#elif defined(__GLIBC__) +#include <errno.h> +#endif + +#include <iostream> +#include <limits> +#include <mutex> +#include <sstream> +#include <string> +#include <utility> +#include <vector> + +#include "base/strings.h" +#include "cutils/threads.h" + +// Headers for LogMessage::LogLine. +#ifdef __ANDROID__ +#include <android/set_abort_message.h> +#include "cutils/log.h" +#else +#include <sys/types.h> +#include <unistd.h> +#endif + +namespace android { +namespace base { + +static std::mutex logging_lock; + +#ifdef __ANDROID__ +static LogFunction gLogger = LogdLogger(); +#else +static LogFunction gLogger = StderrLogger; +#endif + +static bool gInitialized = false; +static LogSeverity gMinimumLogSeverity = INFO; +static std::unique_ptr<std::string> gProgramInvocationName; + +#if defined(__GLIBC__) +static const char* getprogname() { + return program_invocation_short_name; +} +#endif + +static const char* ProgramInvocationName() { + if (gProgramInvocationName == nullptr) { + gProgramInvocationName.reset(new std::string(getprogname())); + } + + return gProgramInvocationName->c_str(); +} + +void StderrLogger(LogId, LogSeverity severity, const char*, const char* file, + unsigned int line, const char* message) { + static const char* log_characters = "VDIWEF"; + CHECK_EQ(strlen(log_characters), FATAL + 1U); + char severity_char = log_characters[severity]; + fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(), + severity_char, getpid(), gettid(), file, line, message); +} + + +#ifdef __ANDROID__ +LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) { +} + +static const android_LogPriority kLogSeverityToAndroidLogPriority[] = { + ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, + ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, +}; +static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1, + "Mismatch in size of kLogSeverityToAndroidLogPriority and values " + "in LogSeverity"); + +static const log_id kLogIdToAndroidLogId[] = { + LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM, +}; +static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1, + "Mismatch in size of kLogIdToAndroidLogId and values in LogId"); + +void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag, + const char* file, unsigned int line, + const char* message) { + int priority = kLogSeverityToAndroidLogPriority[severity]; + if (id == DEFAULT) { + id = default_log_id_; + } + + log_id lg_id = kLogIdToAndroidLogId[id]; + + if (priority == ANDROID_LOG_FATAL) { + __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line, + message); + } else { + __android_log_buf_print(lg_id, priority, tag, "%s", message); + } +} +#endif + +void InitLogging(char* argv[], LogFunction&& logger) { + SetLogger(std::forward<LogFunction>(logger)); + InitLogging(argv); +} + +void InitLogging(char* argv[]) { + if (gInitialized) { + return; + } + + gInitialized = true; + + // Stash the command line for later use. We can use /proc/self/cmdline on + // Linux to recover this, but we don't have that luxury on the Mac, and there + // are a couple of argv[0] variants that are commonly used. + if (argv != nullptr) { + gProgramInvocationName.reset(new std::string(basename(argv[0]))); + } + + const char* tags = getenv("ANDROID_LOG_TAGS"); + if (tags == nullptr) { + return; + } + + std::vector<std::string> specs = Split(tags, " "); + for (size_t i = 0; i < specs.size(); ++i) { + // "tag-pattern:[vdiwefs]" + std::string spec(specs[i]); + if (spec.size() == 3 && StartsWith(spec, "*:")) { + switch (spec[2]) { + case 'v': + gMinimumLogSeverity = VERBOSE; + continue; + case 'd': + gMinimumLogSeverity = DEBUG; + continue; + case 'i': + gMinimumLogSeverity = INFO; + continue; + case 'w': + gMinimumLogSeverity = WARNING; + continue; + case 'e': + gMinimumLogSeverity = ERROR; + continue; + case 'f': + gMinimumLogSeverity = FATAL; + continue; + // liblog will even suppress FATAL if you say 's' for silent, but that's + // crazy! + case 's': + gMinimumLogSeverity = FATAL; + continue; + } + } + LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags + << ")"; + } +} + +void SetLogger(LogFunction&& logger) { + std::lock_guard<std::mutex> lock(logging_lock); + gLogger = std::move(logger); +} + +// This indirection greatly reduces the stack impact of having lots of +// checks/logging in a function. +class LogMessageData { + public: + LogMessageData(const char* file, unsigned int line, LogId id, + LogSeverity severity, int error) + : file_(file), + line_number_(line), + id_(id), + severity_(severity), + error_(error) { + const char* last_slash = strrchr(file, '/'); + file = (last_slash == nullptr) ? file : last_slash + 1; + } + + const char* GetFile() const { + return file_; + } + + unsigned int GetLineNumber() const { + return line_number_; + } + + LogSeverity GetSeverity() const { + return severity_; + } + + LogId GetId() const { + return id_; + } + + int GetError() const { + return error_; + } + + std::ostream& GetBuffer() { + return buffer_; + } + + std::string ToString() const { + return buffer_.str(); + } + + private: + std::ostringstream buffer_; + const char* const file_; + const unsigned int line_number_; + const LogId id_; + const LogSeverity severity_; + const int error_; + + DISALLOW_COPY_AND_ASSIGN(LogMessageData); +}; + +LogMessage::LogMessage(const char* file, unsigned int line, LogId id, + LogSeverity severity, int error) + : data_(new LogMessageData(file, line, id, severity, error)) { +} + +LogMessage::~LogMessage() { + if (data_->GetSeverity() < gMinimumLogSeverity) { + return; // No need to format something we're not going to output. + } + + // Finish constructing the message. + if (data_->GetError() != -1) { + data_->GetBuffer() << ": " << strerror(data_->GetError()); + } + std::string msg(data_->ToString()); + + if (msg.find('\n') == std::string::npos) { + LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), + data_->GetSeverity(), msg.c_str()); + } else { + msg += '\n'; + size_t i = 0; + while (i < msg.size()) { + size_t nl = msg.find('\n', i); + msg[nl] = '\0'; + LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), + data_->GetSeverity(), &msg[i]); + i = nl + 1; + } + } + + // Abort if necessary. + if (data_->GetSeverity() == FATAL) { +#ifdef __ANDROID__ + android_set_abort_message(msg.c_str()); +#endif + abort(); + } +} + +std::ostream& LogMessage::stream() { + return data_->GetBuffer(); +} + +void LogMessage::LogLine(const char* file, unsigned int line, LogId id, + LogSeverity severity, const char* message) { + const char* tag = ProgramInvocationName(); + std::lock_guard<std::mutex> lock(logging_lock); + gLogger(id, severity, tag, file, line, message); +} + +ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) { + old_ = gMinimumLogSeverity; + gMinimumLogSeverity = level; +} + +ScopedLogSeverity::~ScopedLogSeverity() { + gMinimumLogSeverity = old_; +} + +} // namespace base +} // namespace android diff --git a/base/logging_test.cpp b/base/logging_test.cpp new file mode 100644 index 0000000..d947c1d --- /dev/null +++ b/base/logging_test.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2015 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 "base/logging.h" + +#include <regex> +#include <string> + +#include "base/file.h" +#include "base/stringprintf.h" +#include "test_utils.h" + +#include <gtest/gtest.h> + +#ifdef __ANDROID__ +#define HOST_TEST(suite, name) TEST(suite, DISABLED_ ## name) +#else +#define HOST_TEST(suite, name) TEST(suite, name) +#endif + +class CapturedStderr { + public: + CapturedStderr() : old_stderr_(-1) { + init(); + } + + ~CapturedStderr() { + reset(); + } + + int fd() const { + return temp_file_.fd; + } + + private: + void init() { + old_stderr_ = dup(STDERR_FILENO); + ASSERT_NE(-1, old_stderr_); + ASSERT_NE(-1, dup2(fd(), STDERR_FILENO)); + } + + void reset() { + ASSERT_NE(-1, dup2(old_stderr_, STDERR_FILENO)); + ASSERT_EQ(0, close(old_stderr_)); + } + + TemporaryFile temp_file_; + int old_stderr_; +}; + +TEST(logging, CHECK) { + ASSERT_DEATH(CHECK(false), "Check failed: false "); + CHECK(true); + + ASSERT_DEATH(CHECK_EQ(0, 1), "Check failed: 0 == 1 "); + CHECK_EQ(0, 0); + + ASSERT_DEATH(CHECK_STREQ("foo", "bar"), R"(Check failed: "foo" == "bar")"); + CHECK_STREQ("foo", "foo"); +} + +std::string make_log_pattern(android::base::LogSeverity severity, + const char* message) { + static const char* log_characters = "VDIWEF"; + char log_char = log_characters[severity]; + return android::base::StringPrintf( + "%c[[:space:]]+[[:digit:]]+[[:space:]]+[[:digit:]]+ " __FILE__ + ":[[:digit:]]+] %s", + log_char, message); +} + +TEST(logging, LOG) { + ASSERT_DEATH(LOG(FATAL) << "foobar", "foobar"); + + { + CapturedStderr cap; + LOG(WARNING) << "foobar"; + ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0)); + + std::string output; + android::base::ReadFdToString(cap.fd(), &output); + + std::regex message_regex( + make_log_pattern(android::base::WARNING, "foobar")); + ASSERT_TRUE(std::regex_search(output, message_regex)); + } + + { + CapturedStderr cap; + LOG(INFO) << "foobar"; + ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0)); + + std::string output; + android::base::ReadFdToString(cap.fd(), &output); + + std::regex message_regex( + make_log_pattern(android::base::INFO, "foobar")); + ASSERT_TRUE(std::regex_search(output, message_regex)); + } + + { + CapturedStderr cap; + LOG(DEBUG) << "foobar"; + ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0)); + + std::string output; + android::base::ReadFdToString(cap.fd(), &output); + ASSERT_TRUE(output.empty()); + } + + { + android::base::ScopedLogSeverity severity(android::base::DEBUG); + CapturedStderr cap; + LOG(DEBUG) << "foobar"; + ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0)); + + std::string output; + android::base::ReadFdToString(cap.fd(), &output); + + std::regex message_regex( + make_log_pattern(android::base::DEBUG, "foobar")); + ASSERT_TRUE(std::regex_search(output, message_regex)); + } +} + +TEST(logging, PLOG) { + { + CapturedStderr cap; + errno = ENOENT; + PLOG(INFO) << "foobar"; + ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0)); + + std::string output; + android::base::ReadFdToString(cap.fd(), &output); + + std::regex message_regex(make_log_pattern( + android::base::INFO, "foobar: No such file or directory")); + ASSERT_TRUE(std::regex_search(output, message_regex)); + } +} + +TEST(logging, UNIMPLEMENTED) { + { + CapturedStderr cap; + errno = ENOENT; + UNIMPLEMENTED(ERROR); + ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0)); + + std::string output; + android::base::ReadFdToString(cap.fd(), &output); + + std::string expected_message = + android::base::StringPrintf("%s unimplemented ", __PRETTY_FUNCTION__); + std::regex message_regex( + make_log_pattern(android::base::ERROR, expected_message.c_str())); + ASSERT_TRUE(std::regex_search(output, message_regex)); + } +} diff --git a/base/stringprintf.cpp b/base/stringprintf.cpp new file mode 100644 index 0000000..d55ff52 --- /dev/null +++ b/base/stringprintf.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2011 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 "base/stringprintf.h" + +#include <stdio.h> + +#include <string> + +namespace android { +namespace base { + +void StringAppendV(std::string* dst, const char* format, va_list ap) { + // First try with a small fixed size buffer + char space[1024]; + + // It's possible for methods that use a va_list to invalidate + // the data in it upon use. The fix is to make a copy + // of the structure before using it and use that copy instead. + va_list backup_ap; + va_copy(backup_ap, ap); + int result = vsnprintf(space, sizeof(space), format, backup_ap); + va_end(backup_ap); + + if (result < static_cast<int>(sizeof(space))) { + if (result >= 0) { + // Normal case -- everything fit. + dst->append(space, result); + return; + } + + if (result < 0) { + // Just an error. + return; + } + } + + // Increase the buffer size to the size requested by vsnprintf, + // plus one for the closing \0. + int length = result + 1; + char* buf = new char[length]; + + // Restore the va_list before we use it again + va_copy(backup_ap, ap); + result = vsnprintf(buf, length, format, backup_ap); + va_end(backup_ap); + + if (result >= 0 && result < length) { + // It fit + dst->append(buf, result); + } + delete[] buf; +} + +std::string StringPrintf(const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + std::string result; + StringAppendV(&result, fmt, ap); + va_end(ap); + return result; +} + +void StringAppendF(std::string* dst, const char* format, ...) { + va_list ap; + va_start(ap, format); + StringAppendV(dst, format, ap); + va_end(ap); +} + +} // namespace base +} // namespace android diff --git a/base/stringprintf_test.cpp b/base/stringprintf_test.cpp new file mode 100644 index 0000000..5cc2086 --- /dev/null +++ b/base/stringprintf_test.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 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 "base/stringprintf.h" + +#include <gtest/gtest.h> + +#include <string> + +TEST(StringPrintfTest, HexSizeT) { + size_t size = 0x00107e59; + EXPECT_EQ("00107e59", android::base::StringPrintf("%08zx", size)); + EXPECT_EQ("0x00107e59", android::base::StringPrintf("0x%08zx", size)); +} + +TEST(StringPrintfTest, StringAppendF) { + std::string s("a"); + android::base::StringAppendF(&s, "b"); + EXPECT_EQ("ab", s); +} + +TEST(StringPrintfTest, Errno) { + errno = 123; + android::base::StringPrintf("hello %s", "world"); + EXPECT_EQ(123, errno); +} + +void TestN(size_t n) { + char* buf = new char[n + 1]; + memset(buf, 'x', n); + buf[n] = '\0'; + std::string s(android::base::StringPrintf("%s", buf)); + EXPECT_EQ(buf, s); + delete[] buf; +} + +TEST(StringPrintfTest, At1023) { + TestN(1023); +} + +TEST(StringPrintfTest, At1024) { + TestN(1024); +} + +TEST(StringPrintfTest, At1025) { + TestN(1025); +} diff --git a/base/strings.cpp b/base/strings.cpp new file mode 100644 index 0000000..6f698d9 --- /dev/null +++ b/base/strings.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2015 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 "base/strings.h" + +#include <stdlib.h> +#include <string.h> + +#include <string> +#include <vector> + +namespace android { +namespace base { + +#define CHECK_NE(a, b) \ + if ((a) == (b)) abort(); + +std::vector<std::string> Split(const std::string& s, + const std::string& delimiters) { + CHECK_NE(delimiters.size(), 0U); + + std::vector<std::string> split; + if (s.size() == 0) { + // Split("", d) returns {} rather than {""}. + return split; + } + + size_t base = 0; + size_t found; + do { + found = s.find_first_of(delimiters, base); + if (found != base) { + split.push_back(s.substr(base, found - base)); + } + + base = found + 1; + } while (found != s.npos); + + return split; +} + +std::string Trim(const std::string& s) { + std::string result; + + if (s.size() == 0) { + return result; + } + + size_t start_index = 0; + size_t end_index = s.size() - 1; + + // Skip initial whitespace. + while (start_index < s.size()) { + if (!isspace(s[start_index])) { + break; + } + start_index++; + } + + // Skip terminating whitespace. + while (end_index >= start_index) { + if (!isspace(s[end_index])) { + break; + } + end_index--; + } + + // All spaces, no beef. + if (end_index < start_index) { + return ""; + } + // Start_index is the first non-space, end_index is the last one. + return s.substr(start_index, end_index - start_index + 1); +} + +template <typename StringT> +std::string Join(const std::vector<StringT>& strings, char separator) { + if (strings.empty()) { + return ""; + } + + std::string result(strings[0]); + for (size_t i = 1; i < strings.size(); ++i) { + result += separator; + result += strings[i]; + } + return result; +} + +// Explicit instantiations. +template std::string Join<std::string>(const std::vector<std::string>& strings, + char separator); +template std::string Join<const char*>(const std::vector<const char*>& strings, + char separator); + +bool StartsWith(const std::string& s, const char* prefix) { + return s.compare(0, strlen(prefix), prefix) == 0; +} + +bool EndsWith(const std::string& s, const char* suffix) { + size_t suffix_length = strlen(suffix); + size_t string_length = s.size(); + if (suffix_length > string_length) { + return false; + } + size_t offset = string_length - suffix_length; + return s.compare(offset, suffix_length, suffix) == 0; +} + +} // namespace base +} // namespace android diff --git a/base/strings_test.cpp b/base/strings_test.cpp new file mode 100644 index 0000000..1bf07a1 --- /dev/null +++ b/base/strings_test.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2015 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 "base/strings.h" + +#include <gtest/gtest.h> + +#include <string> +#include <vector> + +TEST(strings, split_empty) { + std::vector<std::string> parts = android::base::Split("", ","); + ASSERT_EQ(0U, parts.size()); +} + +TEST(strings, split_single) { + std::vector<std::string> parts = android::base::Split("foo", ","); + ASSERT_EQ(1U, parts.size()); + ASSERT_EQ("foo", parts[0]); +} + +TEST(strings, split_simple) { + std::vector<std::string> parts = android::base::Split("foo,bar,baz", ","); + ASSERT_EQ(3U, parts.size()); + ASSERT_EQ("foo", parts[0]); + ASSERT_EQ("bar", parts[1]); + ASSERT_EQ("baz", parts[2]); +} + +TEST(strings, split_with_empty_part) { + std::vector<std::string> parts = android::base::Split("foo,,bar", ","); + ASSERT_EQ(2U, parts.size()); + ASSERT_EQ("foo", parts[0]); + ASSERT_EQ("bar", parts[1]); +} + +TEST(strings, split_null_char) { + std::vector<std::string> parts = + android::base::Split(std::string("foo\0bar", 7), std::string("\0", 1)); + ASSERT_EQ(2U, parts.size()); + ASSERT_EQ("foo", parts[0]); + ASSERT_EQ("bar", parts[1]); +} + +TEST(strings, split_any) { + std::vector<std::string> parts = android::base::Split("foo:bar,baz", ",:"); + ASSERT_EQ(3U, parts.size()); + ASSERT_EQ("foo", parts[0]); + ASSERT_EQ("bar", parts[1]); + ASSERT_EQ("baz", parts[2]); +} + +TEST(strings, split_any_with_empty_part) { + std::vector<std::string> parts = android::base::Split("foo:,bar", ",:"); + ASSERT_EQ(2U, parts.size()); + ASSERT_EQ("foo", parts[0]); + ASSERT_EQ("bar", parts[1]); +} + +TEST(strings, trim_empty) { + ASSERT_EQ("", android::base::Trim("")); +} + +TEST(strings, trim_already_trimmed) { + ASSERT_EQ("foo", android::base::Trim("foo")); +} + +TEST(strings, trim_left) { + ASSERT_EQ("foo", android::base::Trim(" foo")); +} + +TEST(strings, trim_right) { + ASSERT_EQ("foo", android::base::Trim("foo ")); +} + +TEST(strings, trim_both) { + ASSERT_EQ("foo", android::base::Trim(" foo ")); +} + +TEST(strings, trim_no_trim_middle) { + ASSERT_EQ("foo bar", android::base::Trim("foo bar")); +} + +TEST(strings, trim_other_whitespace) { + ASSERT_EQ("foo", android::base::Trim("\v\tfoo\n\f")); +} + +TEST(strings, join_nothing) { + std::vector<std::string> list = {}; + ASSERT_EQ("", android::base::Join(list, ',')); +} + +TEST(strings, join_single) { + std::vector<std::string> list = {"foo"}; + ASSERT_EQ("foo", android::base::Join(list, ',')); +} + +TEST(strings, join_simple) { + std::vector<std::string> list = {"foo", "bar", "baz"}; + ASSERT_EQ("foo,bar,baz", android::base::Join(list, ',')); +} + +TEST(strings, join_separator_in_vector) { + std::vector<std::string> list = {",", ","}; + ASSERT_EQ(",,,", android::base::Join(list, ',')); +} + +TEST(strings, startswith_empty) { + ASSERT_FALSE(android::base::StartsWith("", "foo")); + ASSERT_TRUE(android::base::StartsWith("", "")); +} + +TEST(strings, startswith_simple) { + ASSERT_TRUE(android::base::StartsWith("foo", "")); + ASSERT_TRUE(android::base::StartsWith("foo", "f")); + ASSERT_TRUE(android::base::StartsWith("foo", "fo")); + ASSERT_TRUE(android::base::StartsWith("foo", "foo")); +} + +TEST(strings, startswith_prefix_too_long) { + ASSERT_FALSE(android::base::StartsWith("foo", "foobar")); +} + +TEST(strings, startswith_contains_prefix) { + ASSERT_FALSE(android::base::StartsWith("foobar", "oba")); + ASSERT_FALSE(android::base::StartsWith("foobar", "bar")); +} + +TEST(strings, endswith_empty) { + ASSERT_FALSE(android::base::EndsWith("", "foo")); + ASSERT_TRUE(android::base::EndsWith("", "")); +} + +TEST(strings, endswith_simple) { + ASSERT_TRUE(android::base::EndsWith("foo", "")); + ASSERT_TRUE(android::base::EndsWith("foo", "o")); + ASSERT_TRUE(android::base::EndsWith("foo", "oo")); + ASSERT_TRUE(android::base::EndsWith("foo", "foo")); +} + +TEST(strings, endswith_prefix_too_long) { + ASSERT_FALSE(android::base::EndsWith("foo", "foobar")); +} + +TEST(strings, endswith_contains_prefix) { + ASSERT_FALSE(android::base::EndsWith("foobar", "oba")); + ASSERT_FALSE(android::base::EndsWith("foobar", "foo")); +} diff --git a/base/test_main.cpp b/base/test_main.cpp new file mode 100644 index 0000000..546923d --- /dev/null +++ b/base/test_main.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2015 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 <gtest/gtest.h> + +#include "base/logging.h" + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + android::base::InitLogging(argv, android::base::StderrLogger); + return RUN_ALL_TESTS(); +} diff --git a/adb/get_my_path_freebsd.c b/base/test_utils.cpp index b06ec66..1f6d3cf 100644 --- a/adb/get_my_path_freebsd.c +++ b/base/test_utils.cpp @@ -1,8 +1,5 @@ /* - * Copyright (C) 2009 bsdroid project - * Alexey Tarasov <tarasov@dodologics.com> - * - * Copyright (C) 2007 The Android Open Source Project + * Copyright (C) 2015 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. @@ -17,20 +14,25 @@ * limitations under the License. */ -#include <sys/types.h> -#include <unistd.h> -#include <limits.h> -#include <stdio.h> - -void -get_my_path(char *exe, size_t maxLen) -{ - char proc[64]; +#include "test_utils.h" - snprintf(proc, sizeof(proc), "/proc/%d/file", getpid()); +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> - int err = readlink(proc, exe, maxLen - 1); +TemporaryFile::TemporaryFile() { + init("/data/local/tmp"); + if (fd == -1) { + init("/tmp"); + } +} - exe[err > 0 ? err : 0] = '\0'; +TemporaryFile::~TemporaryFile() { + close(fd); + unlink(filename); } +void TemporaryFile::init(const char* tmp_dir) { + snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir); + fd = mkstemp(filename); +} diff --git a/base/test_utils.h b/base/test_utils.h new file mode 100644 index 0000000..132d3a7 --- /dev/null +++ b/base/test_utils.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015 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 TEST_UTILS_H +#define TEST_UTILS_H + +class TemporaryFile { + public: + TemporaryFile(); + ~TemporaryFile(); + + int fd; + char filename[1024]; + + private: + void init(const char* tmp_dir); +}; + +#endif // TEST_UTILS_H diff --git a/cpio/Android.mk b/cpio/Android.mk index 575beb2..2aa7297 100644 --- a/cpio/Android.mk +++ b/cpio/Android.mk @@ -10,6 +10,8 @@ LOCAL_MODULE := mkbootfs LOCAL_CFLAGS := -Werror +LOCAL_SHARED_LIBRARIES := libcutils + include $(BUILD_HOST_EXECUTABLE) $(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE)) diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk index c33b263..dd53296 100644 --- a/debuggerd/Android.mk +++ b/debuggerd/Android.mk @@ -5,6 +5,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ backtrace.cpp \ debuggerd.cpp \ + elf_utils.cpp \ getevent.cpp \ tombstone.cpp \ utility.cpp \ @@ -12,7 +13,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SRC_FILES_arm := arm/machine.cpp LOCAL_SRC_FILES_arm64 := arm64/machine.cpp LOCAL_SRC_FILES_mips := mips/machine.cpp -LOCAL_SRC_FILES_mips64 := mips/machine.cpp +LOCAL_SRC_FILES_mips64 := mips64/machine.cpp LOCAL_SRC_FILES_x86 := x86/machine.cpp LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp @@ -22,19 +23,23 @@ LOCAL_CPPFLAGS := \ -Wunused \ -Werror \ +ifeq ($(TARGET_IS_64_BIT),true) +LOCAL_CPPFLAGS += -DTARGET_IS_64_BIT +endif + LOCAL_SHARED_LIBRARIES := \ libbacktrace \ + libbase \ libcutils \ liblog \ libselinux \ -include external/stlport/libstlport.mk +LOCAL_CLANG := true LOCAL_MODULE := debuggerd LOCAL_MODULE_STEM_32 := debuggerd LOCAL_MODULE_STEM_64 := debuggerd64 LOCAL_MULTILIB := both -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk include $(BUILD_EXECUTABLE) @@ -45,7 +50,7 @@ LOCAL_SRC_FILES := crasher.c LOCAL_SRC_FILES_arm := arm/crashglue.S LOCAL_SRC_FILES_arm64 := arm64/crashglue.S LOCAL_SRC_FILES_mips := mips/crashglue.S -LOCAL_SRC_FILES_mips64 := mips/crashglue.S +LOCAL_SRC_FILES_mips64 := mips64/crashglue.S LOCAL_SRC_FILES_x86 := x86/crashglue.S LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c index d315ee5..af86fe9 100644 --- a/debuggerd/crasher.c +++ b/debuggerd/crasher.c @@ -32,16 +32,23 @@ static void maybe_abort() { } } -static int smash_stack(int i __unused) { +static char* smash_stack_dummy_buf; +__attribute__ ((noinline)) static void smash_stack_dummy_function(volatile int* plen) { + smash_stack_dummy_buf[*plen] = 0; +} + +// This must be marked with "__attribute__ ((noinline))", to ensure the +// compiler generates the proper stack guards around this function. +// Assign local array address to global variable to force stack guards. +// Use another noinline function to corrupt the stack. +__attribute__ ((noinline)) static int smash_stack(volatile int* plen) { printf("crasher: deliberately corrupting stack...\n"); - // Unless there's a "big enough" buffer on the stack, gcc - // doesn't bother inserting checks. - char buf[8]; - // If we don't write something relatively unpredictable - // into the buffer and then do something with it, gcc - // optimizes everything away and just returns a constant. - *(int*)(&buf[7]) = (uintptr_t) &buf[0]; - return *(int*)(&buf[0]); + + char buf[128]; + smash_stack_dummy_buf = buf; + // This should corrupt stack guards and make process abort. + smash_stack_dummy_function(plen); + return 0; } static void* global = 0; // So GCC doesn't optimize the tail recursion out of overflow_stack. @@ -59,7 +66,7 @@ static void *noisy(void *x) for(;;) { usleep(250*1000); write(2, &c, 1); - if(c == 'C') *((unsigned*) 0) = 42; + if(c == 'C') *((volatile unsigned*) 0) = 42; } return NULL; } @@ -125,7 +132,8 @@ static int do_action(const char* arg) } else if (!strcmp(arg, "SIGSEGV-non-null")) { sigsegv_non_null(); } else if (!strcmp(arg, "smash-stack")) { - return smash_stack(42); + volatile int len = 128; + return smash_stack(&len); } else if (!strcmp(arg, "stack-overflow")) { overflow_stack(NULL); } else if (!strcmp(arg, "nostack")) { diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp index 06c16f8..039b8ec 100644 --- a/debuggerd/debuggerd.cpp +++ b/debuggerd/debuggerd.cpp @@ -30,6 +30,8 @@ #include <sys/stat.h> #include <sys/poll.h> +#include <selinux/android.h> + #include <log/logger.h> #include <cutils/sockets.h> @@ -45,6 +47,14 @@ #include "tombstone.h" #include "utility.h" +// If the 32 bit executable is compiled on a 64 bit system, +// use the 32 bit socket name. +#if defined(TARGET_IS_64_BIT) && !defined(__LP64__) +#define SOCKET_NAME DEBUGGER32_SOCKET_NAME +#else +#define SOCKET_NAME DEBUGGER_SOCKET_NAME +#endif + struct debugger_request_t { debugger_action_t action; pid_t pid, tid; @@ -124,6 +134,53 @@ static int get_process_info(pid_t tid, pid_t* out_pid, uid_t* out_uid, uid_t* ou return fields == 7 ? 0 : -1; } +static int selinux_enabled; + +/* + * Corresponds with debugger_action_t enum type in + * include/cutils/debugger.h. + */ +static const char *debuggerd_perms[] = { + NULL, /* crash is only used on self, no check applied */ + "dump_tombstone", + "dump_backtrace" +}; + +static bool selinux_action_allowed(int s, pid_t tid, debugger_action_t action) +{ + char *scon = NULL, *tcon = NULL; + const char *tclass = "debuggerd"; + const char *perm; + bool allowed = false; + + if (selinux_enabled <= 0) + return true; + + if (action <= 0 || action >= (sizeof(debuggerd_perms)/sizeof(debuggerd_perms[0]))) { + ALOGE("SELinux: No permission defined for debugger action %d", action); + return false; + } + + perm = debuggerd_perms[action]; + + if (getpeercon(s, &scon) < 0) { + ALOGE("Cannot get peer context from socket\n"); + goto out; + } + + if (getpidcon(tid, &tcon) < 0) { + ALOGE("Cannot get context for tid %d\n", tid); + goto out; + } + + allowed = (selinux_check_access(scon, tcon, tclass, perm, NULL) == 0); + +out: + freecon(scon); + freecon(tcon); + return allowed; +} + static int read_request(int fd, debugger_request_t* out_request) { ucred cr; socklen_t len = sizeof(cr); @@ -158,7 +215,7 @@ static int read_request(int fd, debugger_request_t* out_request) { return -1; } - out_request->action = msg.action; + out_request->action = static_cast<debugger_action_t>(msg.action); out_request->tid = msg.tid; out_request->pid = cr.pid; out_request->uid = cr.uid; @@ -186,6 +243,9 @@ static int read_request(int fd, debugger_request_t* out_request) { ALOGE("tid %d does not exist. ignoring explicit dump request\n", out_request->tid); return -1; } + + if (!selinux_action_allowed(fd, out_request->tid, out_request->action)) + return -1; } else { // No one else is allowed to dump arbitrary processes. return -1; @@ -203,6 +263,85 @@ static bool should_attach_gdb(debugger_request_t* request) { return false; } +#if defined(__LP64__) +static bool is32bit(pid_t tid) { + char* exeline; + if (asprintf(&exeline, "/proc/%d/exe", tid) == -1) { + return false; + } + int fd = TEMP_FAILURE_RETRY(open(exeline, O_RDONLY | O_CLOEXEC)); + int saved_errno = errno; + free(exeline); + if (fd == -1) { + ALOGW("Failed to open /proc/%d/exe %s", tid, strerror(saved_errno)); + return false; + } + + char ehdr[EI_NIDENT]; + ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, &ehdr, sizeof(ehdr))); + TEMP_FAILURE_RETRY(close(fd)); + if (bytes != (ssize_t) sizeof(ehdr) || memcmp(ELFMAG, ehdr, SELFMAG) != 0) { + return false; + } + if (ehdr[EI_CLASS] == ELFCLASS32) { + return true; + } + return false; +} + +static void redirect_to_32(int fd, debugger_request_t* request) { + debugger_msg_t msg; + memset(&msg, 0, sizeof(msg)); + msg.tid = request->tid; + msg.action = request->action; + + int sock_fd = socket_local_client(DEBUGGER32_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, + SOCK_STREAM | SOCK_CLOEXEC); + if (sock_fd < 0) { + ALOGE("Failed to connect to debuggerd32: %s", strerror(errno)); + return; + } + + if (TEMP_FAILURE_RETRY(write(sock_fd, &msg, sizeof(msg))) != (ssize_t) sizeof(msg)) { + ALOGE("Failed to write request to debuggerd32 socket: %s", strerror(errno)); + TEMP_FAILURE_RETRY(close(sock_fd)); + return; + } + + char ack; + if (TEMP_FAILURE_RETRY(read(sock_fd, &ack, 1)) == -1) { + ALOGE("Failed to read ack from debuggerd32 socket: %s", strerror(errno)); + TEMP_FAILURE_RETRY(close(sock_fd)); + return; + } + + char buffer[1024]; + ssize_t bytes_read; + while ((bytes_read = TEMP_FAILURE_RETRY(read(sock_fd, buffer, sizeof(buffer)))) > 0) { + ssize_t bytes_to_send = bytes_read; + ssize_t bytes_written; + do { + bytes_written = TEMP_FAILURE_RETRY(write(fd, buffer + bytes_read - bytes_to_send, + bytes_to_send)); + if (bytes_written == -1) { + if (errno == EAGAIN) { + // Retry the write. + continue; + } + ALOGE("Error while writing data to fd: %s", strerror(errno)); + break; + } + bytes_to_send -= bytes_written; + } while (bytes_written != 0 && bytes_to_send > 0); + if (bytes_to_send != 0) { + ALOGE("Failed to write all data to fd: read %zd, sent %zd", bytes_read, bytes_to_send); + break; + } + } + TEMP_FAILURE_RETRY(close(sock_fd)); +} +#endif + static void handle_request(int fd) { ALOGV("handle_request(%d)\n", fd); @@ -213,6 +352,24 @@ static void handle_request(int fd) { ALOGV("BOOM: pid=%d uid=%d gid=%d tid=%d\n", request.pid, request.uid, request.gid, request.tid); +#if defined(__LP64__) + // On 64 bit systems, requests to dump 32 bit and 64 bit tids come + // to the 64 bit debuggerd. If the process is a 32 bit executable, + // redirect the request to the 32 bit debuggerd. + if (is32bit(request.tid)) { + // Only dump backtrace and dump tombstone requests can be redirected. + if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE + || request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) { + redirect_to_32(fd, &request); + } else { + ALOGE("debuggerd: Not allowed to redirect action %d to 32 bit debuggerd\n", + request.action); + } + TEMP_FAILURE_RETRY(close(fd)); + return; + } +#endif + // At this point, the thread that made the request is blocked in // a read() call. If the thread has crashed, then this gives us // time to PTRACE_ATTACH to it before it has a chance to really fault. @@ -376,7 +533,7 @@ static int do_server() { act.sa_flags = SA_NOCLDWAIT; sigaction(SIGCHLD, &act, 0); - int s = socket_local_server(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); + int s = socket_local_server(SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); if (s < 0) return 1; fcntl(s, F_SETFD, FD_CLOEXEC); @@ -430,7 +587,11 @@ static void usage() { } int main(int argc, char** argv) { + union selinux_callback cb; if (argc == 1) { + selinux_enabled = is_selinux_enabled(); + cb.func_log = selinux_log_callback; + selinux_set_callback(SELINUX_CB_LOG, cb); return do_server(); } diff --git a/debuggerd/elf_utils.cpp b/debuggerd/elf_utils.cpp new file mode 100644 index 0000000..5ea03e7 --- /dev/null +++ b/debuggerd/elf_utils.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2015 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 "DEBUG" + +#include <elf.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include <string> + +#include <backtrace/Backtrace.h> +#include <base/stringprintf.h> +#include <log/log.h> + +#include "elf_utils.h" + +#define NOTE_ALIGN(size) ((size + 3) & ~3) + +template <typename HdrType, typename PhdrType, typename NhdrType> +static bool get_build_id( + Backtrace* backtrace, uintptr_t base_addr, uint8_t* e_ident, std::string* build_id) { + HdrType hdr; + + memcpy(&hdr.e_ident[0], e_ident, EI_NIDENT); + + // First read the rest of the header. + if (backtrace->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT, + sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) { + return false; + } + + for (size_t i = 0; i < hdr.e_phnum; i++) { + PhdrType phdr; + if (backtrace->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize, + reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(phdr)) { + return false; + } + // Looking for the .note.gnu.build-id note. + if (phdr.p_type == PT_NOTE) { + size_t hdr_size = phdr.p_filesz; + uintptr_t addr = base_addr + phdr.p_offset; + while (hdr_size >= sizeof(NhdrType)) { + NhdrType nhdr; + if (backtrace->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) { + return false; + } + addr += sizeof(nhdr); + if (nhdr.n_type == NT_GNU_BUILD_ID) { + // Skip the name (which is the owner and should be "GNU"). + addr += NOTE_ALIGN(nhdr.n_namesz); + uint8_t build_id_data[128]; + if (nhdr.n_namesz > sizeof(build_id_data)) { + ALOGE("Possible corrupted note, name size value is too large: %u", + nhdr.n_namesz); + return false; + } + if (backtrace->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) { + return false; + } + + build_id->clear(); + for (size_t bytes = 0; bytes < nhdr.n_descsz; bytes++) { + *build_id += android::base::StringPrintf("%02x", build_id_data[bytes]); + } + + return true; + } else { + // Move past the extra note data. + hdr_size -= sizeof(nhdr); + size_t skip_bytes = NOTE_ALIGN(nhdr.n_namesz) + NOTE_ALIGN(nhdr.n_descsz); + addr += skip_bytes; + if (hdr_size < skip_bytes) { + break; + } + hdr_size -= skip_bytes; + } + } + } + } + return false; +} + +bool elf_get_build_id(Backtrace* backtrace, uintptr_t addr, std::string* build_id) { + // Read and verify the elf magic number first. + uint8_t e_ident[EI_NIDENT]; + if (backtrace->Read(addr, e_ident, SELFMAG) != SELFMAG) { + return false; + } + + if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) { + return false; + } + + // Read the rest of EI_NIDENT. + if (backtrace->Read(addr + SELFMAG, e_ident + SELFMAG, EI_NIDENT - SELFMAG) != EI_NIDENT - SELFMAG) { + return false; + } + + if (e_ident[EI_CLASS] == ELFCLASS32) { + return get_build_id<Elf32_Ehdr, Elf32_Phdr, Elf32_Nhdr>(backtrace, addr, e_ident, build_id); + } else if (e_ident[EI_CLASS] == ELFCLASS64) { + return get_build_id<Elf64_Ehdr, Elf64_Phdr, Elf64_Nhdr>(backtrace, addr, e_ident, build_id); + } + + return false; +} diff --git a/debuggerd/elf_utils.h b/debuggerd/elf_utils.h new file mode 100644 index 0000000..11d0a43 --- /dev/null +++ b/debuggerd/elf_utils.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2015 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 _DEBUGGERD_ELF_UTILS_H +#define _DEBUGGERD_ELF_UTILS_H + +#include <stdint.h> +#include <string> + +class Backtrace; + +bool elf_get_build_id(Backtrace*, uintptr_t, std::string*); + +#endif // _DEBUGGERD_ELF_UTILS_H diff --git a/debuggerd/mips/machine.cpp b/debuggerd/mips/machine.cpp index 97834c7..1145963 100644 --- a/debuggerd/mips/machine.cpp +++ b/debuggerd/mips/machine.cpp @@ -29,22 +29,10 @@ #define R(x) (static_cast<unsigned int>(x)) -// The MIPS uapi ptrace.h has the wrong definition for pt_regs. PTRACE_GETREGS -// writes 64-bit quantities even though the public struct uses 32-bit ones. -struct pt_regs_mips_t { - uint64_t regs[32]; - uint64_t lo; - uint64_t hi; - uint64_t cp0_epc; - uint64_t cp0_badvaddr; - uint64_t cp0_status; - uint64_t cp0_cause; -}; - // If configured to do so, dump memory around *all* registers // for the crashing thread. void dump_memory_and_code(log_t* log, pid_t tid) { - pt_regs_mips_t r; + pt_regs r; if (ptrace(PTRACE_GETREGS, tid, 0, &r)) { return; } @@ -85,7 +73,7 @@ void dump_memory_and_code(log_t* log, pid_t tid) { } void dump_registers(log_t* log, pid_t tid) { - pt_regs_mips_t r; + pt_regs r; if(ptrace(PTRACE_GETREGS, tid, 0, &r)) { _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno)); return; diff --git a/debuggerd/mips64/crashglue.S b/debuggerd/mips64/crashglue.S new file mode 100644 index 0000000..70a6641 --- /dev/null +++ b/debuggerd/mips64/crashglue.S @@ -0,0 +1,48 @@ + .set noat + + .globl crash1 + .globl crashnostack + +crash1: + li $0,0xdead0000+0 + li $1,0xdead0000+1 + li $2,0xdead0000+2 + li $3,0xdead0000+3 + li $4,0xdead0000+4 + li $5,0xdead0000+5 + li $6,0xdead0000+6 + li $7,0xdead0000+7 + li $8,0xdead0000+8 + li $9,0xdead0000+9 + li $10,0xdead0000+10 + li $11,0xdead0000+11 + li $12,0xdead0000+12 + li $13,0xdead0000+13 + li $14,0xdead0000+14 + li $15,0xdead0000+15 + li $16,0xdead0000+16 + li $17,0xdead0000+17 + li $18,0xdead0000+18 + li $19,0xdead0000+19 + li $20,0xdead0000+20 + li $21,0xdead0000+21 + li $22,0xdead0000+22 + li $23,0xdead0000+23 + li $24,0xdead0000+24 + li $25,0xdead0000+25 + li $26,0xdead0000+26 + li $27,0xdead0000+27 + li $28,0xdead0000+28 + # don't trash the stack otherwise the signal handler won't run + #li $29,0xdead0000+29 + li $30,0xdead0000+30 + li $31,0xdead0000+31 + + lw $zero,($0) + b . + + +crashnostack: + li $sp, 0 + lw $zero,($0) + b . diff --git a/debuggerd/mips64/machine.cpp b/debuggerd/mips64/machine.cpp new file mode 100644 index 0000000..ef9092f --- /dev/null +++ b/debuggerd/mips64/machine.cpp @@ -0,0 +1,100 @@ +/* + * Copyright 2014, 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 <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/ptrace.h> + +#include <sys/user.h> + +#include "../utility.h" +#include "../machine.h" + +#define R(x) (static_cast<unsigned long>(x)) + +// If configured to do so, dump memory around *all* registers +// for the crashing thread. +void dump_memory_and_code(log_t* log, pid_t tid) { + pt_regs r; + if (ptrace(PTRACE_GETREGS, tid, 0, &r)) { + return; + } + + static const char REG_NAMES[] = "$0atv0v1a0a1a2a3a4a5a6a7t0t1t2t3s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra"; + + for (int reg = 0; reg < 32; reg++) { + // skip uninteresting registers + if (reg == 0 // $0 + || reg == 26 // $k0 + || reg == 27 // $k1 + || reg == 31 // $ra (done below) + ) + continue; + + uintptr_t addr = R(r.regs[reg]); + + // Don't bother if it looks like a small int or ~= null, or if + // it's in the kernel area. + if (addr < 4096 || addr >= 0x4000000000000000) { + continue; + } + + _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]); + dump_memory(log, tid, addr); + } + + unsigned long pc = R(r.cp0_epc); + unsigned long ra = R(r.regs[31]); + + _LOG(log, logtype::MEMORY, "\ncode around pc:\n"); + dump_memory(log, tid, (uintptr_t)pc); + + if (pc != ra) { + _LOG(log, logtype::MEMORY, "\ncode around ra:\n"); + dump_memory(log, tid, (uintptr_t)ra); + } +} + +void dump_registers(log_t* log, pid_t tid) { + pt_regs r; + if(ptrace(PTRACE_GETREGS, tid, 0, &r)) { + _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno)); + return; + } + + _LOG(log, logtype::REGISTERS, " zr %016lx at %016lx v0 %016lx v1 %016lx\n", + R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3])); + _LOG(log, logtype::REGISTERS, " a0 %016lx a1 %016lx a2 %016lx a3 %016lx\n", + R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7])); + _LOG(log, logtype::REGISTERS, " a4 %016lx a5 %016lx a6 %016lx a7 %016lx\n", + R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11])); + _LOG(log, logtype::REGISTERS, " t0 %016lx t1 %016lx t2 %016lx t3 %016lx\n", + R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15])); + _LOG(log, logtype::REGISTERS, " s0 %016lx s1 %016lx s2 %016lx s3 %016lx\n", + R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19])); + _LOG(log, logtype::REGISTERS, " s4 %016lx s5 %016lx s6 %016lx s7 %016lx\n", + R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23])); + _LOG(log, logtype::REGISTERS, " t8 %016lx t9 %016lx k0 %016lx k1 %016lx\n", + R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27])); + _LOG(log, logtype::REGISTERS, " gp %016lx sp %016lx s8 %016lx ra %016lx\n", + R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31])); + _LOG(log, logtype::REGISTERS, " hi %016lx lo %016lx bva %016lx epc %016lx\n", + R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc)); +} diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp index 0c1b80f..094ab48 100644 --- a/debuggerd/tombstone.cpp +++ b/debuggerd/tombstone.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "DEBUG" +#include <arpa/inet.h> #include <dirent.h> #include <errno.h> #include <fcntl.h> @@ -33,6 +34,7 @@ #include <private/android_filesystem_config.h> +#include <base/stringprintf.h> #include <cutils/properties.h> #include <log/log.h> #include <log/logger.h> @@ -45,9 +47,12 @@ #include <UniquePtr.h> +#include <string> + +#include "backtrace.h" +#include "elf_utils.h" #include "machine.h" #include "tombstone.h" -#include "backtrace.h" #define STACK_WORDS 16 @@ -233,48 +238,36 @@ static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) { static void dump_stack_segment( Backtrace* backtrace, log_t* log, uintptr_t* sp, size_t words, int label) { + // Read the data all at once. + word_t stack_data[words]; + size_t bytes_read = backtrace->Read(*sp, reinterpret_cast<uint8_t*>(&stack_data[0]), sizeof(word_t) * words); + words = bytes_read / sizeof(word_t); + std::string line; for (size_t i = 0; i < words; i++) { - word_t stack_content; - if (!backtrace->ReadWord(*sp, &stack_content)) { - break; - } - - const backtrace_map_t* map = backtrace->FindMap(stack_content); - const char* map_name; - if (!map) { - map_name = ""; + line = " "; + if (i == 0 && label >= 0) { + // Print the label once. + line += android::base::StringPrintf("#%02d ", label); } else { - map_name = map->name.c_str(); + line += " "; } - uintptr_t offset = 0; - std::string func_name(backtrace->GetFunctionName(stack_content, &offset)); - if (!func_name.empty()) { - if (!i && label >= 0) { + line += android::base::StringPrintf("%" PRIPTR " %" PRIPTR, *sp, stack_data[i]); + + backtrace_map_t map; + backtrace->FillInMap(stack_data[i], &map); + if (BacktraceMap::IsValid(map) && !map.name.empty()) { + line += " " + map.name; + uintptr_t offset = 0; + std::string func_name(backtrace->GetFunctionName(stack_data[i], &offset)); + if (!func_name.empty()) { + line += " (" + func_name; if (offset) { - _LOG(log, logtype::STACK, " #%02d %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n", - label, *sp, stack_content, map_name, func_name.c_str(), offset); - } else { - _LOG(log, logtype::STACK, " #%02d %" PRIPTR " %" PRIPTR " %s (%s)\n", - label, *sp, stack_content, map_name, func_name.c_str()); + line += android::base::StringPrintf("+%" PRIuPTR, offset); } - } else { - if (offset) { - _LOG(log, logtype::STACK, " %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n", - *sp, stack_content, map_name, func_name.c_str(), offset); - } else { - _LOG(log, logtype::STACK, " %" PRIPTR " %" PRIPTR " %s (%s)\n", - *sp, stack_content, map_name, func_name.c_str()); - } - } - } else { - if (!i && label >= 0) { - _LOG(log, logtype::STACK, " #%02d %" PRIPTR " %" PRIPTR " %s\n", - label, *sp, stack_content, map_name); - } else { - _LOG(log, logtype::STACK, " %" PRIPTR " %" PRIPTR " %s\n", - *sp, stack_content, map_name); + line += ')'; } } + _LOG(log, logtype::STACK, "%s\n", line.c_str()); *sp += sizeof(word_t); } @@ -325,61 +318,83 @@ static void dump_stack(Backtrace* backtrace, log_t* log) { } } -static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log) { - if (backtrace->NumFrames()) { - _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n"); - dump_backtrace_to_log(backtrace, log, " "); - - _LOG(log, logtype::STACK, "\nstack:\n"); - dump_stack(backtrace, log); - } -} - -static void dump_map(log_t* log, const backtrace_map_t* map, bool fault_addr) { - _LOG(log, logtype::MAPS, "%s%" PRIPTR "-%" PRIPTR " %c%c%c %7" PRIdPTR " %s\n", - (fault_addr? "--->" : " "), map->start, map->end - 1, - (map->flags & PROT_READ) ? 'r' : '-', (map->flags & PROT_WRITE) ? 'w' : '-', - (map->flags & PROT_EXEC) ? 'x' : '-', - (map->end - map->start), map->name.c_str()); -} - -static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid) { +static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, pid_t tid) { + bool print_fault_address_marker = false; + uintptr_t addr = 0; siginfo_t si; memset(&si, 0, sizeof(si)); if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) { - _LOG(log, logtype::MAPS, "cannot get siginfo for %d: %s\n", tid, strerror(errno)); - return; + _LOG(log, logtype::ERROR, "cannot get siginfo for %d: %s\n", tid, strerror(errno)); + } else { + print_fault_address_marker = signal_has_si_addr(si.si_signo); + addr = reinterpret_cast<uintptr_t>(si.si_addr); } - bool has_fault_address = signal_has_si_addr(si.si_signo); - uintptr_t addr = reinterpret_cast<uintptr_t>(si.si_addr); - - _LOG(log, logtype::MAPS, "\nmemory map: %s\n", has_fault_address ? "(fault address prefixed with --->)" : ""); - - if (has_fault_address && (addr < map->begin()->start)) { - _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " before any mapped regions\n", addr); + _LOG(log, logtype::MAPS, "\n"); + if (!print_fault_address_marker) { + _LOG(log, logtype::MAPS, "memory map:\n"); + } else { + _LOG(log, logtype::MAPS, "memory map: (fault address prefixed with --->)\n"); + if (map->begin() != map->end() && addr < map->begin()->start) { + _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " before any mapped regions\n", + addr); + print_fault_address_marker = false; + } } - BacktraceMap::const_iterator prev = map->begin(); + std::string line; for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) { - if (addr >= (*prev).end && addr < (*it).start) { - _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " between mapped regions\n", addr); + line = " "; + if (print_fault_address_marker) { + if (addr < it->start) { + _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " between mapped regions\n", + addr); + print_fault_address_marker = false; + } else if (addr >= it->start && addr < it->end) { + line = "--->"; + print_fault_address_marker = false; + } + } + line += android::base::StringPrintf("%" PRIPTR "-%" PRIPTR " ", it->start, it->end - 1); + if (it->flags & PROT_READ) { + line += 'r'; + } else { + line += '-'; + } + if (it->flags & PROT_WRITE) { + line += 'w'; + } else { + line += '-'; } - prev = it; - bool in_map = has_fault_address && (addr >= (*it).start) && (addr < (*it).end); - dump_map(log, &*it, in_map); + if (it->flags & PROT_EXEC) { + line += 'x'; + } else { + line += '-'; + } + line += android::base::StringPrintf(" %8" PRIxPTR, it->end - it->start); + if (it->name.length() > 0) { + line += " " + it->name; + std::string build_id; + if ((it->flags & PROT_READ) && elf_get_build_id(backtrace, it->start, &build_id)) { + line += " (BuildId: " + build_id + ")"; + } + } + _LOG(log, logtype::MAPS, "%s\n", line.c_str()); } - if (has_fault_address && (addr >= (*prev).end)) { - _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " after any mapped regions\n", addr); + if (print_fault_address_marker) { + _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " after any mapped regions\n", + addr); } } -static void dump_thread(Backtrace* backtrace, log_t* log) { - dump_registers(log, backtrace->Tid()); - dump_backtrace_and_stack(backtrace, log); +static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log) { + if (backtrace->NumFrames()) { + _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n"); + dump_backtrace_to_log(backtrace, log, " "); - dump_memory_and_code(log, backtrace->Tid()); - dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid()); + _LOG(log, logtype::STACK, "\nstack:\n"); + dump_stack(backtrace, log); + } } // Return true if some thread is not detached cleanly @@ -425,9 +440,10 @@ static bool dump_sibling_thread_report( _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n"); dump_thread_info(log, pid, new_tid); + dump_registers(log, new_tid); UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map)); if (backtrace->Unwind(0)) { - dump_thread(backtrace.get(), log); + dump_backtrace_and_stack(backtrace.get(), log); } log->current_tid = log->crashed_tid; @@ -458,7 +474,7 @@ static void dump_log_file( } logger_list = android_logger_list_open( - android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid); + android_name_to_log_id(filename), ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, tail, pid); if (!logger_list) { ALOGE("Unable to open %s: %s\n", filename, strerror(errno)); @@ -626,10 +642,13 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, int si_code UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid)); UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get())); + dump_abort_message(backtrace.get(), log, abort_msg_address); + dump_registers(log, tid); if (backtrace->Unwind(0)) { - dump_abort_message(backtrace.get(), log, abort_msg_address); - dump_thread(backtrace.get(), log); + dump_backtrace_and_stack(backtrace.get(), log); } + dump_memory_and_code(log, tid); + dump_all_maps(backtrace.get(), map.get(), log, tid); if (want_logs) { dump_logs(log, pid, 5); diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp index 2baf9de..e10feff 100644 --- a/debuggerd/utility.cpp +++ b/debuggerd/utility.cpp @@ -131,12 +131,6 @@ int wait_for_sigstop(pid_t tid, int* total_sleep_time_usec, bool* detach_failed) return -1; } -#if defined (__mips__) -#define DUMP_MEMORY_AS_ASCII 1 -#else -#define DUMP_MEMORY_AS_ASCII 0 -#endif - void dump_memory(log_t* log, pid_t tid, uintptr_t addr) { char code_buffer[64]; char ascii_buffer[32]; @@ -183,7 +177,6 @@ void dump_memory(log_t* log, pid_t tid, uintptr_t addr) { static_cast<uintptr_t>(data)); } -#if DUMP_MEMORY_AS_ASCII for (size_t j = 0; j < sizeof(long); j++) { /* * Our isprint() allows high-ASCII characters that display @@ -197,7 +190,6 @@ void dump_memory(log_t* log, pid_t tid, uintptr_t addr) { *asc_out++ = '.'; } } -#endif p += sizeof(long); } *asc_out = '\0'; diff --git a/debuggerd/utility.h b/debuggerd/utility.h index 58a882c..49b46e8 100644 --- a/debuggerd/utility.h +++ b/debuggerd/utility.h @@ -26,8 +26,10 @@ #define ABI_STRING "arm" #elif defined(__aarch64__) #define ABI_STRING "arm64" -#elif defined(__mips__) +#elif defined(__mips__) && !defined(__LP64__) #define ABI_STRING "mips" +#elif defined(__mips__) && defined(__LP64__) +#define ABI_STRING "mips64" #elif defined(__i386__) #define ABI_STRING "x86" #elif defined(__x86_64__) diff --git a/fastboot/Android.mk b/fastboot/Android.mk index e11691f..7b2975b 100644 --- a/fastboot/Android.mk +++ b/fastboot/Android.mk @@ -19,10 +19,11 @@ include $(CLEAR_VARS) LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \ $(LOCAL_PATH)/../../extras/ext4_utils \ $(LOCAL_PATH)/../../extras/f2fs_utils -LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c fs.c +LOCAL_SRC_FILES := protocol.c engine.c bootimg_utils.cpp fastboot.cpp util.c fs.c LOCAL_MODULE := fastboot LOCAL_MODULE_TAGS := debug -LOCAL_CFLAGS += -std=gnu99 -Werror +LOCAL_CONLYFLAGS += -std=gnu99 +LOCAL_CFLAGS += -Wall -Wextra -Werror ifeq ($(HOST_OS),linux) LOCAL_SRC_FILES += usb_linux.c util_linux.c @@ -32,6 +33,7 @@ ifeq ($(HOST_OS),darwin) LOCAL_SRC_FILES += usb_osx.c util_osx.c LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit \ -framework Carbon + LOCAL_CFLAGS += -Wno-unused-parameter endif ifeq ($(HOST_OS),windows) @@ -51,10 +53,11 @@ endif LOCAL_STATIC_LIBRARIES := \ $(EXTRA_STATIC_LIBS) \ - libzipfile \ - libunz \ + libziparchive-host \ libext4_utils_host \ libsparse_host \ + libutils \ + liblog \ libz ifneq ($(HOST_OS),windows) @@ -71,6 +74,16 @@ LOCAL_REQUIRED_MODULES := libf2fs_fmt_host_dyn LOCAL_STATIC_LIBRARIES += libf2fs_utils_host libf2fs_ioutils_host libf2fs_dlutils_host endif +# libc++ not available on windows yet +ifneq ($(HOST_OS),windows) + LOCAL_CXX_STL := libc++_static +endif + +# Don't add anything here, we don't want additional shared dependencies +# on the host fastboot tool, and shared libraries that link against libc++ +# will violate ODR +LOCAL_SHARED_LIBRARIES := + include $(BUILD_HOST_EXECUTABLE) my_dist_files := $(LOCAL_BUILT_MODULE) diff --git a/fastboot/bootimg.c b/fastboot/bootimg_utils.cpp index 240784f..d8905a6 100644 --- a/fastboot/bootimg.c +++ b/fastboot/bootimg_utils.cpp @@ -26,12 +26,12 @@ * SUCH DAMAGE. */ +#include "bootimg_utils.h" + #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <bootimg.h> - void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline) { strcpy((char*) h->cmdline, cmdline); @@ -47,7 +47,6 @@ boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offs unsigned ramdisk_actual; unsigned second_actual; unsigned page_mask; - boot_img_hdr *hdr; page_mask = page_size - 1; @@ -57,9 +56,8 @@ boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offs *bootimg_size = page_size + kernel_actual + ramdisk_actual + second_actual; - hdr = calloc(*bootimg_size, 1); - - if(hdr == 0) { + boot_img_hdr* hdr = reinterpret_cast<boot_img_hdr*>(calloc(*bootimg_size, 1)); + if (hdr == 0) { return hdr; } diff --git a/fastbootd/trigger.h b/fastboot/bootimg_utils.h index d2d9573..b1a86cd 100644 --- a/fastbootd/trigger.h +++ b/fastboot/bootimg_utils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2013, Google Inc. + * Copyright (C) 2015 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -11,9 +11,6 @@ * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -29,12 +26,24 @@ * SUCH DAMAGE. */ -#ifndef __FASTBOOTD_TRIGGER_H_ -#define __FASTBOOTD_TRIGGER_H_ +#ifndef _FASTBOOT_BOOTIMG_UTILS_H_ +#define _FASTBOOT_BOOTIMG_UTILS_H_ -#include "commands/partitions.h" -#include "vendor_trigger.h" +#include <bootimg.h> -int load_trigger(); +#if defined(__cplusplus) +extern "C" { +#endif + +void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline); +boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset, + void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset, + void *second, unsigned second_size, unsigned second_offset, + unsigned page_size, unsigned base, unsigned tags_offset, + unsigned *bootimg_size); + +#if defined(__cplusplus) +} +#endif #endif diff --git a/fastboot/fastboot.c b/fastboot/fastboot.cpp index 43d05aa..e139bcd 100644 --- a/fastboot/fastboot.c +++ b/fastboot/fastboot.cpp @@ -44,10 +44,10 @@ #include <sys/types.h> #include <unistd.h> -#include <bootimg.h> #include <sparse/sparse.h> -#include <zipfile/zipfile.h> +#include <ziparchive/zip_archive.h> +#include "bootimg_utils.h" #include "fastboot.h" #include "fs.h" @@ -59,14 +59,6 @@ char cur_product[FB_RESPONSE_SZ + 1]; -void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline); - -boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset, - void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset, - void *second, unsigned second_size, unsigned second_offset, - unsigned page_size, unsigned base, unsigned tags_offset, - unsigned *bootimg_size); - static usb_handle *usb = 0; static const char *serial = 0; static const char *product = 0; @@ -106,12 +98,10 @@ static struct { {"vendor.img", "vendor.sig", "vendor", true}, }; -void get_my_path(char *path); - char *find_item(const char *item, const char *product) { char *dir; - char *fn; + const char *fn; char path[PATH_MAX + 128]; if(!strcmp(item,"boot")) { @@ -234,7 +224,7 @@ int match_fastboot(usb_ifc_info *info) int list_devices_callback(usb_ifc_info *info) { if (match_fastboot_with_serial(info, NULL) == 0) { - char* serial = info->serial_number; + const char* serial = info->serial_number; if (!info->writable) { serial = "no permissions"; // like "adb devices" } @@ -244,7 +234,7 @@ int list_devices_callback(usb_ifc_info *info) // output compatible with "adb devices" if (!long_listing) { printf("%s\tfastboot\n", serial); - } else if (!info->device_path) { + } else if (strcmp("", info->device_path) == 0) { printf("%-22s fastboot\n", serial); } else { printf("%-22s fastboot %s\n", serial, info->device_path); @@ -300,7 +290,7 @@ void usage(void) " flash it\n" " devices list all connected devices\n" " continue continue with autoboot\n" - " reboot reboot device normally\n" + " reboot [bootloader] reboot device, optionally into bootloader\n" " reboot-bootloader reboot device into bootloader\n" " help show this help message\n" "\n" @@ -389,30 +379,26 @@ void *load_bootable_image(const char *kernel, const char *ramdisk, return bdata; } -void *unzip_file(zipfile_t zip, const char *name, unsigned *sz) +static void* unzip_file(ZipArchiveHandle zip, const char* entry_name, unsigned* sz) { - void *data; - zipentry_t entry; - unsigned datasz; - - entry = lookup_zipentry(zip, name); - if (entry == NULL) { - fprintf(stderr, "archive does not contain '%s'\n", name); + ZipEntryName zip_entry_name(entry_name); + ZipEntry zip_entry; + if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) { + fprintf(stderr, "archive does not contain '%s'\n", entry_name); return 0; } - *sz = get_zipentry_size(entry); + *sz = zip_entry.uncompressed_length; - datasz = *sz * 1.001; - data = malloc(datasz); - - if(data == 0) { - fprintf(stderr, "failed to allocate %d bytes\n", *sz); + uint8_t* data = reinterpret_cast<uint8_t*>(malloc(zip_entry.uncompressed_length)); + if (data == NULL) { + fprintf(stderr, "failed to allocate %u bytes for '%s'\n", *sz, entry_name); return 0; } - if (decompress_zipentry(entry, data, datasz)) { - fprintf(stderr, "failed to unzip '%s' from archive\n", name); + int error = ExtractToMemory(zip, &zip_entry, data, zip_entry.uncompressed_length); + if (error != 0) { + fprintf(stderr, "failed to extract '%s': %s\n", entry_name, ErrorCodeString(error)); free(data); return 0; } @@ -420,27 +406,28 @@ void *unzip_file(zipfile_t zip, const char *name, unsigned *sz) return data; } -static int unzip_to_file(zipfile_t zip, char *name) -{ - int fd; - char *data; - unsigned sz; - - fd = fileno(tmpfile()); - if (fd < 0) { +static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) { + FILE* fp = tmpfile(); + if (fp == NULL) { + fprintf(stderr, "failed to create temporary file for '%s': %s\n", + entry_name, strerror(errno)); return -1; } - data = unzip_file(zip, name, &sz); - if (data == 0) { + ZipEntryName zip_entry_name(entry_name); + ZipEntry zip_entry; + if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) { + fprintf(stderr, "archive does not contain '%s'\n", entry_name); return -1; } - if (write(fd, data, sz) != (ssize_t)sz) { - fd = -1; + int fd = fileno(fp); + int error = ExtractEntryToFile(zip, &zip_entry, fd); + if (error != 0) { + fprintf(stderr, "failed to extract '%s': %s\n", entry_name, ErrorCodeString(error)); + return -1; } - free(data); lseek(fd, 0, SEEK_SET); return fd; } @@ -461,7 +448,6 @@ static char *strip(char *s) static int setup_requirement_line(char *name) { char *val[MAX_OPTIONS]; - const char **out; char *prod = NULL; unsigned n, count; char *x; @@ -501,10 +487,11 @@ static int setup_requirement_line(char *name) name = strip(name); if (name == 0) return -1; - /* work around an unfortunate name mismatch */ - if (!strcmp(name,"board")) name = "product"; + const char* var = name; + // Work around an unfortunate name mismatch. + if (!strcmp(name,"board")) var = "product"; - out = malloc(sizeof(char*) * count); + const char** out = reinterpret_cast<const char**>(malloc(sizeof(char*) * count)); if (out == 0) return -1; for(n = 0; n < count; n++) { @@ -518,7 +505,7 @@ static int setup_requirement_line(char *name) } } - fb_queue_require(prod, name, invert, n, out); + fb_queue_require(prod, var, invert, n, out); return 0; } @@ -551,21 +538,17 @@ void queue_info_dump(void) static struct sparse_file **load_sparse_files(int fd, int max_size) { - struct sparse_file *s; - int files; - struct sparse_file **out_s; - - s = sparse_file_import_auto(fd, false); + struct sparse_file* s = sparse_file_import_auto(fd, false, true); if (!s) { die("cannot sparse read file\n"); } - files = sparse_file_resparse(s, max_size, NULL, 0); + int files = sparse_file_resparse(s, max_size, NULL, 0); if (files < 0) { die("Failed to resparse\n"); } - out_s = calloc(sizeof(struct sparse_file *), files + 1); + sparse_file** out_s = reinterpret_cast<sparse_file**>(calloc(sizeof(struct sparse_file *), files + 1)); if (!out_s) { die("Failed to allocate sparse file array\n"); } @@ -682,11 +665,11 @@ static int load_buf(usb_handle *usb, const char *fname, static void flash_buf(const char *pname, struct fastboot_buffer *buf) { - struct sparse_file **s; + sparse_file** s; switch (buf->type) { case FB_BUFFER_SPARSE: - s = buf->data; + s = reinterpret_cast<sparse_file**>(buf->data); while (*s) { int64_t sz64 = sparse_file_len(*s, true, false); fb_queue_flash_sparse(pname, *s++, sz64); @@ -710,63 +693,44 @@ void do_flash(usb_handle *usb, const char *pname, const char *fname) flash_buf(pname, &buf); } -void do_update_signature(zipfile_t zip, char *fn) +void do_update_signature(ZipArchiveHandle zip, char *fn) { - void *data; unsigned sz; - data = unzip_file(zip, fn, &sz); + void* data = unzip_file(zip, fn, &sz); if (data == 0) return; fb_queue_download("signature", data, sz); fb_queue_command("signature", "installing signature"); } -void do_update(usb_handle *usb, char *fn, int erase_first) +void do_update(usb_handle *usb, const char *filename, int erase_first) { - void *zdata; - unsigned zsize; - void *data; - unsigned sz; - zipfile_t zip; - int fd; - int rc; - struct fastboot_buffer buf; - size_t i; - queue_info_dump(); fb_queue_query_save("product", cur_product, sizeof(cur_product)); - zdata = load_file(fn, &zsize); - if (zdata == 0) die("failed to load '%s': %s", fn, strerror(errno)); - - zip = init_zipfile(zdata, zsize); - if(zip == 0) die("failed to access zipdata in '%s'"); + ZipArchiveHandle zip; + int error = OpenArchive(filename, &zip); + if (error != 0) { + die("failed to open zip file '%s': %s", filename, ErrorCodeString(error)); + } - data = unzip_file(zip, "android-info.txt", &sz); + unsigned sz; + void* data = unzip_file(zip, "android-info.txt", &sz); if (data == 0) { - char *tmp; - /* fallback for older zipfiles */ - data = unzip_file(zip, "android-product.txt", &sz); - if ((data == 0) || (sz < 1)) { - die("update package has no android-info.txt or android-product.txt"); - } - tmp = malloc(sz + 128); - if (tmp == 0) die("out of memory"); - sprintf(tmp,"board=%sversion-baseband=0.66.04.19\n",(char*)data); - data = tmp; - sz = strlen(tmp); + die("update package '%s' has no android-info.txt", filename); } - setup_requirements(data, sz); + setup_requirements(reinterpret_cast<char*>(data), sz); - for (i = 0; i < ARRAY_SIZE(images); i++) { - fd = unzip_to_file(zip, images[i].img_name); + for (size_t i = 0; i < ARRAY_SIZE(images); i++) { + int fd = unzip_to_file(zip, images[i].img_name); if (fd < 0) { if (images[i].is_optional) continue; die("update package missing %s", images[i].img_name); } - rc = load_buf_fd(usb, fd, &buf); + fastboot_buffer buf; + int rc = load_buf_fd(usb, fd, &buf); if (rc) die("cannot load %s from flash", images[i].img_name); do_update_signature(zip, images[i].sig_name); if (erase_first && needs_erase(images[i].part_name)) { @@ -778,6 +742,8 @@ void do_update(usb_handle *usb, char *fn, int erase_first) * program exits. */ } + + CloseArchive(zip); } void do_send_signature(char *fn) @@ -800,24 +766,22 @@ void do_send_signature(char *fn) void do_flashall(usb_handle *usb, int erase_first) { - char *fname; - void *data; - unsigned sz; - struct fastboot_buffer buf; - size_t i; - queue_info_dump(); fb_queue_query_save("product", cur_product, sizeof(cur_product)); - fname = find_item("info", product); + char* fname = find_item("info", product); if (fname == 0) die("cannot find android-info.txt"); - data = load_file(fname, &sz); + + unsigned sz; + void* data = load_file(fname, &sz); if (data == 0) die("could not load android-info.txt: %s", strerror(errno)); - setup_requirements(data, sz); - for (i = 0; i < ARRAY_SIZE(images); i++) { + setup_requirements(reinterpret_cast<char*>(data), sz); + + for (size_t i = 0; i < ARRAY_SIZE(images); i++) { fname = find_item(images[i].part_name, product); + fastboot_buffer buf; if (load_buf(usb, fname, &buf)) { if (images[i].is_optional) continue; @@ -988,6 +952,7 @@ int main(int argc, char **argv) unsigned sz; int status; int c; + int longindex; const struct option longopts[] = { {"base", required_argument, 0, 'b'}, @@ -996,13 +961,14 @@ int main(int argc, char **argv) {"ramdisk_offset", required_argument, 0, 'r'}, {"tags_offset", required_argument, 0, 't'}, {"help", 0, 0, 'h'}, + {"unbuffered", 0, 0, 0}, {0, 0, 0, 0} }; serial = getenv("ANDROID_SERIAL"); while (1) { - c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lp:c:i:m:h", longopts, NULL); + c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lp:c:i:m:h", longopts, &longindex); if (c < 0) { break; } @@ -1063,6 +1029,12 @@ int main(int argc, char **argv) break; case '?': return 1; + case 0: + if (strcmp("unbuffered", longopts[longindex].name) == 0) { + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + } + break; default: abort(); } @@ -1145,6 +1117,14 @@ int main(int argc, char **argv) } else if(!strcmp(*argv, "reboot")) { wants_reboot = 1; skip(1); + if (argc > 0) { + if (!strcmp(*argv, "bootloader")) { + wants_reboot = 0; + wants_reboot_bootloader = 1; + skip(1); + } + } + require(0); } else if(!strcmp(*argv, "reboot-bootloader")) { wants_reboot_bootloader = 1; skip(1); diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index fc5d4f4..1786e49 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -31,6 +31,10 @@ #include "usb.h" +#if defined(__cplusplus) +extern "C" { +#endif + struct sparse_file; /* protocol.c - fastboot protocol */ @@ -67,7 +71,13 @@ double now(); char *mkmsg(const char *fmt, ...); void die(const char *fmt, ...); +void get_my_path(char *path); + /* Current product */ extern char cur_product[FB_RESPONSE_SZ + 1]; +#if defined(__cplusplus) +} +#endif + #endif diff --git a/fastboot/fastboot_protocol.txt b/fastboot/fastboot_protocol.txt index 2248992..37b1959 100644 --- a/fastboot/fastboot_protocol.txt +++ b/fastboot/fastboot_protocol.txt @@ -12,8 +12,8 @@ Basic Requirements ------------------ * Two bulk endpoints (in, out) are required -* Max packet size must be 64 bytes for full-speed and 512 bytes for - high-speed USB +* Max packet size must be 64 bytes for full-speed, 512 bytes for + high-speed and 1024 bytes for Super Speed USB. * The protocol is entirely host-driven and synchronous (unlike the multi-channel, bi-directional, asynchronous ADB protocol) diff --git a/fastboot/fs.h b/fastboot/fs.h index 8444081..307772b 100644 --- a/fastboot/fs.h +++ b/fastboot/fs.h @@ -3,10 +3,18 @@ #include <stdint.h> +#if defined(__cplusplus) +extern "C" { +#endif + struct fs_generator; const struct fs_generator* fs_get_generator(const char *fs_type); int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize); +#if defined(__cplusplus) +} +#endif + #endif diff --git a/fastboot/protocol.c b/fastboot/protocol.c index 84e9837..5b97600 100644 --- a/fastboot/protocol.c +++ b/fastboot/protocol.c @@ -216,7 +216,7 @@ int fb_download_data(usb_handle *usb, const void *data, unsigned size) } } -#define USB_BUF_SIZE 512 +#define USB_BUF_SIZE 1024 static char usb_buf[USB_BUF_SIZE]; static int usb_buf_len; @@ -305,7 +305,10 @@ int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s) return -1; } - fb_download_data_sparse_flush(usb); + r = fb_download_data_sparse_flush(usb); + if (r < 0) { + return -1; + } return _command_end(usb); } diff --git a/fastboot/usb.h b/fastboot/usb.h index 17cf0a9..c7b748e 100644 --- a/fastboot/usb.h +++ b/fastboot/usb.h @@ -29,6 +29,10 @@ #ifndef _USB_H_ #define _USB_H_ +#if defined(__cplusplus) +extern "C" { +#endif + typedef struct usb_handle usb_handle; typedef struct usb_ifc_info usb_ifc_info; @@ -64,4 +68,8 @@ int usb_read(usb_handle *h, void *_data, int len); int usb_write(usb_handle *h, const void *_data, int len); int usb_wait_for_disconnect(usb_handle *h); +#if defined(__cplusplus) +} +#endif + #endif diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c index fabbd51..022f364 100644 --- a/fastboot/usb_linux.c +++ b/fastboot/usb_linux.c @@ -223,6 +223,13 @@ static int filter_usb_device(char* sysfs_name, } else { out = ept->bEndpointAddress; } + + // For USB 3.0 devices skip the SS Endpoint Companion descriptor + if (check((struct usb_descriptor_hdr *)ptr, len, + USB_DT_SS_ENDPOINT_COMP, USB_DT_SS_EP_COMP_SIZE) == 0) { + len -= USB_DT_SS_EP_COMP_SIZE; + ptr += USB_DT_SS_EP_COMP_SIZE; + } } info.has_bulk_in = (in != -1); diff --git a/fastboot/usb_osx.c b/fastboot/usb_osx.c index 0f55e0d..0b6c515 100644 --- a/fastboot/usb_osx.c +++ b/fastboot/usb_osx.c @@ -328,7 +328,8 @@ static int try_device(io_service_t device, usb_handle *handle) { ERR("GetLocationId"); goto error; } - snprintf(handle->info.device_path, sizeof(handle->info.device_path), "usb:%lX", locationId); + snprintf(handle->info.device_path, sizeof(handle->info.device_path), + "usb:%" PRIu32 "X", (unsigned int)locationId); kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex); diff --git a/fastbootd/Android.mk b/fastbootd/Android.mk deleted file mode 100644 index 6aa7400..0000000 --- a/fastbootd/Android.mk +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright (C) 2013 Google Inc. -# -# 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. - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_C_INCLUDES := \ - external/openssl/include \ - external/mdnsresponder/mDNSShared \ - $(LOCAL_PATH)/include \ - external/zlib/ \ - -LOCAL_SRC_FILES := \ - config.c \ - commands.c \ - commands/boot.c \ - commands/flash.c \ - commands/partitions.c \ - commands/virtual_partitions.c \ - fastbootd.c \ - protocol.c \ - network_discovery.c \ - socket_client.c \ - secure.c \ - transport.c \ - transport_socket.c \ - trigger.c \ - usb_linux_client.c \ - utils.c \ - -LOCAL_MODULE := fastbootd -LOCAL_MODULE_TAGS := optional -LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter -DFLASH_CERT -LOCAL_LDFLAGS := -ldl - -LOCAL_STATIC_LIBRARIES := \ - libc \ - libcrypto_static \ - libcutils \ - libmdnssd \ - libsparse_static \ - libz - -LOCAL_HAL_STATIC_LIBRARIES := libvendortrigger - -LOCAL_FORCE_STATIC_EXECUTABLE := true - -include $(BUILD_EXECUTABLE) - -include $(CLEAR_VARS) -LOCAL_C_INCLUDES := \ - external/zlib/ - -LOCAL_SRC_FILES := \ - commands/partitions.c \ - other/gptedit.c \ - utils.c - -LOCAL_MODULE := gptedit -LOCAL_MODULE_TAGS := optional -LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter - -LOCAL_STATIC_LIBRARIES := \ - libsparse_static \ - libc \ - libcutils \ - libz - -LOCAL_FORCE_STATIC_EXECUTABLE := true - -include $(BUILD_EXECUTABLE) - -# vendor trigger HAL -include $(CLEAR_VARS) -LOCAL_CFLAGS := -Wall -Werror -LOCAL_MODULE := libvendortrigger.default -LOCAL_MODULE_TAGS := optional -LOCAL_SRC_FILES := vendor_trigger_default.c -LOCAL_STATIC_LIBRARIES := libcutils -include $(BUILD_STATIC_LIBRARY) diff --git a/fastbootd/bootimg.h b/fastbootd/bootimg.h deleted file mode 100644 index 44fde92..0000000 --- a/fastbootd/bootimg.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#ifndef _BOOT_IMAGE_H_ -#define _BOOT_IMAGE_H_ - -typedef struct boot_img_hdr boot_img_hdr; - -#define BOOT_MAGIC "ANDROID!" -#define BOOT_MAGIC_SIZE 8 -#define BOOT_NAME_SIZE 16 -#define BOOT_ARGS_SIZE 512 - -struct boot_img_hdr -{ - unsigned char magic[BOOT_MAGIC_SIZE]; - - unsigned kernel_size; /* size in bytes */ - unsigned kernel_addr; /* physical load addr */ - - unsigned ramdisk_size; /* size in bytes */ - unsigned ramdisk_addr; /* physical load addr */ - - unsigned second_size; /* size in bytes */ - unsigned second_addr; /* physical load addr */ - - unsigned tags_addr; /* physical addr for kernel tags */ - unsigned page_size; /* flash page size we assume */ - unsigned unused[2]; /* future expansion: should be 0 */ - - unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */ - - unsigned char cmdline[BOOT_ARGS_SIZE]; - - unsigned id[8]; /* timestamp / checksum / sha1 / etc */ -}; - -/* -** +-----------------+ -** | boot header | 1 page -** +-----------------+ -** | kernel | n pages -** +-----------------+ -** | ramdisk | m pages -** +-----------------+ -** | second stage | o pages -** +-----------------+ -** -** n = (kernel_size + page_size - 1) / page_size -** m = (ramdisk_size + page_size - 1) / page_size -** o = (second_size + page_size - 1) / page_size -** -** 0. all entities are page_size aligned in flash -** 1. kernel and ramdisk are required (size != 0) -** 2. second is optional (second_size == 0 -> no second) -** 3. load each element (kernel, ramdisk, second) at -** the specified physical address (kernel_addr, etc) -** 4. prepare tags at tag_addr. kernel_args[] is -** appended to the kernel commandline in the tags. -** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr -** 6. if second_size != 0: jump to second_addr -** else: jump to kernel_addr -*/ - -boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, - void *ramdisk, unsigned ramdisk_size, - void *second, unsigned second_size, - unsigned page_size, - unsigned *bootimg_size); - -void bootimg_set_cmdline(boot_img_hdr *hdr, const char *cmdline); -#endif diff --git a/fastbootd/commands.c b/fastbootd/commands.c deleted file mode 100644 index 98b7866..0000000 --- a/fastbootd/commands.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <inttypes.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <unistd.h> -#include <sys/reboot.h> -#include <fcntl.h> - -#include "bootimg.h" -#include "commands/boot.h" -#include "commands/flash.h" -#include "commands/partitions.h" -#include "commands/virtual_partitions.h" -#include "debug.h" -#include "protocol.h" -#include "trigger.h" -#include "utils.h" - -#define ATAGS_LOCATION "/proc/atags" - -static void cmd_boot(struct protocol_handle *phandle, const char *arg) -{ - int sz, atags_sz, new_atags_sz; - int rv; - unsigned kernel_actual; - unsigned ramdisk_actual; - unsigned second_actual; - void *kernel_ptr; - void *ramdisk_ptr; - void *second_ptr; - struct boot_img_hdr *hdr; - char *ptr = NULL; - char *atags_ptr = NULL; - char *new_atags = NULL; - int data_fd = 0; - - D(DEBUG, "cmd_boot %s\n", arg); - - if (phandle->download_fd < 0) { - fastboot_fail(phandle, "no kernel file"); - return; - } - - atags_ptr = read_atags(ATAGS_LOCATION, &atags_sz); - if (atags_ptr == NULL) { - fastboot_fail(phandle, "atags read error"); - goto error; - } - - // TODO: With cms we can also verify partition name included as - // cms signed attribute - if (flash_validate_certificate(phandle->download_fd, &data_fd) != 1) { - fastboot_fail(phandle, "Access forbiden you need the certificate"); - return; - } - - sz = get_file_size(data_fd); - - ptr = (char *) mmap(NULL, sz, PROT_READ, - MAP_POPULATE | MAP_PRIVATE, data_fd, 0); - - hdr = (struct boot_img_hdr *) ptr; - - if (ptr == MAP_FAILED) { - fastboot_fail(phandle, "internal fastbootd error"); - goto error; - } - - if ((size_t) sz < sizeof(*hdr)) { - fastboot_fail(phandle, "invalid bootimage header"); - goto error; - } - - kernel_actual = ROUND_TO_PAGE(hdr->kernel_size, hdr->page_size); - ramdisk_actual = ROUND_TO_PAGE(hdr->ramdisk_size, hdr->page_size); - second_actual = ROUND_TO_PAGE(hdr->second_size, hdr->page_size); - - new_atags = (char *) create_atags((unsigned *) atags_ptr, atags_sz, hdr, &new_atags_sz); - - if (new_atags == NULL) { - fastboot_fail(phandle, "atags generate error"); - goto error; - } - if (new_atags_sz > 0x4000) { - fastboot_fail(phandle, "atags file to large"); - goto error; - } - - if ((int) (hdr->page_size + kernel_actual + ramdisk_actual) < sz) { - fastboot_fail(phandle, "incomplete bootimage"); - goto error; - } - - kernel_ptr = (void *)((uintptr_t) ptr + hdr->page_size); - ramdisk_ptr = (void *)((uintptr_t) kernel_ptr + kernel_actual); - second_ptr = (void *)((uintptr_t) ramdisk_ptr + ramdisk_actual); - - D(INFO, "preparing to boot"); - // Prepares boot physical address. Addresses from header are ignored - rv = prepare_boot_linux(hdr->kernel_addr, kernel_ptr, kernel_actual, - hdr->ramdisk_addr, ramdisk_ptr, ramdisk_actual, - hdr->second_addr, second_ptr, second_actual, - hdr->tags_addr, new_atags, ROUND_TO_PAGE(new_atags_sz, hdr->page_size)); - if (rv < 0) { - fastboot_fail(phandle, "kexec prepare failed"); - goto error; - } - - fastboot_okay(phandle, ""); - - free(atags_ptr); - munmap(ptr, sz); - free(new_atags); - close(data_fd); - - D(INFO, "Kexec going to reboot"); - reboot(LINUX_REBOOT_CMD_KEXEC); - - fastboot_fail(phandle, "reboot error"); - - return; - -error: - - if (atags_ptr != NULL) - free(atags_ptr); - if (ptr != NULL) - munmap(ptr, sz); - -} - -static void cmd_erase(struct protocol_handle *phandle, const char *arg) -{ - int partition_fd; - char path[PATH_MAX]; - D(DEBUG, "cmd_erase %s\n", arg); - - if (flash_find_entry(arg, path, PATH_MAX)) { - fastboot_fail(phandle, "partition table doesn't exist"); - return; - } - - if (path == NULL) { - fastboot_fail(phandle, "Couldn't find partition"); - return; - } - - partition_fd = flash_get_partiton(path); - if (partition_fd < 0) { - fastboot_fail(phandle, "partiton file does not exists"); - } - - if (flash_erase(partition_fd)) { - fastboot_fail(phandle, "failed to erase partition"); - flash_close(partition_fd); - return; - } - - if (flash_close(partition_fd) < 0) { - D(ERR, "could not close device %s", strerror(errno)); - fastboot_fail(phandle, "failed to erase partition"); - return; - } - fastboot_okay(phandle, ""); -} - -static int GPT_header_location() { - const char *location_str = fastboot_getvar("gpt_sector"); - char *str; - int location; - - if (!strcmp("", location_str)) { - D(INFO, "GPT location not specified using second sector"); - return 1; - } - else { - location = strtoul(location_str, &str, 10); - D(INFO, "GPT location specified as %d", location); - - if (*str != '\0') - return -1; - - return location - 1; - } -} - -static void cmd_gpt_layout(struct protocol_handle *phandle, const char *arg) { - struct GPT_entry_table *oldtable; - int location; - struct GPT_content content; - const char *device; - device = fastboot_getvar("blockdev"); - - if (!strcmp(device, "")) { - fastboot_fail(phandle, "blockdev not defined in config file"); - return; - } - - //TODO: add same verification as in cmd_flash - if (phandle->download_fd < 0) { - fastboot_fail(phandle, "no layout file"); - return; - } - - location = GPT_header_location(); - oldtable = GPT_get_device(device, location); - - GPT_default_content(&content, oldtable); - if (oldtable == NULL) - D(WARN, "Could not get old gpt table"); - else - GPT_release_device(oldtable); - - if (!GPT_parse_file(phandle->download_fd, &content)) { - fastboot_fail(phandle, "Could not parse partition config file"); - return; - } - - if (trigger_gpt_layout(&content)) { - fastboot_fail(phandle, "Vendor forbids this opperation"); - GPT_release_content(&content); - return; - } - - if (!GPT_write_content(device, &content)) { - fastboot_fail(phandle, "Unable to write gpt file"); - GPT_release_content(&content); - return; - } - - GPT_release_content(&content); - fastboot_okay(phandle, ""); -} - -static void cmd_flash(struct protocol_handle *phandle, const char *arg) -{ - int partition; - uint64_t sz; - char data[BOOT_MAGIC_SIZE]; - char path[PATH_MAX]; - ssize_t header_sz = 0; - int data_fd = 0; - - D(DEBUG, "cmd_flash %s\n", arg); - - if (try_handle_virtual_partition(phandle, arg)) { - return; - } - - if (phandle->download_fd < 0) { - fastboot_fail(phandle, "no kernel file"); - return; - } - - if (flash_find_entry(arg, path, PATH_MAX)) { - fastboot_fail(phandle, "partition table doesn't exist"); - return; - } - - if (flash_validate_certificate(phandle->download_fd, &data_fd) != 1) { - fastboot_fail(phandle, "Access forbiden you need certificate"); - return; - } - - // TODO: Maybe its goot idea to check whether the partition is bootable - if (!strcmp(arg, "boot") || !strcmp(arg, "recovery")) { - if (read_data_once(data_fd, data, BOOT_MAGIC_SIZE) < BOOT_MAGIC_SIZE) { - fastboot_fail(phandle, "incoming data read error, cannot read boot header"); - return; - } - if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { - fastboot_fail(phandle, "image is not a boot image"); - return; - } - } - - partition = flash_get_partiton(path); - - sz = get_file_size64(data_fd); - - sz -= header_sz; - - if (sz > get_file_size64(partition)) { - flash_close(partition); - D(WARN, "size of file too large"); - fastboot_fail(phandle, "size of file too large"); - return; - } - - D(INFO, "writing %"PRId64" bytes to '%s'\n", sz, arg); - - if (flash_write(partition, phandle->download_fd, sz, header_sz)) { - fastboot_fail(phandle, "flash write failure"); - return; - } - D(INFO, "partition '%s' updated\n", arg); - - flash_close(partition); - close(data_fd); - - fastboot_okay(phandle, ""); -} - -static void cmd_continue(struct protocol_handle *phandle, const char *arg) -{ - fastboot_okay(phandle, ""); -#if 0 - udc_stop(); - - boot_linux_from_flash(); -#endif -} - -static void cmd_getvar(struct protocol_handle *phandle, const char *arg) -{ - const char *value; - D(DEBUG, "cmd_getvar %s\n", arg); - - value = fastboot_getvar(arg); - - fastboot_okay(phandle, value); -} - -static void cmd_download(struct protocol_handle *phandle, const char *arg) -{ - unsigned len = strtoul(arg, NULL, 16); - int old_fd; - - if (len > 256 * 1024 * 1024) { - fastboot_fail(phandle, "data too large"); - return; - } - - fastboot_data(phandle, len); - - old_fd = protocol_get_download(phandle); - if (old_fd >= 0) { - off_t len = lseek(old_fd, 0, SEEK_END); - D(INFO, "disposing of unused fd %d, size %ld", old_fd, len); - close(old_fd); - } - - phandle->download_fd = protocol_handle_download(phandle, len); - if (phandle->download_fd < 0) { - fastboot_fail(phandle, "download failed"); - return; - } - - fastboot_okay(phandle, ""); -} - -static void cmd_oem(struct protocol_handle *phandle, const char *arg) { - const char *response = ""; - - //TODO: Maybe it should get download descriptor also - if (trigger_oem_cmd(arg, &response)) - fastboot_fail(phandle, response); - else - fastboot_okay(phandle, response); -} - -void commands_init() -{ - virtual_partition_register("partition-table", cmd_gpt_layout); - - fastboot_register("boot", cmd_boot); - fastboot_register("erase:", cmd_erase); - fastboot_register("flash:", cmd_flash); - fastboot_register("continue", cmd_continue); - fastboot_register("getvar:", cmd_getvar); - fastboot_register("download:", cmd_download); - fastboot_register("oem", cmd_oem); - //fastboot_publish("version", "0.5"); - //fastboot_publish("product", "swordfish"); - //fastboot_publish("kernel", "lk"); -} diff --git a/fastbootd/commands/boot.c b/fastbootd/commands/boot.c deleted file mode 100644 index 922914b..0000000 --- a/fastbootd/commands/boot.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <sys/syscall.h> -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <unistd.h> - -#include "boot.h" -#include "debug.h" -#include "utils.h" -#include "bootimg.h" - - -#define KEXEC_ARM_ATAGS_OFFSET 0x1000 -#define KEXEC_ARM_ZIMAGE_OFFSET 0x8000 - -#define MEMORY_SIZE 0x0800000 -#define START_ADDRESS 0x44000000 -#define KERNEL_START (START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET) - -#define ATAG_NONE_TYPE 0x00000000 -#define ATAG_CORE_TYPE 0x54410001 -#define ATAG_RAMDISK_TYPE 0x54410004 -#define ATAG_INITRD2_TYPE 0x54420005 -#define ATAG_CMDLINE_TYPE 0x54410009 - -#define MAX_ATAG_SIZE 0x4000 - -struct atag_info { - unsigned size; - unsigned type; -}; - -struct atag_initrd2 { - unsigned start; - unsigned size; -}; - -struct atag_cmdline { - char cmdline[0]; -}; - -struct atag { - struct atag_info info; - union { - struct atag_initrd2 initrd2; - struct atag_cmdline cmdline; - } data; -}; - - -long kexec_load(unsigned int entry, unsigned long nr_segments, - struct kexec_segment *segment, unsigned long flags) { - return syscall(__NR_kexec_load, entry, nr_segments, segment, flags); -} - -/* - * Prepares arguments for kexec - * Kernel address is not set into kernel_phys - * Ramdisk is set to position relative to kernel - */ -int prepare_boot_linux(uintptr_t kernel_phys, void *kernel_addr, int kernel_size, - uintptr_t ramdisk_phys, void *ramdisk_addr, int ramdisk_size, - uintptr_t second_phys, void *second_addr, int second_size, - uintptr_t atags_phys, void *atags_addr, int atags_size) { - struct kexec_segment segment[4]; - int segment_count = 2; - unsigned entry = START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET; - int rv; - int page_size = getpagesize(); - - segment[0].buf = kernel_addr; - segment[0].bufsz = kernel_size; - segment[0].mem = (void *) KERNEL_START; - segment[0].memsz = ROUND_TO_PAGE(kernel_size, page_size); - - if (kernel_size > MEMORY_SIZE - KEXEC_ARM_ZIMAGE_OFFSET) { - D(INFO, "Kernel image too big"); - return -1; - } - - segment[1].buf = atags_addr; - segment[1].bufsz = atags_size; - segment[1].mem = (void *) (START_ADDRESS + KEXEC_ARM_ATAGS_OFFSET); - segment[1].memsz = ROUND_TO_PAGE(atags_size, page_size); - - D(INFO, "Ramdisk size is %d", ramdisk_size); - - if (ramdisk_size != 0) { - segment[segment_count].buf = ramdisk_addr; - segment[segment_count].bufsz = ramdisk_size; - segment[segment_count].mem = (void *) (KERNEL_START + ramdisk_phys - kernel_phys); - segment[segment_count].memsz = ROUND_TO_PAGE(ramdisk_phys, page_size); - ++segment_count; - } - - D(INFO, "Ramdisk size is %d", ramdisk_size); - if (second_size != 0) { - segment[segment_count].buf = second_addr; - segment[segment_count].bufsz = second_size; - segment[segment_count].mem = (void *) (KERNEL_START + second_phys - kernel_phys); - segment[segment_count].memsz = ROUND_TO_PAGE(second_size, page_size); - entry = second_phys; - ++segment_count; - } - - rv = kexec_load(entry, segment_count, segment, KEXEC_ARCH_DEFAULT); - - if (rv != 0) { - D(INFO, "Kexec_load returned non-zero exit code: %s\n", strerror(errno)); - return -1; - } - - return 1; - -} - -unsigned *create_atags(unsigned *atags_position, int atag_size, const struct boot_img_hdr *hdr, int *size) { - struct atag *current_tag = (struct atag *) atags_position; - unsigned *current_tag_raw = atags_position; - unsigned *new_atags = malloc(ROUND_TO_PAGE(atag_size + BOOT_ARGS_SIZE * sizeof(char), - hdr->page_size)); - //This pointer will point into the beggining of buffer free space - unsigned *natags_raw_buff = new_atags; - int new_atags_size = 0; - int current_size; - int cmdl_length; - - // copy tags from current atag file - while (current_tag->info.type != ATAG_NONE_TYPE) { - switch (current_tag->info.type) { - case ATAG_CMDLINE_TYPE: - case ATAG_RAMDISK_TYPE: - case ATAG_INITRD2_TYPE: break; - default: - memcpy((void *)natags_raw_buff, (void *)current_tag_raw, current_tag->info.size * sizeof(unsigned)); - natags_raw_buff += current_tag->info.size; - new_atags_size += current_tag->info.size; - } - - current_tag_raw += current_tag->info.size; - current_tag = (struct atag *) current_tag_raw; - - if (current_tag_raw >= atags_position + atag_size) { - D(ERR, "Critical error in atags"); - return NULL; - } - } - - // set INITRD2 tag - if (hdr->ramdisk_size > 0) { - current_size = (sizeof(struct atag_info) + sizeof(struct atag_initrd2)) / sizeof(unsigned); - *((struct atag *) natags_raw_buff) = (struct atag) { - .info = { - .size = current_size, - .type = ATAG_INITRD2_TYPE - }, - .data = { - .initrd2 = (struct atag_initrd2) { - .start = hdr->ramdisk_addr, - .size = hdr->ramdisk_size - } - } - }; - - new_atags_size += current_size; - natags_raw_buff += current_size; - } - - // set ATAG_CMDLINE - cmdl_length = strnlen((char *) hdr->cmdline, BOOT_ARGS_SIZE - 1); - current_size = sizeof(struct atag_info) + (1 + cmdl_length); - current_size = (current_size + sizeof(unsigned) - 1) / sizeof(unsigned); - *((struct atag *) natags_raw_buff) = (struct atag) { - .info = { - .size = current_size, - .type = ATAG_CMDLINE_TYPE - }, - }; - - //copy cmdline and ensure that there is null character - memcpy(((struct atag *) natags_raw_buff)->data.cmdline.cmdline, - (char *) hdr->cmdline, cmdl_length); - ((struct atag *) natags_raw_buff)->data.cmdline.cmdline[cmdl_length] = '\0'; - - new_atags_size += current_size; - natags_raw_buff += current_size; - - // set ATAG_NONE - *((struct atag *) natags_raw_buff) = (struct atag) { - .info = { - .size = 0, - .type = ATAG_NONE_TYPE - }, - }; - new_atags_size += sizeof(struct atag_info) / sizeof(unsigned); - natags_raw_buff += sizeof(struct atag_info) / sizeof(unsigned); - - *size = new_atags_size * sizeof(unsigned); - return new_atags; -} - -char *read_atags(const char * path, int *atags_sz) { - int afd = -1; - char *atags_ptr = NULL; - - afd = open(path, O_RDONLY); - if (afd < 0) { - D(ERR, "wrong atags file"); - return 0; - } - - atags_ptr = (char *) malloc(MAX_ATAG_SIZE); - if (atags_ptr == NULL) { - D(ERR, "insufficient memory"); - return 0; - } - - *atags_sz = read(afd, atags_ptr, MAX_ATAG_SIZE); - - close(afd); - return atags_ptr; -} - diff --git a/fastbootd/commands/boot.h b/fastbootd/commands/boot.h deleted file mode 100644 index a5efd01..0000000 --- a/fastbootd/commands/boot.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#ifndef __FASTBOOT_BOOT_H -#define __FASTBOOT_BOOT_H - -#include <sys/cdefs.h> -#include <linux/kexec.h> - -#include "bootimg.h" - -#define KEXEC_TYPE_DEFAULT 0 -#define KEXEC_TYPE_CRASH 1 - -int prepare_boot_linux(uintptr_t, void *, int, uintptr_t, void *, int, - uintptr_t, void *, int, uintptr_t, void *, int); -unsigned *create_atags(unsigned *, int, const struct boot_img_hdr *, int *); -long kexec_load(unsigned int, unsigned long, struct kexec_segment *, unsigned long); -char *read_atags(const char *, int *); - -#endif /* _SYS_KEXEC_H */ - diff --git a/fastbootd/commands/flash.c b/fastbootd/commands/flash.c deleted file mode 100644 index 1eb4d1b..0000000 --- a/fastbootd/commands/flash.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <sys/stat.h> -#include <fcntl.h> -#include <inttypes.h> -#include <sys/mman.h> - -#include "flash.h" -#include "protocol.h" -#include "debug.h" -#include "utils.h" -#include "commands/partitions.h" - -#ifdef FLASH_CERT -#include "secure.h" -#endif - -#define ALLOWED_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-." -#define BUFFER_SIZE 1024 * 1024 -#define MIN(a, b) (a > b ? b : a) - - -int flash_find_entry(const char *name, char *out, size_t outlen) -{ -//TODO: Assumption: All the partitions has they unique name - - const char *path = fastboot_getvar("device-directory"); - size_t length; - if (strcmp(path, "") == 0) { - D(ERR, "device-directory: not defined in config file"); - return -1; - } - - length = strspn(name, ALLOWED_CHARS); - if (length != strlen(name)) { - D(ERR, "Not allowed char in name: %c", name[length]); - return -1; - } - - if (snprintf(out, outlen, "%s%s", path, name) >= (int) outlen) { - D(ERR, "Too long path to partition file"); - return -1; - } - - if (access(out, F_OK ) == -1) { - D(ERR, "could not find partition file %s", name); - return -1; - } - - return 0; -} - -int flash_erase(int fd) -{ - int64_t size; - size = get_block_device_size(fd); - D(DEBUG, "erase %"PRId64" data from %d\n", size, fd); - - return wipe_block_device(fd, size); -} - -int flash_write(int partition_fd, int data_fd, ssize_t size, ssize_t skip) -{ - ssize_t written = 0; - struct GPT_mapping input; - struct GPT_mapping output; - - while (written < size) { - int current_size = MIN(size - written, BUFFER_SIZE); - - if (gpt_mmap(&input, written + skip, current_size, data_fd)) { - D(ERR, "Error in writing data, unable to map data file %zd at %zd size %d", size, skip, current_size); - return -1; - } - if (gpt_mmap(&output, written, current_size, partition_fd)) { - D(ERR, "Error in writing data, unable to map output partition"); - return -1; - } - - memcpy(output.ptr, input.ptr, current_size); - - gpt_unmap(&input); - gpt_unmap(&output); - - written += current_size; - } - - return 0; -} - -#ifdef FLASH_CERT - -int flash_validate_certificate(int signed_fd, int *data_fd) { - int ret = 0; - const char *cert_path; - X509_STORE *store = NULL; - CMS_ContentInfo *content_info; - BIO *content; - - cert_path = fastboot_getvar("certificate-path"); - if (!strcmp(cert_path, "")) { - D(ERR, "could not find cert-key value in config file"); - goto finish; - } - - store = cert_store_from_path(cert_path); - if (store == NULL) { - D(ERR, "unable to create certification store"); - goto finish; - } - - if (cert_read(signed_fd, &content_info, &content)) { - D(ERR, "reading data failed"); - goto finish; - } - - ret = cert_verify(content, content_info, store, data_fd); - cert_release(content, content_info); - - return ret; - -finish: - if (store != NULL) - cert_release_store(store); - - return ret; -} - -#else -int flash_validate_certificate(int signed_fd, int *data_fd) { - return 1; -} -#endif diff --git a/fastbootd/commands/flash.h b/fastbootd/commands/flash.h deleted file mode 100644 index 5a64cab..0000000 --- a/fastbootd/commands/flash.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#ifndef _FASTBOOTD_ERASE_H -#define _FASTBOOTD_ERASE_H - -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include "debug.h" - -int flash_find_entry(const char *, char *, size_t); -int flash_erase(int fd); - -static inline int flash_get_partiton(const char *path) { - return open(path, O_RDWR); -} - -static inline int flash_close(int fd) { - return close(fd); -} - -int flash_write(int partition, int data, ssize_t size, ssize_t skip); - -static inline ssize_t read_data_once(int fd, char *buffer, ssize_t size) { - ssize_t readcount = 0; - ssize_t len; - - while ((len = TEMP_FAILURE_RETRY(read(fd, (void *) &buffer[readcount], size - readcount))) > 0) { - readcount += len; - } - if (len < 0) { - D(ERR, "Read error:%s", strerror(errno)); - return len; - } - - return readcount; -} - -int flash_validate_certificate(int signed_fd, int *data_fd); - -#endif - diff --git a/fastbootd/commands/partitions.c b/fastbootd/commands/partitions.c deleted file mode 100644 index 74232e6..0000000 --- a/fastbootd/commands/partitions.c +++ /dev/null @@ -1,772 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#include <endian.h> -#include <zlib.h> -#include <linux/hdreg.h> -#include <sys/ioctl.h> -#include <stdlib.h> -#include <cutils/config_utils.h> -#include <inttypes.h> - -#include "partitions.h" -#include "debug.h" -#include "utils.h" -#include "protocol.h" - -#define BLKRRPART _IO(0x12,95) /* re-read partition table */ -#define BLKSSZGET _IO(0x12,104) - -#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y)) -#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y))) -#define ALIGN_DOWN(x, y) ((y) * ((x) / (y))) - - -const uint8_t partition_type_uuid[16] = { - 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44, - 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7, -}; - -//TODO: There is assumption that we are using little endian - -static void GPT_entry_clear(struct GPT_entry_raw *entry) -{ - memset(entry, 0, sizeof(*entry)); -} - -/* - * returns mapped location to choosen area - * mapped_ptr is pointer to whole area mapped (it can be bigger then requested) - */ -int gpt_mmap(struct GPT_mapping *mapping, uint64_t location, int size, int fd) -{ - unsigned int location_diff = location & ~PAGE_MASK; - - mapping->size = ALIGN(size + location_diff, PAGE_SIZE); - - uint64_t sz = get_file_size64(fd); - if (sz < size + location) { - D(ERR, "the location of mapping area is outside of the device size %" PRId64, sz); - return 1; - } - location = ALIGN_DOWN(location, PAGE_SIZE); - - mapping->map_ptr = mmap64(NULL, mapping->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, location); - - if (mapping->map_ptr == MAP_FAILED) { - mapping->ptr = MAP_FAILED; - D(ERR, "map failed: %s", strerror(errno)); - return 1; - } - - mapping->ptr = (void *)((char *) mapping->map_ptr + location_diff); - return 0; -} - -void gpt_unmap(struct GPT_mapping *mapping) { - munmap(mapping->map_ptr, mapping->size); -} - - -#define LBA_ADDR(table, value) ((uint64_t) (table)->sector_size * (value)) - -int GPT_map_from_content(struct GPT_entry_table *table, const struct GPT_content *content) -{ - - // Mapping header - if (gpt_mmap(&table->header_map, LBA_ADDR(table, content->header.current_lba), - table->sector_size, table->fd)) { - D(ERR, "unable to map header:%s\n", strerror(errno)); - goto error_header; - } - - table->header = (struct GPT_header *) table->header_map.ptr; - - table->partition_table_size = ROUND_UP(content->header.entries_count * sizeof(*table->entries), - table->sector_size); - - // Mapping entry table - if (gpt_mmap(&table->entries_map, LBA_ADDR(table, content->header.entries_lba), - table->partition_table_size, table->fd)) { - D(ERR, "unable to map entries"); - goto error_signature; - } - - table->entries = (struct GPT_entry_raw *) table->entries_map.ptr; - - // Mapping secondary header - if (gpt_mmap(&table->sec_header_map, LBA_ADDR(table, content->header.backup_lba), - table->sector_size, table->fd)) { - D(ERR, "unable to map backup gpt header"); - goto error_sec_header; - } - - // Mapping secondary entries table - if (gpt_mmap(&table->sec_entries_map, - LBA_ADDR(table, content->header.backup_lba) - table->partition_table_size, - table->partition_table_size, table->fd)) { - D(ERR, "unable to map secondary gpt table"); - goto error_sec_entries; - } - - table->second_header = (struct GPT_header *) table->sec_header_map.ptr; - table->second_entries = (struct GPT_entry_raw *) table->sec_entries_map.ptr; - table->second_valid = strcmp("EFI PART", (char *) table->second_header->signature) == 0; - - return 0; - -error_sec_entries: - gpt_unmap(&table->sec_header_map); -error_sec_header: - gpt_unmap(&table->entries_map); -error_signature: - gpt_unmap(&table->header_map); -error_header: - return 1; -} - -int GPT_map(struct GPT_entry_table *table, unsigned header_lba) -{ - struct GPT_content content; - struct GPT_mapping mapping; - struct GPT_header *header; - - if (gpt_mmap(&mapping, LBA_ADDR(table, header_lba), table->sector_size, table->fd)) { - D(ERR, "unable to map header: %s", strerror(errno)); - goto error_header; - } - - header = (struct GPT_header *) mapping.ptr; - - if (strcmp("EFI PART", (char *) header->signature)) { - D(ERR, "GPT entry not valid"); - goto error_signature; - } - - content.header = *header; - - gpt_unmap(&mapping); - - return GPT_map_from_content(table, &content); - -error_signature: - gpt_unmap(&table->header_map); -error_header: - return 1; -} - -struct GPT_entry_table* GPT_get_device(const char *path, unsigned header_lba) -{ - struct GPT_entry_table *table; - size_t sector_bytes; - - table = (struct GPT_entry_table *) malloc(sizeof(*table)); - table->fd = open(path, O_RDWR); - - if (table->fd < 0) { - D(ERR, "unable to open file %s:%s\n", path, strerror(errno)); - return NULL; - } - - if (!ioctl(table->fd, BLKSSZGET, §or_bytes)) { - table->sector_size = (unsigned) sector_bytes; - D(INFO, "Got sector size %d", table->sector_size); - } else { - D(WARN, "unable to get sector size, assuming 512"); - table->sector_size = 512; - } - - if (GPT_map(table, header_lba)) { - D(ERR, "Could not map gpt"); - return NULL; - } - - return table; -} - -static struct GPT_entry_table* GPT_get_from_content(const char *path, const struct GPT_content *content) -{ - struct GPT_entry_table *table; - size_t sector_bytes; - - table = (struct GPT_entry_table *) malloc(sizeof(*table)); - table->fd = open(path, O_RDWR); - - if (table->fd < 0) { - D(ERR, "unable to open file %s:%s\n", path, strerror(errno)); - return NULL; - } - - if (!ioctl(table->fd, BLKSSZGET, §or_bytes)) { - table->sector_size = (unsigned) sector_bytes; - D(INFO, "Got sector size %d", table->sector_size); - } else { - D(WARN, "unable to get sector size %s, assuming 512", strerror(errno)); - table->sector_size = 512; - } - - if (GPT_map_from_content(table, content)) { - D(ERR, "Could not map gpt"); - return NULL; - } - - return table; -} - - -void GPT_release_device(struct GPT_entry_table *table) -{ - gpt_unmap(&table->header_map); - gpt_unmap(&table->entries_map); - gpt_unmap(&table->sec_header_map); - gpt_unmap(&table->sec_entries_map); - close(table->fd); - free(table); -} - -static int GPT_check_overlap(struct GPT_entry_table *table, struct GPT_entry_raw *entry); -static int GPT_check_overlap_except(struct GPT_entry_table *table, - struct GPT_entry_raw *entry, - struct GPT_entry_raw *exclude); - -void GPT_edit_entry(struct GPT_entry_table *table, - struct GPT_entry_raw *old_entry, - struct GPT_entry_raw *new_entry) -{ - struct GPT_entry_raw *current_entry = GPT_get_pointer(table, old_entry); - - if (GPT_check_overlap_except(table, new_entry, current_entry)) { - D(ERR, "Couldn't add overlaping partition"); - return; - } - - if (current_entry == NULL) { - D(ERR, "Couldn't find entry"); - return; - } - - *current_entry = *new_entry; -} - -int GPT_delete_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry) -{ - struct GPT_entry_raw *raw = GPT_get_pointer(table, entry); - - if (raw == NULL) { - D(ERR, "could not find entry"); - return 1; - } - D(DEBUG, "Deleting gpt entry '%s'\n", raw->partition_guid); - - // Entry in the middle of table may become empty - GPT_entry_clear(raw); - - return 0; -} - -void GPT_add_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry) -{ - unsigned i; - int inserted = 0; - if (GPT_check_overlap(table, entry)) { - D(ERR, "Couldn't add overlaping partition"); - return; - } - - if (GPT_get_pointer(table, entry) != NULL) { - D(WARN, "Add entry fault, this entry already exists"); - return; - } - - struct GPT_entry_raw *entries = table->entries; - - for (i = 0; i < table->header->entries_count; ++i) { - if (!entries[i].type_guid[0]) { - inserted = 1; - D(DEBUG, "inserting"); - memcpy(&entries[i], entry, sizeof(entries[i])); - break; - } - } - - if (!inserted) { - D(ERR, "Unable to find empty partion entry"); - } -} - -struct GPT_entry_raw *GPT_get_pointer_by_UTFname(struct GPT_entry_table *table, const uint16_t *name); - -struct GPT_entry_raw *GPT_get_pointer(struct GPT_entry_table *table, struct GPT_entry_raw *entry) -{ - if (entry->partition_guid[0] != 0) - return GPT_get_pointer_by_guid(table, (const char *) entry->partition_guid); - else if (entry->name[0] != 0) - return GPT_get_pointer_by_UTFname(table, entry->name); - - D(WARN, "Name or guid needed to find entry"); - return NULL; -} - -struct GPT_entry_raw *GPT_get_pointer_by_guid(struct GPT_entry_table *table, const char *name) -{ - int current = (int) table->header->entries_count; - - for (current = current - 1; current >= 0; --current) { - if (strncmp((char *) name, - (char *) table->entries[current].partition_guid, 16) == 0) { - return &table->entries[current]; - } - } - - return NULL; -} - -int strncmp_UTF16_char(const uint16_t *s1, const char *s2, size_t n) -{ - if (n == 0) - return (0); - do { - if (((*s1) & 127) != *s2++) - return (((unsigned char) ((*s1) & 127)) - *(unsigned char *)--s2); - if (*s1++ == 0) - break; - } while (--n != 0); - return (0); -} - -int strncmp_UTF16(const uint16_t *s1, const uint16_t *s2, size_t n) -{ - if (n == 0) - return (0); - do { - if ((*s1) != *s2++) - return (*s1 - *--s2); - if (*s1++ == 0) - break; - } while (--n != 0); - return (0); -} - -struct GPT_entry_raw *GPT_get_pointer_by_name(struct GPT_entry_table *table, const char *name) -{ - int count = (int) table->header->entries_count; - int current; - - for (current = 0; current < count; ++current) { - if (strncmp_UTF16_char(table->entries[current].name, - (char *) name, 16) == 0) { - return &table->entries[current]; - } - } - - return NULL; -} - -struct GPT_entry_raw *GPT_get_pointer_by_UTFname(struct GPT_entry_table *table, const uint16_t *name) -{ - int count = (int) table->header->entries_count; - int current; - - for (current = 0; current < count; ++current) { - if (strncmp_UTF16(table->entries[current].name, - name, GPT_NAMELEN) == 0) { - return &table->entries[current]; - } - } - - return NULL; -} - -void GPT_sync(struct GPT_entry_table *table) -{ - uint32_t crc; - - //calculate crc32 - crc = crc32(0, Z_NULL, 0); - crc = crc32(crc, (void*) table->entries, table->header->entries_count * sizeof(*table->entries)); - table->header->partition_array_checksum = crc; - - table->header->header_checksum = 0; - crc = crc32(0, Z_NULL, 0); - crc = crc32(crc, (void*) table->header, table->header->header_size); - table->header->header_checksum = crc; - - //sync secondary partion - if (table->second_valid) { - memcpy((void *)table->second_entries, (void *) table->entries, table->partition_table_size); - memcpy((void *)table->second_header, (void *)table->header, sizeof(*table->header)); - } - - if(!ioctl(table->fd, BLKRRPART, NULL)) { - D(WARN, "Unable to force kernel to refresh partition table"); - } -} - -void GPT_to_UTF16(uint16_t *to, const char *from, int n) -{ - int i; - for (i = 0; i < (n - 1) && (to[i] = from[i]) != '\0'; ++i); - to[i] = '\0'; -} - -void GPT_from_UTF16(char *to, const uint16_t *from, int n) -{ - int i; - for (i = 0; i < (n - 1) && (to[i] = from[i] & 127) != '\0'; ++i); - to[i] = '\0'; -} - -static int GPT_check_overlap_except(struct GPT_entry_table *table, - struct GPT_entry_raw *entry, - struct GPT_entry_raw *exclude) { - int current = (int) table->header->entries_count; - int dontcheck; - struct GPT_entry_raw *current_entry; - if (entry->last_lba < entry->first_lba) { - D(WARN, "Start address have to be less than end address"); - return 1; - } - - for (current = current - 1; current >= 0; --current) { - current_entry = &table->entries[current]; - dontcheck = strncmp((char *) entry->partition_guid, - (char *) current_entry->partition_guid , 16) == 0; - dontcheck |= current_entry->type_guid[0] == 0; - dontcheck |= current_entry == exclude; - - if (!dontcheck && ((entry->last_lba >= current_entry->first_lba && - entry->first_lba < current_entry->last_lba ))) { - return 1; - } - } - - return 0; -} - -static int GPT_check_overlap(struct GPT_entry_table *table, struct GPT_entry_raw *entry) -{ - return GPT_check_overlap_except(table, entry, NULL); -} - -static char *get_key_value(char *ptr, char **key, char **value) -{ - *key = ptr; - ptr = strchr(ptr, '='); - - if (ptr == NULL) - return NULL; - - *ptr++ = '\0'; - *value = ptr; - ptr = strchr(ptr, ';'); - - if (ptr == NULL) - ptr = *value + strlen(*value); - else - *ptr = '\0'; - - *key = strip(*key); - *value = strip(*value); - - return ptr; -} - -//TODO: little endian? -static int add_key_value(const char *key, const char *value, struct GPT_entry_raw *entry) -{ - char *endptr; - if (!strcmp(key, "type")) { - strncpy((char *) entry->type_guid, value, 16); - entry->type_guid[15] = 0; - } - else if (!strcmp(key, "guid")) { - strncpy((char *) entry->partition_guid, value, 16); - entry->type_guid[15] = 0; - } - else if (!strcmp(key, "firstlba")) { - entry->first_lba = strtoul(value, &endptr, 10); - if (*endptr != '\0') goto error; - } - else if (!strcmp(key, "lastlba")) { - entry->last_lba = strtoul(value, &endptr, 10); - if (*endptr != '\0') goto error; - } - else if (!strcmp(key, "flags")) { - entry->flags = strtoul(value, &endptr, 16); - if (*endptr != '\0') goto error; - } - else if (!strcmp(key, "name")) { - GPT_to_UTF16(entry->name, value, GPT_NAMELEN); - } - else { - goto error; - } - - return 0; - -error: - D(ERR, "Could not find key or parse value: %s,%s", key, value); - return 1; -} - -int GPT_parse_entry(char *string, struct GPT_entry_raw *entry) -{ - char *ptr = string; - char *key, *value; - - while ((ptr = get_key_value(ptr, &key, &value)) != NULL) { - if (add_key_value(key, value, entry)) { - D(WARN, "key or value not valid: %s %s", key, value); - return 1; - } - } - - return 0; -} - -void entry_set_guid(int n, uint8_t *guid) -{ - int fd; - fd = open("/dev/urandom", O_RDONLY); - read(fd, guid, 16); - close(fd); - - //rfc4122 - guid[8] = (guid[8] & 0x3F) | 0x80; - guid[7] = (guid[7] & 0x0F) | 0x40; -} - -void GPT_default_content(struct GPT_content *content, struct GPT_entry_table *table) -{ - if (table != NULL) { - memcpy(&content->header, table->header, sizeof(content->header)); - content->header.header_size = sizeof(content->header); - content->header.entry_size = sizeof(struct GPT_entry_raw); - } - else { - D(WARN, "Could not locate old gpt table, using default values"); - memset(&content->header, 0, sizeof(content->header) / sizeof(int)); - content->header = (struct GPT_header) { - .revision = 0x10000, - .header_size = sizeof(content->header), - .header_checksum = 0, - .reserved_zeros = 0, - .current_lba = 1, - .backup_lba = 1, - .entry_size = sizeof(struct GPT_entry_raw), - .partition_array_checksum = 0 - }; - strncpy((char *)content->header.signature, "EFI PART", 8); - strncpy((char *)content->header.disk_guid, "ANDROID MMC DISK", 16); - } -} - -static int get_config_uint64(cnode *node, uint64_t *ptr, const char *name) -{ - const char *tmp; - uint64_t val; - char *endptr; - if ((tmp = config_str(node, name, NULL))) { - val = strtoull(tmp, &endptr, 10); - if (*endptr != '\0') { - D(WARN, "Value for %s is not a number: %s", name, tmp); - return 1; - } - *ptr = val; - return 0; - } - return 1; -} - -static int get_config_string(cnode *node, char *ptr, int max_len, const char *name) -{ - size_t begin, end; - const char *value = config_str(node, name, NULL); - if (!value) - return -1; - - begin = strcspn(value, "\"") + 1; - end = strcspn(&value[begin], "\""); - - if ((int) end > max_len) { - D(WARN, "Identifier \"%s\" too long", value); - return -1; - } - - strncpy(ptr, &value[begin], end); - if((int) end < max_len) - ptr[end] = 0; - return 0; -} - -static void GPT_parse_header(cnode *node, struct GPT_content *content) -{ - get_config_uint64(node, &content->header.current_lba, "header_lba"); - get_config_uint64(node, &content->header.backup_lba, "backup_lba"); - get_config_uint64(node, &content->header.first_usable_lba, "first_lba"); - get_config_uint64(node, &content->header.last_usable_lba, "last_lba"); - get_config_uint64(node, &content->header.entries_lba, "entries_lba"); - get_config_string(node, (char *) content->header.disk_guid, 16, "guid"); -} - -static int GPT_parse_partitions(cnode *node, struct GPT_content *content) -{ - cnode *current; - int i; - uint64_t partition_size; - struct GPT_entry_raw *entry; - for (i = 0, current = node->first_child; current; current = current->next, ++i) { - entry = &content->entries[i]; - entry_set_guid(i, content->entries[i].partition_guid); - memcpy(&content->entries[i].type_guid, partition_type_uuid, 16); - if (get_config_uint64(current, &entry->first_lba, "first_lba")) { - D(ERR, "first_lba not specified"); - return 1; - } - if (get_config_uint64(current, &partition_size, "partition_size")) { - D(ERR, "partition_size not specified"); - return 1; - } - if (config_str(current, "system", NULL)) { - entry->flags |= GPT_FLAG_SYSTEM; - } - if (config_str(current, "bootable", NULL)) { - entry->flags |= GPT_FLAG_BOOTABLE; - } - if (config_str(current, "readonly", NULL)) { - entry->flags |= GPT_FLAG_READONLY; - } - if (config_str(current, "automount", NULL)) { - entry->flags |= GPT_FLAG_DOAUTOMOUNT; - } - - get_config_uint64(current, &content->entries[i].flags, "flags"); - content->entries[i].last_lba = content->entries[i].first_lba + partition_size - 1; - GPT_to_UTF16(content->entries[i].name, current->name, 16); - } - return 0; -} - -static inline int cnode_count(cnode *node) -{ - int i; - cnode *current; - for (i = 0, current = node->first_child; current; current = current->next, ++i) - ; - return i; -} - - -static int GPT_parse_cnode(cnode *root, struct GPT_content *content) -{ - cnode *partnode; - - if (!(partnode = config_find(root, "partitions"))) { - D(ERR, "Could not find partition table"); - return 0; - } - - GPT_parse_header(root, content); - - content->header.entries_count = cnode_count(partnode); - content->entries = malloc(content->header.entries_count * sizeof(struct GPT_entry_raw)); - - if (GPT_parse_partitions(partnode, content)) { - D(ERR, "Could not parse partitions"); - return 0; - } - - return 1; -} - -int GPT_parse_file(int fd, struct GPT_content *content) -{ - char *data; - int size; - int ret; - cnode *root = config_node("", ""); - - size = get_file_size(fd); - data = (char *) mmap(NULL, size + 1, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - - if (data == NULL) { - if (size == 0) - D(ERR, "config file empty"); - else - D(ERR, "Out of memory"); - return 0; - } - - data[size - 1] = 0; - config_load(root, data); - - if (root->first_child == NULL) { - D(ERR, "Could not read config file"); - return 0; - } - - ret = GPT_parse_cnode(root, content); - munmap(data, size); - return ret; -} - -void GPT_release_content(struct GPT_content *content) -{ - free(content->entries); -} - -int GPT_write_content(const char *device, struct GPT_content *content) -{ - struct GPT_entry_table *maptable; - - maptable = GPT_get_from_content(device, content); - if (maptable == NULL) { - D(ERR, "could not map device"); - return 0; - } - - memcpy(maptable->header, &content->header, sizeof(*maptable->header)); - memcpy(maptable->entries, content->entries, - content->header.entries_count * sizeof(*maptable->entries)); - - GPT_sync(maptable); - GPT_release_device(maptable); - - return 1; -} - diff --git a/fastbootd/commands/partitions.h b/fastbootd/commands/partitions.h deleted file mode 100644 index 9a6a88d..0000000 --- a/fastbootd/commands/partitions.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - - -#ifndef __FASTBOOTD_PATITIONS_ -#define __FASTBOOTD_PATITIONS_ - -#include <stdint.h> - -#define GPT_ENTRIES 128 -#define GPT_NAMELEN 36 - -#define GPT_FLAG_SYSTEM (1ULL << 0) -#define GPT_FLAG_BOOTABLE (1ULL << 2) -#define GPT_FLAG_READONLY (1ULL << 60) -#define GPT_FLAG_DOAUTOMOUNT (1ULL << 63) - -// it should be passed in little endian order -struct GPT_entry_raw { - uint8_t type_guid[16]; - uint8_t partition_guid[16]; - uint64_t first_lba; // little endian - uint64_t last_lba; - uint64_t flags; - uint16_t name[GPT_NAMELEN]; // UTF-16 LE -}; - -struct GPT_mapping { - void *map_ptr; - void *ptr; - unsigned size; -}; - -struct GPT_entry_table { - int fd; - - struct GPT_mapping header_map; - struct GPT_mapping entries_map; - struct GPT_mapping sec_header_map; - struct GPT_mapping sec_entries_map; - - struct GPT_header *header; - struct GPT_entry_raw *entries; - struct GPT_header *second_header; - struct GPT_entry_raw *second_entries; - - unsigned sector_size; - unsigned partition_table_size; - int second_valid; -}; - -struct GPT_header { - uint8_t signature[8]; - uint32_t revision; - uint32_t header_size; - uint32_t header_checksum; - uint32_t reserved_zeros; - uint64_t current_lba; - uint64_t backup_lba; - uint64_t first_usable_lba; - uint64_t last_usable_lba; - uint8_t disk_guid[16]; - uint64_t entries_lba; - uint32_t entries_count; - uint32_t entry_size; - uint32_t partition_array_checksum; - // the rest should be filled with zeros -} __attribute__((packed)); - -struct GPT_content { - struct GPT_header header; - struct GPT_entry_raw *entries; -}; - - -struct GPT_entry_table* GPT_get_device(const char *, unsigned lba); - -void GPT_release_device(struct GPT_entry_table *); - -void GPT_edit_entry(struct GPT_entry_table *table, - struct GPT_entry_raw *old_entry, - struct GPT_entry_raw *new_entry); - -int GPT_delete_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry); - -void GPT_add_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry); - -struct GPT_entry_raw *GPT_get_pointer(struct GPT_entry_table *table, struct GPT_entry_raw *entry); -struct GPT_entry_raw *GPT_get_pointer_by_guid(struct GPT_entry_table *, const char *); -struct GPT_entry_raw *GPT_get_pointer_by_name(struct GPT_entry_table *, const char *); - -//Use after every edit operation -void GPT_sync(); - -void GPT_to_UTF16(uint16_t *, const char *, int ); -void GPT_from_UTF16(char *, const uint16_t *, int); - -int GPT_parse_entry(char *string, struct GPT_entry_raw *entry); - -void GPT_default_content(struct GPT_content *content, struct GPT_entry_table *table); - -void GPT_release_content(struct GPT_content *content); - -int GPT_parse_file(int fd, struct GPT_content *content); - -int GPT_write_content(const char *device, struct GPT_content *content); - -int gpt_mmap(struct GPT_mapping *mapping, uint64_t location, int size, int fd); - -void gpt_unmap(struct GPT_mapping *mapping); - -#endif diff --git a/fastbootd/commands/virtual_partitions.c b/fastbootd/commands/virtual_partitions.c deleted file mode 100644 index 813f485..0000000 --- a/fastbootd/commands/virtual_partitions.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include "commands/virtual_partitions.h" -#include "debug.h" - -static struct virtual_partition *partitions = NULL; - -int try_handle_virtual_partition(struct protocol_handle *handle, const char *arg) -{ - struct virtual_partition *current; - - for (current = partitions; current != NULL; current = current->next) { - if (!strcmp(current->name, arg)) { - current->handler(handle, arg); - } - } - - return 0; -} - -void virtual_partition_register( - const char * name, - void (*handler)(struct protocol_handle *phandle, const char *arg)) -{ - struct virtual_partition *new; - new = malloc(sizeof(*new)); - if (new) { - new->name = name; - new->handler = handler; - new->next = partitions; - partitions = new; - } - else { - D(ERR, "Out of memory"); - } -} diff --git a/fastbootd/commands/virtual_partitions.h b/fastbootd/commands/virtual_partitions.h deleted file mode 100644 index 88df71e..0000000 --- a/fastbootd/commands/virtual_partitions.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#ifndef FASTBOOTD_VIRTUAL_PARTITIONS_H -#define FASTBOOTD_VIRTUAL_PARTITIONS_H - -#include "protocol.h" - -struct virtual_partition { - struct virtual_partition *next; - const char *name; - void (*handler)(struct protocol_handle *phandle, const char *arg); -}; - -int try_handle_virtual_partition(struct protocol_handle *handle, const char *arg); - -void virtual_partition_register( - const char * name, - void (*handler)(struct protocol_handle *phandle, const char *arg)); - -#endif diff --git a/fastbootd/config.c b/fastbootd/config.c deleted file mode 100644 index fe6da69..0000000 --- a/fastbootd/config.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <fcntl.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> - -#include "protocol.h" -#include "utils.h" - -#include "debug.h" - -// TODO: change config path -#define CONFIG_PATH "/data/fastboot.cfg" - -static int config_parse_line(char *line) -{ - char *c; - char *key; - char *value; - - c = strchr(line, '#'); - if (c) - *c = '\0'; - - if (strspn(line, " \t") == strlen(line)) - return 0; - - c = strchr(line, '='); - if (c == NULL) - return -1; - - key = line; - *c = '\0'; - value = c + 1; - - key = strip(key); - value = strip(value); - - key = strdup(key); - value = strdup(value); - - fastboot_publish(key, value); - - return 0; -} - -static void config_parse(char *buffer) -{ - char *saveptr; - char *str = buffer; - char *line = buffer; - int c; - int ret; - - for (c = 1; line != NULL; c++) { - line = strtok_r(str, "\r\n", &saveptr); - if (line != NULL) { - D(VERBOSE, "'%s'", line); - ret = config_parse_line(line); - if (ret < 0) { - D(WARN, "error parsing " CONFIG_PATH " line %d", c); - } - } - str = NULL; - } -} - -void config_init() -{ - int fd; - off_t len; - ssize_t ret; - size_t count = 0; - char *buffer; - - fd = open(CONFIG_PATH, O_RDONLY); - if (fd < 0) { - D(ERR, "failed to open " CONFIG_PATH); - return; - } - - len = lseek(fd, 0, SEEK_END); - if (len < 0) { - D(ERR, "failed to seek to end of " CONFIG_PATH); - return; - } - - lseek(fd, 0, SEEK_SET); - - buffer = malloc(len + 1); - if (buffer == NULL) { - D(ERR, "failed to allocate %ld bytes", len); - return; - } - - while (count < (size_t)len) { - ret = read(fd, buffer + count, len - count); - if (ret < 0 && errno != EINTR) { - D(ERR, "failed to read " CONFIG_PATH ": %d %s", errno, strerror(errno)); - return; - } - if (ret == 0) { - D(ERR, "early EOF reading " CONFIG_PATH); - return; - } - - count += ret; - } - - buffer[len] = '\0'; - - config_parse(buffer); - - free(buffer); -} diff --git a/fastbootd/fastbootd.c b/fastbootd/fastbootd.c deleted file mode 100644 index 2b51b33..0000000 --- a/fastbootd/fastbootd.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2013 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 <unistd.h> -#include <cutils/klog.h> -#include <getopt.h> -#include <stdlib.h> - -#include "debug.h" -#include "trigger.h" -#include "socket_client.h" -#include "secure.h" - -unsigned int debug_level = DEBUG; - -void commands_init(); -void usb_init(); -void config_init(); -int transport_socket_init(); -int network_discovery_init(); -void ssh_server_start(); - -int main(int argc, char **argv) -{ - int socket_client = 0; - int c; - int network = 1; - - klog_init(); - klog_set_level(6); - - const struct option longopts[] = { - {"socket", no_argument, 0, 'S'}, - {"nonetwork", no_argument, 0, 'n'}, - {0, 0, 0, 0} - }; - - while (1) { - c = getopt_long(argc, argv, "Sn", longopts, NULL); - /* Alphabetical cases */ - if (c < 0) - break; - switch (c) { - case 'S': - socket_client = 1; - break; - case 'n': - network = 0; - break; - case '?': - return 1; - default: - return 0; - } - } - - (void)argc; - (void)argv; - - klog_init(); - klog_set_level(6); - - if (socket_client) { - //TODO: Shouldn't we change current tty into raw mode? - run_socket_client(); - } - else { - cert_init_crypto(); - config_init(); - load_trigger(); - commands_init(); - usb_init(); - - if (network) { - if (!transport_socket_init()) - exit(1); - ssh_server_start(); - network_discovery_init(); - } - - while (1) { - sleep(1); - } - } - return 0; -} diff --git a/fastbootd/network_discovery.c b/fastbootd/network_discovery.c deleted file mode 100644 index 1cd3e48..0000000 --- a/fastbootd/network_discovery.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <stdio.h> -#include <string.h> -#include <dns_sd.h> -#include <cutils/properties.h> -#include <unistd.h> - -#include "debug.h" -#include "network_discovery.h" -#include "utils.h" - -#define MDNS_SERVICE_NAME "mdnsd" -#define MDNS_SERVICE_STATUS "init.svc.mdnsd" -#define FASTBOOTD_TYPE "_fastbootd._tcp" -#define FASTBOOTD_DOMAIN "local." -#define FASTBOOTD_NAME "fastbootd" - - -static void reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags, DNSServiceErrorType errorCode, - const char *name, const char *regtype, const char *domain, void *context) -{ - (void)sdref; // Unused - (void)flags; // Unused - (void)context; // Unused - if (errorCode == kDNSServiceErr_ServiceNotRunning) { - fprintf(stderr, "Error code %d\n", errorCode); - } - - - printf("Got a reply for service %s.%s%s: ", name, regtype, domain); - - if (errorCode == kDNSServiceErr_NoError) - { - if (flags & kDNSServiceFlagsAdd) - printf("Name now registered and active\n"); - else - printf("Name registration removed\n"); - if (errorCode == kDNSServiceErr_NameConflict) - printf("Name in use, please choose another\n"); - else - printf("Error %d\n", errorCode); - - if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout); - } -} - -static int register_service() { - DNSServiceRef sdref = NULL; - const char *domain = FASTBOOTD_DOMAIN; - const char *type = FASTBOOTD_TYPE; - const char *host = NULL; - char name[PROP_VALUE_MAX]; - uint16_t port = 22; - int flags = 0; - DNSServiceErrorType result; - property_get("ro.serialno", name, ""); - if (!strcmp(name, "")) { - D(ERR, "No property serialno"); - return -1; - } - - result = DNSServiceRegister(&sdref, flags, kDNSServiceInterfaceIndexAny, - name, type, domain, host, port, - 0, NULL, reg_reply, NULL); - if (result != kDNSServiceErr_NoError) { - D(ERR, "Unable to register service"); - return -1; - } - return 0; -} - - -int network_discovery_init() -{ - D(INFO, "Starting discovery"); - if (service_start(MDNS_SERVICE_NAME)) { - D(ERR, "Unable to start discovery"); - return -1; - } - - if (register_service()) { - D(ERR, "Unable to register service"); - return -1; - } - - return 0; -} - diff --git a/fastbootd/network_discovery.h b/fastbootd/network_discovery.h deleted file mode 100644 index 75fda63..0000000 --- a/fastbootd/network_discovery.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#ifndef _FASTBOOTD_NETWORK_DISCOVERY_H -#define _FASTBOOTD_NETWORK_DISCOVERY_H - -int network_discovery_init(); - -#endif diff --git a/fastbootd/other/gptedit.c b/fastbootd/other/gptedit.c deleted file mode 100644 index d423529..0000000 --- a/fastbootd/other/gptedit.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <getopt.h> -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include <cutils/klog.h> - -#include "commands/partitions.h" -#include "debug.h" - -unsigned int debug_level = DEBUG; -//TODO: add tool to generate config file - -void usage() { - fprintf(stderr, - "usage: test_gpt [ <option> ] <file>\n" - "\n" - "options:\n" - " -p print partitions\n" - " -c print config file\n" - " -a adds new partition\n" - " -d deletes partition (-o needed)\n" - "\n" - " -n name@startlba,endlba new partition detail\n" - " -o old partition name\n" - " -t type guid\n" - " -g partition guid\n" - " -l gpt_location specyfies gpt secto\n" - ); - -} - -void printGPT(struct GPT_entry_table *table); -void addGPT(struct GPT_entry_table *table, const char *arg, const char *guid, const char *tguid); -void deleteGPT(struct GPT_entry_table *table, const char *name); -void configPrintGPT(struct GPT_entry_table *table); - -int main(int argc, char *argv[]) { - int print_cmd = 0; - int config_cmd = 0; - int add_cmd = 0; - int del_cmd = 0; - int sync_cmd = 0; - int c; - const char *new_partition = NULL; - const char *old_partition = NULL; - const char *type_guid = NULL; - const char *partition_guid = NULL; - unsigned gpt_location = 1; - - klog_init(); - klog_set_level(6); - - const struct option longopts[] = { - {"print", no_argument, 0, 'p'}, - {"config-print", no_argument, 0, 'c'}, - {"add", no_argument, 0, 'a'}, - {"del", no_argument, 0, 'd'}, - {"new", required_argument, 0, 'n'}, - {"old", required_argument, 0, 'o'}, - {"type", required_argument, 0, 't'}, - {"sync", required_argument, 0, 's'}, - {"guid", required_argument, 0, 'g'}, - {"location", required_argument, 0, 'l'}, - {0, 0, 0, 0} - }; - - while (1) { - c = getopt_long(argc, argv, "pcadt:g:n:o:sl:", longopts, NULL); - /* Alphabetical cases */ - if (c < 0) - break; - switch (c) { - case 'p': - print_cmd = 1; - break; - case 'c': - config_cmd = 1; - break; - case 'a': - add_cmd = 1; - break; - case 'd': - del_cmd = 1; - break; - case 'n': - new_partition = optarg; - break; - case 'o': - old_partition = optarg; - break; - case 't': - type_guid = optarg; - case 'g': - partition_guid = optarg; - break; - case 's': - sync_cmd = 1; - break; - case 'l': - gpt_location = strtoul(optarg, NULL, 10); - fprintf(stderr, "Got offset as %d", gpt_location); - break; - case '?': - return 1; - default: - abort(); - } - } - - argc -= optind; - argv += optind; - - if (argc < 1) { - usage(); - return 1; - } - - const char *path = argv[0]; - struct GPT_entry_table *table = GPT_get_device(path, gpt_location); - if (table == NULL) { - fprintf(stderr, "unable to get GPT table from %s\n", path); - return 1; - } - - if (add_cmd) - addGPT(table, new_partition, partition_guid, type_guid); - if (del_cmd) - deleteGPT(table, old_partition); - if (print_cmd) - printGPT(table); - if (config_cmd) - configPrintGPT(table); - if (sync_cmd) - GPT_sync(table); - - GPT_release_device(table); - - return 0; -} - -void printGPT(struct GPT_entry_table *table) { - struct GPT_entry_raw *entry = table->entries; - unsigned n, m; - char name[GPT_NAMELEN + 1]; - - printf("ptn start block end block name\n"); - printf("---- ------------- -------------\n"); - - for (n = 0; n < table->header->entries_count; n++, entry++) { - if (entry->type_guid[0] == 0) - continue; - for (m = 0; m < GPT_NAMELEN; m++) { - name[m] = entry->name[m] & 127; - } - name[m] = 0; - printf("#%03d %13"PRId64" %13"PRId64" %s\n", - n + 1, entry->first_lba, entry->last_lba, name); - } -} - -void configPrintGPT(struct GPT_entry_table *table) { - struct GPT_entry_raw *entry = table->entries; - unsigned n, m; - char name[GPT_NAMELEN + 1]; - char temp_guid[17]; - temp_guid[16] = 0; - - printf("header_lba %"PRId64"\n", table->header->current_lba); - printf("backup_lba %"PRId64"\n", table->header->backup_lba); - printf("first_lba %"PRId64"\n", table->header->first_usable_lba); - printf("last_lba %"PRId64"\n", table->header->last_usable_lba); - printf("entries_lba %"PRId64"\n", table->header->entries_lba); - snprintf(temp_guid, 17, "%s", table->header->disk_guid); - printf("guid \"%s\"", temp_guid); - - printf("\npartitions {\n"); - - for (n = 0; n < table->header->entries_count; n++, entry++) { - uint64_t size = entry->last_lba - entry->first_lba + 1; - - if (entry->type_guid[0] == 0) - continue; - for (m = 0; m < GPT_NAMELEN; m++) { - name[m] = entry->name[m] & 127; - } - name[m] = 0; - - printf(" %s {\n", name); - snprintf(temp_guid, 17, "%s", entry->partition_guid); - printf(" guid \"%s\"\n", temp_guid); - printf(" first_lba %"PRId64"\n", entry->first_lba); - printf(" partition_size %"PRId64"\n", size); - if (entry->flags & GPT_FLAG_SYSTEM) - printf(" system\n"); - if (entry->flags & GPT_FLAG_BOOTABLE) - printf(" bootable\n"); - if (entry->flags & GPT_FLAG_READONLY) - printf(" readonly\n"); - if (entry->flags & GPT_FLAG_DOAUTOMOUNT) - printf(" automount\n"); - printf(" }\n\n"); - } - printf("}\n"); -} - -void addGPT(struct GPT_entry_table *table, const char *str , const char *guid, const char *tguid) { - char *c, *c2; - char *arg = malloc(strlen(str)); - char *name = arg; - unsigned start, end; - strcpy(arg, str); - if (guid == NULL || tguid == NULL) { - fprintf(stderr, "Type guid and partion guid needed"); - free(arg); - return; - } - - c = strchr(arg, '@'); - - if (c == NULL) { - fprintf(stderr, "Wrong entry format"); - free(arg); - return; - } - - *c++ = '\0'; - - c2 = strchr(c, ','); - - if (c2 == NULL) { - fprintf(stderr, "Wrong entry format"); - free(arg); - return; - } - - start = strtoul(c, NULL, 10); - *c2++ = '\0'; - end = strtoul(c2, NULL, 10); - - struct GPT_entry_raw data; - strncpy((char *)data.partition_guid, guid, 15); - data.partition_guid[15] = '\0'; - strncpy((char *)data.type_guid, tguid, 15); - data.type_guid[15] = '\0'; - GPT_to_UTF16(data.name, name, GPT_NAMELEN); - data.first_lba = start; - data.last_lba = end; - - fprintf(stderr, "Adding (%d,%d) %s as, [%s, %s]", start, end, name, (char *) data.type_guid, (char *) data.partition_guid); - GPT_add_entry(table, &data); - free(arg); -} - -void deleteGPT(struct GPT_entry_table *table, const char *name) { - struct GPT_entry_raw *entry; - - if (name == NULL) { - fprintf(stderr, "Need partition name"); - return; - } - - entry = GPT_get_pointer_by_name(table, name); - - if (!entry) { - fprintf(stderr, "Unable to find partition: %s", name); - return; - } - GPT_delete_entry(table, entry); -} - diff --git a/fastbootd/other/partitions.sample.cfg b/fastbootd/other/partitions.sample.cfg deleted file mode 100644 index 49562cf..0000000 --- a/fastbootd/other/partitions.sample.cfg +++ /dev/null @@ -1,60 +0,0 @@ - -header_lba 1 -backup_lba 101 -first_lba 43 -last_lba 100 -entries_lba 2 - -partitions { - #You can generate this as output from gptedit -c - SOS { - first_lba 28672 - partition_size 16384 - } - - DTB { - first_lba 45056 - partition_size 8192 - } - - LNX { - first_lba 53248 - partition_size 16384 - } - - APP { - first_lba 69632 - partition_size 1048576 - } - - CAC { - first_lba 1118208 - partition_size 1572864 - } - - MSC { - first_lba 2691072 - partition_size 4096 - } - - USP { - first_lba 2695168 - partition_size 65536 - } - - MDA { - first_lba 2760704 - partition_size 4096 - } - - FCT { - first_lba 2764800 - partition_size 32768 - } - - UDA { - first_lba 2797568 - partition_size 27975680 - } -} - diff --git a/fastbootd/other/sign/src/SignImg.java b/fastbootd/other/sign/src/SignImg.java deleted file mode 100644 index 338d427..0000000 --- a/fastbootd/other/sign/src/SignImg.java +++ /dev/null @@ -1,181 +0,0 @@ -package signtool; - -import java.io.*; -import java.util.Properties; -import java.util.ArrayList; - -import javax.mail.internet.*; -import javax.mail.MessagingException; -import javax.mail.Session; -import javax.activation.MailcapCommandMap; -import javax.activation.CommandMap; - -import java.security.PrivateKey; -import java.security.Security; -import java.security.KeyFactory; -import java.security.KeyStore; -import java.security.NoSuchAlgorithmException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.security.cert.X509Certificate; -import java.security.cert.CertificateFactory; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateEncodingException; - -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; -import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; -import org.bouncycastle.operator.ContentSigner; -import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; -import org.bouncycastle.cms.CMSProcessableByteArray; -import org.bouncycastle.cms.CMSSignedGenerator; -import org.bouncycastle.cms.CMSSignedDataGenerator; -import org.bouncycastle.cms.CMSSignedGenerator; -import org.bouncycastle.cms.CMSProcessable; -import org.bouncycastle.cms.CMSSignedData; -import org.bouncycastle.cms.CMSTypedData; -import org.bouncycastle.cert.jcajce.JcaCertStore; -import org.bouncycastle.util.Store; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.DEROutputStream; -import org.bouncycastle.asn1.ASN1Object; - - -public class SignImg { - - /* It reads private key in pkcs#8 formate - * Conversion: - * openssl pkcs8 -topk8 -nocrypt -outform DER < inkey.pem > outkey.pk8 - */ - private static PrivateKey getPrivateKey(String path) throws IOException, FileNotFoundException, NoSuchAlgorithmException, InvalidKeySpecException { - File file = new File(path); - FileInputStream fis = new FileInputStream(file); - byte[] data = new byte[(int)file.length()]; - fis.read(data); - fis.close(); - - PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(data); - KeyFactory kf = KeyFactory.getInstance("RSA"); - PrivateKey privateKey = kf.generatePrivate(kspec); - - return privateKey; - } - - private static MimeBodyPart getContent(String path) throws IOException, FileNotFoundException, MessagingException { - MimeBodyPart body = new MimeBodyPart(); - - File file = new File(path); - FileInputStream fis = new FileInputStream(file); - byte[] data = new byte[(int)file.length()]; - fis.read(data); - fis.close(); - - body.setContent(data, "application/octet-stream"); - - return body; - } - - private static CMSProcessableByteArray getCMSContent(String path) throws IOException, FileNotFoundException, MessagingException { - File file = new File(path); - FileInputStream fis = new FileInputStream(file); - byte[] data = new byte[(int)file.length()]; - fis.read(data); - fis.close(); - CMSProcessableByteArray cms = new CMSProcessableByteArray(data); - - return cms; - } - - private static X509Certificate readCert(String path) throws IOException, FileNotFoundException, CertificateException { - File file = new File(path); - FileInputStream is = new FileInputStream(file); - - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - Certificate cert = cf.generateCertificate(is); - is.close(); - - return (X509Certificate) cert; - } - - private static void save(MimeBodyPart content, String path) throws IOException, FileNotFoundException, MessagingException { - File file = new File(path); - FileOutputStream os = new FileOutputStream(file); - - content.writeTo(os); - - os.close(); - } - - private static Store certToStore(X509Certificate certificate) throws CertificateEncodingException { - ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>(); - certList.add(certificate); - return new JcaCertStore(certList); - } - - public static void setDefaultMailcap() - { - MailcapCommandMap _mailcap = - (MailcapCommandMap)CommandMap.getDefaultCommandMap(); - - _mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature"); - _mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime"); - _mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature"); - _mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime"); - _mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed"); - - CommandMap.setDefaultCommandMap(_mailcap); - } - - public static void main(String[] args) { - try { - if (args.length < 4) { - System.out.println("Usage: signimg data private_key certificate output"); - return; - } - System.out.println("Signing the image"); - setDefaultMailcap(); - - Security.addProvider(new BouncyCastleProvider()); - - PrivateKey key = getPrivateKey(args[1]); - System.out.println("File read sucessfully"); - - CMSSignedDataGenerator generator = new CMSSignedDataGenerator(); - - CMSTypedData body = getCMSContent(args[0]); - System.out.println("Content read sucessfully"); - - X509Certificate cert = (X509Certificate) readCert(args[2]); - System.out.println("Certificate read sucessfully"); - - ContentSigner sha256Signer = new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").build(key); - - Store certs = certToStore(cert); - - generator.addCertificates(certs); - generator.addSignerInfoGenerator( - new JcaSignerInfoGeneratorBuilder( - new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()) - .build(sha256Signer, cert)); - - CMSSignedData signed = generator.generate(body, true); - System.out.println("Signed"); - - Properties props = System.getProperties(); - Session session = Session.getDefaultInstance(props, null); - - File file = new File(args[3]); - FileOutputStream os = new FileOutputStream(file); - - ASN1InputStream asn1 = new ASN1InputStream(signed.getEncoded()); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - DEROutputStream dOut = new DEROutputStream(os); - dOut.writeObject(ASN1Object.fromByteArray(signed.getEncoded())); - - } - catch (Exception ex) { - System.out.println("Exception during programm execution: " + ex.getMessage()); - } - } -} diff --git a/fastbootd/protocol.c b/fastbootd/protocol.c deleted file mode 100644 index 3908020..0000000 --- a/fastbootd/protocol.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "debug.h" -#include "protocol.h" -#include "transport.h" - -#define STATE_OFFLINE 0 -#define STATE_COMMAND 1 -#define STATE_COMPLETE 2 -#define STATE_ERROR 3 - -struct fastboot_cmd { - struct fastboot_cmd *next; - const char *prefix; - unsigned prefix_len; - void (*execute)(struct protocol_handle *phandle, const char *arg); -}; - -struct fastboot_var { - struct fastboot_var *next; - const char *name; - const char *value; -}; - -static struct fastboot_cmd *cmdlist; - -void fastboot_register(const char *prefix, - void (*phandle)(struct protocol_handle *phandle, const char *arg)) -{ - struct fastboot_cmd *cmd; - cmd = malloc(sizeof(*cmd)); - if (cmd) { - cmd->prefix = prefix; - cmd->prefix_len = strlen(prefix); - cmd->execute = phandle; - cmd->next = cmdlist; - cmdlist = cmd; - } -} - -static struct fastboot_var *varlist; - -void fastboot_publish(const char *name, const char *value) -{ - struct fastboot_var *var; - var = malloc(sizeof(*var)); - if (var) { - var->name = name; - var->value = value; - var->next = varlist; - varlist = var; - } -} - -const char *fastboot_getvar(const char *name) -{ - struct fastboot_var *var; - - for (var = varlist; var; var = var->next) { - if (!strcmp(var->name, name)) { - return var->value; - } - } - - return ""; -} - -int protocol_handle_download(struct protocol_handle *phandle, size_t len) -{ - return transport_handle_download(phandle->transport_handle, len); -} - -static ssize_t protocol_handle_write(struct protocol_handle *phandle, - char *buffer, size_t len) -{ - return transport_handle_write(phandle->transport_handle, buffer, len); -} - -static void fastboot_ack(struct protocol_handle *phandle, const char *code, - const char *reason) -{ - char response[64]; - - if (phandle->state != STATE_COMMAND) - return; - - if (reason == 0) - reason = ""; - - snprintf(response, 64, "%s%s", code, reason); - phandle->state = STATE_COMPLETE; - - protocol_handle_write(phandle, response, strlen(response)); -} - -void fastboot_fail(struct protocol_handle *phandle, const char *reason) -{ - fastboot_ack(phandle, "FAIL", reason); -} - -void fastboot_okay(struct protocol_handle *phandle, const char *info) -{ - fastboot_ack(phandle, "OKAY", info); -} - -void fastboot_data(struct protocol_handle *phandle, size_t len) -{ - char response[64]; - ssize_t ret; - - snprintf(response, 64, "DATA%08zx", len); - ret = protocol_handle_write(phandle, response, strlen(response)); - if (ret < 0) - return; -} - -void protocol_handle_command(struct protocol_handle *phandle, char *buffer) -{ - D(INFO,"fastboot: %s\n", buffer); - - struct fastboot_cmd *cmd; - - for (cmd = cmdlist; cmd; cmd = cmd->next) { - if (memcmp(buffer, cmd->prefix, cmd->prefix_len)) - continue; - phandle->state = STATE_COMMAND; - cmd->execute(phandle, buffer + cmd->prefix_len); - if (phandle->state == STATE_COMMAND) - fastboot_fail(phandle, "unknown reason"); - return; - } - - fastboot_fail(phandle, "unknown command"); -} - -struct protocol_handle *create_protocol_handle(struct transport_handle *thandle) -{ - struct protocol_handle *phandle; - - phandle = calloc(sizeof(struct protocol_handle), 1); - - phandle->transport_handle = thandle; - phandle->state = STATE_OFFLINE; - phandle->download_fd = -1; - - pthread_mutex_init(&phandle->lock, NULL); - - return phandle; -} - -int protocol_get_download(struct protocol_handle *phandle) -{ - int fd; - - pthread_mutex_lock(&phandle->lock); - fd = phandle->download_fd; - phandle->download_fd = -1; - pthread_mutex_unlock(&phandle->lock); - - return fd; -} diff --git a/fastbootd/protocol.h b/fastbootd/protocol.h deleted file mode 100644 index ea2a8df..0000000 --- a/fastbootd/protocol.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#ifndef _FASTBOOTD_PROTOCOL_H_ -#define _FASTBOOTD_PROTOCOL_H_ - -#include <pthread.h> -#include <stddef.h> - -struct protocol_handle { - struct transport_handle *transport_handle; - unsigned int state; - int download_fd; - - pthread_mutex_t lock; -}; - -void fastboot_register(const char *prefix, - void (*handle)(struct protocol_handle *handle, const char *arg)); - -void fastboot_publish(const char *name, const char *value); -const char *fastboot_getvar(const char *name); - -struct protocol_handle *create_protocol_handle(struct transport_handle *t); -void protocol_handle_command(struct protocol_handle *handle, char *buffer); -int protocol_handle_download(struct protocol_handle *phandle, size_t len); -int protocol_get_download(struct protocol_handle *phandle); - -void fastboot_fail(struct protocol_handle *handle, const char *reason); -void fastboot_okay(struct protocol_handle *handle, const char *reason); -void fastboot_data(struct protocol_handle *handle, size_t len); - -#endif diff --git a/fastbootd/secure.c b/fastbootd/secure.c deleted file mode 100644 index 186e026..0000000 --- a/fastbootd/secure.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - - -#include <openssl/pem.h> -#include <openssl/engine.h> -#include <openssl/x509.h> -#include <openssl/x509v3.h> -#include <openssl/pem.h> -#include <openssl/cms.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> - -#include "secure.h" -#include "debug.h" -#include "utils.h" - - -void cert_init_crypto() { - CRYPTO_malloc_init(); - ERR_load_crypto_strings(); - OpenSSL_add_all_algorithms(); - ENGINE_load_builtin_engines(); -} - -X509_STORE *cert_store_from_path(const char *path) { - - X509_STORE *store; - struct stat st; - X509_LOOKUP *lookup; - - if (stat(path, &st)) { - D(ERR, "Unable to stat cert path"); - goto error; - } - - if (!(store = X509_STORE_new())) { - goto error; - } - - if (S_ISDIR(st.st_mode)) { - lookup = X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir()); - if (lookup == NULL) - goto error; - if (!X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM)) { - D(ERR, "Error loading cert directory %s", path); - goto error; - } - } - else if(S_ISREG(st.st_mode)) { - lookup = X509_STORE_add_lookup(store,X509_LOOKUP_file()); - if (lookup == NULL) - goto error; - if (!X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM)) { - D(ERR, "Error loading cert directory %s", path); - goto error; - } - } - else { - D(ERR, "cert path is not directory or regular file"); - goto error; - } - - return store; - -error: - return NULL; -} - - -int cert_read(int fd, CMS_ContentInfo **content, BIO **output) { - BIO *input; - *output = NULL; - - - input = BIO_new_fd(fd, BIO_NOCLOSE); - if (input == NULL) { - D(ERR, "Unable to open input"); - goto error; - } - - //TODO: - // read with d2i_CMS_bio to support DER - // with java or just encode data with base64 - *content = SMIME_read_CMS(input, output); - if (*content == NULL) { - unsigned long err = ERR_peek_last_error(); - D(ERR, "Unable to parse input file: %s", ERR_lib_error_string(err)); - goto error_read; - } - - BIO_free(input); - - return 0; - -error_read: - BIO_free(input); -error: - return 1; -} - -int cert_verify(BIO *content, CMS_ContentInfo *content_info, X509_STORE *store, int *out_fd) { - BIO *output_temp; - int ret; - - *out_fd = create_temp_file(); - if (*out_fd < 0) { - D(ERR, "unable to create temporary file"); - return -1; - } - - output_temp = BIO_new_fd(*out_fd, BIO_NOCLOSE); - if (output_temp == NULL) { - D(ERR, "unable to create temporary bio"); - close(*out_fd); - return -1; - } - - ret = CMS_verify(content_info, NULL ,store, content, output_temp, 0); - - if (ret == 0) { - char buf[256]; - unsigned long err = ERR_peek_last_error(); - D(ERR, "Verification failed with reason: %s, %s", ERR_lib_error_string(err), ERR_error_string(err, buf)); - D(ERR, "Data used: content %p", content); - } - - ERR_clear_error(); - ERR_remove_state(0); - - BIO_free(output_temp); - - return ret; -} - -void cert_release(BIO *content, CMS_ContentInfo *info) { - BIO_free(content); - CMS_ContentInfo_free(info); -} - diff --git a/fastbootd/secure.h b/fastbootd/secure.h deleted file mode 100644 index 878a643..0000000 --- a/fastbootd/secure.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#ifndef _FASTBOOTD_SECURE_H -#define _FASTBOOTD_SECURE_H - -#include <openssl/ssl.h> -#include <openssl/x509.h> -#include <openssl/x509v3.h> -#include <openssl/pem.h> -#include <openssl/cms.h> - -void cert_init_crypto(); - -X509_STORE *cert_store_from_path(const char*stream); - -static inline void cert_release_store(X509_STORE *store) { - X509_STORE_free(store); -} - -int cert_read(int fd, CMS_ContentInfo **content, BIO **output); -int cert_verify(BIO *content, CMS_ContentInfo *content_info, X509_STORE *store, int *out_fd); -void cert_release(BIO *content, CMS_ContentInfo *info); - -#endif diff --git a/fastbootd/socket_client.c b/fastbootd/socket_client.c deleted file mode 100644 index da636db..0000000 --- a/fastbootd/socket_client.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <stdio.h> -#include <cutils/sockets.h> -#include <poll.h> -#include <unistd.h> - -#include "utils.h" - -#define BUFFER_SIZE 256 - -#define STDIN_FD 0 -#define STDOUT_FD 1 -#define STDERR_FD 2 - -void run_socket_client() { - int fd; - char buffer[BUFFER_SIZE]; - int n; - struct pollfd fds[2]; - - fd = socket_local_client("fastbootd", - ANDROID_SOCKET_NAMESPACE_RESERVED, - SOCK_STREAM); - - if (fd < 0) { - fprintf(stderr, "ERROR: Unable to open fastbootd socket\n"); - return; - } - - fds[0].fd = STDIN_FD; - fds[0].events = POLLIN; - fds[1].fd = fd; - fds[1].events = POLLIN; - - while(true) { - if (poll(fds, 2, -1) <= 0) { - fprintf(stderr, "ERROR: socket error"); - return; - } - - if (fds[0].revents & POLLIN) { - if ((n = read(STDIN_FD, buffer, BUFFER_SIZE)) < 0) { - goto error; - } - - if (bulk_write(fd, buffer, n) < 0) { - goto error; - } - } - - if (fds[1].revents & POLLIN) { - if ((n = read(fd, buffer, BUFFER_SIZE)) < 0) { - goto error; - } - - if (bulk_write(STDOUT_FD, buffer, n) < 0) { - goto error; - } - } - } - -error: - fprintf(stderr, "Transport error\n"); -} diff --git a/fastbootd/socket_client.h b/fastbootd/socket_client.h deleted file mode 100644 index 4481ff2..0000000 --- a/fastbootd/socket_client.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#ifndef _FASTBOOTD_SOCKET_CLIENT_H -#define _FASTBOOTD_SOCKET_CLIENT_H - -void run_socket_client(); - -#endif diff --git a/fastbootd/transport.c b/fastbootd/transport.c deleted file mode 100644 index 9a16fd7..0000000 --- a/fastbootd/transport.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2013 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 <pthread.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/mman.h> - -#include "debug.h" -#include "protocol.h" -#include "transport.h" - -#define COMMAND_BUF_SIZE 64 - -ssize_t transport_handle_write(struct transport_handle *thandle, char *buffer, size_t len) -{ - return thandle->transport->write(thandle, buffer, len); -} - -void transport_handle_close(struct transport_handle *thandle) -{ - thandle->transport->close(thandle); -} - -int transport_handle_download(struct transport_handle *thandle, size_t len) -{ - ssize_t ret; - size_t n = 0; - int fd; - // TODO: move out of /dev - char tempname[] = "/dev/fastboot_download_XXXXXX"; - char *buffer; - - fd = mkstemp(tempname); - if (fd < 0) - return -1; - - unlink(tempname); - - ftruncate(fd, len); - - buffer = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (buffer == MAP_FAILED) { - D(ERR, "mmap(%zu) failed: %d %s", len, errno, strerror(errno)); - goto err; - } - - while (n < len) { - ret = thandle->transport->read(thandle, buffer + n, len - n); - if (ret <= 0) { - D(WARN, "transport read failed, ret=%zd %s", ret, strerror(-ret)); - break; - } - n += ret; - } - - munmap(buffer, len); - - if (n != len) - goto err; - - return fd; - -err: - close(fd); - transport_handle_close(thandle); - return -1; -} - -static void *transport_data_thread(void *arg) -{ - struct transport_handle *thandle = arg; - struct protocol_handle *phandle = create_protocol_handle(thandle); - - while (!thandle->stopped) { - int ret; - char buffer[COMMAND_BUF_SIZE + 1]; - D(VERBOSE, "transport_data_thread\n"); - - ret = thandle->transport->read(thandle, buffer, COMMAND_BUF_SIZE); - if (ret <= 0) { - D(DEBUG, "ret = %d\n", ret); - break; - } - if (ret > 0) { - buffer[ret] = 0; - //TODO: multiple threads - protocol_handle_command(phandle, buffer); - } - } - - transport_handle_close(thandle); - free(thandle); - - return NULL; -} - -static void *transport_connect_thread(void *arg) -{ - struct transport *transport = arg; - while (!transport->stopped) { - struct transport_handle *thandle; - pthread_t thread; - pthread_attr_t attr; - - D(VERBOSE, "transport_connect_thread\n"); - thandle = transport->connect(transport); - if (thandle == NULL) { - D(ERR, "transport connect failed\n"); - sleep(1); - continue; - } - thandle->transport = transport; - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - pthread_create(&thread, &attr, transport_data_thread, thandle); - - sleep(1); - } - - return NULL; -} - -void transport_register(struct transport *transport) -{ - pthread_t thread; - pthread_attr_t attr; - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - pthread_create(&thread, &attr, transport_connect_thread, transport); -} diff --git a/fastbootd/transport.h b/fastbootd/transport.h deleted file mode 100644 index 209340d..0000000 --- a/fastbootd/transport.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2013 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 _FASTBOOTD_TRANSPORT_H_ -#define _FASTBOOTD_TRANSPORT_H_ - -#include <stdbool.h> - -struct transport_handle { - struct transport *transport; - - bool stopped; -}; - -struct transport { - void (*init)(); - void (*close)(struct transport_handle *thandle); - ssize_t (*read)(struct transport_handle *thandle, void *data, size_t len); - ssize_t (*write)(struct transport_handle *thandle, const void *data, size_t len); - struct transport_handle *(*connect)(struct transport *transport); - bool stopped; -}; - -void transport_register(struct transport *transport); -ssize_t transport_handle_write(struct transport_handle *handle, char *buffer, size_t len); -int transport_handle_download(struct transport_handle *handle, size_t len); - -#endif diff --git a/fastbootd/transport_socket.c b/fastbootd/transport_socket.c deleted file mode 100644 index 664d473..0000000 --- a/fastbootd/transport_socket.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <stdlib.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <unistd.h> -#include <cutils/sockets.h> - -#include "debug.h" -#include "transport.h" -#include "utils.h" - - -#define container_of(ptr, type, member) \ - ((type*)((char*)(ptr) - offsetof(type, member))) - -#define SOCKET_WORKING 0 -#define SOCKET_STOPPED -1 - - -struct socket_transport { - struct transport transport; - - int fd; -}; - -struct socket_handle { - struct transport_handle handle; - - int fd; -}; - -void socket_close(struct transport_handle *thandle) -{ - struct socket_handle * handle = container_of(thandle, struct socket_handle, handle); - close(handle->fd); -} - -struct transport_handle *socket_connect(struct transport *transport) -{ - struct socket_handle *handle = calloc(sizeof(struct socket_handle), 1); - struct socket_transport *socket_transport = container_of(transport, struct socket_transport, transport); - struct sockaddr addr; - socklen_t alen = sizeof(addr); - - handle->fd = accept(socket_transport->fd, &addr, &alen); - - if (handle->fd < 0) { - D(WARN, "socket connect error"); - return NULL; - } - - D(DEBUG, "[ socket_thread - registering device ]"); - return &handle->handle; -} - -ssize_t socket_write(struct transport_handle *thandle, const void *data, size_t len) -{ - ssize_t ret; - struct socket_handle *handle = container_of(thandle, struct socket_handle, handle); - - D(DEBUG, "about to write (fd=%d, len=%zu)", handle->fd, len); - ret = bulk_write(handle->fd, data, len); - if (ret < 0) { - D(ERR, "ERROR: fd = %d, ret = %zd", handle->fd, ret); - return -1; - } - D(DEBUG, "[ socket_write done fd=%d ]", handle->fd); - return ret; -} - -ssize_t socket_read(struct transport_handle *thandle, void *data, size_t len) -{ - ssize_t ret; - struct socket_handle *handle = container_of(thandle, struct socket_handle, handle); - - D(DEBUG, "about to read (fd=%d, len=%zu)", handle->fd, len); - ret = bulk_read(handle->fd, data, len); - if (ret < 0) { - D(ERR, "ERROR: fd = %d, ret = %zd", handle->fd, ret); - return -1; - } - D(DEBUG, "[ socket_read done fd=%d ret=%zd]", handle->fd, ret); - return ret; -} - -static int listen_socket_init(struct socket_transport *socket_transport) -{ - int s = android_get_control_socket("fastbootd"); - - if (s < 0) { - D(WARN, "android_get_control_socket(fastbootd): %s\n", strerror(errno)); - return 0; - } - - if (listen(s, 4) < 0) { - D(WARN, "listen(control socket): %s\n", strerror(errno)); - return 0; - } - - socket_transport->fd = s; - - return 1; -} - - -int transport_socket_init() -{ - struct socket_transport *socket_transport = malloc(sizeof(struct socket_transport)); - - socket_transport->transport.connect = socket_connect; - socket_transport->transport.close = socket_close; - socket_transport->transport.read = socket_read; - socket_transport->transport.write = socket_write; - - if (!listen_socket_init(socket_transport)) { - D(ERR, "socket transport init failed"); - free(socket_transport); - return 0; - } - - transport_register(&socket_transport->transport); - return 1; -} - diff --git a/fastbootd/trigger.c b/fastbootd/trigger.c deleted file mode 100644 index df0f895..0000000 --- a/fastbootd/trigger.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <dlfcn.h> - -#include <hardware/hardware.h> -#include "debug.h" -#include "trigger.h" -#include "protocol.h" -#include "vendor_trigger.h" - -static const int version = 1; - -int load_trigger() { - int libversion; - - if (trigger_init() != 0) { - D(ERR, "libvendortrigger failed to initialize"); - return 1; - } - - if (trigger_check_version(version, &libversion)) { - D(ERR, "Library report incompability"); - return 1; - } - - D(INFO, "libvendortrigger loaded"); - return 0; -} diff --git a/fastbootd/usb_linux_client.c b/fastbootd/usb_linux_client.c deleted file mode 100644 index 64420e9..0000000 --- a/fastbootd/usb_linux_client.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * 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. - */ - -#include <endian.h> -#include <fcntl.h> -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <sys/ioctl.h> -#include <sys/types.h> - -#include <linux/usb/ch9.h> -#include <linux/usb/functionfs.h> - -#include "debug.h" -#include "transport.h" -#include "utils.h" - -#define TRACE_TAG TRACE_USB - -#define MAX_PACKET_SIZE_FS 64 -#define MAX_PACKET_SIZE_HS 512 - -#define cpu_to_le16(x) htole16(x) -#define cpu_to_le32(x) htole32(x) - -#define FASTBOOT_CLASS 0xff -#define FASTBOOT_SUBCLASS 0x42 -#define FASTBOOT_PROTOCOL 0x3 - -#define USB_FFS_FASTBOOT_PATH "/dev/usb-ffs/adb/" -#define USB_FFS_FASTBOOT_EP(x) USB_FFS_FASTBOOT_PATH#x - -#define USB_FFS_FASTBOOT_EP0 USB_FFS_FASTBOOT_EP(ep0) -#define USB_FFS_FASTBOOT_OUT USB_FFS_FASTBOOT_EP(ep1) -#define USB_FFS_FASTBOOT_IN USB_FFS_FASTBOOT_EP(ep2) - -#define container_of(ptr, type, member) \ - ((type*)((char*)(ptr) - offsetof(type, member))) - -struct usb_transport { - struct transport transport; - - pthread_cond_t notify; - pthread_mutex_t lock; - - int control; - int bulk_out; /* "out" from the host's perspective => source for fastbootd */ - int bulk_in; /* "in" from the host's perspective => sink for fastbootd */ -}; - -struct usb_handle { - struct transport_handle handle; -}; - -static const struct { - struct usb_functionfs_descs_head header; - struct { - struct usb_interface_descriptor intf; - struct usb_endpoint_descriptor_no_audio source; - struct usb_endpoint_descriptor_no_audio sink; - } __attribute__((packed)) fs_descs, hs_descs; -} __attribute__((packed)) descriptors = { - .header = { - .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC), - .length = cpu_to_le32(sizeof(descriptors)), - .fs_count = 3, - .hs_count = 3, - }, - .fs_descs = { - .intf = { - .bLength = sizeof(descriptors.fs_descs.intf), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bNumEndpoints = 2, - .bInterfaceClass = FASTBOOT_CLASS, - .bInterfaceSubClass = FASTBOOT_SUBCLASS, - .bInterfaceProtocol = FASTBOOT_PROTOCOL, - .iInterface = 1, /* first string from the provided table */ - }, - .source = { - .bLength = sizeof(descriptors.fs_descs.source), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 1 | USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_FS, - }, - .sink = { - .bLength = sizeof(descriptors.fs_descs.sink), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 2 | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_FS, - }, - }, - .hs_descs = { - .intf = { - .bLength = sizeof(descriptors.hs_descs.intf), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bNumEndpoints = 2, - .bInterfaceClass = FASTBOOT_CLASS, - .bInterfaceSubClass = FASTBOOT_SUBCLASS, - .bInterfaceProtocol = FASTBOOT_PROTOCOL, - .iInterface = 1, /* first string from the provided table */ - }, - .source = { - .bLength = sizeof(descriptors.hs_descs.source), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 1 | USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_HS, - }, - .sink = { - .bLength = sizeof(descriptors.hs_descs.sink), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 2 | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_HS, - }, - }, -}; - -#define STR_INTERFACE_ "Fastboot Interface" - -static const struct { - struct usb_functionfs_strings_head header; - struct { - __le16 code; - const char str1[sizeof(STR_INTERFACE_)]; - } __attribute__((packed)) lang0; -} __attribute__((packed)) strings = { - .header = { - .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC), - .length = cpu_to_le32(sizeof(strings)), - .str_count = cpu_to_le32(1), - .lang_count = cpu_to_le32(1), - }, - .lang0 = { - cpu_to_le16(0x0409), /* en-us */ - STR_INTERFACE_, - }, -}; - -static int init_functionfs(struct usb_transport *usb_transport) -{ - ssize_t ret; - - D(VERBOSE, "OPENING %s", USB_FFS_FASTBOOT_EP0); - usb_transport->control = open(USB_FFS_FASTBOOT_EP0, O_RDWR); - if (usb_transport->control < 0) { - D(ERR, "[ %s: cannot open control endpoint: errno=%d]", USB_FFS_FASTBOOT_EP0, errno); - goto err; - } - - ret = write(usb_transport->control, &descriptors, sizeof(descriptors)); - if (ret < 0) { - D(ERR, "[ %s: write descriptors failed: errno=%d ]", USB_FFS_FASTBOOT_EP0, errno); - goto err; - } - - ret = write(usb_transport->control, &strings, sizeof(strings)); - if (ret < 0) { - D(ERR, "[ %s: writing strings failed: errno=%d]", USB_FFS_FASTBOOT_EP0, errno); - goto err; - } - - usb_transport->bulk_out = open(USB_FFS_FASTBOOT_OUT, O_RDWR); - if (usb_transport->bulk_out < 0) { - D(ERR, "[ %s: cannot open bulk-out ep: errno=%d ]", USB_FFS_FASTBOOT_OUT, errno); - goto err; - } - - usb_transport->bulk_in = open(USB_FFS_FASTBOOT_IN, O_RDWR); - if (usb_transport->bulk_in < 0) { - D(ERR, "[ %s: cannot open bulk-in ep: errno=%d ]", USB_FFS_FASTBOOT_IN, errno); - goto err; - } - - return 0; - -err: - if (usb_transport->bulk_in > 0) { - close(usb_transport->bulk_in); - usb_transport->bulk_in = -1; - } - if (usb_transport->bulk_out > 0) { - close(usb_transport->bulk_out); - usb_transport->bulk_out = -1; - } - if (usb_transport->control > 0) { - close(usb_transport->control); - usb_transport->control = -1; - } - return -1; -} - -static ssize_t usb_write(struct transport_handle *thandle, const void *data, size_t len) -{ - ssize_t ret; - struct transport *t = thandle->transport; - struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport); - - D(DEBUG, "about to write (fd=%d, len=%zu)", usb_transport->bulk_in, len); - ret = bulk_write(usb_transport->bulk_in, data, len); - if (ret < 0) { - D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_in, ret); - return -1; - } - D(DEBUG, "[ usb_write done fd=%d ]", usb_transport->bulk_in); - return ret; -} - -ssize_t usb_read(struct transport_handle *thandle, void *data, size_t len) -{ - ssize_t ret; - struct transport *t = thandle->transport; - struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport); - - D(DEBUG, "about to read (fd=%d, len=%zu)", usb_transport->bulk_out, len); - ret = bulk_read(usb_transport->bulk_out, data, len); - if (ret < 0) { - D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_out, ret); - return -1; - } - D(DEBUG, "[ usb_read done fd=%d ret=%zd]", usb_transport->bulk_out, ret); - return ret; -} - -void usb_close(struct transport_handle *thandle) -{ - int err; - struct transport *t = thandle->transport; - struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport); - - err = ioctl(usb_transport->bulk_in, FUNCTIONFS_CLEAR_HALT); - if (err < 0) - D(WARN, "[ kick: source (fd=%d) clear halt failed (%d) ]", usb_transport->bulk_in, errno); - - err = ioctl(usb_transport->bulk_out, FUNCTIONFS_CLEAR_HALT); - if (err < 0) - D(WARN, "[ kick: sink (fd=%d) clear halt failed (%d) ]", usb_transport->bulk_out, errno); - - pthread_mutex_lock(&usb_transport->lock); - close(usb_transport->control); - close(usb_transport->bulk_out); - close(usb_transport->bulk_in); - usb_transport->control = usb_transport->bulk_out = usb_transport->bulk_in = -1; - - pthread_cond_signal(&usb_transport->notify); - pthread_mutex_unlock(&usb_transport->lock); -} - -struct transport_handle *usb_connect(struct transport *transport) -{ - int ret; - struct usb_handle *usb_handle = calloc(sizeof(struct usb_handle), 1); - struct usb_transport *usb_transport = container_of(transport, struct usb_transport, transport); - - pthread_mutex_lock(&usb_transport->lock); - while (usb_transport->control != -1) - pthread_cond_wait(&usb_transport->notify, &usb_transport->lock); - pthread_mutex_unlock(&usb_transport->lock); - - ret = init_functionfs(usb_transport); - if (ret < 0) { - D(ERR, "usb connect: failed to initialize usb transport"); - return NULL; - } - - D(DEBUG, "[ usb_thread - registering device ]"); - return &usb_handle->handle; -} - -void usb_init() -{ - struct usb_transport *usb_transport = calloc(1, sizeof(struct usb_transport)); - - usb_transport->transport.connect = usb_connect; - usb_transport->transport.close = usb_close; - usb_transport->transport.read = usb_read; - usb_transport->transport.write = usb_write; - usb_transport->control = -1; - usb_transport->bulk_out = -1; - usb_transport->bulk_out = -1; - - pthread_cond_init(&usb_transport->notify, NULL); - pthread_mutex_init(&usb_transport->lock, NULL); - - transport_register(&usb_transport->transport); -} - diff --git a/fastbootd/utils.c b/fastbootd/utils.c deleted file mode 100644 index bef2463..0000000 --- a/fastbootd/utils.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <stdio.h> -#include <sys/ioctl.h> -#include <linux/fs.h> -#include <stdlib.h> -#include <cutils/properties.h> - -#include "utils.h" -#include "debug.h" - -#ifndef BLKDISCARD -#define BLKDISCARD _IO(0x12,119) -#endif - -#ifndef BLKSECDISCARD -#define BLKSECDISCARD _IO(0x12,125) -#endif - -#define READ_BUF_SIZE (16*1024) - -int get_stream_size(FILE *stream) { - int size; - fseek(stream, 0, SEEK_END); - size = ftell(stream); - fseek(stream, 0, SEEK_SET); - return size; -} - -uint64_t get_block_device_size(int fd) -{ - uint64_t size = 0; - int ret; - - ret = ioctl(fd, BLKGETSIZE64, &size); - - if (ret) - return 0; - - return size; -} - -uint64_t get_file_size(int fd) -{ - struct stat buf; - int ret; - int64_t computed_size; - - ret = fstat(fd, &buf); - if (ret) - return 0; - - if (S_ISREG(buf.st_mode)) - computed_size = buf.st_size; - else if (S_ISBLK(buf.st_mode)) - computed_size = get_block_device_size(fd); - else - computed_size = 0; - - return computed_size; -} - -uint64_t get_file_size64(int fd) -{ - struct stat64 buf; - int ret; - uint64_t computed_size; - - ret = fstat64(fd, &buf); - if (ret) - return 0; - - if (S_ISREG(buf.st_mode)) - computed_size = buf.st_size; - else if (S_ISBLK(buf.st_mode)) - computed_size = get_block_device_size(fd); - else - computed_size = 0; - - return computed_size; -} - - -char *strip(char *str) -{ - int n; - - n = strspn(str, " \t"); - str += n; - n = strcspn(str, " \t"); - str[n] = '\0'; - - return str; -} - -int wipe_block_device(int fd, int64_t len) -{ - uint64_t range[2]; - int ret; - - range[0] = 0; - range[1] = len; - ret = ioctl(fd, BLKSECDISCARD, &range); - if (ret < 0) { - range[0] = 0; - range[1] = len; - ret = ioctl(fd, BLKDISCARD, &range); - if (ret < 0) { - D(WARN, "Discard failed\n"); - return 1; - } else { - D(WARN, "Wipe via secure discard failed, used discard instead\n"); - return 0; - } - } - - return 0; -} - -int create_temp_file() { - char tempname[] = "/dev/fastboot_data_XXXXXX"; - int fd; - - fd = mkstemp(tempname); - if (fd < 0) - return -1; - - unlink(tempname); - - return fd; -} - -ssize_t bulk_write(int bulk_in, const char *buf, size_t length) -{ - size_t count = 0; - ssize_t ret; - - do { - ret = TEMP_FAILURE_RETRY(write(bulk_in, buf + count, length - count)); - if (ret < 0) { - D(WARN, "[ bulk_write failed fd=%d length=%zu errno=%d %s ]", - bulk_in, length, errno, strerror(errno)); - return -1; - } else { - count += ret; - } - } while (count < length); - - D(VERBOSE, "[ bulk_write done fd=%d ]", bulk_in); - return count; -} - -ssize_t bulk_read(int bulk_out, char *buf, size_t length) -{ - ssize_t ret; - size_t n = 0; - - while (n < length) { - size_t to_read = (length - n > READ_BUF_SIZE) ? READ_BUF_SIZE : length - n; - ret = TEMP_FAILURE_RETRY(read(bulk_out, buf + n, to_read)); - if (ret < 0) { - D(WARN, "[ bulk_read failed fd=%d length=%zu errno=%d %s ]", - bulk_out, length, errno, strerror(errno)); - return ret; - } - n += ret; - if (ret < (ssize_t)to_read) { - D(VERBOSE, "bulk_read short read, ret=%zd to_read=%zu n=%zu length=%zu", - ret, to_read, n, length); - break; - } - } - - return n; -} - -#define NAP_TIME 200 // 200 ms between polls -static int wait_for_property(const char *name, const char *desired_value, int maxwait) -{ - char value[PROPERTY_VALUE_MAX] = {'\0'}; - int maxnaps = (maxwait * 1000) / NAP_TIME; - - if (maxnaps < 1) { - maxnaps = 1; - } - - while (maxnaps-- > 0) { - usleep(NAP_TIME * 1000); - if (property_get(name, value, NULL)) { - if (desired_value == NULL || strcmp(value, desired_value) == 0) { - return 0; - } - } - } - return -1; /* failure */ -} - -int service_start(const char *service_name) -{ - int result = 0; - char property_value[PROPERTY_VALUE_MAX]; - - property_get(service_name, property_value, ""); - if (strcmp("running", property_value) != 0) { - D(INFO, "Starting %s", service_name); - property_set("ctl.start", service_name); - if (wait_for_property(service_name, "running", 5)) - result = -1; - } - - return result; -} - -int service_stop(const char *service_name) -{ - int result = 0; - - D(INFO, "Stopping MDNSD"); - property_set("ctl.stop", service_name); - if (wait_for_property(service_name, "stopped", 5)) - result = -1; - - return result; -} - -int ssh_server_start() -{ - return service_start("sshd"); -} diff --git a/fastbootd/utils.h b/fastbootd/utils.h deleted file mode 100644 index 3d98699..0000000 --- a/fastbootd/utils.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#ifndef _FASTBOOT_UTLIS_H -#define _FASTBOOT_UTILS_H - -#include <stdio.h> - -int get_stream_size(FILE *); - -char *strip(char *str); - -uint64_t get_file_size64(int fd); -uint64_t get_file_size(int fd); -uint64_t get_block_device_size(int fd); -int wipe_block_device(int fd, int64_t len); -int create_temp_file(); -ssize_t bulk_read(int bulk_out, char *buf, size_t length); -ssize_t bulk_write(int bulk_in, const char *buf, size_t length); -int service_start(const char *service_name); -int service_stop(const char *service_name); -int ssh_server_start(); - -#define ROUND_TO_PAGE(address,pagesize) ((address + pagesize - 1) & (~(pagesize - 1))) - -#define ROUND_UP(number,size) (((number + size - 1) / size) * size) - -#endif diff --git a/fastbootd/vendor_trigger.h b/fastbootd/vendor_trigger.h deleted file mode 100644 index 0c83be6..0000000 --- a/fastbootd/vendor_trigger.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#ifndef __VENDOR_TRIGGER_H_ -#define __VENDOR_TRIGGER_H_ - -__BEGIN_DECLS - -struct GPT_entry_raw; -struct GPT_content; - -/* - * Implemented in libvendortrigger to handle platform-specific behavior. - */ - -/* - * trigger_init() is called once at startup time before calling any other method - * - * returns 0 on success and nonzero on error - */ -int trigger_init(void); - -/* - * This function runs once after trigger_init completes. - * - * version is number parameter indicating version on the fastbootd side - * libversion is version indicateing version of the library version - * - * returns 0 if it can cooperate with the current version and 1 in opposite - */ -int trigger_check_version(const int version, int *libversion); - -/* - * Return value -1 forbid the action from the vendor site and sets errno - */ -int trigger_gpt_layout(struct GPT_content *); -int trigger_oem_cmd(const char *arg, const char **response); - -__END_DECLS - -#endif diff --git a/fastbootd/vendor_trigger_default.c b/fastbootd/vendor_trigger_default.c deleted file mode 100644 index 3627024..0000000 --- a/fastbootd/vendor_trigger_default.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2009-2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <stdlib.h> -#include <cutils/klog.h> -#include <vendor_trigger.h> - -static const int version = 1; - -int trigger_init(void) { - klog_init(); - klog_set_level(7); - return 0; -} - -int trigger_check_version(const int fastboot_version, int *libversion) { - KLOG_DEBUG("fastbootd", "%s: %d (%d)", __func__, fastboot_version, version); - *libversion = version; - return !(fastboot_version == version); -} - -int trigger_gpt_layout(struct GPT_content *table) { - KLOG_DEBUG("fastbootd", "%s: %p", __func__, table); - return 0; -} - -int trigger_oem_cmd(const char *arg, const char **response) { - KLOG_DEBUG("fastbootd", "%s: %s", __func__, arg); - return 0; -} diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk index 0ec6c4b..8ed5cc9 100644 --- a/fs_mgr/Android.mk +++ b/fs_mgr/Android.mk @@ -12,8 +12,8 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH)/include \ external/openssl/include LOCAL_MODULE:= libfs_mgr -LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static -LOCAL_C_INCLUDES += system/extras/ext4_utils +LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static libsquashfs_utils +LOCAL_C_INCLUDES += system/extras/ext4_utils system/extras/squashfs_utils LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_CFLAGS := -Werror @@ -38,8 +38,9 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) -LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static +LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static libsquashfs_utils LOCAL_STATIC_LIBRARIES += libsparse_static libz libselinux +LOCAL_CXX_STL := libc++_static LOCAL_CFLAGS := -Werror diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c index 8533ff6..5f639b7 100644 --- a/fs_mgr/fs_mgr.c +++ b/fs_mgr/fs_mgr.c @@ -28,6 +28,10 @@ #include <libgen.h> #include <time.h> #include <sys/swap.h> +#include <dirent.h> +#include <ext4.h> +#include <ext4_sb.h> +#include <ext4_crypt.h> #include <linux/loop.h> #include <private/android_filesystem_config.h> @@ -116,10 +120,23 @@ static void check_fs(char *blk_device, char *fs_type, char *target) * filesytsem due to an error, e2fsck is still run to do a full check * fix the filesystem. */ + errno = 0; ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts); - INFO("%s(): mount(%s,%s,%s)=%d\n", __func__, blk_device, target, fs_type, ret); + INFO("%s(): mount(%s,%s,%s)=%d: %s\n", + __func__, blk_device, target, fs_type, ret, strerror(errno)); if (!ret) { - umount(target); + int i; + for (i = 0; i < 5; i++) { + // Try to umount 5 times before continuing on. + // Should we try rebooting if all attempts fail? + int result = umount(target); + if (result == 0) { + INFO("%s(): unmount(%s) succeeded\n", __func__, target); + break; + } + ERROR("%s(): umount(%s)=%d: %s\n", __func__, target, result, strerror(errno)); + sleep(1); + } } /* @@ -176,19 +193,22 @@ static void remove_trailing_slashes(char *n) * Mark the given block device as read-only, using the BLKROSET ioctl. * Return 0 on success, and -1 on error. */ -static void fs_set_blk_ro(const char *blockdev) +int fs_mgr_set_blk_ro(const char *blockdev) { int fd; + int rc = -1; int ON = 1; - fd = open(blockdev, O_RDONLY); + fd = TEMP_FAILURE_RETRY(open(blockdev, O_RDONLY | O_CLOEXEC)); if (fd < 0) { // should never happen - return; + return rc; } - ioctl(fd, BLKROSET, &ON); - close(fd); + rc = ioctl(fd, BLKROSET, &ON); + TEMP_FAILURE_RETRY(close(fd)); + + return rc; } /* @@ -214,7 +234,7 @@ static int __mount(const char *source, const char *target, const struct fstab_re save_errno = errno; INFO("%s(source=%s,target=%s,type=%s)=%d\n", __func__, source, target, rec->fs_type, ret); if ((ret == 0) && (mountflags & MS_RDONLY) != 0) { - fs_set_blk_ro(source); + fs_mgr_set_blk_ro(source); } errno = save_errno; return ret; @@ -338,6 +358,150 @@ static int mount_with_alternatives(struct fstab *fstab, int start_idx, int *end_ return 0; } +static int translate_ext_labels(struct fstab_rec *rec) +{ + DIR *blockdir = NULL; + struct dirent *ent; + char *label; + size_t label_len; + int ret = -1; + + if (strncmp(rec->blk_device, "LABEL=", 6)) + return 0; + + label = rec->blk_device + 6; + label_len = strlen(label); + + if (label_len > 16) { + ERROR("FS label is longer than allowed by filesystem\n"); + goto out; + } + + + blockdir = opendir("/dev/block"); + if (!blockdir) { + ERROR("couldn't open /dev/block\n"); + goto out; + } + + while ((ent = readdir(blockdir))) { + int fd; + char super_buf[1024]; + struct ext4_super_block *sb; + + if (ent->d_type != DT_BLK) + continue; + + fd = openat(dirfd(blockdir), ent->d_name, O_RDONLY); + if (fd < 0) { + ERROR("Cannot open block device /dev/block/%s\n", ent->d_name); + goto out; + } + + if (TEMP_FAILURE_RETRY(lseek(fd, 1024, SEEK_SET)) < 0 || + TEMP_FAILURE_RETRY(read(fd, super_buf, 1024)) != 1024) { + /* Probably a loopback device or something else without a readable + * superblock. + */ + close(fd); + continue; + } + + sb = (struct ext4_super_block *)super_buf; + if (sb->s_magic != EXT4_SUPER_MAGIC) { + INFO("/dev/block/%s not ext{234}\n", ent->d_name); + continue; + } + + if (!strncmp(label, sb->s_volume_name, label_len)) { + char *new_blk_device; + + if (asprintf(&new_blk_device, "/dev/block/%s", ent->d_name) < 0) { + ERROR("Could not allocate block device string\n"); + goto out; + } + + INFO("resolved label %s to %s\n", rec->blk_device, new_blk_device); + + free(rec->blk_device); + rec->blk_device = new_blk_device; + ret = 0; + break; + } + } + +out: + closedir(blockdir); + return ret; +} + +// Check to see if a mountable volume has encryption requirements +static int handle_encryptable(struct fstab *fstab, const struct fstab_rec* rec) +{ + /* If this is block encryptable, need to trigger encryption */ + if ( (rec->fs_mgr_flags & MF_FORCECRYPT) + || (device_is_force_encrypted() && fs_mgr_is_encryptable(rec))) { + if (umount(rec->mount_point) == 0) { + return FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION; + } else { + WARNING("Could not umount %s (%s) - allow continue unencrypted\n", + rec->mount_point, strerror(errno)); + return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED; + } + } + + // Deal with file level encryption + if (rec->fs_mgr_flags & MF_FILEENCRYPTION) { + // Default or not yet initialized encryption requires no more work here + if (!e4crypt_non_default_key(rec->mount_point)) { + INFO("%s is default file encrypted\n", rec->mount_point); + return FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED; + } + + INFO("%s is non-default file encrypted\n", rec->mount_point); + + // Uses non-default key, so must unmount and set up temp file system + if (umount(rec->mount_point)) { + ERROR("Failed to umount %s - rebooting\n", rec->mount_point); + return FS_MGR_MNTALL_FAIL; + } + + if (fs_mgr_do_tmpfs_mount(rec->mount_point) != 0) { + ERROR("Failed to mount a tmpfs at %s\n", rec->mount_point); + return FS_MGR_MNTALL_FAIL; + } + + // Mount data temporarily so we can access unencrypted dir + char tmp_mnt[PATH_MAX]; + strlcpy(tmp_mnt, rec->mount_point, sizeof(tmp_mnt)); + strlcat(tmp_mnt, "/tmp_mnt", sizeof(tmp_mnt)); + if (mkdir(tmp_mnt, 0700)) { + ERROR("Failed to create temp mount point\n"); + return FS_MGR_MNTALL_FAIL; + } + + if (fs_mgr_do_mount(fstab, rec->mount_point, + rec->blk_device, tmp_mnt)) { + ERROR("Error temp mounting encrypted file system\n"); + return FS_MGR_MNTALL_FAIL; + } + + // Link it to the normal place so ext4_crypt functions work normally + strlcat(tmp_mnt, "/unencrypted", sizeof(tmp_mnt)); + char link_path[PATH_MAX]; + strlcpy(link_path, rec->mount_point, sizeof(link_path)); + strlcat(link_path, "/unencrypted", sizeof(link_path)); + if (symlink(tmp_mnt, link_path)) { + ERROR("Error creating symlink to unencrypted directory\n"); + return FS_MGR_MNTALL_FAIL; + } + + return FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED; + } + + return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED; +} + /* When multiple fstab records share the same mount_point, it will * try to mount each one in turn, and ignore any duplicates after a * first successful mount. @@ -369,6 +533,17 @@ int fs_mgr_mount_all(struct fstab *fstab) continue; } + /* Translate LABEL= file system labels into block devices */ + if (!strcmp(fstab->recs[i].fs_type, "ext2") || + !strcmp(fstab->recs[i].fs_type, "ext3") || + !strcmp(fstab->recs[i].fs_type, "ext4")) { + int tret = translate_ext_labels(&fstab->recs[i]); + if (tret < 0) { + ERROR("Could not translate label to block device\n"); + continue; + } + } + if (fstab->recs[i].fs_mgr_flags & MF_WAIT) { wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT); } @@ -391,25 +566,21 @@ int fs_mgr_mount_all(struct fstab *fstab) /* Deal with encryptability. */ if (!mret) { - /* If this is encryptable, need to trigger encryption */ - if ( (fstab->recs[attempted_idx].fs_mgr_flags & MF_FORCECRYPT) - || (device_is_force_encrypted() - && fs_mgr_is_encryptable(&fstab->recs[attempted_idx]))) { - if (umount(fstab->recs[attempted_idx].mount_point) == 0) { - if (encryptable == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) { - ERROR("Will try to encrypt %s %s\n", fstab->recs[attempted_idx].mount_point, - fstab->recs[attempted_idx].fs_type); - encryptable = FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION; - } else { - ERROR("Only one encryptable/encrypted partition supported\n"); - encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED; - } - } else { - INFO("Could not umount %s - allow continue unencrypted\n", - fstab->recs[attempted_idx].mount_point); - continue; + int status = handle_encryptable(fstab, &fstab->recs[attempted_idx]); + + if (status == FS_MGR_MNTALL_FAIL) { + /* Fatal error - no point continuing */ + return status; + } + + if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) { + if (encryptable != FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) { + // Log and continue + ERROR("Only one encryptable/encrypted partition supported\n"); } + encryptable = status; } + /* Success! Go get the next one */ continue; } diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c index c2da28a..51f398e 100644 --- a/fs_mgr/fs_mgr_fstab.c +++ b/fs_mgr/fs_mgr_fstab.c @@ -26,6 +26,7 @@ struct fs_mgr_flag_values { char *key_loc; + char *verity_loc; long long part_length; char *label; int partnum; @@ -62,6 +63,7 @@ static struct flag_list fs_mgr_flags[] = { { "check", MF_CHECK }, { "encryptable=",MF_CRYPT }, { "forceencrypt=",MF_FORCECRYPT }, + { "fileencryption",MF_FILEENCRYPTION }, { "nonremovable",MF_NONREMOVABLE }, { "voldmanaged=",MF_VOLDMANAGED}, { "length=", MF_LENGTH }, @@ -123,6 +125,14 @@ static int parse_flags(char *flags, struct flag_list *fl, * location of the keys. Get it and return it. */ flag_vals->key_loc = strdup(strchr(p, '=') + 1); + } else if ((fl[i].flag == MF_VERIFY) && flag_vals) { + /* If the verify flag is followed by an = and the + * location for the verity state, get it and return it. + */ + char *start = strchr(p, '='); + if (start) { + flag_vals->verity_loc = strdup(start + 1); + } } else if ((fl[i].flag == MF_FORCECRYPT) && flag_vals) { /* The forceencrypt flag is followed by an = and the * location of the keys. Get it and return it. @@ -312,6 +322,7 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path) fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags, &flag_vals, NULL, 0); fstab->recs[cnt].key_loc = flag_vals.key_loc; + fstab->recs[cnt].verity_loc = flag_vals.verity_loc; fstab->recs[cnt].length = flag_vals.part_length; fstab->recs[cnt].label = flag_vals.label; fstab->recs[cnt].partnum = flag_vals.partnum; @@ -429,27 +440,32 @@ struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const ch return fs_mgr_get_entry_for_mount_point_after(NULL, fstab, path); } -int fs_mgr_is_voldmanaged(struct fstab_rec *fstab) +int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab) { return fstab->fs_mgr_flags & MF_VOLDMANAGED; } -int fs_mgr_is_nonremovable(struct fstab_rec *fstab) +int fs_mgr_is_nonremovable(const struct fstab_rec *fstab) { return fstab->fs_mgr_flags & MF_NONREMOVABLE; } -int fs_mgr_is_verified(struct fstab_rec *fstab) +int fs_mgr_is_verified(const struct fstab_rec *fstab) { return fstab->fs_mgr_flags & MF_VERIFY; } -int fs_mgr_is_encryptable(struct fstab_rec *fstab) +int fs_mgr_is_encryptable(const struct fstab_rec *fstab) { return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT); } -int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab) +int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab) +{ + return fstab->fs_mgr_flags & MF_FILEENCRYPTION; +} + +int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab) { return fstab->fs_mgr_flags & MF_NOEMULATEDSD; } diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index fd58306..2d252e4 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -21,6 +21,7 @@ #include <fs_mgr.h> #define INFO(x...) KLOG_INFO("fs_mgr", x) +#define WARNING(x...) KLOG_WARNING("fs_mgr", x) #define ERROR(x...) KLOG_ERROR("fs_mgr", x) #define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000" @@ -76,8 +77,10 @@ #define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only external storage */ #define MF_FORMATTABLE 0x1000 +#define MF_FILEENCRYPTION 0x2000 #define DM_BUF_SIZE 4096 -#endif /* __CORE_FS_MGR_PRIV_H */ +int fs_mgr_set_blk_ro(const char *blockdev); +#endif /* __CORE_FS_MGR_PRIV_H */ diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c index a82db4e..6ef46ba 100644 --- a/fs_mgr/fs_mgr_verity.c +++ b/fs_mgr/fs_mgr_verity.c @@ -38,13 +38,38 @@ #include "mincrypt/sha256.h" #include "ext4_sb.h" +#include "squashfs_utils.h" #include "fs_mgr_priv.h" #include "fs_mgr_priv_verity.h" +#define FSTAB_PREFIX "/fstab." + #define VERITY_METADATA_SIZE 32768 #define VERITY_TABLE_RSA_KEY "/verity_key" +#define METADATA_MAGIC 0x01564c54 +#define METADATA_TAG_MAX_LENGTH 63 +#define METADATA_EOD "eod" + +#define VERITY_LASTSIG_TAG "verity_lastsig" + +#define VERITY_STATE_TAG "verity_state" +#define VERITY_STATE_HEADER 0x83c0ae9d +#define VERITY_STATE_VERSION 1 + +#define VERITY_KMSG_RESTART "dm-verity device corrupted" +#define VERITY_KMSG_BUFSIZE 1024 + +#define __STRINGIFY(x) #x +#define STRINGIFY(x) __STRINGIFY(x) + +struct verity_state { + uint32_t header; + uint32_t version; + int32_t mode; +}; + extern struct fs_info info; static RSAPublicKey *load_key(char *path) @@ -116,11 +141,25 @@ out: return retval; } -static int get_target_device_size(char *blk_device, uint64_t *device_size) +static int squashfs_get_target_device_size(char *blk_device, uint64_t *device_size) +{ + struct squashfs_info sq_info; + + if (squashfs_parse_sb(blk_device, &sq_info) >= 0) { + *device_size = sq_info.bytes_used_4K_padded; + return 0; + } else { + return -1; + } +} + +static int ext4_get_target_device_size(char *blk_device, uint64_t *device_size) { int data_device; struct ext4_super_block sb; - struct fs_info info = {0}; + struct fs_info info; + + info.len = 0; /* Only len is set to 0 to ask the device for real size. */ data_device = TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC)); if (data_device == -1) { @@ -147,16 +186,38 @@ static int get_target_device_size(char *blk_device, uint64_t *device_size) return 0; } -static int read_verity_metadata(char *block_device, char **signature, char **table) +static int get_fs_size(char *fs_type, char *blk_device, uint64_t *device_size) { + if (!strcmp(fs_type, "ext4")) { + if (ext4_get_target_device_size(blk_device, device_size) < 0) { + ERROR("Failed to get ext4 fs size on %s.", blk_device); + return -1; + } + } else if (!strcmp(fs_type, "squashfs")) { + if (squashfs_get_target_device_size(blk_device, device_size) < 0) { + ERROR("Failed to get squashfs fs size on %s.", blk_device); + return -1; + } + } else { + ERROR("%s: Unsupported filesystem for verity.", fs_type); + return -1; + } + return 0; +} + +static int read_verity_metadata(uint64_t device_size, char *block_device, char **signature, + char **table) { unsigned magic_number; unsigned table_length; - uint64_t device_length; int protocol_version; int device; int retval = FS_MGR_SETUP_VERITY_FAIL; - *signature = 0; - *table = 0; + + *signature = NULL; + + if (table) { + *table = NULL; + } device = TEMP_FAILURE_RETRY(open(block_device, O_RDONLY | O_CLOEXEC)); if (device == -1) { @@ -164,12 +225,7 @@ static int read_verity_metadata(char *block_device, char **signature, char **tab goto out; } - // find the start of the verity metadata - if (get_target_device_size(block_device, &device_length) < 0) { - ERROR("Could not get target device size.\n"); - goto out; - } - if (TEMP_FAILURE_RETRY(lseek64(device, device_length, SEEK_SET)) < 0) { + if (TEMP_FAILURE_RETRY(lseek64(device, device_size, SEEK_SET)) < 0) { ERROR("Could not seek to start of verity metadata block.\n"); goto out; } @@ -190,8 +246,7 @@ static int read_verity_metadata(char *block_device, char **signature, char **tab #endif if (magic_number != VERITY_METADATA_MAGIC_NUMBER) { - ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n", - device_length); + ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n", device_size); goto out; } @@ -217,6 +272,11 @@ static int read_verity_metadata(char *block_device, char **signature, char **tab goto out; } + if (!table) { + retval = FS_MGR_SETUP_VERITY_SUCCESS; + goto out; + } + // get the size of the table if (TEMP_FAILURE_RETRY(read(device, &table_length, sizeof(table_length))) != sizeof(table_length)) { @@ -244,10 +304,13 @@ out: TEMP_FAILURE_RETRY(close(device)); if (retval != FS_MGR_SETUP_VERITY_SUCCESS) { - free(*table); free(*signature); - *table = 0; - *signature = 0; + *signature = NULL; + + if (table) { + free(*table); + *table = NULL; + } } return retval; @@ -292,15 +355,12 @@ static int get_verity_device_name(struct dm_ioctl *io, char *name, int fd, char return 0; } -static int load_verity_table(struct dm_ioctl *io, char *name, char *blockdev, int fd, char *table) +static int load_verity_table(struct dm_ioctl *io, char *name, uint64_t device_size, int fd, char *table, + int mode) { char *verity_params; char *buffer = (char*) io; - uint64_t device_size = 0; - - if (get_target_device_size(blockdev, &device_size) < 0) { - return -1; - } + size_t bufsize; verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG); @@ -315,7 +375,15 @@ static int load_verity_table(struct dm_ioctl *io, char *name, char *blockdev, in // build the verity params here verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec); - if (sprintf(verity_params, "%s", table) < 0) { + bufsize = DM_BUF_SIZE - (verity_params - buffer); + + if (mode == VERITY_MODE_EIO) { + // allow operation with older dm-verity drivers that are unaware + // of the mode parameter by omitting it; this also means that we + // cannot use logging mode with these drivers, they always cause + // an I/O error for corrupted blocks + strcpy(verity_params, table); + } else if (snprintf(verity_params, bufsize, "%s %d", table, mode) < 0) { return -1; } @@ -354,36 +422,515 @@ static int test_access(char *device) { return -1; } -static int set_verified_property(char *name) { - int ret; - char *key; - ret = asprintf(&key, "partition.%s.verified", name); - if (ret < 0) { - ERROR("Error formatting verified property"); - return ret; - } - ret = PROP_NAME_MAX - strlen(key); - if (ret < 0) { - ERROR("Verified property name is too long"); +static int check_verity_restart(const char *fname) +{ + char buffer[VERITY_KMSG_BUFSIZE + 1]; + int fd; + int rc = 0; + ssize_t size; + struct stat s; + + fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC)); + + if (fd == -1) { + if (errno != ENOENT) { + ERROR("Failed to open %s (%s)\n", fname, strerror(errno)); + } + goto out; + } + + if (fstat(fd, &s) == -1) { + ERROR("Failed to fstat %s (%s)\n", fname, strerror(errno)); + goto out; + } + + size = VERITY_KMSG_BUFSIZE; + + if (size > s.st_size) { + size = s.st_size; + } + + if (lseek(fd, s.st_size - size, SEEK_SET) == -1) { + ERROR("Failed to lseek %jd %s (%s)\n", (intmax_t)(s.st_size - size), fname, + strerror(errno)); + goto out; + } + + if (TEMP_FAILURE_RETRY(read(fd, buffer, size)) != size) { + ERROR("Failed to read %zd bytes from %s (%s)\n", size, fname, + strerror(errno)); + goto out; + } + + buffer[size] = '\0'; + + if (strstr(buffer, VERITY_KMSG_RESTART) != NULL) { + rc = 1; + } + +out: + if (fd != -1) { + TEMP_FAILURE_RETRY(close(fd)); + } + + return rc; +} + +static int was_verity_restart() +{ + static const char *files[] = { + "/sys/fs/pstore/console-ramoops", + "/proc/last_kmsg", + NULL + }; + int i; + + for (i = 0; files[i]; ++i) { + if (check_verity_restart(files[i])) { + return 1; + } + } + + return 0; +} + +static int metadata_add(FILE *fp, long start, const char *tag, + unsigned int length, off64_t *offset) +{ + if (fseek(fp, start, SEEK_SET) < 0 || + fprintf(fp, "%s %u\n", tag, length) < 0) { return -1; } - ret = property_set(key, "1"); - if (ret < 0) - ERROR("Error setting verified property %s: %d", key, ret); - free(key); - return ret; + + *offset = ftell(fp); + + if (fseek(fp, length, SEEK_CUR) < 0 || + fprintf(fp, METADATA_EOD " 0\n") < 0) { + return -1; + } + + return 0; +} + +static int metadata_find(const char *fname, const char *stag, + unsigned int slength, off64_t *offset) +{ + FILE *fp = NULL; + char tag[METADATA_TAG_MAX_LENGTH + 1]; + int rc = -1; + int n; + long start = 0x4000; /* skip cryptfs metadata area */ + uint32_t magic; + unsigned int length = 0; + + if (!fname) { + return -1; + } + + fp = fopen(fname, "r+"); + + if (!fp) { + ERROR("Failed to open %s (%s)\n", fname, strerror(errno)); + goto out; + } + + /* check magic */ + if (fseek(fp, start, SEEK_SET) < 0 || + fread(&magic, sizeof(magic), 1, fp) != 1) { + ERROR("Failed to read magic from %s (%s)\n", fname, strerror(errno)); + goto out; + } + + if (magic != METADATA_MAGIC) { + magic = METADATA_MAGIC; + + if (fseek(fp, start, SEEK_SET) < 0 || + fwrite(&magic, sizeof(magic), 1, fp) != 1) { + ERROR("Failed to write magic to %s (%s)\n", fname, strerror(errno)); + goto out; + } + + rc = metadata_add(fp, start + sizeof(magic), stag, slength, offset); + if (rc < 0) { + ERROR("Failed to add metadata to %s: %s\n", fname, strerror(errno)); + } + + goto out; + } + + start += sizeof(magic); + + while (1) { + n = fscanf(fp, "%" STRINGIFY(METADATA_TAG_MAX_LENGTH) "s %u\n", + tag, &length); + + if (n == 2 && strcmp(tag, METADATA_EOD)) { + /* found a tag */ + start = ftell(fp); + + if (!strcmp(tag, stag) && length == slength) { + *offset = start; + rc = 0; + goto out; + } + + start += length; + + if (fseek(fp, length, SEEK_CUR) < 0) { + ERROR("Failed to seek %s (%s)\n", fname, strerror(errno)); + goto out; + } + } else { + rc = metadata_add(fp, start, stag, slength, offset); + if (rc < 0) { + ERROR("Failed to write metadata to %s: %s\n", fname, + strerror(errno)); + } + goto out; + } + } + +out: + if (fp) { + fflush(fp); + fclose(fp); + } + + return rc; +} + +static int write_verity_state(const char *fname, off64_t offset, int32_t mode) +{ + int fd; + int rc = -1; + struct verity_state s = { VERITY_STATE_HEADER, VERITY_STATE_VERSION, mode }; + + fd = TEMP_FAILURE_RETRY(open(fname, O_WRONLY | O_SYNC | O_CLOEXEC)); + + if (fd == -1) { + ERROR("Failed to open %s (%s)\n", fname, strerror(errno)); + goto out; + } + + if (TEMP_FAILURE_RETRY(pwrite64(fd, &s, sizeof(s), offset)) != sizeof(s)) { + ERROR("Failed to write %zu bytes to %s to offset %" PRIu64 " (%s)\n", + sizeof(s), fname, offset, strerror(errno)); + goto out; + } + + rc = 0; + +out: + if (fd != -1) { + TEMP_FAILURE_RETRY(close(fd)); + } + + return rc; +} + +static int read_verity_state(const char *fname, off64_t offset, int *mode) +{ + int fd = -1; + int rc = -1; + struct verity_state s; + + fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC)); + + if (fd == -1) { + ERROR("Failed to open %s (%s)\n", fname, strerror(errno)); + goto out; + } + + if (TEMP_FAILURE_RETRY(pread64(fd, &s, sizeof(s), offset)) != sizeof(s)) { + ERROR("Failed to read %zu bytes from %s offset %" PRIu64 " (%s)\n", + sizeof(s), fname, offset, strerror(errno)); + goto out; + } + + if (s.header != VERITY_STATE_HEADER) { + /* space allocated, but no state written. write default state */ + *mode = VERITY_MODE_DEFAULT; + rc = write_verity_state(fname, offset, *mode); + goto out; + } + + if (s.version != VERITY_STATE_VERSION) { + ERROR("Unsupported verity state version (%u)\n", s.version); + goto out; + } + + if (s.mode < VERITY_MODE_EIO || + s.mode > VERITY_MODE_LAST) { + ERROR("Unsupported verity mode (%u)\n", s.mode); + goto out; + } + + *mode = s.mode; + rc = 0; + +out: + if (fd != -1) { + TEMP_FAILURE_RETRY(close(fd)); + } + + return rc; +} + +static int compare_last_signature(struct fstab_rec *fstab, int *match) +{ + char tag[METADATA_TAG_MAX_LENGTH + 1]; + char *signature = NULL; + int fd = -1; + int rc = -1; + uint8_t curr[SHA256_DIGEST_SIZE]; + uint8_t prev[SHA256_DIGEST_SIZE]; + off64_t offset = 0; + uint64_t device_size; + + *match = 1; + + // get verity filesystem size + if (get_fs_size(fstab->fs_type, fstab->blk_device, &device_size) < 0) { + ERROR("Failed to get filesystem size\n"); + goto out; + } + + if (read_verity_metadata(device_size, fstab->blk_device, &signature, NULL) < 0) { + ERROR("Failed to read verity signature from %s\n", fstab->mount_point); + goto out; + } + + SHA256_hash(signature, RSANUMBYTES, curr); + + if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s", + basename(fstab->mount_point)) >= (int)sizeof(tag)) { + ERROR("Metadata tag name too long for %s\n", fstab->mount_point); + goto out; + } + + if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_SIZE, + &offset) < 0) { + goto out; + } + + fd = TEMP_FAILURE_RETRY(open(fstab->verity_loc, O_RDWR | O_SYNC | O_CLOEXEC)); + + if (fd == -1) { + ERROR("Failed to open %s: %s\n", fstab->verity_loc, strerror(errno)); + goto out; + } + + if (TEMP_FAILURE_RETRY(pread64(fd, prev, sizeof(prev), + offset)) != sizeof(prev)) { + ERROR("Failed to read %zu bytes from %s offset %" PRIu64 " (%s)\n", + sizeof(prev), fstab->verity_loc, offset, strerror(errno)); + goto out; + } + + *match = !memcmp(curr, prev, SHA256_DIGEST_SIZE); + + if (!*match) { + /* update current signature hash */ + if (TEMP_FAILURE_RETRY(pwrite64(fd, curr, sizeof(curr), + offset)) != sizeof(curr)) { + ERROR("Failed to write %zu bytes to %s offset %" PRIu64 " (%s)\n", + sizeof(curr), fstab->verity_loc, offset, strerror(errno)); + goto out; + } + } + + rc = 0; + +out: + free(signature); + + if (fd != -1) { + TEMP_FAILURE_RETRY(close(fd)); + } + + return rc; +} + +static int get_verity_state_offset(struct fstab_rec *fstab, off64_t *offset) +{ + char tag[METADATA_TAG_MAX_LENGTH + 1]; + + if (snprintf(tag, sizeof(tag), VERITY_STATE_TAG "_%s", + basename(fstab->mount_point)) >= (int)sizeof(tag)) { + ERROR("Metadata tag name too long for %s\n", fstab->mount_point); + return -1; + } + + return metadata_find(fstab->verity_loc, tag, sizeof(struct verity_state), + offset); +} + +static int load_verity_state(struct fstab_rec *fstab, int *mode) +{ + off64_t offset = 0; + int match = 0; + + if (get_verity_state_offset(fstab, &offset) < 0) { + /* fall back to stateless behavior */ + *mode = VERITY_MODE_EIO; + return 0; + } + + if (was_verity_restart()) { + /* device was restarted after dm-verity detected a corrupted + * block, so switch to logging mode */ + *mode = VERITY_MODE_LOGGING; + return write_verity_state(fstab->verity_loc, offset, *mode); + } + + if (!compare_last_signature(fstab, &match) && !match) { + /* partition has been reflashed, reset dm-verity state */ + *mode = VERITY_MODE_DEFAULT; + return write_verity_state(fstab->verity_loc, offset, *mode); + } + + return read_verity_state(fstab->verity_loc, offset, mode); +} + +int fs_mgr_load_verity_state(int *mode) +{ + char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; + char propbuf[PROPERTY_VALUE_MAX]; + int rc = -1; + int i; + int current; + struct fstab *fstab = NULL; + + /* return the default mode, unless any of the verified partitions are in + * logging mode, in which case return that */ + *mode = VERITY_MODE_DEFAULT; + + property_get("ro.hardware", propbuf, ""); + snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf); + + fstab = fs_mgr_read_fstab(fstab_filename); + + if (!fstab) { + ERROR("Failed to read %s\n", fstab_filename); + goto out; + } + + for (i = 0; i < fstab->num_entries; i++) { + if (!fs_mgr_is_verified(&fstab->recs[i])) { + continue; + } + + rc = load_verity_state(&fstab->recs[i], ¤t); + if (rc < 0) { + continue; + } + + if (current == VERITY_MODE_LOGGING) { + *mode = current; + } + } + + rc = 0; + +out: + if (fstab) { + fs_mgr_free_fstab(fstab); + } + + return rc; +} + +int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback) +{ + _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE]; + char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; + char *mount_point; + char propbuf[PROPERTY_VALUE_MAX]; + char *status; + int fd = -1; + int i; + int mode; + int rc = -1; + off64_t offset = 0; + struct dm_ioctl *io = (struct dm_ioctl *) buffer; + struct fstab *fstab = NULL; + + fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC)); + + if (fd == -1) { + ERROR("Error opening device mapper (%s)\n", strerror(errno)); + goto out; + } + + property_get("ro.hardware", propbuf, ""); + snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf); + + fstab = fs_mgr_read_fstab(fstab_filename); + + if (!fstab) { + ERROR("Failed to read %s\n", fstab_filename); + goto out; + } + + for (i = 0; i < fstab->num_entries; i++) { + if (!fs_mgr_is_verified(&fstab->recs[i])) { + continue; + } + + if (get_verity_state_offset(&fstab->recs[i], &offset) < 0 || + read_verity_state(fstab->recs[i].verity_loc, offset, &mode) < 0) { + continue; + } + + mount_point = basename(fstab->recs[i].mount_point); + verity_ioctl_init(io, mount_point, 0); + + if (ioctl(fd, DM_TABLE_STATUS, io)) { + ERROR("Failed to query DM_TABLE_STATUS for %s (%s)\n", mount_point, + strerror(errno)); + continue; + } + + status = &buffer[io->data_start + sizeof(struct dm_target_spec)]; + + if (*status == 'C') { + if (write_verity_state(fstab->recs[i].verity_loc, offset, + VERITY_MODE_LOGGING) < 0) { + continue; + } + } + + if (callback) { + callback(&fstab->recs[i], mount_point, mode, *status); + } + } + + rc = 0; + +out: + if (fstab) { + fs_mgr_free_fstab(fstab); + } + + if (fd) { + TEMP_FAILURE_RETRY(close(fd)); + } + + return rc; } int fs_mgr_setup_verity(struct fstab_rec *fstab) { int retval = FS_MGR_SETUP_VERITY_FAIL; int fd = -1; + int mode; char *verity_blk_name = 0; char *verity_table = 0; char *verity_table_signature = 0; + uint64_t device_size = 0; - char buffer[DM_BUF_SIZE]; + _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE]; struct dm_ioctl *io = (struct dm_ioctl *) buffer; char *mount_point = basename(fstab->mount_point); @@ -391,16 +938,15 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { io->flags |= 1; io->target_count = 1; - // check to ensure that the verity device is ext4 - // TODO: support non-ext4 filesystems - if (strcmp(fstab->fs_type, "ext4")) { - ERROR("Cannot verify non-ext4 device (%s)", fstab->fs_type); + // get verity filesystem size + if (get_fs_size(fstab->fs_type, fstab->blk_device, &device_size) < 0) { return retval; } // read the verity block at the end of the block device // send error code up the chain so we can detect attempts to disable verity - retval = read_verity_metadata(fstab->blk_device, + retval = read_verity_metadata(device_size, + fstab->blk_device, &verity_table_signature, &verity_table); if (retval < 0) { @@ -434,8 +980,19 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { goto out; } + if (load_verity_state(fstab, &mode) < 0) { + /* if accessing or updating the state failed, switch to the default + * safe mode. This makes sure the device won't end up in an endless + * restart loop, and no corrupted data will be exposed to userspace + * without a warning. */ + mode = VERITY_MODE_EIO; + } + + INFO("Enabling dm-verity for %s (mode %d)\n", mount_point, mode); + // load the verity mapping table - if (load_verity_table(io, mount_point, fstab->blk_device, fd, verity_table) < 0) { + if (load_verity_table(io, mount_point, device_size, fd, verity_table, + mode) < 0) { goto out; } @@ -444,6 +1001,9 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { goto out; } + // mark the underlying block device as read-only + fs_mgr_set_blk_ro(fstab->blk_device); + // assign the new verity block device as the block device free(fstab->blk_device); fstab->blk_device = verity_blk_name; @@ -454,8 +1014,7 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { goto out; } - // set the property indicating that the partition is verified - retval = set_verified_property(mount_point); + retval = FS_MGR_SETUP_VERITY_SUCCESS; out: if (fd != -1) { diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 5a6ad2d..68af452 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -31,6 +31,15 @@ extern "C" { #endif +// Verity modes +enum verity_mode { + VERITY_MODE_EIO = 0, + VERITY_MODE_LOGGING = 1, + VERITY_MODE_RESTART = 2, + VERITY_MODE_LAST = VERITY_MODE_RESTART, + VERITY_MODE_DEFAULT = VERITY_MODE_RESTART +}; + /* * The entries must be kept in the same order as they were seen in the fstab. * Unless explicitly requested, a lookup on mount point should always @@ -58,13 +67,20 @@ struct fstab_rec { unsigned int zram_size; }; +// Callback function for verity status +typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab, + const char *mount_point, int mode, int status); + struct fstab *fs_mgr_read_fstab(const char *fstab_path); void fs_mgr_free_fstab(struct fstab *fstab); +#define FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED 5 +#define FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED 4 #define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 3 #define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 2 #define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 1 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 0 +#define FS_MGR_MNTALL_FAIL -1 int fs_mgr_mount_all(struct fstab *fstab); #define FS_MGR_DOMNT_FAILED -1 @@ -75,15 +91,18 @@ int fs_mgr_do_tmpfs_mount(char *n_name); int fs_mgr_unmount_all(struct fstab *fstab); int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_device, int size); +int fs_mgr_load_verity_state(int *mode); +int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback); int fs_mgr_add_entry(struct fstab *fstab, const char *mount_point, const char *fs_type, const char *blk_device); struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path); -int fs_mgr_is_voldmanaged(struct fstab_rec *fstab); -int fs_mgr_is_nonremovable(struct fstab_rec *fstab); -int fs_mgr_is_verified(struct fstab_rec *fstab); -int fs_mgr_is_encryptable(struct fstab_rec *fstab); -int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab); +int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab); +int fs_mgr_is_nonremovable(const struct fstab_rec *fstab); +int fs_mgr_is_verified(const struct fstab_rec *fstab); +int fs_mgr_is_encryptable(const struct fstab_rec *fstab); +int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab); +int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab); int fs_mgr_is_formattable(struct fstab_rec *fstab); int fs_mgr_swapon_all(struct fstab *fstab); @@ -94,4 +113,3 @@ int fs_mgr_do_format(struct fstab_rec *fstab); #endif #endif /* __CORE_FS_MGR_H */ - diff --git a/healthd/Android.mk b/healthd/Android.mk index 1d238b1..07e1d73 100644 --- a/healthd/Android.mk +++ b/healthd/Android.mk @@ -1,7 +1,5 @@ # Copyright 2013 The Android Open Source Project -ifneq ($(BUILD_TINY_ANDROID),true) - LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) @@ -77,5 +75,3 @@ include $(BUILD_PHONY_PACKAGE) _add-charger-image := _img_modules := - -endif diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp index 9388ed0..7ea8250 100644 --- a/healthd/BatteryMonitor.cpp +++ b/healthd/BatteryMonitor.cpp @@ -389,7 +389,6 @@ void BatteryMonitor::init(struct healthd_config *hc) { if (!strcmp(name, ".") || !strcmp(name, "..")) continue; - char buf[20]; // Look for "type" file in each subdirectory path.clear(); path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name); diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp index 74bcbfd..09667a1 100644 --- a/healthd/BatteryPropertiesRegistrar.cpp +++ b/healthd/BatteryPropertiesRegistrar.cpp @@ -48,13 +48,13 @@ void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesLis Mutex::Autolock _l(mRegistrationLock); // check whether this is a duplicate for (size_t i = 0; i < mListeners.size(); i++) { - if (mListeners[i]->asBinder() == listener->asBinder()) { + if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener)) { return; } } mListeners.add(listener); - listener->asBinder()->linkToDeath(this); + IInterface::asBinder(listener)->linkToDeath(this); } healthd_battery_update(); } @@ -64,8 +64,8 @@ void BatteryPropertiesRegistrar::unregisterListener(const sp<IBatteryPropertiesL return; Mutex::Autolock _l(mRegistrationLock); for (size_t i = 0; i < mListeners.size(); i++) { - if (mListeners[i]->asBinder() == listener->asBinder()) { - mListeners[i]->asBinder()->unlinkToDeath(this); + if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener)) { + IInterface::asBinder(mListeners[i])->unlinkToDeath(this); mListeners.removeAt(i); break; } @@ -93,7 +93,7 @@ void BatteryPropertiesRegistrar::binderDied(const wp<IBinder>& who) { Mutex::Autolock _l(mRegistrationLock); for (size_t i = 0; i < mListeners.size(); i++) { - if (mListeners[i]->asBinder() == who) { + if (IInterface::asBinder(mListeners[i]) == who) { mListeners.removeAt(i); break; } diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp index f4171bd..1fee855 100644 --- a/healthd/healthd.cpp +++ b/healthd/healthd.cpp @@ -65,7 +65,6 @@ static int epollfd; #define MAX_EPOLL_EVENTS 40 static int uevent_fd; static int wakealarm_fd; -static int binder_fd; // -1 for no epoll timeout static int awake_poll_interval = -1; diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp index 5039649..78f8403 100644 --- a/healthd/healthd_mode_charger.cpp +++ b/healthd/healthd_mode_charger.cpp @@ -88,7 +88,7 @@ struct frame { int min_capacity; bool level_only; - gr_surface surface; + GRSurface* surface; }; struct animation { @@ -115,7 +115,7 @@ struct charger { struct key_state keys[KEY_MAX + 1]; struct animation *batt_anim; - gr_surface surf_unknown; + GRSurface* surf_unknown; }; static struct frame batt_anim_frames[] = { @@ -273,7 +273,7 @@ static void android_green(void) } /* returns the last y-offset of where the surface ends */ -static int draw_surface_centered(struct charger* /*charger*/, gr_surface surface) +static int draw_surface_centered(struct charger* /*charger*/, GRSurface* surface) { int w; int h; @@ -344,7 +344,6 @@ static void reset_animation(struct animation *anim) static void update_screen_state(struct charger *charger, int64_t now) { struct animation *batt_anim = charger->batt_anim; - int cur_frame; int disp_time; if (!batt_anim->run || now < charger->next_screen_transition) @@ -387,7 +386,6 @@ static void update_screen_state(struct charger *charger, int64_t now) /* animation starting, set up the animation */ if (batt_anim->cur_frame == 0) { - int ret; LOGV("[%" PRId64 "] animation starting\n", now); if (batt_prop && batt_prop->batteryLevel >= 0 && batt_anim->num_frames != 0) { @@ -510,7 +508,6 @@ static void set_next_key_check(struct charger *charger, static void process_key(struct charger *charger, int code, int64_t now) { struct key_state *key = &charger->keys[code]; - int64_t next_key_check; if (code == KEY_POWER) { if (key->down) { @@ -583,7 +580,6 @@ void healthd_mode_charger_heartbeat() { struct charger *charger = &charger_state; int64_t now = curr_time_ms(); - int ret; handle_input_state(charger, now); handle_power_supply_state(charger, now); @@ -618,8 +614,6 @@ int healthd_mode_charger_preparetowait(void) int64_t now = curr_time_ms(); int64_t next_event = INT64_MAX; int64_t timeout; - struct input_event ev; - int ret; LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n", now, charger->next_screen_transition, charger->next_key_check, @@ -687,7 +681,7 @@ void healthd_mode_charger_init(struct healthd_config* config) charger->batt_anim = &battery_animation; - gr_surface* scale_frames; + GRSurface** scale_frames; int scale_count; ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames); if (ret < 0) { diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h index e07d322..290682a 100644 --- a/include/backtrace/Backtrace.h +++ b/include/backtrace/Backtrace.h @@ -39,14 +39,11 @@ struct backtrace_frame_data_t { uintptr_t pc; // The absolute pc. uintptr_t sp; // The top of the stack. size_t stack_size; // The size of the stack, zero indicate an unknown stack size. - const backtrace_map_t* map; // The map associated with the given pc. + backtrace_map_t map; // The map associated with the given pc. std::string func_name; // The function name associated with this pc, NULL if not found. uintptr_t func_offset; // pc relative to the start of the function, only valid if func_name is not NULL. }; -// Forward declarations. -class BacktraceImpl; - #if defined(__APPLE__) struct __darwin_ucontext; typedef __darwin_ucontext ucontext_t; @@ -72,26 +69,32 @@ public: virtual ~Backtrace(); // Get the current stack trace and store in the backtrace_ structure. - virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL); + virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0; // Get the function name and offset into the function given the pc. // If the string is empty, then no valid function name was found. virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset); - // Find the map associated with the given pc. - virtual const backtrace_map_t* FindMap(uintptr_t pc); + // Fill in the map data associated with the given pc. + virtual void FillInMap(uintptr_t pc, backtrace_map_t* map); // Read the data at a specific address. virtual bool ReadWord(uintptr_t ptr, word_t* out_value) = 0; + // Read arbitrary data from a specific address. If a read request would + // span from one map to another, this call only reads up until the end + // of the current map. + // Returns the total number of bytes actually read. + virtual size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) = 0; + // Create a string representing the formatted line of backtrace information // for a single frame. virtual std::string FormatFrameData(size_t frame_num); virtual std::string FormatFrameData(const backtrace_frame_data_t* frame); - pid_t Pid() { return pid_; } - pid_t Tid() { return tid_; } - size_t NumFrames() { return frames_.size(); } + pid_t Pid() const { return pid_; } + pid_t Tid() const { return tid_; } + size_t NumFrames() const { return frames_.size(); } const backtrace_frame_data_t* GetFrame(size_t frame_num) { if (frame_num >= frames_.size()) { @@ -111,7 +114,11 @@ public: BacktraceMap* GetMap() { return map_; } protected: - Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map); + Backtrace(pid_t pid, pid_t tid, BacktraceMap* map); + + // The name returned is not demangled, GetFunctionName() takes care of + // demangling the name. + virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) = 0; virtual bool VerifyReadWordArgs(uintptr_t ptr, word_t* out_value); @@ -124,10 +131,6 @@ protected: bool map_shared_; std::vector<backtrace_frame_data_t> frames_; - - BacktraceImpl* impl_; - - friend class BacktraceImpl; }; #endif // _BACKTRACE_BACKTRACE_H diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h index 4ed23a8..da96307 100644 --- a/include/backtrace/BacktraceMap.h +++ b/include/backtrace/BacktraceMap.h @@ -33,6 +33,8 @@ #include <string> struct backtrace_map_t { + backtrace_map_t(): start(0), end(0), flags(0) {} + uintptr_t start; uintptr_t end; int flags; @@ -48,15 +50,16 @@ public: virtual ~BacktraceMap(); - // Get the map data structure for the given address. - virtual const backtrace_map_t* Find(uintptr_t addr); + // Fill in the map data structure for the given address. + virtual void FillIn(uintptr_t addr, backtrace_map_t* map); // The flags returned are the same flags as used by the mmap call. // The values are PROT_*. int GetFlags(uintptr_t pc) { - const backtrace_map_t* map = Find(pc); - if (map) { - return map->flags; + backtrace_map_t map; + FillIn(pc, &map); + if (IsValid(map)) { + return map.flags; } return PROT_NONE; } @@ -75,6 +78,10 @@ public: virtual bool Build(); + static inline bool IsValid(const backtrace_map_t& map) { + return map.end > 0; + } + protected: BacktraceMap(pid_t pid); diff --git a/include/ctest/ctest.h b/include/ctest/ctest.h deleted file mode 100644 index 1a83b20..0000000 --- a/include/ctest/ctest.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. - */ - -/** - * Very simple unit testing framework. - */ - -#ifndef __CUTILS_TEST_H -#define __CUTILS_TEST_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Adds a test to the test suite. - */ -#define addTest(test) addNamedTest(#test, &test) - -/** - * Asserts that a condition is true. The test fails if it isn't. - */ -#define assertTrue(value, message) assertTrueWithSource(value, __FILE__, __LINE__, message); - -/** - * Asserts that a condition is false. The test fails if the value is true. - */ -#define assertFalse(value, message) assertTrueWithSource(!value, __FILE__, __LINE__, message); - -/** Fails a test with the given message. */ -#define fail(message) assertTrueWithSource(0, __FILE__, __LINE__, message); - -/** - * Asserts that two values are ==. - */ -#define assertSame(a, b) assertTrueWithSource(a == b, __FILE__, __LINE__, "Expected same value."); - -/** - * Asserts that two values are !=. - */ -#define assertNotSame(a, b) assertTrueWithSource(a != b, __FILE__, __LINE__,\ - "Expected different values"); - -/** - * Runs a test suite. - */ -void runTests(void); - -// Do not call these functions directly. Use macros above instead. -void addNamedTest(const char* name, void (*test)(void)); -void assertTrueWithSource(int value, const char* file, int line, char* message); - -#ifdef __cplusplus -} -#endif - -#endif /* __CUTILS_TEST_H */ diff --git a/include/cutils/android_reboot.h b/include/cutils/android_reboot.h index 8c30e8e..85e1b7e 100644 --- a/include/cutils/android_reboot.h +++ b/include/cutils/android_reboot.h @@ -27,7 +27,7 @@ __BEGIN_DECLS /* Properties */ #define ANDROID_RB_PROPERTY "sys.powerctl" -int android_reboot(int cmd, int flags, char *arg); +int android_reboot(int cmd, int flags, const char *arg); __END_DECLS diff --git a/include/cutils/aref.h b/include/cutils/aref.h index 460ac02..3bd36ea 100644 --- a/include/cutils/aref.h +++ b/include/cutils/aref.h @@ -20,11 +20,7 @@ #include <stddef.h> #include <sys/cdefs.h> -#ifdef ANDROID_SMP -#include <cutils/atomic-inline.h> -#else #include <cutils/atomic.h> -#endif __BEGIN_DECLS diff --git a/include/cutils/atomic-arm.h b/include/cutils/atomic-arm.h deleted file mode 100644 index 6b031b6..0000000 --- a/include/cutils/atomic-arm.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 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 ANDROID_CUTILS_ATOMIC_ARM_H -#define ANDROID_CUTILS_ATOMIC_ARM_H - -#include <stdint.h> - -#ifndef ANDROID_ATOMIC_INLINE -#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline)) -#endif - -extern ANDROID_ATOMIC_INLINE void android_compiler_barrier() -{ - __asm__ __volatile__ ("" : : : "memory"); -} - -extern ANDROID_ATOMIC_INLINE void android_memory_barrier() -{ -#if ANDROID_SMP == 0 - android_compiler_barrier(); -#else - __asm__ __volatile__ ("dmb" : : : "memory"); -#endif -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_acquire_load(volatile const int32_t *ptr) -{ - int32_t value = *ptr; - android_memory_barrier(); - return value; -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_release_load(volatile const int32_t *ptr) -{ - android_memory_barrier(); - return *ptr; -} - -extern ANDROID_ATOMIC_INLINE -void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr) -{ - *ptr = value; - android_memory_barrier(); -} - -extern ANDROID_ATOMIC_INLINE -void android_atomic_release_store(int32_t value, volatile int32_t *ptr) -{ - android_memory_barrier(); - *ptr = value; -} - -extern ANDROID_ATOMIC_INLINE -int android_atomic_cas(int32_t old_value, int32_t new_value, - volatile int32_t *ptr) -{ - int32_t prev, status; - do { - __asm__ __volatile__ ("ldrex %0, [%3]\n" - "mov %1, #0\n" - "teq %0, %4\n" -#ifdef __thumb2__ - "it eq\n" -#endif - "strexeq %1, %5, [%3]" - : "=&r" (prev), "=&r" (status), "+m"(*ptr) - : "r" (ptr), "Ir" (old_value), "r" (new_value) - : "cc"); - } while (__builtin_expect(status != 0, 0)); - return prev != old_value; -} - -extern ANDROID_ATOMIC_INLINE -int android_atomic_acquire_cas(int32_t old_value, int32_t new_value, - volatile int32_t *ptr) -{ - int status = android_atomic_cas(old_value, new_value, ptr); - android_memory_barrier(); - return status; -} - -extern ANDROID_ATOMIC_INLINE -int android_atomic_release_cas(int32_t old_value, int32_t new_value, - volatile int32_t *ptr) -{ - android_memory_barrier(); - return android_atomic_cas(old_value, new_value, ptr); -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr) -{ - int32_t prev, tmp, status; - android_memory_barrier(); - do { - __asm__ __volatile__ ("ldrex %0, [%4]\n" - "add %1, %0, %5\n" - "strex %2, %1, [%4]" - : "=&r" (prev), "=&r" (tmp), - "=&r" (status), "+m" (*ptr) - : "r" (ptr), "Ir" (increment) - : "cc"); - } while (__builtin_expect(status != 0, 0)); - return prev; -} - -extern ANDROID_ATOMIC_INLINE int32_t android_atomic_inc(volatile int32_t *addr) -{ - return android_atomic_add(1, addr); -} - -extern ANDROID_ATOMIC_INLINE int32_t android_atomic_dec(volatile int32_t *addr) -{ - return android_atomic_add(-1, addr); -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_and(int32_t value, volatile int32_t *ptr) -{ - int32_t prev, tmp, status; - android_memory_barrier(); - do { - __asm__ __volatile__ ("ldrex %0, [%4]\n" - "and %1, %0, %5\n" - "strex %2, %1, [%4]" - : "=&r" (prev), "=&r" (tmp), - "=&r" (status), "+m" (*ptr) - : "r" (ptr), "Ir" (value) - : "cc"); - } while (__builtin_expect(status != 0, 0)); - return prev; -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_or(int32_t value, volatile int32_t *ptr) -{ - int32_t prev, tmp, status; - android_memory_barrier(); - do { - __asm__ __volatile__ ("ldrex %0, [%4]\n" - "orr %1, %0, %5\n" - "strex %2, %1, [%4]" - : "=&r" (prev), "=&r" (tmp), - "=&r" (status), "+m" (*ptr) - : "r" (ptr), "Ir" (value) - : "cc"); - } while (__builtin_expect(status != 0, 0)); - return prev; -} - -#endif /* ANDROID_CUTILS_ATOMIC_ARM_H */ diff --git a/include/cutils/atomic-arm64.h b/include/cutils/atomic-arm64.h deleted file mode 100644 index 7ae47d7..0000000 --- a/include/cutils/atomic-arm64.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#ifndef ANDROID_CUTILS_ATOMIC_AARCH64_H -#define ANDROID_CUTILS_ATOMIC_AARCH64_H - -#include <stdint.h> - -#ifndef ANDROID_ATOMIC_INLINE -#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline)) -#endif - -/* - TODOAArch64: Revisit the below functions and check for potential - optimizations using assembly code or otherwise. -*/ - -extern ANDROID_ATOMIC_INLINE -void android_compiler_barrier(void) -{ - __asm__ __volatile__ ("" : : : "memory"); -} - -extern ANDROID_ATOMIC_INLINE -void android_memory_barrier(void) -{ - __asm__ __volatile__ ("dmb ish" : : : "memory"); -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_acquire_load(volatile const int32_t *ptr) -{ - int32_t value = *ptr; - android_memory_barrier(); - return value; -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_release_load(volatile const int32_t *ptr) -{ - android_memory_barrier(); - return *ptr; -} - -extern ANDROID_ATOMIC_INLINE -void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr) -{ - *ptr = value; - android_memory_barrier(); -} - -extern ANDROID_ATOMIC_INLINE -void android_atomic_release_store(int32_t value, volatile int32_t *ptr) -{ - android_memory_barrier(); - *ptr = value; -} - -extern ANDROID_ATOMIC_INLINE -int android_atomic_cas(int32_t old_value, int32_t new_value, - volatile int32_t *ptr) -{ - return __sync_val_compare_and_swap(ptr, old_value, new_value) != old_value; -} - -extern ANDROID_ATOMIC_INLINE -int android_atomic_acquire_cas(int32_t old_value, int32_t new_value, - volatile int32_t *ptr) -{ - int status = android_atomic_cas(old_value, new_value, ptr); - android_memory_barrier(); - return status; -} - -extern ANDROID_ATOMIC_INLINE -int android_atomic_release_cas(int32_t old_value, int32_t new_value, - volatile int32_t *ptr) -{ - android_memory_barrier(); - return android_atomic_cas(old_value, new_value, ptr); -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr) -{ - int32_t prev, status; - android_memory_barrier(); - do { - prev = *ptr; - status = android_atomic_cas(prev, prev + increment, ptr); - } while (__builtin_expect(status != 0, 0)); - return prev; -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_inc(volatile int32_t *addr) -{ - return android_atomic_add(1, addr); -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_dec(volatile int32_t *addr) -{ - return android_atomic_add(-1, addr); -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_and(int32_t value, volatile int32_t *ptr) -{ - int32_t prev, status; - android_memory_barrier(); - do { - prev = *ptr; - status = android_atomic_cas(prev, prev & value, ptr); - } while (__builtin_expect(status != 0, 0)); - return prev; -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_or(int32_t value, volatile int32_t *ptr) -{ - int32_t prev, status; - android_memory_barrier(); - do { - prev = *ptr; - status = android_atomic_cas(prev, prev | value, ptr); - } while (__builtin_expect(status != 0, 0)); - return prev; -} - -#endif /* ANDROID_CUTILS_ATOMIC_AARCH64_H */ diff --git a/include/cutils/atomic-inline.h b/include/cutils/atomic-inline.h deleted file mode 100644 index a31e913..0000000 --- a/include/cutils/atomic-inline.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 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 ANDROID_CUTILS_ATOMIC_INLINE_H -#define ANDROID_CUTILS_ATOMIC_INLINE_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Inline declarations and macros for some special-purpose atomic - * operations. These are intended for rare circumstances where a - * memory barrier needs to be issued inline rather than as a function - * call. - * - * Most code should not use these. - * - * Anything that does include this file must set ANDROID_SMP to either - * 0 or 1, indicating compilation for UP or SMP, respectively. - * - * Macros defined in this header: - * - * void ANDROID_MEMBAR_FULL(void) - * Full memory barrier. Provides a compiler reordering barrier, and - * on SMP systems emits an appropriate instruction. - */ - -#if !defined(ANDROID_SMP) -# error "Must define ANDROID_SMP before including atomic-inline.h" -#endif - -#if defined(__aarch64__) -#include <cutils/atomic-arm64.h> -#elif defined(__arm__) -#include <cutils/atomic-arm.h> -#elif defined(__i386__) -#include <cutils/atomic-x86.h> -#elif defined(__x86_64__) -#include <cutils/atomic-x86_64.h> -#elif defined(__mips64) -#include <cutils/atomic-mips64.h> -#elif defined(__mips__) -#include <cutils/atomic-mips.h> -#else -#error atomic operations are unsupported -#endif - -#if ANDROID_SMP == 0 -#define ANDROID_MEMBAR_FULL android_compiler_barrier -#else -#define ANDROID_MEMBAR_FULL android_memory_barrier -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* ANDROID_CUTILS_ATOMIC_INLINE_H */ diff --git a/include/cutils/atomic-mips.h b/include/cutils/atomic-mips.h deleted file mode 100644 index 5d4f097..0000000 --- a/include/cutils/atomic-mips.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 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 ANDROID_CUTILS_ATOMIC_MIPS_H -#define ANDROID_CUTILS_ATOMIC_MIPS_H - -#include <stdint.h> - -#ifndef ANDROID_ATOMIC_INLINE -#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline)) -#endif - -extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void) -{ - __asm__ __volatile__ ("" : : : "memory"); -} - -#if ANDROID_SMP == 0 -extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void) -{ - android_compiler_barrier(); -} -#else -extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void) -{ - __asm__ __volatile__ ("sync" : : : "memory"); -} -#endif - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_acquire_load(volatile const int32_t *ptr) -{ - int32_t value = *ptr; - android_memory_barrier(); - return value; -} - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_release_load(volatile const int32_t *ptr) -{ - android_memory_barrier(); - return *ptr; -} - -extern ANDROID_ATOMIC_INLINE void -android_atomic_acquire_store(int32_t value, volatile int32_t *ptr) -{ - *ptr = value; - android_memory_barrier(); -} - -extern ANDROID_ATOMIC_INLINE void -android_atomic_release_store(int32_t value, volatile int32_t *ptr) -{ - android_memory_barrier(); - *ptr = value; -} - -extern ANDROID_ATOMIC_INLINE int -android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr) -{ - int32_t prev, status; - do { - __asm__ __volatile__ ( - " ll %[prev], (%[ptr])\n" - " li %[status], 1\n" - " bne %[prev], %[old], 9f\n" - " move %[status], %[new_value]\n" - " sc %[status], (%[ptr])\n" - "9:\n" - : [prev] "=&r" (prev), [status] "=&r" (status) - : [ptr] "r" (ptr), [old] "r" (old_value), [new_value] "r" (new_value) - ); - } while (__builtin_expect(status == 0, 0)); - return prev != old_value; -} - -extern ANDROID_ATOMIC_INLINE int -android_atomic_acquire_cas(int32_t old_value, - int32_t new_value, - volatile int32_t *ptr) -{ - int status = android_atomic_cas(old_value, new_value, ptr); - android_memory_barrier(); - return status; -} - -extern ANDROID_ATOMIC_INLINE int -android_atomic_release_cas(int32_t old_value, - int32_t new_value, - volatile int32_t *ptr) -{ - android_memory_barrier(); - return android_atomic_cas(old_value, new_value, ptr); -} - - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_add(int32_t increment, volatile int32_t *ptr) -{ - int32_t prev, status; - android_memory_barrier(); - do { - __asm__ __volatile__ ( - " ll %[prev], (%[ptr])\n" - " addu %[status], %[prev], %[inc]\n" - " sc %[status], (%[ptr])\n" - : [status] "=&r" (status), [prev] "=&r" (prev) - : [ptr] "r" (ptr), [inc] "Ir" (increment) - ); - } while (__builtin_expect(status == 0, 0)); - return prev; -} - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_inc(volatile int32_t *addr) -{ - return android_atomic_add(1, addr); -} - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_dec(volatile int32_t *addr) -{ - return android_atomic_add(-1, addr); -} - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_and(int32_t value, volatile int32_t *ptr) -{ - int32_t prev, status; - android_memory_barrier(); - do { - __asm__ __volatile__ ( - " ll %[prev], (%[ptr])\n" - " and %[status], %[prev], %[value]\n" - " sc %[status], (%[ptr])\n" - : [prev] "=&r" (prev), [status] "=&r" (status) - : [ptr] "r" (ptr), [value] "Ir" (value) - ); - } while (__builtin_expect(status == 0, 0)); - return prev; -} - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_or(int32_t value, volatile int32_t *ptr) -{ - int32_t prev, status; - android_memory_barrier(); - do { - __asm__ __volatile__ ( - " ll %[prev], (%[ptr])\n" - " or %[status], %[prev], %[value]\n" - " sc %[status], (%[ptr])\n" - : [prev] "=&r" (prev), [status] "=&r" (status) - : [ptr] "r" (ptr), [value] "Ir" (value) - ); - } while (__builtin_expect(status == 0, 0)); - return prev; -} - -#endif /* ANDROID_CUTILS_ATOMIC_MIPS_H */ diff --git a/include/cutils/atomic-mips64.h b/include/cutils/atomic-mips64.h deleted file mode 100644 index 9d8f65e..0000000 --- a/include/cutils/atomic-mips64.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 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 ANDROID_CUTILS_ATOMIC_MIPS64_H -#define ANDROID_CUTILS_ATOMIC_MIPS64_H - -#include <stdint.h> - -#ifndef ANDROID_ATOMIC_INLINE -#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline)) -#endif - -extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void) -{ - __asm__ __volatile__ ("" : : : "memory"); -} - -extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void) -{ - __asm__ __volatile__ ("sync" : : : "memory"); -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_acquire_load(volatile const int32_t *ptr) -{ - int32_t value = *ptr; - android_memory_barrier(); - return value; -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_release_load(volatile const int32_t *ptr) -{ - android_memory_barrier(); - return *ptr; -} - -extern ANDROID_ATOMIC_INLINE -void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr) -{ - *ptr = value; - android_memory_barrier(); -} - -extern ANDROID_ATOMIC_INLINE -void android_atomic_release_store(int32_t value, volatile int32_t *ptr) -{ - android_memory_barrier(); - *ptr = value; -} - -extern ANDROID_ATOMIC_INLINE -int android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr) -{ - int32_t prev, status; - do { - __asm__ __volatile__ ( - " ll %[prev], (%[ptr])\n" - " li %[status], 1\n" - " bne %[prev], %[old], 9f\n" - " move %[status], %[new_value]\n" - " sc %[status], (%[ptr])\n" - "9:\n" - : [prev] "=&r" (prev), [status] "=&r" (status) - : [ptr] "r" (ptr), [old] "r" (old_value), [new_value] "r" (new_value) - ); - } while (__builtin_expect(status == 0, 0)); - return prev != old_value; -} - -extern ANDROID_ATOMIC_INLINE -int android_atomic_acquire_cas(int32_t old_value, - int32_t new_value, - volatile int32_t *ptr) -{ - int status = android_atomic_cas(old_value, new_value, ptr); - android_memory_barrier(); - return status; -} - -extern ANDROID_ATOMIC_INLINE -int android_atomic_release_cas(int32_t old_value, - int32_t new_value, - volatile int32_t *ptr) -{ - android_memory_barrier(); - return android_atomic_cas(old_value, new_value, ptr); -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr) -{ - int32_t prev, status; - android_memory_barrier(); - do { - __asm__ __volatile__ ( - " ll %[prev], (%[ptr])\n" - " addu %[status], %[prev], %[inc]\n" - " sc %[status], (%[ptr])\n" - : [status] "=&r" (status), [prev] "=&r" (prev) - : [ptr] "r" (ptr), [inc] "Ir" (increment) - ); - } while (__builtin_expect(status == 0, 0)); - return prev; -} - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_inc(volatile int32_t *addr) -{ - return android_atomic_add(1, addr); -} - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_dec(volatile int32_t *addr) -{ - return android_atomic_add(-1, addr); -} - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_and(int32_t value, volatile int32_t *ptr) -{ - int32_t prev, status; - android_memory_barrier(); - do { - __asm__ __volatile__ ( - " ll %[prev], (%[ptr])\n" - " and %[status], %[prev], %[value]\n" - " sc %[status], (%[ptr])\n" - : [prev] "=&r" (prev), [status] "=&r" (status) - : [ptr] "r" (ptr), [value] "Ir" (value) - ); - } while (__builtin_expect(status == 0, 0)); - return prev; -} - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_or(int32_t value, volatile int32_t *ptr) -{ - int32_t prev, status; - android_memory_barrier(); - do { - __asm__ __volatile__ ( - " ll %[prev], (%[ptr])\n" - " or %[status], %[prev], %[value]\n" - " sc %[status], (%[ptr])\n" - : [prev] "=&r" (prev), [status] "=&r" (status) - : [ptr] "r" (ptr), [value] "Ir" (value) - ); - } while (__builtin_expect(status == 0, 0)); - return prev; -} - -#endif /* ANDROID_CUTILS_ATOMIC_MIPS_H */ diff --git a/include/cutils/atomic-x86.h b/include/cutils/atomic-x86.h deleted file mode 100644 index 06bf1a3..0000000 --- a/include/cutils/atomic-x86.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 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 ANDROID_CUTILS_ATOMIC_X86_H -#define ANDROID_CUTILS_ATOMIC_X86_H - -#include <stdint.h> - -#ifndef ANDROID_ATOMIC_INLINE -#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline)) -#endif - -extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void) -{ - __asm__ __volatile__ ("" : : : "memory"); -} - -#if ANDROID_SMP == 0 -extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void) -{ - android_compiler_barrier(); -} -#else -extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void) -{ - __asm__ __volatile__ ("mfence" : : : "memory"); -} -#endif - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_acquire_load(volatile const int32_t *ptr) -{ - int32_t value = *ptr; - android_compiler_barrier(); - return value; -} - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_release_load(volatile const int32_t *ptr) -{ - android_memory_barrier(); - return *ptr; -} - -extern ANDROID_ATOMIC_INLINE void -android_atomic_acquire_store(int32_t value, volatile int32_t *ptr) -{ - *ptr = value; - android_memory_barrier(); -} - -extern ANDROID_ATOMIC_INLINE void -android_atomic_release_store(int32_t value, volatile int32_t *ptr) -{ - android_compiler_barrier(); - *ptr = value; -} - -extern ANDROID_ATOMIC_INLINE int -android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr) -{ - int32_t prev; - __asm__ __volatile__ ("lock; cmpxchgl %1, %2" - : "=a" (prev) - : "q" (new_value), "m" (*ptr), "0" (old_value) - : "memory"); - return prev != old_value; -} - -extern ANDROID_ATOMIC_INLINE int -android_atomic_acquire_cas(int32_t old_value, - int32_t new_value, - volatile int32_t *ptr) -{ - /* Loads are not reordered with other loads. */ - return android_atomic_cas(old_value, new_value, ptr); -} - -extern ANDROID_ATOMIC_INLINE int -android_atomic_release_cas(int32_t old_value, - int32_t new_value, - volatile int32_t *ptr) -{ - /* Stores are not reordered with other stores. */ - return android_atomic_cas(old_value, new_value, ptr); -} - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_add(int32_t increment, volatile int32_t *ptr) -{ - __asm__ __volatile__ ("lock; xaddl %0, %1" - : "+r" (increment), "+m" (*ptr) - : : "memory"); - /* increment now holds the old value of *ptr */ - return increment; -} - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_inc(volatile int32_t *addr) -{ - return android_atomic_add(1, addr); -} - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_dec(volatile int32_t *addr) -{ - return android_atomic_add(-1, addr); -} - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_and(int32_t value, volatile int32_t *ptr) -{ - int32_t prev, status; - do { - prev = *ptr; - status = android_atomic_cas(prev, prev & value, ptr); - } while (__builtin_expect(status != 0, 0)); - return prev; -} - -extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_or(int32_t value, volatile int32_t *ptr) -{ - int32_t prev, status; - do { - prev = *ptr; - status = android_atomic_cas(prev, prev | value, ptr); - } while (__builtin_expect(status != 0, 0)); - return prev; -} - -#endif /* ANDROID_CUTILS_ATOMIC_X86_H */ diff --git a/include/cutils/atomic-x86_64.h b/include/cutils/atomic-x86_64.h deleted file mode 100644 index 99cb070..0000000 --- a/include/cutils/atomic-x86_64.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#ifndef ANDROID_CUTILS_ATOMIC_X86_64_H -#define ANDROID_CUTILS_ATOMIC_X86_64_H - -#include <stdint.h> - -#ifndef ANDROID_ATOMIC_INLINE -#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline)) -#endif - -extern ANDROID_ATOMIC_INLINE -void android_compiler_barrier(void) -{ - __asm__ __volatile__ ("" : : : "memory"); -} - -extern ANDROID_ATOMIC_INLINE -void android_memory_barrier(void) -{ - __asm__ __volatile__ ("mfence" : : : "memory"); -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_acquire_load(volatile const int32_t *ptr) -{ - int32_t value = *ptr; - android_compiler_barrier(); - return value; -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_release_load(volatile const int32_t *ptr) -{ - android_memory_barrier(); - return *ptr; -} - -extern ANDROID_ATOMIC_INLINE -void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr) -{ - *ptr = value; - android_memory_barrier(); -} - -extern ANDROID_ATOMIC_INLINE -void android_atomic_release_store(int32_t value, volatile int32_t *ptr) -{ - android_compiler_barrier(); - *ptr = value; -} - -extern ANDROID_ATOMIC_INLINE -int android_atomic_cas(int32_t old_value, int32_t new_value, - volatile int32_t *ptr) -{ - int32_t prev; - __asm__ __volatile__ ("lock; cmpxchgl %1, %2" - : "=a" (prev) - : "q" (new_value), "m" (*ptr), "0" (old_value) - : "memory"); - return prev != old_value; -} - -extern ANDROID_ATOMIC_INLINE -int android_atomic_acquire_cas(int32_t old_value, int32_t new_value, - volatile int32_t *ptr) -{ - /* Loads are not reordered with other loads. */ - return android_atomic_cas(old_value, new_value, ptr); -} - -extern ANDROID_ATOMIC_INLINE -int android_atomic_release_cas(int32_t old_value, int32_t new_value, - volatile int32_t *ptr) -{ - /* Stores are not reordered with other stores. */ - return android_atomic_cas(old_value, new_value, ptr); -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr) -{ - __asm__ __volatile__ ("lock; xaddl %0, %1" - : "+r" (increment), "+m" (*ptr) - : : "memory"); - /* increment now holds the old value of *ptr */ - return increment; -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_inc(volatile int32_t *addr) -{ - return android_atomic_add(1, addr); -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_dec(volatile int32_t *addr) -{ - return android_atomic_add(-1, addr); -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_and(int32_t value, volatile int32_t *ptr) -{ - int32_t prev, status; - do { - prev = *ptr; - status = android_atomic_cas(prev, prev & value, ptr); - } while (__builtin_expect(status != 0, 0)); - return prev; -} - -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_or(int32_t value, volatile int32_t *ptr) -{ - int32_t prev, status; - do { - prev = *ptr; - status = android_atomic_cas(prev, prev | value, ptr); - } while (__builtin_expect(status != 0, 0)); - return prev; -} - -#endif /* ANDROID_CUTILS_ATOMIC_X86_64_H */ diff --git a/include/cutils/atomic.h b/include/cutils/atomic.h index 79409a7..ded972a 100644 --- a/include/cutils/atomic.h +++ b/include/cutils/atomic.h @@ -19,9 +19,10 @@ #include <stdint.h> #include <sys/types.h> +#include <stdatomic.h> -#ifdef __cplusplus -extern "C" { +#ifndef ANDROID_ATOMIC_INLINE +#define ANDROID_ATOMIC_INLINE static inline #endif /* @@ -77,11 +78,41 @@ extern "C" { * These have the same characteristics (e.g. what happens on overflow) * as the equivalent non-atomic C operations. */ -int32_t android_atomic_inc(volatile int32_t* addr); -int32_t android_atomic_dec(volatile int32_t* addr); -int32_t android_atomic_add(int32_t value, volatile int32_t* addr); -int32_t android_atomic_and(int32_t value, volatile int32_t* addr); -int32_t android_atomic_or(int32_t value, volatile int32_t* addr); +ANDROID_ATOMIC_INLINE +int32_t android_atomic_inc(volatile int32_t* addr) +{ + volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr; + /* Int32_t, if it exists, is the same as int_least32_t. */ + return atomic_fetch_add_explicit(a, 1, memory_order_release); +} + +ANDROID_ATOMIC_INLINE +int32_t android_atomic_dec(volatile int32_t* addr) +{ + volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr; + return atomic_fetch_sub_explicit(a, 1, memory_order_release); +} + +ANDROID_ATOMIC_INLINE +int32_t android_atomic_add(int32_t value, volatile int32_t* addr) +{ + volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr; + return atomic_fetch_add_explicit(a, value, memory_order_release); +} + +ANDROID_ATOMIC_INLINE +int32_t android_atomic_and(int32_t value, volatile int32_t* addr) +{ + volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr; + return atomic_fetch_and_explicit(a, value, memory_order_release); +} + +ANDROID_ATOMIC_INLINE +int32_t android_atomic_or(int32_t value, volatile int32_t* addr) +{ + volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr; + return atomic_fetch_or_explicit(a, value, memory_order_release); +} /* * Perform an atomic load with "acquire" or "release" ordering. @@ -96,29 +127,53 @@ int32_t android_atomic_or(int32_t value, volatile int32_t* addr); * this comment, you are in the vast majority, and should not be * using release loads or replacing them with anything other than * locks or default sequentially consistent atomics. - * - * This is only necessary if you need the memory barrier. A 32-bit read - * from a 32-bit aligned address is atomic on all supported platforms. */ -int32_t android_atomic_acquire_load(volatile const int32_t* addr); -int32_t android_atomic_release_load(volatile const int32_t* addr); +ANDROID_ATOMIC_INLINE +int32_t android_atomic_acquire_load(volatile const int32_t* addr) +{ + volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr; + return atomic_load_explicit(a, memory_order_acquire); +} + +ANDROID_ATOMIC_INLINE +int32_t android_atomic_release_load(volatile const int32_t* addr) +{ + volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr; + atomic_thread_fence(memory_order_seq_cst); + /* Any reasonable clients of this interface would probably prefer */ + /* something weaker. But some remaining clients seem to be */ + /* abusing this API in strange ways, e.g. by using it as a fence. */ + /* Thus we are conservative until we can get rid of remaining */ + /* clients (and this function). */ + return atomic_load_explicit(a, memory_order_relaxed); +} /* * Perform an atomic store with "acquire" or "release" ordering. * - * Note that the notion of a "acquire" ordering for a store does not + * Note that the notion of an "acquire" ordering for a store does not * really fit into the C11 or C++11 memory model. The extra ordering * is normally observable only by code using memory_order_relaxed * atomics, or data races. In the rare cases in which such ordering * is called for, use memory_order_relaxed atomics and a trailing * atomic_thread_fence (typically with memory_order_release, * not memory_order_acquire!) instead. - * - * This is only necessary if you need the memory barrier. A 32-bit write - * to a 32-bit aligned address is atomic on all supported platforms. */ -void android_atomic_acquire_store(int32_t value, volatile int32_t* addr); -void android_atomic_release_store(int32_t value, volatile int32_t* addr); +ANDROID_ATOMIC_INLINE +void android_atomic_acquire_store(int32_t value, volatile int32_t* addr) +{ + volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr; + atomic_store_explicit(a, value, memory_order_relaxed); + atomic_thread_fence(memory_order_seq_cst); + /* Again overly conservative to accomodate weird clients. */ +} + +ANDROID_ATOMIC_INLINE +void android_atomic_release_store(int32_t value, volatile int32_t* addr) +{ + volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr; + atomic_store_explicit(a, value, memory_order_release); +} /* * Compare-and-set operation with "acquire" or "release" ordering. @@ -132,10 +187,44 @@ void android_atomic_release_store(int32_t value, volatile int32_t* addr); * Implementations that use the release CAS in a loop may be less efficient * than possible, because we re-issue the memory barrier on each iteration. */ +ANDROID_ATOMIC_INLINE int android_atomic_acquire_cas(int32_t oldvalue, int32_t newvalue, - volatile int32_t* addr); + volatile int32_t* addr) +{ + volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr; + return (int)(!atomic_compare_exchange_strong_explicit( + a, &oldvalue, newvalue, + memory_order_acquire, + memory_order_acquire)); +} + +ANDROID_ATOMIC_INLINE int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue, - volatile int32_t* addr); + volatile int32_t* addr) +{ + volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr; + return (int)(!atomic_compare_exchange_strong_explicit( + a, &oldvalue, newvalue, + memory_order_release, + memory_order_relaxed)); +} + +/* + * Fence primitives. + */ +ANDROID_ATOMIC_INLINE +void android_compiler_barrier(void) +{ + __asm__ __volatile__ ("" : : : "memory"); + /* Could probably also be: */ + /* atomic_signal_fence(memory_order_seq_cst); */ +} + +ANDROID_ATOMIC_INLINE +void android_memory_barrier(void) +{ + atomic_thread_fence(memory_order_seq_cst); +} /* * Aliases for code using an older version of this header. These are now @@ -145,8 +234,4 @@ int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue, #define android_atomic_write android_atomic_release_store #define android_atomic_cmpxchg android_atomic_release_cas -#ifdef __cplusplus -} // extern "C" -#endif - #endif // ANDROID_CUTILS_ATOMIC_H diff --git a/include/cutils/cpu_info.h b/include/cutils/cpu_info.h deleted file mode 100644 index 78c1884..0000000 --- a/include/cutils/cpu_info.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - */ - -#ifndef __CUTILS_CPU_INFO_H -#define __CUTILS_CPU_INFO_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* returns a string contiaining an ASCII representation of the CPU serial number, -** or NULL if cpu info not available. -** The string is a static variable, so don't call free() on it. -*/ -extern const char* get_cpu_serial_number(void); - -#ifdef __cplusplus -} -#endif - -#endif /* __CUTILS_CPU_INFO_H */ diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h index bae687d..285e1af 100644 --- a/include/cutils/debugger.h +++ b/include/cutils/debugger.h @@ -17,20 +17,14 @@ #ifndef __CUTILS_DEBUGGER_H #define __CUTILS_DEBUGGER_H +#include <sys/cdefs.h> #include <sys/types.h> -#ifdef __cplusplus -extern "C" { -#endif +__BEGIN_DECLS -#define DEBUGGER32_SOCKET_NAME "android:debuggerd" -#define DEBUGGER64_SOCKET_NAME "android:debuggerd64" - -#if defined(__LP64__) -#define DEBUGGER_SOCKET_NAME DEBUGGER64_SOCKET_NAME -#else -#define DEBUGGER_SOCKET_NAME DEBUGGER32_SOCKET_NAME -#endif +#define DEBUGGER_SOCKET_NAME "android:debuggerd" +#define DEBUGGER32_SOCKET_NAME "android:debuggerd32" +#define DEBUGGER64_SOCKET_NAME DEBUGGER_SOCKET_NAME typedef enum { // dump a crash @@ -41,23 +35,17 @@ typedef enum { DEBUGGER_ACTION_DUMP_BACKTRACE, } debugger_action_t; -typedef struct { - debugger_action_t action; +// Make sure that all values have a fixed size so that this structure +// is the same for 32 bit and 64 bit processes. +// NOTE: Any changes to this structure must also be reflected in +// bionic/linker/debugger.cpp. +typedef struct __attribute__((packed)) { + int32_t action; pid_t tid; - uintptr_t abort_msg_address; + uint64_t abort_msg_address; int32_t original_si_code; } debugger_msg_t; -#if defined(__LP64__) -// For a 64 bit process to contact the 32 bit debuggerd. -typedef struct { - debugger_action_t action; - pid_t tid; - uint32_t abort_msg_address; - int32_t original_si_code; -} debugger32_msg_t; -#endif - /* Dumps a process backtrace, registers, and stack to a tombstone file (requires root). * Stores the tombstone path in the provided buffer. * Returns 0 on success, -1 on error. @@ -84,8 +72,6 @@ int dump_backtrace_to_file(pid_t tid, int fd); */ int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs); -#ifdef __cplusplus -} -#endif +__END_DECLS #endif /* __CUTILS_DEBUGGER_H */ diff --git a/include/cutils/klog.h b/include/cutils/klog.h index d5ae6d7..295d62b 100644 --- a/include/cutils/klog.h +++ b/include/cutils/klog.h @@ -18,6 +18,7 @@ #define _CUTILS_KLOG_H_ #include <sys/cdefs.h> +#include <sys/uio.h> #include <stdarg.h> __BEGIN_DECLS @@ -26,9 +27,10 @@ void klog_init(void); int klog_get_level(void); void klog_set_level(int level); /* TODO: void klog_close(void); - and make klog_fd users thread safe. */ + void klog_write(int level, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); -void klog_vwrite(int level, const char *fmt, va_list ap); +void klog_writev(int level, const struct iovec* iov, int iov_count); __END_DECLS diff --git a/include/cutils/memory.h b/include/cutils/memory.h index e725cdd..4d26882 100644 --- a/include/cutils/memory.h +++ b/include/cutils/memory.h @@ -30,7 +30,7 @@ void android_memset16(uint16_t* dst, uint16_t value, size_t size); /* size is given in bytes and must be multiple of 4 */ void android_memset32(uint32_t* dst, uint32_t value, size_t size); -#if !HAVE_STRLCPY +#if defined(__GLIBC__) || defined(_WIN32) /* Declaration of strlcpy() for platforms that don't already have it. */ size_t strlcpy(char *dst, const char *src, size_t size); #endif diff --git a/include/cutils/open_memstream.h b/include/cutils/open_memstream.h index b7998be..c1a81eb 100644 --- a/include/cutils/open_memstream.h +++ b/include/cutils/open_memstream.h @@ -19,7 +19,7 @@ #include <stdio.h> -#ifndef HAVE_OPEN_MEMSTREAM +#if defined(__APPLE__) #ifdef __cplusplus extern "C" { @@ -31,6 +31,6 @@ FILE* open_memstream(char** bufp, size_t* sizep); } #endif -#endif /*!HAVE_OPEN_MEMSTREAM*/ +#endif /* __APPLE__ */ #endif /*__CUTILS_OPEN_MEMSTREAM_H__*/ diff --git a/include/cutils/partition_utils.h b/include/cutils/partition_utils.h index 597df92..72ca80d 100644 --- a/include/cutils/partition_utils.h +++ b/include/cutils/partition_utils.h @@ -20,7 +20,6 @@ __BEGIN_DECLS int partition_wiped(char *source); -void erase_footer(const char *dev_path, long long size); __END_DECLS diff --git a/include/cutils/properties.h b/include/cutils/properties.h index 798db8b..24aa224 100644 --- a/include/cutils/properties.h +++ b/include/cutils/properties.h @@ -126,22 +126,6 @@ int property_get(const char *key, char *value, const char *default_value) { #endif -#ifdef HAVE_SYSTEM_PROPERTY_SERVER -/* - * We have an external property server instead of built-in libc support. - * Used by the simulator. - */ -#define SYSTEM_PROPERTY_PIPE_NAME "/tmp/android-sysprop" - -enum { - kSystemPropertyUnknown = 0, - kSystemPropertyGet, - kSystemPropertySet, - kSystemPropertyList -}; -#endif /*HAVE_SYSTEM_PROPERTY_SERVER*/ - - #ifdef __cplusplus } #endif diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h index daf43ec..f8076ca 100644 --- a/include/cutils/sockets.h +++ b/include/cutils/sockets.h @@ -18,6 +18,7 @@ #define __CUTILS_SOCKETS_H #include <errno.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> @@ -25,7 +26,7 @@ #ifdef HAVE_WINSOCK #include <winsock2.h> typedef int socklen_t; -#elif HAVE_SYS_SOCKET_H +#else #include <sys/socket.h> #endif @@ -46,30 +47,19 @@ extern "C" { */ static inline int android_get_control_socket(const char *name) { - char key[64] = ANDROID_SOCKET_ENV_PREFIX; - const char *val; - int fd; + char key[64]; + snprintf(key, sizeof(key), ANDROID_SOCKET_ENV_PREFIX "%s", name); - /* build our environment variable, counting cycles like a wolf ... */ -#if HAVE_STRLCPY - strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, - name, - sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); -#else /* for the host, which may lack the almightly strncpy ... */ - strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, - name, - sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); - key[sizeof(key)-1] = '\0'; -#endif - - val = getenv(key); - if (!val) + const char* val = getenv(key); + if (!val) { return -1; + } errno = 0; - fd = strtol(val, NULL, 10); - if (errno) + int fd = strtol(val, NULL, 10); + if (errno) { return -1; + } return fd; } diff --git a/include/cutils/str_parms.h b/include/cutils/str_parms.h index 66f3637..aa1435a 100644 --- a/include/cutils/str_parms.h +++ b/include/cutils/str_parms.h @@ -18,6 +18,9 @@ #define __CUTILS_STR_PARMS_H #include <stdint.h> +#include <sys/cdefs.h> + +__BEGIN_DECLS struct str_parms; @@ -52,4 +55,6 @@ char *str_parms_to_str(struct str_parms *str_parms); /* debug */ void str_parms_dump(struct str_parms *str_parms); +__END_DECLS + #endif /* __CUTILS_STR_PARMS_H */ diff --git a/include/cutils/threads.h b/include/cutils/threads.h index acf8f48..3133cdb 100644 --- a/include/cutils/threads.h +++ b/include/cutils/threads.h @@ -29,20 +29,22 @@ extern "C" { /***********************************************************************/ /***********************************************************************/ -#ifdef HAVE_PTHREADS +#if !defined(_WIN32) #include <pthread.h> +#include <sys/types.h> typedef struct { pthread_mutex_t lock; int has_tls; pthread_key_t tls; - } thread_store_t; +extern pid_t gettid(); + #define THREAD_STORE_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0 } -#elif defined HAVE_WIN32_THREADS +#else // !defined(_WIN32) #include <windows.h> @@ -51,20 +53,17 @@ typedef struct { int has_tls; DWORD tls; CRITICAL_SECTION lock; - } thread_store_t; #define THREAD_STORE_INITIALIZER { 0, 0, 0, {0, 0, 0, 0, 0, 0} } -#else -# error "no thread_store_t implementation for your platform !!" -#endif +#endif // !defined(_WIN32) typedef void (*thread_store_destruct_t)(void* value); extern void* thread_store_get(thread_store_t* store); -extern void thread_store_set(thread_store_t* store, +extern void thread_store_set(thread_store_t* store, void* value, thread_store_destruct_t destroy); @@ -76,7 +75,7 @@ extern void thread_store_set(thread_store_t* store, /***********************************************************************/ /***********************************************************************/ -#ifdef HAVE_PTHREADS +#if !defined(_WIN32) typedef pthread_mutex_t mutex_t; @@ -98,10 +97,10 @@ static __inline__ void mutex_destroy(mutex_t* lock) { pthread_mutex_destroy(lock); } -#endif -#ifdef HAVE_WIN32_THREADS -typedef struct { +#else // !defined(_WIN32) + +typedef struct { int init; CRITICAL_SECTION lock[1]; } mutex_t; @@ -134,10 +133,10 @@ static __inline__ void mutex_destroy(mutex_t* lock) { if (lock->init) { lock->init = 0; - DeleteCriticalSection(lock->lock); + DeleteCriticalSection(lock->lock); } } -#endif +#endif // !defined(_WIN32) #ifdef __cplusplus } diff --git a/include/cutils/trace.h b/include/cutils/trace.h index fd24561..e4ed179 100644 --- a/include/cutils/trace.h +++ b/include/cutils/trace.h @@ -18,6 +18,7 @@ #define _LIBS_CUTILS_TRACE_H #include <inttypes.h> +#include <stdatomic.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> @@ -26,11 +27,6 @@ #include <unistd.h> #include <cutils/compiler.h> -#ifdef ANDROID_SMP -#include <cutils/atomic-inline.h> -#else -#include <cutils/atomic.h> -#endif __BEGIN_DECLS @@ -84,14 +80,6 @@ __BEGIN_DECLS #error ATRACE_TAG must be defined to be one of the tags defined in cutils/trace.h #endif -#ifdef HAVE_ANDROID_OS -/** - * Maximum size of a message that can be logged to the trace buffer. - * Note this message includes a tag, the pid, and the string given as the name. - * Names should be kept short to get the most use of the trace buffer. - */ -#define ATRACE_MESSAGE_LENGTH 1024 - /** * Opens the trace file for writing and reads the property for initial tags. * The atrace.tags.enableflags property sets the tags to trace. @@ -125,7 +113,7 @@ void atrace_set_tracing_enabled(bool enabled); * Nonzero indicates setup has completed. * Note: This does NOT indicate whether or not setup was successful. */ -extern volatile int32_t atrace_is_ready; +extern atomic_bool atrace_is_ready; /** * Set of ATRACE_TAG flags to trace for, initialized to ATRACE_TAG_NOT_READY. @@ -148,7 +136,7 @@ extern int atrace_marker_fd; #define ATRACE_INIT() atrace_init() static inline void atrace_init() { - if (CC_UNLIKELY(!android_atomic_acquire_load(&atrace_is_ready))) { + if (CC_UNLIKELY(!atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) { atrace_setup(); } } @@ -184,11 +172,8 @@ static inline uint64_t atrace_is_tag_enabled(uint64_t tag) static inline void atrace_begin(uint64_t tag, const char* name) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - char buf[ATRACE_MESSAGE_LENGTH]; - size_t len; - - len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "B|%d|%s", getpid(), name); - write(atrace_marker_fd, buf, len); + void atrace_begin_body(const char*); + atrace_begin_body(name); } } @@ -218,12 +203,8 @@ static inline void atrace_async_begin(uint64_t tag, const char* name, int32_t cookie) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - char buf[ATRACE_MESSAGE_LENGTH]; - size_t len; - - len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "S|%d|%s|%" PRId32, - getpid(), name, cookie); - write(atrace_marker_fd, buf, len); + void atrace_async_begin_body(const char*, int32_t); + atrace_async_begin_body(name, cookie); } } @@ -232,20 +213,14 @@ static inline void atrace_async_begin(uint64_t tag, const char* name, * This should have a corresponding ATRACE_ASYNC_BEGIN. */ #define ATRACE_ASYNC_END(name, cookie) atrace_async_end(ATRACE_TAG, name, cookie) -static inline void atrace_async_end(uint64_t tag, const char* name, - int32_t cookie) +static inline void atrace_async_end(uint64_t tag, const char* name, int32_t cookie) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - char buf[ATRACE_MESSAGE_LENGTH]; - size_t len; - - len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "F|%d|%s|%" PRId32, - getpid(), name, cookie); - write(atrace_marker_fd, buf, len); + void atrace_async_end_body(const char*, int32_t); + atrace_async_end_body(name, cookie); } } - /** * Traces an integer counter value. name is used to identify the counter. * This can be used to track how a value changes over time. @@ -254,12 +229,8 @@ static inline void atrace_async_end(uint64_t tag, const char* name, static inline void atrace_int(uint64_t tag, const char* name, int32_t value) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - char buf[ATRACE_MESSAGE_LENGTH]; - size_t len; - - len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId32, - getpid(), name, value); - write(atrace_marker_fd, buf, len); + void atrace_int_body(const char*, int32_t); + atrace_int_body(name, value); } } @@ -271,28 +242,11 @@ static inline void atrace_int(uint64_t tag, const char* name, int32_t value) static inline void atrace_int64(uint64_t tag, const char* name, int64_t value) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - char buf[ATRACE_MESSAGE_LENGTH]; - size_t len; - - len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId64, - getpid(), name, value); - write(atrace_marker_fd, buf, len); + void atrace_int64_body(const char*, int64_t); + atrace_int64_body(name, value); } } -#else // not HAVE_ANDROID_OS - -#define ATRACE_INIT() -#define ATRACE_GET_ENABLED_TAGS() -#define ATRACE_ENABLED() 0 -#define ATRACE_BEGIN(name) -#define ATRACE_END() -#define ATRACE_ASYNC_BEGIN(name, cookie) -#define ATRACE_ASYNC_END(name, cookie) -#define ATRACE_INT(name, value) - -#endif // not HAVE_ANDROID_OS - __END_DECLS #endif // _LIBS_CUTILS_TRACE_H diff --git a/include/cutils/uevent.h b/include/cutils/uevent.h index 4cca7e5..da1c2aa 100644 --- a/include/cutils/uevent.h +++ b/include/cutils/uevent.h @@ -27,6 +27,7 @@ extern "C" { int uevent_open_socket(int buf_sz, bool passcred); ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length); ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer, size_t length, uid_t *uid); +ssize_t uevent_kernel_recv(int socket, void *buffer, size_t length, bool require_group, uid_t *uid); #ifdef __cplusplus } diff --git a/include/log/log.h b/include/log/log.h index ace12d6..ce253e2 100644 --- a/include/log/log.h +++ b/include/log/log.h @@ -28,14 +28,12 @@ #ifndef _LIBS_LOG_LOG_H #define _LIBS_LOG_LOG_H -#include <sys/types.h> -#ifdef HAVE_PTHREADS -#include <pthread.h> -#endif #include <stdarg.h> #include <stdio.h> +#include <sys/types.h> #include <time.h> #include <unistd.h> + #include <log/logd.h> #include <log/uio.h> @@ -69,6 +67,23 @@ extern "C" { // --------------------------------------------------------------------- +#ifndef __predict_false +#define __predict_false(exp) __builtin_expect((exp) != 0, 0) +#endif + +/* + * -DLINT_RLOG in sources that you want to enforce that all logging + * goes to the radio log buffer. If any logging goes to any of the other + * log buffers, there will be a compile or link error to highlight the + * problem. This is not a replacement for a full audit of the code since + * this only catches compiled code, not ifdef'd debug code. Options to + * defining this, either temporarily to do a spot check, or permanently + * to enforce, in all the communications trees; We have hopes to ensure + * that by supplying just the radio log buffer that the communications + * teams will have their one-stop shop for triaging issues. + */ +#ifndef LINT_RLOG + /* * Simplified macro to send a verbose log message using the current LOG_TAG. */ @@ -81,14 +96,12 @@ extern "C" { #endif #endif -#define CONDITION(cond) (__builtin_expect((cond)!=0, 0)) - #ifndef ALOGV_IF #if LOG_NDEBUG #define ALOGV_IF(cond, ...) ((void)0) #else #define ALOGV_IF(cond, ...) \ - ( (CONDITION(cond)) \ + ( (__predict_false(cond)) \ ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif @@ -103,7 +116,7 @@ extern "C" { #ifndef ALOGD_IF #define ALOGD_IF(cond, ...) \ - ( (CONDITION(cond)) \ + ( (__predict_false(cond)) \ ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif @@ -117,7 +130,7 @@ extern "C" { #ifndef ALOGI_IF #define ALOGI_IF(cond, ...) \ - ( (CONDITION(cond)) \ + ( (__predict_false(cond)) \ ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif @@ -131,7 +144,7 @@ extern "C" { #ifndef ALOGW_IF #define ALOGW_IF(cond, ...) \ - ( (CONDITION(cond)) \ + ( (__predict_false(cond)) \ ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif @@ -145,7 +158,7 @@ extern "C" { #ifndef ALOGE_IF #define ALOGE_IF(cond, ...) \ - ( (CONDITION(cond)) \ + ( (__predict_false(cond)) \ ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif @@ -203,7 +216,8 @@ extern "C" { * Simplified macro to send a verbose system log message using the current LOG_TAG. */ #ifndef SLOGV -#define __SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) +#define __SLOGV(...) \ + ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) #if LOG_NDEBUG #define SLOGV(...) do { if (0) { __SLOGV(__VA_ARGS__); } } while (0) #else @@ -211,14 +225,12 @@ extern "C" { #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)) \ + ( (__predict_false(cond)) \ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif @@ -228,12 +240,13 @@ extern "C" { * 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__)) +#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)) \ + ( (__predict_false(cond)) \ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif @@ -242,12 +255,13 @@ extern "C" { * 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__)) +#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)) \ + ( (__predict_false(cond)) \ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif @@ -256,12 +270,13 @@ extern "C" { * 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__)) +#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)) \ + ( (__predict_false(cond)) \ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif @@ -270,23 +285,27 @@ extern "C" { * 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__)) +#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)) \ + ( (__predict_false(cond)) \ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif +#endif /* !LINT_RLOG */ + // --------------------------------------------------------------------- /* * Simplified macro to send a verbose radio log message using the current LOG_TAG. */ #ifndef RLOGV -#define __RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) +#define __RLOGV(...) \ + ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) #if LOG_NDEBUG #define RLOGV(...) do { if (0) { __RLOGV(__VA_ARGS__); } } while (0) #else @@ -294,14 +313,12 @@ extern "C" { #endif #endif -#define CONDITION(cond) (__builtin_expect((cond)!=0, 0)) - #ifndef RLOGV_IF #if LOG_NDEBUG #define RLOGV_IF(cond, ...) ((void)0) #else #define RLOGV_IF(cond, ...) \ - ( (CONDITION(cond)) \ + ( (__predict_false(cond)) \ ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif @@ -311,12 +328,13 @@ extern "C" { * Simplified macro to send a debug radio log message using the current LOG_TAG. */ #ifndef RLOGD -#define RLOGD(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) +#define RLOGD(...) \ + ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) #endif #ifndef RLOGD_IF #define RLOGD_IF(cond, ...) \ - ( (CONDITION(cond)) \ + ( (__predict_false(cond)) \ ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif @@ -325,12 +343,13 @@ extern "C" { * Simplified macro to send an info radio log message using the current LOG_TAG. */ #ifndef RLOGI -#define RLOGI(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) +#define RLOGI(...) \ + ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) #endif #ifndef RLOGI_IF #define RLOGI_IF(cond, ...) \ - ( (CONDITION(cond)) \ + ( (__predict_false(cond)) \ ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif @@ -339,12 +358,13 @@ extern "C" { * Simplified macro to send a warning radio log message using the current LOG_TAG. */ #ifndef RLOGW -#define RLOGW(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) +#define RLOGW(...) \ + ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) #endif #ifndef RLOGW_IF #define RLOGW_IF(cond, ...) \ - ( (CONDITION(cond)) \ + ( (__predict_false(cond)) \ ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif @@ -353,12 +373,13 @@ extern "C" { * Simplified macro to send an error radio log message using the current LOG_TAG. */ #ifndef RLOGE -#define RLOGE(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) +#define RLOGE(...) \ + ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) #endif #ifndef RLOGE_IF #define RLOGE_IF(cond, ...) \ - ( (CONDITION(cond)) \ + ( (__predict_false(cond)) \ ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif @@ -374,7 +395,7 @@ extern "C" { */ #ifndef LOG_ALWAYS_FATAL_IF #define LOG_ALWAYS_FATAL_IF(cond, ...) \ - ( (CONDITION(cond)) \ + ( (__predict_false(cond)) \ ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \ : (void)0 ) #endif @@ -534,8 +555,23 @@ typedef enum { #define android_btWriteLog(tag, type, payload, len) \ __android_log_btwrite(tag, type, payload, len) +/* + * IF_ALOG uses android_testLog, but IF_ALOG can be overridden. + * android_testLog will remain constant in its purpose as a wrapper + * for Android logging filter policy, and can be subject to + * change. It can be reused by the developers that override + * IF_ALOG as a convenient means to reimplement their policy + * over Android. + */ +#if LOG_NDEBUG /* Production */ +#define android_testLog(prio, tag) \ + (__android_log_is_loggable(prio, tag, ANDROID_LOG_DEBUG) != 0) +#else +#define android_testLog(prio, tag) \ + (__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE) != 0) +#endif + // TODO: remove these prototypes and their users -#define android_testLog(prio, tag) (1) #define android_writevLog(vec,num) do{}while(0) #define android_write1Log(str,len) do{}while (0) #define android_setMinPriority(tag, prio) do{}while(0) @@ -546,11 +582,15 @@ typedef enum { typedef enum log_id { LOG_ID_MIN = 0, +#ifndef LINT_RLOG LOG_ID_MAIN = 0, +#endif LOG_ID_RADIO = 1, +#ifndef LINT_RLOG LOG_ID_EVENTS = 2, LOG_ID_SYSTEM = 3, LOG_ID_CRASH = 4, +#endif LOG_ID_MAX } log_id_t; @@ -558,6 +598,12 @@ typedef enum log_id { #define typeof_log_id_t unsigned char /* + * Use the per-tag properties "log.tag.<tagname>" to generate a runtime + * result of non-zero to expose a log. + */ +int __android_log_is_loggable(int prio, const char *tag, int def); + +/* * Send a simple string to the log. */ int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text); diff --git a/include/log/log_read.h b/include/log/log_read.h index 946711a..1b70aff 100644 --- a/include/log/log_read.h +++ b/include/log/log_read.h @@ -100,6 +100,12 @@ public: log_time local(*this); return local -= T; } + log_time operator+= (const timespec &T); + log_time operator+ (const timespec &T) const + { + log_time local(*this); + return local += T; + } // log_time bool operator== (const log_time &T) const @@ -134,6 +140,12 @@ public: log_time local(*this); return local -= T; } + log_time operator+= (const log_time &T); + log_time operator+ (const log_time &T) const + { + log_time local(*this); + return local += T; + } uint64_t nsec() const { diff --git a/include/log/logd.h b/include/log/logd.h index 2e6f220..0fe515f 100644 --- a/include/log/logd.h +++ b/include/log/logd.h @@ -23,16 +23,17 @@ #include <android/log.h> /* the rest is only used internally by the system */ -#include <time.h> -#include <stdio.h> -#include <unistd.h> -#include <stdint.h> -#include <sys/types.h> -#ifdef HAVE_PTHREADS +#if !defined(_WIN32) #include <pthread.h> #endif -#include <log/uio.h> #include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +#include <log/uio.h> #ifdef __cplusplus extern "C" { diff --git a/include/log/logger.h b/include/log/logger.h index 53be1d3..f030dab 100644 --- a/include/log/logger.h +++ b/include/log/logger.h @@ -154,6 +154,13 @@ ssize_t android_logger_get_prune_list(struct logger_list *logger_list, int android_logger_set_prune_list(struct logger_list *logger_list, char *buf, size_t len); +#define ANDROID_LOG_RDONLY O_RDONLY +#define ANDROID_LOG_WRONLY O_WRONLY +#define ANDROID_LOG_RDWR O_RDWR +#define ANDROID_LOG_ACCMODE O_ACCMODE +#define ANDROID_LOG_NONBLOCK O_NONBLOCK +#define ANDROID_LOG_PSTORE 0x80000000 + struct logger_list *android_logger_list_alloc(int mode, unsigned int tail, pid_t pid); diff --git a/include/log/logprint.h b/include/log/logprint.h index 481c96e..1e42b47 100644 --- a/include/log/logprint.h +++ b/include/log/logprint.h @@ -36,6 +36,7 @@ typedef enum { FORMAT_TIME, FORMAT_THREADTIME, FORMAT_LONG, + FORMAT_COLOR, } AndroidLogPrintFormat; typedef struct AndroidLogFormat_t AndroidLogFormat; diff --git a/include/log/uio.h b/include/log/uio.h index a71f515..7059da5 100644 --- a/include/log/uio.h +++ b/include/log/uio.h @@ -14,20 +14,23 @@ * limitations under the License. */ -// -// implementation of sys/uio.h for platforms that don't have it (Win32) -// #ifndef _LIBS_CUTILS_UIO_H #define _LIBS_CUTILS_UIO_H -#ifdef HAVE_SYS_UIO_H +#if !defined(_WIN32) + #include <sys/uio.h> + #else #ifdef __cplusplus extern "C" { #endif +// +// Implementation of sys/uio.h for Win32. +// + #include <stddef.h> struct iovec { @@ -42,7 +45,7 @@ extern int writev( int fd, const struct iovec* vecs, int count ); } #endif -#endif /* !HAVE_SYS_UIO_H */ +#endif #endif /* _LIBS_UTILS_UIO_H */ diff --git a/include/memtrack/memtrack.h b/include/memtrack/memtrack.h index 0f1f85e..3917300 100644 --- a/include/memtrack/memtrack.h +++ b/include/memtrack/memtrack.h @@ -121,7 +121,7 @@ ssize_t memtrack_proc_gl_total(struct memtrack_proc *p); ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p); /** - * memtrack_proc_gl_total + * memtrack_proc_other_total * * Same as memtrack_proc_graphics_total, but counts miscellaneous memory * not tracked by gl or graphics calls above. @@ -131,7 +131,7 @@ ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p); ssize_t memtrack_proc_other_total(struct memtrack_proc *p); /** - * memtrack_proc_gl_pss + * memtrack_proc_other_pss * * Same as memtrack_proc_graphics_total, but counts miscellaneous memory * not tracked by gl or graphics calls above. diff --git a/include/private/android_filesystem_capability.h b/include/private/android_filesystem_capability.h index 0505cda..b92d3db 100644 --- a/include/private/android_filesystem_capability.h +++ b/include/private/android_filesystem_capability.h @@ -105,7 +105,9 @@ struct vfs_cap_data { #define CAP_MAC_ADMIN 33 #define CAP_SYSLOG 34 #define CAP_WAKE_ALARM 35 -#define CAP_LAST_CAP CAP_WAKE_ALARM +#define CAP_BLOCK_SUSPEND 36 +#define CAP_AUDIT_READ 37 +#define CAP_LAST_CAP CAP_AUDIT_READ #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP) #define CAP_TO_INDEX(x) ((x) >> 5) #define CAP_TO_MASK(x) (1 << ((x) & 31)) diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h index 2f528b9..02fe2b5 100644 --- a/include/private/android_filesystem_config.h +++ b/include/private/android_filesystem_config.h @@ -22,8 +22,7 @@ #ifndef _ANDROID_FILESYSTEM_CONFIG_H_ #define _ANDROID_FILESYSTEM_CONFIG_H_ -#include <string.h> -#include <sys/stat.h> +#include <sys/cdefs.h> #include <sys/types.h> #include <stdint.h> @@ -83,6 +82,11 @@ #define AID_CACHE 2001 /* cache access */ #define AID_DIAG 2002 /* access to diagnostic resources */ +/* The range 2900-2999 is reserved for OEM, and must never be + * used here */ +#define AID_OEM_RESERVED_START 2900 +#define AID_OEM_RESERVED_END 2999 + /* The 3000 series are intended for use as supplemental group id's only. * They indicate special Android capabilities that the kernel is aware of. */ #define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */ @@ -109,6 +113,14 @@ #define AID_SHARED_GID_END 59999 /* start of gids for apps in each user to share */ #if !defined(EXCLUDE_FS_CONFIG_STRUCTURES) +/* + * Used in: + * bionic/libc/bionic/stubs.cpp + * external/libselinux/src/android.c + * system/core/logd/LogStatistics.cpp + * system/core/init/ueventd.cpp + * system/core/init/util.cpp + */ struct android_id_info { const char *name; unsigned aid; @@ -186,124 +198,26 @@ struct fs_path_config { const char *prefix; }; -/* Rules for directories. -** These rules are applied based on "first match", so they -** should start with the most specific path and work their -** way up to the root. -*/ - -static const struct fs_path_config android_dirs[] = { - { 00770, AID_SYSTEM, AID_CACHE, 0, "cache" }, - { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" }, - { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" }, - { 00771, AID_ROOT, AID_ROOT, 0, "data/dalvik-cache" }, - { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" }, - { 00771, AID_SHELL, AID_SHELL, 0, "data/local/tmp" }, - { 00771, AID_SHELL, AID_SHELL, 0, "data/local" }, - { 01771, AID_SYSTEM, AID_MISC, 0, "data/misc" }, - { 00770, AID_DHCP, AID_DHCP, 0, "data/misc/dhcp" }, - { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" }, - { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" }, - { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" }, - { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" }, - { 00750, AID_ROOT, AID_SHELL, 0, "sbin" }, - { 00755, AID_ROOT, AID_SHELL, 0, "system/bin" }, - { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" }, - { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin" }, - { 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" }, - { 00755, AID_ROOT, AID_SHELL, 0, "vendor" }, - { 00777, AID_ROOT, AID_ROOT, 0, "sdcard" }, - { 00755, AID_ROOT, AID_ROOT, 0, 0 }, -}; - -/* Rules for files. -** These rules are applied based on "first match", so they -** should start with the most specific path and work their -** way up to the root. Prefixes ending in * denotes wildcard -** and will allow partial matches. -*/ -static const struct fs_path_config android_files[] = { - { 00440, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.rc" }, - { 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.sh" }, - { 00440, AID_ROOT, AID_SHELL, 0, "system/etc/init.trout.rc" }, - { 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.ril" }, - { 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.testmenu" }, - { 00550, AID_DHCP, AID_SHELL, 0, "system/etc/dhcpcd/dhcpcd-run-hooks" }, - { 00444, AID_RADIO, AID_AUDIO, 0, "system/etc/AudioPara4.csv" }, - { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/ppp/*" }, - { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/rc.*" }, - { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app/*" }, - { 00644, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/*" }, - { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private/*" }, - { 00644, AID_APP, AID_APP, 0, "data/data/*" }, - { 00755, AID_ROOT, AID_ROOT, 0, "system/bin/ping" }, +/* Rules for directories and files has moved to system/code/libcutils/fs_config.c */ - /* the following file is INTENTIONALLY set-gid and not set-uid. - * Do not change. */ - { 02750, AID_ROOT, AID_INET, 0, "system/bin/netcfg" }, +__BEGIN_DECLS - /* the following five files are INTENTIONALLY set-uid, but they - * are NOT included on user builds. */ - { 04750, AID_ROOT, AID_SHELL, 0, "system/xbin/su" }, - { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/librank" }, - { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procrank" }, - { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" }, - { 04770, AID_ROOT, AID_RADIO, 0, "system/bin/pppd-ril" }, - - /* the following files have enhanced capabilities and ARE included in user builds. */ - { 00750, AID_ROOT, AID_SHELL, (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" }, - - { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" }, - { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" }, - { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" }, - { 00755, AID_ROOT, AID_ROOT, 0, "system/lib/valgrind/*" }, - { 00755, AID_ROOT, AID_ROOT, 0, "system/lib64/valgrind/*" }, - { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" }, - { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor/bin/*" }, - { 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" }, - { 00750, AID_ROOT, AID_SHELL, 0, "sbin/*" }, - { 00755, AID_ROOT, AID_ROOT, 0, "bin/*" }, - { 00750, AID_ROOT, AID_SHELL, 0, "init*" }, - { 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" }, - { 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" }, - { 00644, AID_ROOT, AID_ROOT, 0, 0 }, -}; - -static inline void fs_config(const char *path, int dir, - unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities) -{ - const struct fs_path_config *pc; - int plen; +/* + * Used in: + * build/tools/fs_config/fs_config.c + * build/tools/fs_get_stats/fs_get_stats.c + * external/genext2fs/genext2fs.c + * external/squashfs-tools/squashfs-tools/android.c + * system/core/cpio/mkbootfs.c + * system/core/adb/file_sync_service.cpp + * system/extras/ext4_utils/canned_fs_config.c + */ +void fs_config(const char *path, int dir, + unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities); - if (path[0] == '/') { - path++; - } +ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc); - pc = dir ? android_dirs : android_files; - plen = strlen(path); - for(; pc->prefix; pc++){ - int len = strlen(pc->prefix); - if (dir) { - if(plen < len) continue; - if(!strncmp(pc->prefix, path, len)) break; - continue; - } - /* If name ends in * then allow partial matches. */ - if (pc->prefix[len -1] == '*') { - if(!strncmp(pc->prefix, path, len - 1)) break; - } else if (plen == len){ - if(!strncmp(pc->prefix, path, len)) break; - } - } - *uid = pc->uid; - *gid = pc->gid; - *mode = (*mode & (~07777)) | pc->mode; - *capabilities = pc->capabilities; +__END_DECLS -#if 0 - fprintf(stderr,"< '%s' '%s' %d %d %o >\n", - path, pc->prefix ? pc->prefix : "", *uid, *gid, *mode); -#endif -} #endif #endif diff --git a/include/private/android_logger.h b/include/private/android_logger.h new file mode 100644 index 0000000..04238a6 --- /dev/null +++ b/include/private/android_logger.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2015 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. + */ + +/* This file is used to define the internal protocol for the Android Logger */ + +#ifndef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_ +#define _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_ + +#include <stdint.h> + +#include <log/log.h> +#include <log/log_read.h> + +#define LOGGER_MAGIC 'l' + +/* Header Structure to pstore */ +typedef struct __attribute__((__packed__)) { + uint8_t magic; + uint16_t len; + uint16_t uid; + uint16_t pid; +} android_pmsg_log_header_t; + +/* Header Structure to logd, and second header for pstore */ +typedef struct __attribute__((__packed__)) { + typeof_log_id_t id; + uint16_t tid; + log_time realtime; +} android_log_header_t; + +/* Event Header Structure to logd */ +typedef struct __attribute__((__packed__)) { + int32_t tag; // Little Endian Order +} android_event_header_t; + +/* Event payload EVENT_TYPE_INT */ +typedef struct __attribute__((__packed__)) { + int8_t type; // EVENT_TYPE_INT + int32_t data; // Little Endian Order +} android_event_int_t; + +/* Event with single EVENT_TYPE_INT */ +typedef struct __attribute__((__packed__)) { + android_event_header_t header; + android_event_int_t payload; +} android_log_event_int_t; + +/* Event payload EVENT_TYPE_LONG */ +typedef struct __attribute__((__packed__)) { + int8_t type; // EVENT_TYPE_LONG + int64_t data; // Little Endian Order +} android_event_long_t; + +/* Event with single EVENT_TYPE_LONG */ +typedef struct __attribute__((__packed__)) { + android_event_header_t header; + android_event_long_t payload; +} android_log_event_long_t; + +/* + * Event payload EVENT_TYPE_STRING + * + * Danger: do not embed this structure into another structure. + * This structure uses a flexible array member, and when + * compiled using g++, __builtin_object_size(data, 1) returns + * a bad value. This is possibly a g++ bug, or a bug due to + * the fact that flexible array members are not supported + * in C++. + * http://stackoverflow.com/questions/4412749/are-flexible-array-members-valid-in-c + */ +typedef struct __attribute__((__packed__)) { + int8_t type; // EVENT_TYPE_STRING; + int32_t length; // Little Endian Order + char data[]; +} android_event_string_t; + +/* Event with single EVENT_TYPE_STRING */ +typedef struct __attribute__((__packed__)) { + android_event_header_t header; + int8_t type; // EVENT_TYPE_STRING; + int32_t length; // Little Endian Order + char data[]; +} android_log_event_string_t; + +#endif diff --git a/include/system/graphics.h b/include/system/graphics.h index c3fca97..efd48cb 100644 --- a/include/system/graphics.h +++ b/include/system/graphics.h @@ -45,9 +45,12 @@ enum { /* * "linear" color pixel formats: * - * The pixel formats below contain sRGB data but are otherwise treated - * as linear formats, i.e.: no special operation is performed when - * reading or writing into a buffer in one of these formats + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. + * + * The color space determines, for example, if the formats are linear or + * gamma-corrected; or whether any special operations are performed when + * reading or writing into a buffer in one of these formats. */ HAL_PIXEL_FORMAT_RGBA_8888 = 1, HAL_PIXEL_FORMAT_RGBX_8888 = 2, @@ -55,25 +58,8 @@ enum { HAL_PIXEL_FORMAT_RGB_565 = 4, HAL_PIXEL_FORMAT_BGRA_8888 = 5, - /* - * sRGB color pixel formats: - * - * The red, green and blue components are stored in sRGB space, and converted - * to linear space when read, using the standard sRGB to linear equation: - * - * Clinear = Csrgb / 12.92 for Csrgb <= 0.04045 - * = (Csrgb + 0.055 / 1.055)^2.4 for Csrgb > 0.04045 - * - * When written the inverse transformation is performed: - * - * Csrgb = 12.92 * Clinear for Clinear <= 0.0031308 - * = 1.055 * Clinear^(1/2.4) - 0.055 for Clinear > 0.0031308 - * - * - * The alpha component, if present, is always stored in linear space and - * is left unmodified when read or written. - * - */ + // Deprecated sRGB formats for source code compatibility + // Not for use in new code HAL_PIXEL_FORMAT_sRGB_A_8888 = 0xC, HAL_PIXEL_FORMAT_sRGB_X_8888 = 0xD, @@ -111,6 +97,8 @@ enum { * cr_offset = y_size * cb_offset = y_size + c_size * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. */ HAL_PIXEL_FORMAT_YV12 = 0x32315659, // YCrCb 4:2:0 Planar @@ -135,6 +123,8 @@ enum { * * size = stride * height * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. */ HAL_PIXEL_FORMAT_Y8 = 0x20203859, @@ -159,6 +149,10 @@ enum { * * size = stride * height * 2 * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer, except that dataSpace field + * HAL_DATASPACE_DEPTH indicates that this buffer contains a depth + * image where each sample is a distance value measured by a depth camera. */ HAL_PIXEL_FORMAT_Y16 = 0x20363159, @@ -167,7 +161,7 @@ enum { * * This format is exposed outside of the camera HAL to applications. * - * RAW_SENSOR is a single-channel, 16-bit, little endian format, typically + * RAW16 is a single-channel, 16-bit, little endian format, typically * representing raw Bayer-pattern images from an image sensor, with minimal * processing. * @@ -193,9 +187,15 @@ enum { * - GRALLOC_USAGE_HW_CAMERA_* * - GRALLOC_USAGE_SW_* * - GRALLOC_USAGE_RENDERSCRIPT + * + * When used with ANativeWindow, the dataSpace should be + * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial + * extra metadata to define. */ HAL_PIXEL_FORMAT_RAW16 = 0x20, - HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20, // TODO(rubenbrunk): Remove RAW_SENSOR. + + // Temporary alias for source code compatibility; do not use in new code + HAL_PIXEL_FORMAT_RAW_SENSOR = HAL_PIXEL_FORMAT_RAW16, /* * Android RAW10 format: @@ -244,6 +244,10 @@ enum { * - GRALLOC_USAGE_HW_CAMERA_* * - GRALLOC_USAGE_SW_* * - GRALLOC_USAGE_RENDERSCRIPT + * + * When used with ANativeWindow, the dataSpace field should be + * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial + * extra metadata to define. */ HAL_PIXEL_FORMAT_RAW10 = 0x25, @@ -261,6 +265,10 @@ enum { * - GRALLOC_USAGE_HW_CAMERA_* * - GRALLOC_USAGE_SW_* * - GRALLOC_USAGE_RENDERSCRIPT + * + * When used with ANativeWindow, the dataSpace field should be + * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial + * extra metadata to define. */ HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24, @@ -276,6 +284,16 @@ enum { * * Buffers of this format must have a height of 1, and width equal to their * size in bytes. + * + * When used with ANativeWindow, the mapping of the dataSpace field to + * buffer contents for BLOB is as follows: + * + * dataSpace value | Buffer contents + * -------------------------------+----------------------------------------- + * HAL_DATASPACE_JFIF | An encoded JPEG image + * HAL_DATASPACE_DEPTH | An android_depth_points buffer + * Other | Unsupported + * */ HAL_PIXEL_FORMAT_BLOB = 0x21, @@ -292,6 +310,8 @@ enum { * framework will assume that sampling the texture will always return an * alpha value of 1.0 (i.e. the buffer contains only opaque pixel values). * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. */ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22, @@ -311,6 +331,9 @@ enum { * * This format is locked for use by gralloc's (*lock_ycbcr) method, and * locking with the (*lock) method will return an error. + * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. */ HAL_PIXEL_FORMAT_YCbCr_420_888 = 0x23, @@ -355,6 +378,42 @@ struct android_ycbcr { }; /** + * Structure used to define depth point clouds for format HAL_PIXEL_FORMAT_BLOB + * with dataSpace value of HAL_DATASPACE_DEPTH. + * When locking a native buffer of the above format and dataSpace value, + * the vaddr pointer can be cast to this structure. + * + * A variable-length list of (x,y,z) 3D points, as floats. + * + * @num_points is the number of points in the list + * + * @xyz_points is the flexible array of floating-point values. + * It contains (num_points) * 3 floats. + * + * For example: + * android_depth_points d = get_depth_buffer(); + * struct { + * float x; float y; float z; + * } firstPoint, lastPoint; + * + * firstPoint.x = d.xyz_points[0]; + * firstPoint.y = d.xyz_points[1]; + * firstPoint.z = d.xyz_points[2]; + * lastPoint.x = d.xyz_points[(d.num_points - 1) * 3 + 0]; + * lastPoint.y = d.xyz_points[(d.num_points - 1) * 3 + 1]; + * lastPoint.z = d.xyz_points[(d.num_points - 1) * 3 + 2]; + */ + +struct android_depth_points { + uint32_t num_points; + + /** reserved for future use, set to 0 by gralloc's (*lock)() */ + uint32_t reserved[8]; + + float xyz_points[]; +}; + +/** * Transformation definitions * * IMPORTANT NOTE: @@ -378,19 +437,33 @@ enum { }; /** - * Colorspace Definitions + * Dataspace Definitions * ====================== * - * Colorspace is the definition of how pixel values should be interpreted. - * It includes primaries (including white point) and the transfer - * characteristic function, which describes both gamma curve and numeric - * range (within the bit depth). + * Dataspace is the definition of how pixel values should be interpreted. + * + * For many formats, this is the colorspace of the image data, which includes + * primaries (including white point) and the transfer characteristic function, + * which describes both gamma curve and numeric range (within the bit depth). + * + * Other dataspaces include depth measurement data from a depth camera. */ -enum { +typedef enum android_dataspace { + /* + * Default-assumption data space, when not explicitly specified. + * + * It is safest to assume the buffer is an image with sRGB primaries and + * encoding ranges, but the consumer and/or the producer of the data may + * simply be using defaults. No automatic gamma transform should be + * expected, except for a possible display gamma transform when drawn to a + * screen. + */ + HAL_DATASPACE_UNKNOWN = 0x0, + /* - * Arbitrary colorspace with manually defined characteristics. - * Colorspace definition must be communicated separately. + * Arbitrary dataspace with manually defined characteristics. Definition + * for colorspaces or other meaning must be communicated separately. * * This is used when specifying primaries, transfer characteristics, * etc. separately. @@ -399,7 +472,57 @@ enum { * where a colorspace can have separately defined primaries, transfer * characteristics, etc. */ - HAL_COLORSPACE_ARBITRARY = 0x1, + HAL_DATASPACE_ARBITRARY = 0x1, + + /* + * RGB Colorspaces + * ----------------- + * + * Primaries are given using (x,y) coordinates in the CIE 1931 definition + * of x and y specified by ISO 11664-1. + * + * Transfer characteristics are the opto-electronic transfer characteristic + * at the source as a function of linear optical intensity (luminance). + */ + + /* + * sRGB linear encoding: + * + * The red, green, and blue components are stored in sRGB space, but + * are linear, not gamma-encoded. + * The RGB primaries and the white point are the same as BT.709. + * + * The values are encoded using the full range ([0,255] for 8-bit) for all + * components. + */ + HAL_DATASPACE_SRGB_LINEAR = 0x200, + + /* + * sRGB gamma encoding: + * + * The red, green and blue components are stored in sRGB space, and + * converted to linear space when read, using the standard sRGB to linear + * equation: + * + * Clinear = Csrgb / 12.92 for Csrgb <= 0.04045 + * = (Csrgb + 0.055 / 1.055)^2.4 for Csrgb > 0.04045 + * + * When written the inverse transformation is performed: + * + * Csrgb = 12.92 * Clinear for Clinear <= 0.0031308 + * = 1.055 * Clinear^(1/2.4) - 0.055 for Clinear > 0.0031308 + * + * + * The alpha component, if present, is always stored in linear space and + * is left unmodified when read or written. + * + * The RGB primaries and the white point are the same as BT.709. + * + * The values are encoded using the full range ([0,255] for 8-bit) for all + * components. + * + */ + HAL_DATASPACE_SRGB = 0x201, /* * YCbCr Colorspaces @@ -429,7 +552,7 @@ enum { * red 0.640 0.330 * white (D65) 0.3127 0.3290 */ - HAL_COLORSPACE_JFIF = 0x101, + HAL_DATASPACE_JFIF = 0x101, /* * ITU-R Recommendation 601 (BT.601) - 625-line @@ -456,7 +579,7 @@ enum { * red 0.640 0.330 * white (D65) 0.3127 0.3290 */ - HAL_COLORSPACE_BT601_625 = 0x102, + HAL_DATASPACE_BT601_625 = 0x102, /* * ITU-R Recommendation 601 (BT.601) - 525-line @@ -483,7 +606,7 @@ enum { * red 0.630 0.340 * white (D65) 0.3127 0.3290 */ - HAL_COLORSPACE_BT601_525 = 0x103, + HAL_DATASPACE_BT601_525 = 0x103, /* * ITU-R Recommendation 709 (BT.709) @@ -504,8 +627,20 @@ enum { * red 0.640 0.330 * white (D65) 0.3127 0.3290 */ - HAL_COLORSPACE_BT709 = 0x104, -}; + HAL_DATASPACE_BT709 = 0x104, + + /* + * The buffer contains depth ranging measurements from a depth camera. + * This value is valid with formats: + * HAL_PIXEL_FORMAT_Y16: 16-bit single channel depth image. + * HAL_PIXEL_FORMAT_BLOB: A depth point cloud, as + * a variable-length float (x,y,z) coordinate point list. + * The point cloud will be represented with the android_depth_points + * structure. + */ + HAL_DATASPACE_DEPTH = 0x1000 + +} android_dataspace_t; #ifdef __cplusplus } diff --git a/include/system/window.h b/include/system/window.h index bf93b79..a875427 100644 --- a/include/system/window.h +++ b/include/system/window.h @@ -262,6 +262,12 @@ enum { * the aspect ratio of the buffers produced. */ NATIVE_WINDOW_STICKY_TRANSFORM = 11, + + /** + * The default data space for the buffers as set by the consumer. + * The values are defined in graphics.h. + */ + NATIVE_WINDOW_DEFAULT_DATASPACE = 12 }; /* Valid operations for the (*perform)() hook. @@ -294,6 +300,8 @@ enum { NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* private */ NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */ NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18, + NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19, + NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */ }; /* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */ @@ -486,30 +494,12 @@ struct ANativeWindow * DO NOT CALL THIS HOOK DIRECTLY. Instead, use the helper functions * defined below. * - * (*perform)() returns -ENOENT if the 'what' parameter is not supported - * by the surface's implementation. - * - * The valid operations are: - * NATIVE_WINDOW_SET_USAGE - * NATIVE_WINDOW_CONNECT (deprecated) - * NATIVE_WINDOW_DISCONNECT (deprecated) - * NATIVE_WINDOW_SET_CROP (private) - * NATIVE_WINDOW_SET_BUFFER_COUNT - * NATIVE_WINDOW_SET_BUFFERS_GEOMETRY (deprecated) - * NATIVE_WINDOW_SET_BUFFERS_TRANSFORM - * NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP - * NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS - * NATIVE_WINDOW_SET_BUFFERS_FORMAT - * NATIVE_WINDOW_SET_SCALING_MODE (private) - * NATIVE_WINDOW_LOCK (private) - * NATIVE_WINDOW_UNLOCK_AND_POST (private) - * NATIVE_WINDOW_API_CONNECT (private) - * NATIVE_WINDOW_API_DISCONNECT (private) - * NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS (private) - * NATIVE_WINDOW_SET_POST_TRANSFORM_CROP (private) + * (*perform)() returns -ENOENT if the 'what' parameter is not supported + * by the surface's implementation. * + * See above for a list of valid operations, such as + * NATIVE_WINDOW_SET_USAGE or NATIVE_WINDOW_CONNECT */ - int (*perform)(struct ANativeWindow* window, int operation, ... ); @@ -799,6 +789,26 @@ static inline int native_window_set_buffers_format( } /* + * native_window_set_buffers_data_space(..., int dataSpace) + * All buffers queued after this call will be associated with the dataSpace + * parameter specified. + * + * dataSpace specifies additional information about the buffer that's dependent + * on the buffer format and the endpoints. For example, it can be used to convey + * the color space of the image data in the buffer, or it can be used to + * indicate that the buffers contain depth measurement data instead of color + * images. The default dataSpace is 0, HAL_DATASPACE_UNKNOWN, unless it has been + * overridden by the consumer. + */ +static inline int native_window_set_buffers_data_space( + struct ANativeWindow* window, + android_dataspace_t dataSpace) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_DATASPACE, + dataSpace); +} + +/* * native_window_set_buffers_transform(..., int transform) * All buffers queued after this call will be displayed transformed according * to the transform parameter specified. @@ -906,6 +916,30 @@ static inline int native_window_set_sideband_stream( sidebandHandle); } +/* + * native_window_set_surface_damage(..., android_native_rect_t* rects, int numRects) + * Set the surface damage (i.e., the region of the surface that has changed + * since the previous frame). The damage set by this call will be reset (to the + * default of full-surface damage) after calling queue, so this must be called + * prior to every frame with damage that does not cover the whole surface if the + * caller desires downstream consumers to use this optimization. + * + * The damage region is specified as an array of rectangles, with the important + * caveat that the origin of the surface is considered to be the bottom-left + * corner, as in OpenGL ES. + * + * If numRects is set to 0, rects may be NULL, and the surface damage will be + * set to the full surface (the same as if this function had not been called for + * this frame). + */ +static inline int native_window_set_surface_damage( + struct ANativeWindow* window, + const android_native_rect_t* rects, size_t numRects) +{ + return window->perform(window, NATIVE_WINDOW_SET_SURFACE_DAMAGE, + rects, numRects); +} + __END_DECLS #endif /* SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H */ diff --git a/include/sysutils/NetlinkEvent.h b/include/sysutils/NetlinkEvent.h index c345cdb..4fa49c5 100644 --- a/include/sysutils/NetlinkEvent.h +++ b/include/sysutils/NetlinkEvent.h @@ -57,6 +57,7 @@ public: bool parseIfInfoMessage(const struct nlmsghdr *nh); bool parseIfAddrMessage(const struct nlmsghdr *nh); bool parseUlogPacketMessage(const struct nlmsghdr *nh); + bool parseNfPacketMessage(struct nlmsghdr *nh); bool parseRtMessage(const struct nlmsghdr *nh); bool parseNdUserOptMessage(const struct nlmsghdr *nh); }; diff --git a/include/sysutils/NetlinkListener.h b/include/sysutils/NetlinkListener.h index 6e52c3b..82465d6 100644 --- a/include/sysutils/NetlinkListener.h +++ b/include/sysutils/NetlinkListener.h @@ -27,6 +27,7 @@ class NetlinkListener : public SocketListener { public: static const int NETLINK_FORMAT_ASCII = 0; static const int NETLINK_FORMAT_BINARY = 1; + static const int NETLINK_FORMAT_BINARY_UNICAST = 2; #if 1 /* temporary version until we can get Motorola to update their diff --git a/include/utils/AndroidThreads.h b/include/utils/AndroidThreads.h index 4eee14d..aad1e82 100644 --- a/include/utils/AndroidThreads.h +++ b/include/utils/AndroidThreads.h @@ -20,7 +20,7 @@ #include <stdint.h> #include <sys/types.h> -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) # include <pthread.h> #endif @@ -73,9 +73,6 @@ extern void androidSetCreateThreadFunc(android_create_thread_fn func); // ------------------------------------------------------------------ // Extra functions working with raw pids. -// Get pid for the current thread. -extern pid_t androidGetTid(); - #ifdef HAVE_ANDROID_OS // Change the priority AND scheduling group of a particular thread. The priority // should be one of the ANDROID_PRIORITY constants. Returns INVALID_OPERATION diff --git a/include/utils/Compat.h b/include/utils/Compat.h index fb7748e..7d96310 100644 --- a/include/utils/Compat.h +++ b/include/utils/Compat.h @@ -19,11 +19,9 @@ #include <unistd.h> -/* Compatibility definitions for non-Linux (i.e., BSD-based) hosts. */ -#ifndef HAVE_OFF64_T -#if _FILE_OFFSET_BITS < 64 -#error "_FILE_OFFSET_BITS < 64; large files are not supported on this platform" -#endif /* _FILE_OFFSET_BITS < 64 */ +#if defined(__APPLE__) + +/* Mac OS has always had a 64-bit off_t, so it doesn't have off64_t. */ typedef off_t off64_t; @@ -31,20 +29,35 @@ static inline off64_t lseek64(int fd, off64_t offset, int whence) { return lseek(fd, offset, whence); } -#ifdef HAVE_PREAD static inline ssize_t pread64(int fd, void* buf, size_t nbytes, off64_t offset) { return pread(fd, buf, nbytes, offset); } -#endif -#endif /* !HAVE_OFF64_T */ +#endif /* __APPLE__ */ + +#if defined(_WIN32) +#define O_CLOEXEC O_NOINHERIT +#define O_NOFOLLOW 0 +#define DEFFILEMODE 0666 +#endif /* _WIN32 */ + +#if defined(_WIN32) +#define ZD "%ld" +#define ZD_TYPE long +#else +#define ZD "%zd" +#define ZD_TYPE ssize_t +#endif -#if HAVE_PRINTF_ZD -# define ZD "%zd" -# define ZD_TYPE ssize_t +/* + * Needed for cases where something should be constexpr if possible, but not + * being constexpr is fine if in pre-C++11 code (such as a const static float + * member variable). + */ +#if __cplusplus >= 201103L +#define CONSTEXPR constexpr #else -# define ZD "%ld" -# define ZD_TYPE long +#define CONSTEXPR #endif /* diff --git a/include/utils/Condition.h b/include/utils/Condition.h index 1c99d1a..5a72519 100644 --- a/include/utils/Condition.h +++ b/include/utils/Condition.h @@ -21,7 +21,7 @@ #include <sys/types.h> #include <time.h> -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) # include <pthread.h> #endif @@ -74,7 +74,7 @@ public: void broadcast(); private: -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) pthread_cond_t mCond; #else void* mState; @@ -83,7 +83,7 @@ private: // --------------------------------------------------------------------------- -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) inline Condition::Condition() { pthread_cond_init(&mCond, NULL); @@ -113,15 +113,15 @@ inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) { return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts); #else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE struct timespec ts; -#if defined(HAVE_POSIX_CLOCKS) +#if defined(__linux__) clock_gettime(CLOCK_REALTIME, &ts); -#else // HAVE_POSIX_CLOCKS +#else // __APPLE__ // we don't support the clocks here. struct timeval t; gettimeofday(&t, NULL); ts.tv_sec = t.tv_sec; ts.tv_nsec= t.tv_usec*1000; -#endif // HAVE_POSIX_CLOCKS +#endif ts.tv_sec += reltime/1000000000; ts.tv_nsec+= reltime%1000000000; if (ts.tv_nsec >= 1000000000) { @@ -149,7 +149,7 @@ inline void Condition::broadcast() { pthread_cond_broadcast(&mCond); } -#endif // HAVE_PTHREADS +#endif // !defined(_WIN32) // --------------------------------------------------------------------------- }; // namespace android diff --git a/include/utils/Endian.h b/include/utils/Endian.h index 19f2504..591cae0 100644 --- a/include/utils/Endian.h +++ b/include/utils/Endian.h @@ -20,21 +20,16 @@ #ifndef _LIBS_UTILS_ENDIAN_H #define _LIBS_UTILS_ENDIAN_H -#if defined(HAVE_ENDIAN_H) - -#include <endian.h> - -#else /*not HAVE_ENDIAN_H*/ +#if defined(__APPLE__) || defined(_WIN32) #define __BIG_ENDIAN 0x1000 #define __LITTLE_ENDIAN 0x0001 +#define __BYTE_ORDER __LITTLE_ENDIAN -#if defined(HAVE_LITTLE_ENDIAN) -# define __BYTE_ORDER __LITTLE_ENDIAN #else -# define __BYTE_ORDER __BIG_ENDIAN -#endif -#endif /*not HAVE_ENDIAN_H*/ +#include <endian.h> + +#endif #endif /*_LIBS_UTILS_ENDIAN_H*/ diff --git a/include/utils/FileMap.h b/include/utils/FileMap.h index dfe6d51..f70fc92 100644 --- a/include/utils/FileMap.h +++ b/include/utils/FileMap.h @@ -24,7 +24,11 @@ #include <utils/Compat.h> -#ifdef HAVE_WIN32_FILEMAP +#if defined(__MINGW32__) +// Ensure that we always pull in winsock2.h before windows.h +#ifdef HAVE_WINSOCK +#include <winsock2.h> +#endif #include <windows.h> #endif @@ -59,6 +63,8 @@ public: bool create(const char* origFileName, int fd, off64_t offset, size_t length, bool readOnly); + ~FileMap(void); + /* * Return the name of the file this map came from, if known. */ @@ -80,19 +86,6 @@ public: off64_t getDataOffset(void) const { return mDataOffset; } /* - * Get a "copy" of the object. - */ - FileMap* acquire(void) { mRefCount++; return this; } - - /* - * Call this when mapping is no longer needed. - */ - void release(void) { - if (--mRefCount <= 0) - delete this; - } - - /* * This maps directly to madvise() values, but allows us to avoid * including <sys/mman.h> everywhere. */ @@ -108,22 +101,19 @@ public: int advise(MapAdvice advice); protected: - // don't delete objects; call release() - ~FileMap(void); private: // these are not implemented FileMap(const FileMap& src); const FileMap& operator=(const FileMap& src); - int mRefCount; // reference count char* mFileName; // original file name, if known void* mBasePtr; // base of mmap area; page aligned size_t mBaseLength; // length, measured from "mBasePtr" off64_t mDataOffset; // offset used when map was created void* mDataPtr; // start of requested data, offset from base size_t mDataLength; // length, measured from "mDataPtr" -#ifdef HAVE_WIN32_FILEMAP +#if defined(__MINGW32__) HANDLE mFileHandle; // Win32 file handle HANDLE mFileMapping; // Win32 file mapping handle #endif diff --git a/include/utils/Mutex.h b/include/utils/Mutex.h index dd201c8..757519b 100644 --- a/include/utils/Mutex.h +++ b/include/utils/Mutex.h @@ -21,11 +21,12 @@ #include <sys/types.h> #include <time.h> -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) # include <pthread.h> #endif #include <utils/Errors.h> +#include <utils/Timers.h> // --------------------------------------------------------------------------- namespace android { @@ -45,7 +46,7 @@ public: PRIVATE = 0, SHARED = 1 }; - + Mutex(); Mutex(const char* name); Mutex(int type, const char* name = NULL); @@ -58,6 +59,16 @@ public: // lock if possible; returns 0 on success, error otherwise status_t tryLock(); +#if HAVE_ANDROID_OS + // lock the mutex, but don't wait longer than timeoutMilliseconds. + // Returns 0 on success, TIMED_OUT for failure due to timeout expiration. + // + // OSX doesn't have pthread_mutex_timedlock() or equivalent. To keep + // capabilities consistent across host OSes, this method is only available + // when building Android binaries. + status_t timedLock(nsecs_t timeoutMilliseconds); +#endif + // Manages the mutex automatically. It'll be locked when Autolock is // constructed and released when Autolock goes out of scope. class Autolock { @@ -71,12 +82,12 @@ public: private: friend class Condition; - + // A mutex cannot be copied Mutex(const Mutex&); Mutex& operator = (const Mutex&); - -#if defined(HAVE_PTHREADS) + +#if !defined(_WIN32) pthread_mutex_t mMutex; #else void _init(); @@ -86,7 +97,7 @@ private: // --------------------------------------------------------------------------- -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) inline Mutex::Mutex() { pthread_mutex_init(&mMutex, NULL); @@ -117,8 +128,17 @@ inline void Mutex::unlock() { inline status_t Mutex::tryLock() { return -pthread_mutex_trylock(&mMutex); } +#if HAVE_ANDROID_OS +inline status_t Mutex::timedLock(nsecs_t timeoutNs) { + const struct timespec ts = { + /* .tv_sec = */ static_cast<time_t>(timeoutNs / 1000000000), + /* .tv_nsec = */ static_cast<long>(timeoutNs % 1000000000), + }; + return -pthread_mutex_timedlock(&mMutex, &ts); +} +#endif -#endif // HAVE_PTHREADS +#endif // !defined(_WIN32) // --------------------------------------------------------------------------- @@ -127,7 +147,7 @@ inline status_t Mutex::tryLock() { * When the function returns, it will go out of scope, and release the * mutex. */ - + typedef Mutex::Autolock AutoMutex; // --------------------------------------------------------------------------- diff --git a/include/utils/RWLock.h b/include/utils/RWLock.h index 90beb5f..e743b1c 100644 --- a/include/utils/RWLock.h +++ b/include/utils/RWLock.h @@ -20,7 +20,7 @@ #include <stdint.h> #include <sys/types.h> -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) # include <pthread.h> #endif @@ -31,7 +31,7 @@ namespace android { // --------------------------------------------------------------------------- -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) /* * Simple mutex class. The implementation is system-dependent. @@ -117,7 +117,7 @@ inline void RWLock::unlock() { pthread_rwlock_unlock(&mRWLock); } -#endif // HAVE_PTHREADS +#endif // !defined(_WIN32) // --------------------------------------------------------------------------- }; // namespace android diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h index 8e15c19..eac6a78 100644 --- a/include/utils/RefBase.h +++ b/include/utils/RefBase.h @@ -491,7 +491,8 @@ public: TYPE::renameRefId(d[i].get(), &s[i], &d[i]); } public: - Renamer(sp<TYPE>* d, sp<TYPE> const* s) : s(s), d(d) { } + Renamer(sp<TYPE>* d, sp<TYPE> const* s) : d(d), s(s) { } + virtual ~Renamer() { } }; memmove(d, s, n*sizeof(sp<TYPE>)); @@ -510,7 +511,8 @@ public: TYPE::renameRefId(d[i].get_refs(), &s[i], &d[i]); } public: - Renamer(wp<TYPE>* d, wp<TYPE> const* s) : s(s), d(d) { } + Renamer(wp<TYPE>* d, wp<TYPE> const* s) : d(d), s(s) { } + virtual ~Renamer() { } }; memmove(d, s, n*sizeof(wp<TYPE>)); diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h index c60680e..ffc03cb 100644 --- a/include/utils/Singleton.h +++ b/include/utils/Singleton.h @@ -65,9 +65,10 @@ private: */ #define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) \ - template<> Mutex Singleton< TYPE >::sLock(Mutex::PRIVATE); \ - template<> TYPE* Singleton< TYPE >::sInstance(0); \ - template class Singleton< TYPE >; + template<> ::android::Mutex \ + (::android::Singleton< TYPE >::sLock)(::android::Mutex::PRIVATE); \ + template<> TYPE* ::android::Singleton< TYPE >::sInstance(0); \ + template class ::android::Singleton< TYPE >; // --------------------------------------------------------------------------- diff --git a/include/utils/Thread.h b/include/utils/Thread.h index df30611..28839fd 100644 --- a/include/utils/Thread.h +++ b/include/utils/Thread.h @@ -21,7 +21,7 @@ #include <sys/types.h> #include <time.h> -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) # include <pthread.h> #endif @@ -71,8 +71,8 @@ public: bool isRunning() const; #ifdef HAVE_ANDROID_OS - // Return the thread's kernel ID, same as the thread itself calling gettid() or - // androidGetTid(), or -1 if the thread is not running. + // Return the thread's kernel ID, same as the thread itself calling gettid(), + // or -1 if the thread is not running. pid_t getTid() const; #endif diff --git a/include/utils/Timers.h b/include/utils/Timers.h index d015421..54ec474 100644 --- a/include/utils/Timers.h +++ b/include/utils/Timers.h @@ -24,6 +24,8 @@ #include <sys/types.h> #include <sys/time.h> +#include <utils/Compat.h> + // ------------------------------------------------------------------ // C API @@ -33,46 +35,46 @@ extern "C" { typedef int64_t nsecs_t; // nano-seconds -static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs) +static CONSTEXPR inline nsecs_t seconds_to_nanoseconds(nsecs_t secs) { return secs*1000000000; } -static inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs) +static CONSTEXPR inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs) { return secs*1000000; } -static inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs) +static CONSTEXPR inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs) { return secs*1000; } -static inline nsecs_t nanoseconds_to_seconds(nsecs_t secs) +static CONSTEXPR inline nsecs_t nanoseconds_to_seconds(nsecs_t secs) { return secs/1000000000; } -static inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs) +static CONSTEXPR inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs) { return secs/1000000; } -static inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs) +static CONSTEXPR inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs) { return secs/1000; } -static inline nsecs_t s2ns(nsecs_t v) {return seconds_to_nanoseconds(v);} -static inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);} -static inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);} -static inline nsecs_t ns2s(nsecs_t v) {return nanoseconds_to_seconds(v);} -static inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);} -static inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);} +static CONSTEXPR inline nsecs_t s2ns(nsecs_t v) {return seconds_to_nanoseconds(v);} +static CONSTEXPR inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);} +static CONSTEXPR inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);} +static CONSTEXPR inline nsecs_t ns2s(nsecs_t v) {return nanoseconds_to_seconds(v);} +static CONSTEXPR inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);} +static CONSTEXPR inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);} -static inline nsecs_t seconds(nsecs_t v) { return s2ns(v); } -static inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); } -static inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); } +static CONSTEXPR inline nsecs_t seconds(nsecs_t v) { return s2ns(v); } +static CONSTEXPR inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); } +static CONSTEXPR inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); } enum { SYSTEM_TIME_REALTIME = 0, // system-wide realtime clock diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h index 5b98de2..b76a5e2 100644 --- a/include/utils/Unicode.h +++ b/include/utils/Unicode.h @@ -22,12 +22,6 @@ extern "C" { -// Definitions exist in C++11 -#if defined __cplusplus && __cplusplus < 201103L -typedef uint32_t char32_t; -typedef uint16_t char16_t; -#endif - // Standard string functions on char16_t strings. int strcmp16(const char16_t *, const char16_t *); int strncmp16(const char16_t *s1, const char16_t *s2, size_t n); diff --git a/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h index 1877494..386a390 100644 --- a/include/ziparchive/zip_archive.h +++ b/include/ziparchive/zip_archive.h @@ -21,6 +21,7 @@ #define LIBZIPARCHIVE_ZIPARCHIVE_H_ #include <stdint.h> +#include <string.h> #include <sys/types.h> #include <utils/Compat.h> @@ -33,8 +34,16 @@ enum { }; struct ZipEntryName { - const char* name; + const uint8_t* name; uint16_t name_length; + + ZipEntryName() {} + + /* + * entry_name has to be an c-style string with only ASCII characters. + */ + explicit ZipEntryName(const char* entry_name) + : name(reinterpret_cast<const uint8_t*>(entry_name)), name_length(strlen(entry_name)) {} }; /* @@ -92,6 +101,9 @@ int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle); * Sets handle to the value of the opaque handle for this file descriptor. * This handle must be released by calling CloseArchive with this handle. * + * If assume_ownership parameter is 'true' calling CloseArchive will close + * the file. + * * This function maps and scans the central directory and builds a table * of entries for future lookups. * @@ -100,7 +112,7 @@ int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle); * Returns 0 on success, and negative values on failure. */ int32_t OpenArchiveFd(const int fd, const char* debugFileName, - ZipArchiveHandle *handle); + ZipArchiveHandle *handle, bool assume_ownership = true); /* * Close archive, releasing resources associated with it. This will @@ -124,24 +136,24 @@ void CloseArchive(ZipArchiveHandle handle); * and length, a call to VerifyCrcAndLengths must be made after entry data * has been processed. */ -int32_t FindEntry(const ZipArchiveHandle handle, const char* entryName, +int32_t FindEntry(const ZipArchiveHandle handle, const ZipEntryName& entryName, ZipEntry* data); /* * Start iterating over all entries of a zip file. The order of iteration * is not guaranteed to be the same as the order of elements - * in the central directory but is stable for a given zip file. |cookie| - * must point to a writeable memory location, and will be set to the value - * of an opaque cookie which can be used to make one or more calls to - * Next. + * in the central directory but is stable for a given zip file. |cookie| will + * contain the value of an opaque cookie which can be used to make one or more + * calls to Next. All calls to StartIteration must be matched by a call to + * EndIteration to free any allocated memory. * * This method also accepts an optional prefix to restrict iteration to - * entry names that start with |prefix|. + * entry names that start with |optional_prefix|. * * Returns 0 on success and negative values on failure. */ int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, - const char* prefix); + const ZipEntryName* optional_prefix); /* * Advance to the next element in the zipfile in iteration order. @@ -152,6 +164,12 @@ int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, int32_t Next(void* cookie, ZipEntry* data, ZipEntryName *name); /* + * End iteration over all entries of a zip file and frees the memory allocated + * in StartIteration. + */ +void EndIteration(void* cookie); + +/* * Uncompress and write an entry to an open file identified by |fd|. * |entry->uncompressed_length| bytes will be written to the file at * its current offset, and the file will be truncated at the end of diff --git a/include/zipfile/zipfile.h b/include/zipfile/zipfile.h deleted file mode 100644 index 0ae4ee4..0000000 --- a/include/zipfile/zipfile.h +++ /dev/null @@ -1,58 +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 _ZIPFILE_ZIPFILE_H -#define _ZIPFILE_ZIPFILE_H - -#include <stddef.h> - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void* zipfile_t; -typedef void* zipentry_t; - -// Provide a buffer. Returns NULL on failure. -zipfile_t init_zipfile(const void* data, size_t size); - -// Release the zipfile resources. -void release_zipfile(zipfile_t file); - -// Get a named entry object. Returns NULL if it doesn't exist -// or if we won't be able to decompress it. The zipentry_t is -// freed by release_zipfile() -zipentry_t lookup_zipentry(zipfile_t file, const char* entryName); - -// Return the size of the entry. -size_t get_zipentry_size(zipentry_t entry); - -// return the filename of this entry, you own the memory returned -char* get_zipentry_name(zipentry_t entry); - -// The buffer must be 1.001 times the buffer size returned -// by get_zipentry_size. Returns nonzero on failure. -int decompress_zipentry(zipentry_t entry, void* buf, int bufsize); - -// iterate through the entries in the zip file. pass a pointer to -// a void* initialized to NULL to start. Returns NULL when done -zipentry_t iterate_zipfile(zipfile_t file, void** cookie); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // _ZIPFILE_ZIPFILE_H diff --git a/init/Android.mk b/init/Android.mk index 228e645..31d2fcd 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -1,73 +1,99 @@ # Copyright 2005 The Android Open Source Project LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) -LOCAL_SRC_FILES:= \ - builtins.c \ - init.c \ - devices.c \ - property_service.c \ - util.c \ - parser.c \ - keychords.c \ - signal_handler.c \ - init_parser.c \ - ueventd.c \ - ueventd_parser.c \ - watchdogd.c - -LOCAL_CFLAGS += -Wno-unused-parameter - -ifeq ($(strip $(INIT_BOOTCHART)),true) -LOCAL_SRC_FILES += bootchart.c -LOCAL_CFLAGS += -DBOOTCHART=1 -endif +# -- ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) -LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_DISABLE_SELINUX=1 +init_options += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_DISABLE_SELINUX=1 +else +init_options += -DALLOW_LOCAL_PROP_OVERRIDE=0 -DALLOW_DISABLE_SELINUX=0 endif -# Enable ueventd logging -#LOCAL_CFLAGS += -DLOG_UEVENTS=1 +init_options += -DLOG_UEVENTS=0 -LOCAL_MODULE:= init +init_cflags += \ + $(init_options) \ + -Wall -Wextra \ + -Wno-unused-parameter \ + -Werror \ + +init_clang := true + +# -- + +include $(CLEAR_VARS) +LOCAL_CPPFLAGS := $(init_cflags) +LOCAL_SRC_FILES:= \ + init_parser.cpp \ + log.cpp \ + parser.cpp \ + util.cpp \ +LOCAL_STATIC_LIBRARIES := libbase +LOCAL_MODULE := libinit +LOCAL_CLANG := $(init_clang) +include $(BUILD_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_CPPFLAGS := $(init_cflags) +LOCAL_SRC_FILES:= \ + bootchart.cpp \ + builtins.cpp \ + devices.cpp \ + init.cpp \ + keychords.cpp \ + property_service.cpp \ + signal_handler.cpp \ + ueventd.cpp \ + ueventd_parser.cpp \ + watchdogd.cpp \ + +LOCAL_MODULE:= init +LOCAL_C_INCLUDES += system/extras/ext4_utils LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT) LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) LOCAL_STATIC_LIBRARIES := \ - libfs_mgr \ - liblogwrap \ - libcutils \ - liblog \ - libc \ - libselinux \ - libmincrypt \ - libext4_utils_static \ - libsparse_static \ - libz - -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk + libinit \ + libfs_mgr \ + libsquashfs_utils \ + liblogwrap \ + libcutils \ + libbase \ + libext4_utils_static \ + libutils \ + liblog \ + libc \ + libselinux \ + libmincrypt \ + libc++_static \ + libdl \ + libsparse_static \ + libz +# Create symlinks +LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \ + ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \ + ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd + +LOCAL_CLANG := $(init_clang) include $(BUILD_EXECUTABLE) -# Make a symlink from /sbin/ueventd and /sbin/watchdogd to /init -SYMLINKS := \ - $(TARGET_ROOT_OUT)/sbin/ueventd \ - $(TARGET_ROOT_OUT)/sbin/watchdogd -$(SYMLINKS): INIT_BINARY := $(LOCAL_MODULE) -$(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk - @echo "Symlink: $@ -> ../$(INIT_BINARY)" - @mkdir -p $(dir $@) - @rm -rf $@ - $(hide) ln -sf ../$(INIT_BINARY) $@ -ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS) -# We need this so that the installed files could be picked up based on the -# local module name -ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \ - $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(SYMLINKS) +include $(CLEAR_VARS) +LOCAL_MODULE := init_tests +LOCAL_SRC_FILES := \ + init_parser_test.cpp \ + util_test.cpp \ + +LOCAL_SHARED_LIBRARIES += \ + libcutils \ + libbase \ + +LOCAL_STATIC_LIBRARIES := libinit +LOCAL_CLANG := $(init_clang) +include $(BUILD_NATIVE_TEST) diff --git a/init/README.BOOTCHART b/init/README.BOOTCHART deleted file mode 100644 index 70cf2c3..0000000 --- a/init/README.BOOTCHART +++ /dev/null @@ -1,52 +0,0 @@ -This version of init contains code to perform "bootcharting", i.e. generating log -files that can be later processed by the tools provided by www.bootchart.org. - -To activate it, you need to define build 'init' with the INIT_BOOTCHART environment -variable defined to 'true', for example: - - touch system/init/init.c - m INIT_BOOTCHART=true - -On the emulator, use the new -bootchart <timeout> option to boot with bootcharting -activated for <timeout> seconds. - -Otherwise, flash your device, and start it. Then create a file on the /data partition -with a command like the following: - - adb shell 'echo $TIMEOUT > /data/bootchart-start' - -Where the value of $TIMEOUT corresponds to the wanted bootcharted period in seconds; -for example, to bootchart for 2 minutes, do: - - adb shell 'echo 120 > /data/bootchart-start' - -Reboot your device, bootcharting will begin and stop after the period you gave. -You can also stop the bootcharting at any moment by doing the following: - - adb shell 'echo 1 > /data/bootchart-stop' - -Note that /data/bootchart-stop is deleted automatically by init at the end of the -bootcharting. This is not the case of /data/bootchart-start, so don't forget to delete it -when you're done collecting data: - - adb shell rm /data/bootchart-start - -The log files are placed in /data/bootchart/. you must run the script tools/grab-bootchart.sh -which will use ADB to retrieve them and create a bootchart.tgz file that can be used with -the bootchart parser/renderer, or even uploaded directly to the form located at: - - http://www.bootchart.org/download.html - -NOTE: the bootchart.org webform doesn't seem to work at the moment, you can generate an - image on your machine by doing the following: - - 1/ download the sources from www.bootchart.org - 2/ unpack them - 3/ in the source directory, type 'ant' to build the bootchart program - 4/ type 'java -jar bootchart.jar /path/to/bootchart.tgz - -technical note: - -this implementation of bootcharting does use the 'bootchartd' script provided by -www.bootchart.org, but a C re-implementation that is directly compiled into our init -program. diff --git a/init/bootchart.c b/init/bootchart.c deleted file mode 100644 index f72fcaa..0000000 --- a/init/bootchart.c +++ /dev/null @@ -1,378 +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. - */ - -/* this code is used to generate a boot sequence profile that can be used - * with the 'bootchart' graphics generation tool. see www.bootchart.org - * note that unlike the original bootchartd, this is not a Bash script but - * some C code that is run right from the init script. - */ - -#include <stdio.h> -#include <time.h> -#include <dirent.h> -#include <unistd.h> -#include <fcntl.h> -#include <unistd.h> -#include <fcntl.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <stdlib.h> -#include <sys/stat.h> -#include "bootchart.h" - -#define VERSION "0.8" -#define SAMPLE_PERIOD 0.2 -#define LOG_ROOT "/data/bootchart" -#define LOG_STAT LOG_ROOT"/proc_stat.log" -#define LOG_PROCS LOG_ROOT"/proc_ps.log" -#define LOG_DISK LOG_ROOT"/proc_diskstats.log" -#define LOG_HEADER LOG_ROOT"/header" -#define LOG_ACCT LOG_ROOT"/kernel_pacct" - -#define LOG_STARTFILE "/data/bootchart-start" -#define LOG_STOPFILE "/data/bootchart-stop" - -static int -unix_read(int fd, void* buff, int len) -{ - int ret; - do { ret = read(fd, buff, len); } while (ret < 0 && errno == EINTR); - return ret; -} - -static int -unix_write(int fd, const void* buff, int len) -{ - int ret; - do { ret = write(fd, buff, len); } while (ret < 0 && errno == EINTR); - return ret; -} - -static int -proc_read(const char* filename, char* buff, size_t buffsize) -{ - int len = 0; - int fd = open(filename, O_RDONLY); - if (fd >= 0) { - len = unix_read(fd, buff, buffsize-1); - close(fd); - } - buff[len > 0 ? len : 0] = 0; - return len; -} - -#define FILE_BUFF_SIZE 65536 - -typedef struct { - int count; - int fd; - char data[FILE_BUFF_SIZE]; -} FileBuffRec, *FileBuff; - -static void -file_buff_open( FileBuff buff, const char* path ) -{ - buff->count = 0; - buff->fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0755); -} - -static void -file_buff_write( FileBuff buff, const void* src, int len ) -{ - while (len > 0) { - int avail = sizeof(buff->data) - buff->count; - if (avail > len) - avail = len; - - memcpy( buff->data + buff->count, src, avail ); - len -= avail; - src = (char*)src + avail; - - buff->count += avail; - if (buff->count == FILE_BUFF_SIZE) { - unix_write( buff->fd, buff->data, buff->count ); - buff->count = 0; - } - } -} - -static void -file_buff_done( FileBuff buff ) -{ - if (buff->count > 0) { - unix_write( buff->fd, buff->data, buff->count ); - buff->count = 0; - } -} - -static void -log_header(void) -{ - FILE* out; - char cmdline[1024]; - char uname[128]; - char cpuinfo[128]; - char* cpu; - char date[32]; - time_t now_t = time(NULL); - struct tm now = *localtime(&now_t); - strftime(date, sizeof(date), "%x %X", &now); - - out = fopen( LOG_HEADER, "w" ); - if (out == NULL) - return; - - proc_read("/proc/cmdline", cmdline, sizeof(cmdline)); - proc_read("/proc/version", uname, sizeof(uname)); - proc_read("/proc/cpuinfo", cpuinfo, sizeof(cpuinfo)); - - cpu = strchr( cpuinfo, ':' ); - if (cpu) { - char* p = strchr(cpu, '\n'); - cpu += 2; - if (p) - *p = 0; - } - - fprintf(out, "version = %s\n", VERSION); - fprintf(out, "title = Boot chart for Android ( %s )\n", date); - fprintf(out, "system.uname = %s\n", uname); - fprintf(out, "system.release = 0.0\n"); - fprintf(out, "system.cpu = %s\n", cpu); - fprintf(out, "system.kernel.options = %s\n", cmdline); - fclose(out); -} - -static void -close_on_exec(int fd) -{ - fcntl(fd, F_SETFD, FD_CLOEXEC); -} - -static void -open_log_file(int* plogfd, const char* logfile) -{ - int logfd = *plogfd; - - /* create log file if needed */ - if (logfd < 0) - { - logfd = open(logfile,O_WRONLY|O_CREAT|O_TRUNC,0755); - if (logfd < 0) { - *plogfd = -2; - return; - } - close_on_exec(logfd); - *plogfd = logfd; - } -} - -static void -do_log_uptime(FileBuff log) -{ - char buff[65]; - int fd, ret, len; - - fd = open("/proc/uptime",O_RDONLY); - if (fd >= 0) { - int ret; - ret = unix_read(fd, buff, 64); - close(fd); - buff[64] = 0; - if (ret >= 0) { - long long jiffies = 100LL*strtod(buff,NULL); - int len; - snprintf(buff,sizeof(buff),"%lld\n",jiffies); - len = strlen(buff); - file_buff_write(log, buff, len); - } - } -} - -static void -do_log_ln(FileBuff log) -{ - file_buff_write(log, "\n", 1); -} - - -static void -do_log_file(FileBuff log, const char* procfile) -{ - char buff[1024]; - int fd; - - do_log_uptime(log); - - /* append file content */ - fd = open(procfile,O_RDONLY); - if (fd >= 0) { - close_on_exec(fd); - for (;;) { - int ret; - ret = unix_read(fd, buff, sizeof(buff)); - if (ret <= 0) - break; - - file_buff_write(log, buff, ret); - if (ret < (int)sizeof(buff)) - break; - } - close(fd); - } - - do_log_ln(log); -} - -static void -do_log_procs(FileBuff log) -{ - DIR* dir = opendir("/proc"); - struct dirent* entry; - - do_log_uptime(log); - - while ((entry = readdir(dir)) != NULL) { - /* only match numeric values */ - char* end; - int pid = strtol( entry->d_name, &end, 10); - if (end != NULL && end > entry->d_name && *end == 0) { - char filename[32]; - char buff[1024]; - char cmdline[1024]; - int len; - int fd; - - /* read command line and extract program name */ - snprintf(filename,sizeof(filename),"/proc/%d/cmdline",pid); - proc_read(filename, cmdline, sizeof(cmdline)); - - /* read process stat line */ - snprintf(filename,sizeof(filename),"/proc/%d/stat",pid); - fd = open(filename,O_RDONLY); - if (fd >= 0) { - len = unix_read(fd, buff, sizeof(buff)-1); - close(fd); - if (len > 0) { - int len2 = strlen(cmdline); - if (len2 > 0) { - /* we want to substitute the process name with its real name */ - const char* p1; - const char* p2; - buff[len] = 0; - p1 = strchr(buff, '('); - p2 = strchr(p1, ')'); - file_buff_write(log, buff, p1+1-buff); - file_buff_write(log, cmdline, strlen(cmdline)); - file_buff_write(log, p2, strlen(p2)); - } else { - /* no substitution */ - file_buff_write(log,buff,len); - } - } - } - } - } - closedir(dir); - do_log_ln(log); -} - -static FileBuffRec log_stat[1]; -static FileBuffRec log_procs[1]; -static FileBuffRec log_disks[1]; - -/* called to setup bootcharting */ -int bootchart_init( void ) -{ - int ret; - char buff[4]; - int timeout = 0, count = 0; - - buff[0] = 0; - proc_read( LOG_STARTFILE, buff, sizeof(buff) ); - if (buff[0] != 0) { - timeout = atoi(buff); - } - else { - /* when running with emulator, androidboot.bootchart=<timeout> - * might be passed by as kernel parameters to specify the bootchart - * timeout. this is useful when using -wipe-data since the /data - * partition is fresh - */ - char cmdline[1024]; - char* s; -#define KERNEL_OPTION "androidboot.bootchart=" - proc_read( "/proc/cmdline", cmdline, sizeof(cmdline) ); - s = strstr(cmdline, KERNEL_OPTION); - if (s) { - s += sizeof(KERNEL_OPTION)-1; - timeout = atoi(s); - } - } - if (timeout == 0) - return 0; - - if (timeout > BOOTCHART_MAX_TIME_SEC) - timeout = BOOTCHART_MAX_TIME_SEC; - - count = (timeout*1000 + BOOTCHART_POLLING_MS-1)/BOOTCHART_POLLING_MS; - - do {ret=mkdir(LOG_ROOT,0755);}while (ret < 0 && errno == EINTR); - - file_buff_open(log_stat, LOG_STAT); - file_buff_open(log_procs, LOG_PROCS); - file_buff_open(log_disks, LOG_DISK); - - /* create kernel process accounting file */ - { - int fd = open( LOG_ACCT, O_WRONLY|O_CREAT|O_TRUNC,0644); - if (fd >= 0) { - close(fd); - acct( LOG_ACCT ); - } - } - - log_header(); - return count; -} - -/* called each time you want to perform a bootchart sampling op */ -int bootchart_step( void ) -{ - do_log_file(log_stat, "/proc/stat"); - do_log_file(log_disks, "/proc/diskstats"); - do_log_procs(log_procs); - - /* we stop when /data/bootchart-stop contains 1 */ - { - char buff[2]; - if (proc_read(LOG_STOPFILE,buff,sizeof(buff)) > 0 && buff[0] == '1') { - return -1; - } - } - - return 0; -} - -void bootchart_finish( void ) -{ - unlink( LOG_STOPFILE ); - file_buff_done(log_stat); - file_buff_done(log_disks); - file_buff_done(log_procs); - acct(NULL); -} diff --git a/init/bootchart.cpp b/init/bootchart.cpp new file mode 100644 index 0000000..95687cb --- /dev/null +++ b/init/bootchart.cpp @@ -0,0 +1,273 @@ +/* + * 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 "bootchart.h" +#include "keywords.h" +#include "log.h" +#include "property_service.h" + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/utsname.h> +#include <time.h> +#include <unistd.h> + +#include <memory> +#include <string> + +#include <base/file.h> + +#define LOG_ROOT "/data/bootchart" +#define LOG_STAT LOG_ROOT"/proc_stat.log" +#define LOG_PROCS LOG_ROOT"/proc_ps.log" +#define LOG_DISK LOG_ROOT"/proc_diskstats.log" +#define LOG_HEADER LOG_ROOT"/header" +#define LOG_ACCT LOG_ROOT"/kernel_pacct" + +#define LOG_STARTFILE LOG_ROOT"/start" +#define LOG_STOPFILE LOG_ROOT"/stop" + +// Polling period in ms. +static const int BOOTCHART_POLLING_MS = 200; + +// Max polling time in seconds. +static const int BOOTCHART_MAX_TIME_SEC = 10*60; + +static long long g_last_bootchart_time; +static int g_remaining_samples; + +static FILE* log_stat; +static FILE* log_procs; +static FILE* log_disks; + +static long long get_uptime_jiffies() { + std::string uptime; + if (!android::base::ReadFileToString("/proc/uptime", &uptime)) { + return 0; + } + return 100LL * strtod(uptime.c_str(), NULL); +} + +static void log_header() { + char date[32]; + time_t now_t = time(NULL); + struct tm now = *localtime(&now_t); + strftime(date, sizeof(date), "%F %T", &now); + + utsname uts; + if (uname(&uts) == -1) { + return; + } + + char fingerprint[PROP_VALUE_MAX]; + if (property_get("ro.build.fingerprint", fingerprint) == -1) { + return; + } + + std::string kernel_cmdline; + android::base::ReadFileToString("/proc/cmdline", &kernel_cmdline); + + FILE* out = fopen(LOG_HEADER, "we"); + if (out == NULL) { + return; + } + fprintf(out, "version = Android init 0.8 " __TIME__ "\n"); + fprintf(out, "title = Boot chart for Android (%s)\n", date); + fprintf(out, "system.uname = %s %s %s %s\n", uts.sysname, uts.release, uts.version, uts.machine); + fprintf(out, "system.release = %s\n", fingerprint); + // TODO: use /proc/cpuinfo "model name" line for x86, "Processor" line for arm. + fprintf(out, "system.cpu = %s\n", uts.machine); + fprintf(out, "system.kernel.options = %s\n", kernel_cmdline.c_str()); + fclose(out); +} + +static void do_log_uptime(FILE* log) { + fprintf(log, "%lld\n", get_uptime_jiffies()); +} + +static void do_log_file(FILE* log, const char* procfile) { + do_log_uptime(log); + + std::string content; + if (android::base::ReadFileToString(procfile, &content)) { + fprintf(log, "%s\n", content.c_str()); + } +} + +static void do_log_procs(FILE* log) { + do_log_uptime(log); + + std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir("/proc"), closedir); + struct dirent* entry; + while ((entry = readdir(dir.get())) != NULL) { + // Only match numeric values. + char* end; + int pid = strtol(entry->d_name, &end, 10); + if (end != NULL && end > entry->d_name && *end == 0) { + char filename[32]; + + // /proc/<pid>/stat only has truncated task names, so get the full + // name from /proc/<pid>/cmdline. + snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid); + std::string cmdline; + android::base::ReadFileToString(filename, &cmdline); + const char* full_name = cmdline.c_str(); // So we stop at the first NUL. + + // Read process stat line. + snprintf(filename, sizeof(filename), "/proc/%d/stat", pid); + std::string stat; + if (android::base::ReadFileToString(filename, &stat)) { + if (!cmdline.empty()) { + // Substitute the process name with its real name. + size_t open = stat.find('('); + size_t close = stat.find_last_of(')'); + if (open != std::string::npos && close != std::string::npos) { + stat.replace(open + 1, close - open - 1, full_name); + } + } + fputs(stat.c_str(), log); + } + } + } + + fputc('\n', log); +} + +static int bootchart_init() { + int timeout = 0; + + std::string start; + android::base::ReadFileToString(LOG_STARTFILE, &start); + if (!start.empty()) { + timeout = atoi(start.c_str()); + } else { + // When running with emulator, androidboot.bootchart=<timeout> + // might be passed by as kernel parameters to specify the bootchart + // timeout. this is useful when using -wipe-data since the /data + // partition is fresh. + std::string cmdline; + android::base::ReadFileToString("/proc/cmdline", &cmdline); +#define KERNEL_OPTION "androidboot.bootchart=" + if (strstr(cmdline.c_str(), KERNEL_OPTION) != NULL) { + timeout = atoi(cmdline.c_str() + sizeof(KERNEL_OPTION) - 1); + } + } + if (timeout == 0) + return 0; + + if (timeout > BOOTCHART_MAX_TIME_SEC) + timeout = BOOTCHART_MAX_TIME_SEC; + + int count = (timeout*1000 + BOOTCHART_POLLING_MS-1)/BOOTCHART_POLLING_MS; + + log_stat = fopen(LOG_STAT, "we"); + if (log_stat == NULL) { + return -1; + } + log_procs = fopen(LOG_PROCS, "we"); + if (log_procs == NULL) { + fclose(log_stat); + return -1; + } + log_disks = fopen(LOG_DISK, "we"); + if (log_disks == NULL) { + fclose(log_stat); + fclose(log_procs); + return -1; + } + + // Create kernel process accounting file. + close(open(LOG_ACCT, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644)); + acct(LOG_ACCT); + + log_header(); + return count; +} + +int do_bootchart_init(int nargs, char** args) { + g_remaining_samples = bootchart_init(); + if (g_remaining_samples < 0) { + ERROR("Bootcharting init failure: %s\n", strerror(errno)); + } else if (g_remaining_samples > 0) { + NOTICE("Bootcharting started (will run for %d s).\n", + (g_remaining_samples * BOOTCHART_POLLING_MS) / 1000); + } else { + NOTICE("Not bootcharting.\n"); + } + return 0; +} + +static int bootchart_step() { + do_log_file(log_stat, "/proc/stat"); + do_log_file(log_disks, "/proc/diskstats"); + do_log_procs(log_procs); + + // Stop if /data/bootchart/stop contains 1. + std::string stop; + if (android::base::ReadFileToString(LOG_STOPFILE, &stop) && stop == "1") { + return -1; + } + + return 0; +} + +/* called to get time (in ms) used by bootchart */ +static long long bootchart_gettime() { + return 10LL*get_uptime_jiffies(); +} + +static void bootchart_finish() { + unlink(LOG_STOPFILE); + fclose(log_stat); + fclose(log_disks); + fclose(log_procs); + acct(NULL); +} + +void bootchart_sample(int* timeout) { + // Do we have any more bootcharting to do? + if (g_remaining_samples <= 0) { + return; + } + + long long current_time = bootchart_gettime(); + int elapsed_time = current_time - g_last_bootchart_time; + + if (elapsed_time >= BOOTCHART_POLLING_MS) { + /* count missed samples */ + while (elapsed_time >= BOOTCHART_POLLING_MS) { + elapsed_time -= BOOTCHART_POLLING_MS; + g_remaining_samples--; + } + /* count may be negative, take a sample anyway */ + g_last_bootchart_time = current_time; + if (bootchart_step() < 0 || g_remaining_samples <= 0) { + bootchart_finish(); + g_remaining_samples = 0; + } + } + if (g_remaining_samples > 0) { + int remaining_time = BOOTCHART_POLLING_MS - elapsed_time; + if (*timeout < 0 || *timeout > remaining_time) { + *timeout = remaining_time; + } + } +} diff --git a/init/bootchart.h b/init/bootchart.h index 39d2d4f..cf61d83 100644 --- a/init/bootchart.h +++ b/init/bootchart.h @@ -17,20 +17,6 @@ #ifndef _BOOTCHART_H #define _BOOTCHART_H -#ifndef BOOTCHART -# define BOOTCHART 0 -#endif - -#if BOOTCHART - -extern int bootchart_init(void); -extern int bootchart_step(void); -extern void bootchart_finish(void); - -# define BOOTCHART_POLLING_MS 200 /* polling period in ms */ -# define BOOTCHART_DEFAULT_TIME_SEC (2*60) /* default polling time in seconds */ -# define BOOTCHART_MAX_TIME_SEC (10*60) /* max polling time in seconds */ - -#endif /* BOOTCHART */ +void bootchart_sample(int* timeout); #endif /* _BOOTCHART_H */ diff --git a/init/builtins.c b/init/builtins.cpp index c192551..4567b04 100644 --- a/init/builtins.c +++ b/init/builtins.cpp @@ -14,30 +14,32 @@ * limitations under the License. */ -#include <sys/types.h> -#include <sys/stat.h> +#include <errno.h> #include <fcntl.h> -#include <unistd.h> -#include <string.h> +#include <net/if.h> #include <stdio.h> -#include <linux/kd.h> -#include <errno.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <linux/if.h> -#include <arpa/inet.h> #include <stdlib.h> +#include <string.h> +#include <sys/socket.h> #include <sys/mount.h> #include <sys/resource.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> #include <sys/wait.h> +#include <unistd.h> #include <linux/loop.h> -#include <cutils/partition_utils.h> -#include <cutils/android_reboot.h> -#include <fs_mgr.h> +#include <ext4_crypt.h> #include <selinux/selinux.h> #include <selinux/label.h> +#include <fs_mgr.h> +#include <base/stringprintf.h> +#include <cutils/partition_utils.h> +#include <cutils/android_reboot.h> +#include <private/android_filesystem_config.h> + #include "init.h" #include "keywords.h" #include "property_service.h" @@ -46,121 +48,22 @@ #include "util.h" #include "log.h" -#include <private/android_filesystem_config.h> +#define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW int add_environment(const char *name, const char *value); -extern int init_module(void *, unsigned long, const char *); - -static int write_file(const char *path, const char *value) -{ - int fd, ret, len; - - fd = open(path, O_WRONLY|O_CREAT|O_NOFOLLOW, 0600); - - if (fd < 0) - return -errno; - - len = strlen(value); - - do { - ret = write(fd, value, len); - } while (ret < 0 && errno == EINTR); - - close(fd); - if (ret < 0) { - return -errno; - } else { - return 0; - } -} - -static int _open(const char *path) -{ - int fd; - - fd = open(path, O_RDONLY | O_NOFOLLOW); - if (fd < 0) - fd = open(path, O_WRONLY | O_NOFOLLOW); - - return fd; -} - -static int _chown(const char *path, unsigned int uid, unsigned int gid) -{ - int fd; - int ret; - - fd = _open(path); - if (fd < 0) { - return -1; - } - - ret = fchown(fd, uid, gid); - if (ret < 0) { - int errno_copy = errno; - close(fd); - errno = errno_copy; - return -1; - } - - close(fd); - - return 0; -} - -static int _chmod(const char *path, mode_t mode) -{ - int fd; - int ret; - - fd = _open(path); - if (fd < 0) { - return -1; - } - - ret = fchmod(fd, mode); - if (ret < 0) { - int errno_copy = errno; - close(fd); - errno = errno_copy; - return -1; - } - - close(fd); - - return 0; -} +// System call provided by bionic but not in any header file. +extern "C" int init_module(void *, unsigned long, const char *); static int insmod(const char *filename, char *options) { - void *module; - unsigned size; - int ret; - - module = read_file(filename, &size); - if (!module) + std::string module; + if (!read_file(filename, &module)) { return -1; + } - ret = init_module(module, size, options); - - free(module); - - return ret; -} - -static int setkey(struct kbentry *kbe) -{ - int fd, ret; - - fd = open("/dev/tty0", O_RDWR | O_SYNC); - if (fd < 0) - return -1; - - ret = ioctl(fd, KDSKBENT, kbe); - - close(fd); - return ret; + // TODO: use finit_module for >= 3.8 kernels. + return init_module(&module[0], module.size(), options); } static int __ifupdown(const char *interface, int up) @@ -185,7 +88,7 @@ static int __ifupdown(const char *interface, int up) ifr.ifr_flags &= ~IFF_UP; ret = ioctl(s, SIOCSIFFLAGS, &ifr); - + done: close(s); return ret; @@ -200,18 +103,6 @@ static void service_start_if_not_disabled(struct service *svc) } } -int do_chdir(int nargs, char **args) -{ - chdir(args[1]); - return 0; -} - -int do_chroot(int nargs, char **args) -{ - chroot(args[1]); - return 0; -} - int do_class_start(int nargs, char **args) { /* Starting a class does not start services @@ -254,9 +145,13 @@ int do_enable(int nargs, char **args) return 0; } -int do_exec(int nargs, char **args) -{ - return -1; +int do_exec(int nargs, char** args) { + service* svc = make_exec_oneshot_service(nargs, args); + if (svc == NULL) { + return -1; + } + service_start(svc, NULL); + return 0; } int do_export(int nargs, char **args) @@ -319,7 +214,7 @@ int do_mkdir(int nargs, char **args) ret = make_dir(args[1], mode); /* chmod in case the directory already exists */ if (ret == -1 && errno == EEXIST) { - ret = _chmod(args[1], mode); + ret = fchmodat(AT_FDCWD, args[1], mode, AT_SYMLINK_NOFOLLOW); } if (ret == -1) { return -errno; @@ -333,20 +228,20 @@ int do_mkdir(int nargs, char **args) gid = decode_uid(args[4]); } - if (_chown(args[1], uid, gid) < 0) { + if (lchown(args[1], uid, gid) == -1) { return -errno; } /* chown may have cleared S_ISUID and S_ISGID, chmod again */ if (mode & (S_ISUID | S_ISGID)) { - ret = _chmod(args[1], mode); + ret = fchmodat(AT_FDCWD, args[1], mode, AT_SYMLINK_NOFOLLOW); if (ret == -1) { return -errno; } } } - return 0; + return e4crypt_set_directory_policy(args[1]); } static struct { @@ -410,7 +305,7 @@ int do_mount(int nargs, char **args) return -1; } - sprintf(tmp, "/dev/block/mtdblock%d", n); + snprintf(tmp, sizeof(tmp), "/dev/block/mtdblock%d", n); if (wait) wait_for_file(tmp, COMMAND_RETRY_TIMEOUT); @@ -424,15 +319,16 @@ int do_mount(int nargs, char **args) struct loop_info info; mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR; - fd = open(source + 5, mode); + fd = open(source + 5, mode | O_CLOEXEC); if (fd < 0) { return -1; } for (n = 0; ; n++) { - sprintf(tmp, "/dev/block/loop%d", n); - loop = open(tmp, mode); + snprintf(tmp, sizeof(tmp), "/dev/block/loop%d", n); + loop = open(tmp, mode | O_CLOEXEC); if (loop < 0) { + close(fd); return -1; } @@ -476,7 +372,7 @@ exit_success: static int wipe_data_via_recovery() { mkdir("/cache/recovery", 0700); - int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC, 0600); + int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0600); if (fd >= 0) { write(fd, "--wipe_data\n", strlen("--wipe_data\n") + 1); write(fd, "--reason=wipe_data_via_recovery\n", strlen("--reason=wipe_data_via_recovery\n") + 1); @@ -489,6 +385,17 @@ static int wipe_data_via_recovery() while (1) { pause(); } // never reached } +/* + * Callback to make a directory from the ext4 code + */ +static int do_mount_alls_make_dir(const char* dir) +{ + if (make_dir(dir, 0700) && errno != EEXIST) { + return -1; + } + + return 0; +} /* * This function might request a reboot, in which case it will @@ -500,7 +407,6 @@ int do_mount_all(int nargs, char **args) int ret = -1; int child_ret = -1; int status; - const char *prop; struct fstab *fstab; if (nargs != 2) { @@ -519,7 +425,7 @@ int do_mount_all(int nargs, char **args) int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); if (wp_ret < 0) { /* Unexpected error code. We will continue anyway. */ - NOTICE("waitpid failed rc=%d, errno=%d\n", wp_ret, errno); + NOTICE("waitpid failed rc=%d: %s\n", wp_ret, strerror(errno)); } if (WIFEXITED(status)) { @@ -558,6 +464,37 @@ int do_mount_all(int nargs, char **args) ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n"); ret = wipe_data_via_recovery(); /* If reboot worked, there is no return. */ + } else if (ret == FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED) { + // We have to create the key files here. Only init can call make_dir, + // and we can't do it from fs_mgr as then fs_mgr would depend on + // make_dir creating a circular dependency. + fstab = fs_mgr_read_fstab(args[1]); + for (int i = 0; i < fstab->num_entries; ++i) { + if (fs_mgr_is_file_encrypted(&fstab->recs[i])) { + if (e4crypt_create_device_key(fstab->recs[i].mount_point, + do_mount_alls_make_dir)) { + ERROR("Could not create device key on %s" + " - continue unencrypted\n", + fstab->recs[i].mount_point); + } + } + } + fs_mgr_free_fstab(fstab); + + if (e4crypt_install_keyring()) { + return -1; + } + property_set("ro.crypto.state", "encrypted"); + + // Although encrypted, we have device key, so we do not need to + // do anything different from the nonencrypted case. + action_for_each_trigger("nonencrypted", action_add_queue_tail); + } else if (ret == FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED) { + if (e4crypt_install_keyring()) { + return -1; + } + property_set("ro.crypto.state", "encrypted"); + property_set("vold.decrypt", "trigger_restart_min_framework"); } else if (ret > 0) { ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret); } @@ -578,33 +515,6 @@ int do_swapon_all(int nargs, char **args) return ret; } -int do_setcon(int nargs, char **args) { - if (is_selinux_enabled() <= 0) - return 0; - if (setcon(args[1]) < 0) { - return -errno; - } - return 0; -} - -int do_setenforce(int nargs, char **args) { - if (is_selinux_enabled() <= 0) - return 0; - if (security_setenforce(atoi(args[1])) < 0) { - return -errno; - } - return 0; -} - -int do_setkey(int nargs, char **args) -{ - struct kbentry kbe; - kbe.kb_table = strtoul(args[1], 0, 0); - kbe.kb_index = strtoul(args[2], 0, 0); - kbe.kb_value = strtoul(args[3], 0, 0); - return setkey(&kbe); -} - int do_setprop(int nargs, char **args) { const char *name = args[1]; @@ -667,7 +577,7 @@ int do_powerctl(int nargs, char **args) int res; int len = 0; int cmd = 0; - char *reboot_target; + const char *reboot_target; res = expand_props(command, args[1], sizeof(command)); if (res) { @@ -727,25 +637,41 @@ int do_sysclktz(int nargs, char **args) return -1; memset(&tz, 0, sizeof(tz)); - tz.tz_minuteswest = atoi(args[1]); + tz.tz_minuteswest = atoi(args[1]); if (settimeofday(NULL, &tz)) return -1; return 0; } +int do_verity_load_state(int nargs, char **args) { + int mode = -1; + int rc = fs_mgr_load_verity_state(&mode); + if (rc == 0 && mode == VERITY_MODE_LOGGING) { + action_for_each_trigger("verity-logging", action_add_queue_tail); + } + return rc; +} + +static void verity_update_property(fstab_rec *fstab, const char *mount_point, int mode, int status) { + property_set(android::base::StringPrintf("partition.%s.verified", mount_point).c_str(), + android::base::StringPrintf("%d", mode).c_str()); +} + +int do_verity_update_state(int nargs, char** args) { + return fs_mgr_update_verity_state(verity_update_property); +} + int do_write(int nargs, char **args) { const char *path = args[1]; const char *value = args[2]; - char prop_val[PROP_VALUE_MAX]; - int ret; - ret = expand_props(prop_val, value, sizeof(prop_val)); - if (ret) { + char expanded_value[256]; + if (expand_props(expanded_value, value, sizeof(expanded_value))) { ERROR("cannot expand '%s' while writing to '%s'\n", value, path); return -EINVAL; } - return write_file(path, prop_val); + return write_file(path, expanded_value); } int do_copy(int nargs, char **args) @@ -760,16 +686,16 @@ int do_copy(int nargs, char **args) if (nargs != 3) return -1; - if (stat(args[1], &info) < 0) + if (stat(args[1], &info) < 0) return -1; - if ((fd1 = open(args[1], O_RDONLY)) < 0) + if ((fd1 = open(args[1], O_RDONLY|O_CLOEXEC)) < 0) goto out_err; - if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0) + if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0660)) < 0) goto out_err; - if (!(buffer = malloc(info.st_size))) + if (!(buffer = (char*) malloc(info.st_size))) goto out_err; p = buffer; @@ -813,10 +739,10 @@ out: int do_chown(int nargs, char **args) { /* GID is optional. */ if (nargs == 3) { - if (_chown(args[2], decode_uid(args[1]), -1) < 0) + if (lchown(args[2], decode_uid(args[1]), -1) == -1) return -errno; } else if (nargs == 4) { - if (_chown(args[3], decode_uid(args[1]), decode_uid(args[2])) < 0) + if (lchown(args[3], decode_uid(args[1]), decode_uid(args[2])) == -1) return -errno; } else { return -1; @@ -839,7 +765,7 @@ static mode_t get_mode(const char *s) { int do_chmod(int nargs, char **args) { mode_t mode = get_mode(args[1]); - if (_chmod(args[2], mode) < 0) { + if (fchmodat(AT_FDCWD, args[2], mode, AT_SYMLINK_NOFOLLOW) < 0) { return -errno; } return 0; @@ -867,34 +793,6 @@ int do_restorecon_recursive(int nargs, char **args) { return ret; } -int do_setsebool(int nargs, char **args) { - const char *name = args[1]; - const char *value = args[2]; - SELboolean b; - int ret; - - if (is_selinux_enabled() <= 0) - return 0; - - b.name = name; - if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on")) - b.value = 1; - else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off")) - b.value = 0; - else { - ERROR("setsebool: invalid value %s\n", value); - return -EINVAL; - } - - if (security_set_boolean_list(1, &b, 0) < 0) { - ret = -errno; - ERROR("setsebool: could not set %s to %s\n", name, value); - return ret; - } - - return 0; -} - int do_loglevel(int nargs, char **args) { int log_level; char log_level_str[PROP_VALUE_MAX] = ""; @@ -941,3 +839,12 @@ int do_wait(int nargs, char **args) } else return -1; } + +int do_installkey(int nargs, char **args) +{ + if (nargs == 2) { + return e4crypt_install_key(args[1]); + } + + return -1; +} diff --git a/init/devices.c b/init/devices.cpp index 73fe223..4944cec 100644 --- a/init/devices.c +++ b/init/devices.cpp @@ -48,12 +48,10 @@ #include "util.h" #include "log.h" -#define UNUSED __attribute__((__unused__)) - #define SYSFS_PREFIX "/sys" -#define FIRMWARE_DIR1 "/etc/firmware" -#define FIRMWARE_DIR2 "/vendor/firmware" -#define FIRMWARE_DIR3 "/firmware/image" +static const char *firmware_dirs[] = { "/etc/firmware", + "/vendor/firmware", + "/firmware/image" }; extern struct selabel_handle *sehandle; @@ -101,7 +99,7 @@ int add_dev_perms(const char *name, const char *attr, mode_t perm, unsigned int uid, unsigned int gid, unsigned short prefix, unsigned short wildcard) { - struct perm_node *node = calloc(1, sizeof(*node)); + struct perm_node *node = (perm_node*) calloc(1, sizeof(*node)); if (!node) return -ENOMEM; @@ -154,7 +152,7 @@ void fixup_sys_perms(const char *upath) if ((strlen(upath) + strlen(dp->attr) + 6) > sizeof(buf)) break; - sprintf(buf,"/sys%s/%s", upath, dp->attr); + snprintf(buf, sizeof(buf), "/sys%s/%s", upath, dp->attr); INFO("fixup %s %d %d 0%o\n", buf, dp->uid, dp->gid, dp->perm); chown(buf, dp->uid, dp->gid); chmod(buf, dp->perm); @@ -191,7 +189,6 @@ static bool perm_path_matches(const char *path, struct perms_ *dp) static mode_t get_device_perm(const char *path, const char **links, unsigned *uid, unsigned *gid) { - mode_t perm; struct listnode *node; struct perm_node *perm_node; struct perms_ *dp; @@ -232,7 +229,7 @@ static mode_t get_device_perm(const char *path, const char **links, } static void make_device(const char *path, - const char *upath UNUSED, + const char */*upath*/, int block, int major, int minor, const char **links) { @@ -269,7 +266,6 @@ static void make_device(const char *path, static void add_platform_device(const char *path) { int path_len = strlen(path); - struct listnode *node; struct platform_node *bus; const char *name = path; @@ -279,18 +275,9 @@ static void add_platform_device(const char *path) name += 9; } - list_for_each_reverse(node, &platform_names) { - bus = node_to_item(node, struct platform_node, list); - if ((bus->path_len < path_len) && - (path[bus->path_len] == '/') && - !strncmp(path, bus->path, bus->path_len)) - /* subdevice of an existing platform, ignore it */ - return; - } - INFO("adding platform device %s (%s)\n", name, path); - bus = calloc(1, sizeof(struct platform_node)); + bus = (platform_node*) calloc(1, sizeof(struct platform_node)); bus->path = strdup(path); bus->path_len = path_len; bus->name = bus->path + (name - path); @@ -367,24 +354,6 @@ static int find_pci_device_prefix(const char *path, char *buf, ssize_t buf_sz) return 0; } -#if LOG_UEVENTS - -static inline suseconds_t get_usecs(void) -{ - struct timeval tv; - gettimeofday(&tv, 0); - return tv.tv_sec * (suseconds_t) 1000000 + tv.tv_usec; -} - -#define log_event_print(x...) INFO(x) - -#else - -#define log_event_print(fmt, args...) do { } while (0) -#define get_usecs() 0 - -#endif - static void parse_event(const char *msg, struct uevent *uevent) { uevent->action = ""; @@ -433,9 +402,11 @@ static void parse_event(const char *msg, struct uevent *uevent) ; } - log_event_print("event { '%s', '%s', '%s', '%s', %d, %d }\n", - uevent->action, uevent->path, uevent->subsystem, - uevent->firmware, uevent->major, uevent->minor); + if (LOG_UEVENTS) { + INFO("event { '%s', '%s', '%s', '%s', %d, %d }\n", + uevent->action, uevent->path, uevent->subsystem, + uevent->firmware, uevent->major, uevent->minor); + } } static char **get_character_device_symlinks(struct uevent *uevent) @@ -451,14 +422,14 @@ static char **get_character_device_symlinks(struct uevent *uevent) if (!pdev) return NULL; - links = malloc(sizeof(char *) * 2); + links = (char**) malloc(sizeof(char *) * 2); if (!links) return NULL; memset(links, 0, sizeof(char *) * 2); /* skip "/devices/platform/<driver>" */ parent = strchr(uevent->path + pdev->path_len, '/'); - if (!*parent) + if (!parent) goto err; if (!strncmp(parent, "/usb", 4)) { @@ -497,15 +468,10 @@ static char **get_block_device_symlinks(struct uevent *uevent) struct platform_node *pdev; char *slash; const char *type; - int width; char buf[256]; char link_path[256]; - int fd; int link_num = 0; - int ret; char *p; - unsigned int size; - struct stat info; pdev = find_platform_device(uevent->path); if (pdev) { @@ -518,7 +484,7 @@ static char **get_block_device_symlinks(struct uevent *uevent) return NULL; } - char **links = malloc(sizeof(char *) * 4); + char **links = (char**) malloc(sizeof(char *) * 4); if (!links) return NULL; memset(links, 0, sizeof(char *) * 4); @@ -667,14 +633,9 @@ static void mkdir_recursive_for_devpath(const char *devpath) mkdir_recursive(dir, 0755); } -static inline void __attribute__((__deprecated__)) kernel_logger() -{ - INFO("kernel logger is deprecated\n"); -} - static void handle_generic_device_event(struct uevent *uevent) { - char *base; + const char *base; const char *name; char devpath[DEVPATH_LEN] = {0}; char **links = NULL; @@ -758,7 +719,7 @@ static void handle_generic_device_event(struct uevent *uevent) make_dir(base, 0755); } else if(!strncmp(uevent->subsystem, "misc", 4) && !strncmp(name, "log_", 4)) { - kernel_logger(); + INFO("kernel logger is deprecated\n"); base = "/dev/log/"; make_dir(base, 0755); name += 4; @@ -840,8 +801,9 @@ static int is_booting(void) static void process_firmware_event(struct uevent *uevent) { - char *root, *loading, *data, *file1 = NULL, *file2 = NULL, *file3 = NULL; + char *root, *loading, *data; int l, loading_fd, data_fd, fw_fd; + size_t i; int booting = is_booting(); INFO("firmware: loading '%s' for '%s'\n", @@ -859,62 +821,49 @@ static void process_firmware_event(struct uevent *uevent) if (l == -1) goto loading_free_out; - l = asprintf(&file1, FIRMWARE_DIR1"/%s", uevent->firmware); - if (l == -1) - goto data_free_out; - - l = asprintf(&file2, FIRMWARE_DIR2"/%s", uevent->firmware); - if (l == -1) - goto data_free_out; - - l = asprintf(&file3, FIRMWARE_DIR3"/%s", uevent->firmware); - if (l == -1) - goto data_free_out; - - loading_fd = open(loading, O_WRONLY); + loading_fd = open(loading, O_WRONLY|O_CLOEXEC); if(loading_fd < 0) - goto file_free_out; + goto data_free_out; - data_fd = open(data, O_WRONLY); + data_fd = open(data, O_WRONLY|O_CLOEXEC); if(data_fd < 0) goto loading_close_out; try_loading_again: - fw_fd = open(file1, O_RDONLY); - if(fw_fd < 0) { - fw_fd = open(file2, O_RDONLY); - if (fw_fd < 0) { - fw_fd = open(file3, O_RDONLY); - if (fw_fd < 0) { - if (booting) { - /* If we're not fully booted, we may be missing - * filesystems needed for firmware, wait and retry. - */ - usleep(100000); - booting = is_booting(); - goto try_loading_again; - } - INFO("firmware: could not open '%s' %d\n", uevent->firmware, errno); - write(loading_fd, "-1", 2); - goto data_close_out; - } + for (i = 0; i < ARRAY_SIZE(firmware_dirs); i++) { + char *file = NULL; + l = asprintf(&file, "%s/%s", firmware_dirs[i], uevent->firmware); + if (l == -1) + goto data_free_out; + fw_fd = open(file, O_RDONLY|O_CLOEXEC); + free(file); + if (fw_fd >= 0) { + if(!load_firmware(fw_fd, loading_fd, data_fd)) + INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware); + else + INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware); + break; } } - - if(!load_firmware(fw_fd, loading_fd, data_fd)) - INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware); - else - INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware); + if (fw_fd < 0) { + if (booting) { + /* If we're not fully booted, we may be missing + * filesystems needed for firmware, wait and retry. + */ + usleep(100000); + booting = is_booting(); + goto try_loading_again; + } + INFO("firmware: could not open '%s': %s\n", uevent->firmware, strerror(errno)); + write(loading_fd, "-1", 2); + goto data_close_out; + } close(fw_fd); data_close_out: close(data_fd); loading_close_out: close(loading_fd); -file_free_out: - free(file1); - free(file2); - free(file3); data_free_out: free(data); loading_free_out: @@ -926,7 +875,6 @@ root_free_out: static void handle_firmware_event(struct uevent *uevent) { pid_t pid; - int ret; if(strcmp(uevent->subsystem, "firmware")) return; @@ -938,7 +886,9 @@ static void handle_firmware_event(struct uevent *uevent) pid = fork(); if (!pid) { process_firmware_event(uevent); - exit(EXIT_SUCCESS); + _exit(EXIT_SUCCESS); + } else if (pid < 0) { + ERROR("could not fork to process firmware event: %s\n", strerror(errno)); } } @@ -977,7 +927,7 @@ void handle_device_fd() ** ** We drain any pending events from the netlink socket every time ** we poke another uevent file to make sure we don't overrun the -** socket's buffer. +** socket's buffer. */ static void do_coldboot(DIR *d) @@ -1023,12 +973,7 @@ static void coldboot(const char *path) } } -void device_init(void) -{ - suseconds_t t0, t1; - struct stat info; - int fd; - +void device_init() { sehandle = NULL; if (is_selinux_enabled() > 0) { sehandle = selinux_android_file_context_handle(); @@ -1037,24 +982,22 @@ void device_init(void) /* is 256K enough? udev uses 16MB! */ device_fd = uevent_open_socket(256*1024, true); - if(device_fd < 0) + if (device_fd == -1) { return; - - fcntl(device_fd, F_SETFD, FD_CLOEXEC); + } fcntl(device_fd, F_SETFL, O_NONBLOCK); - if (stat(coldboot_done, &info) < 0) { - t0 = get_usecs(); - coldboot("/sys/class"); - coldboot("/sys/block"); - coldboot("/sys/devices"); - t1 = get_usecs(); - fd = open(coldboot_done, O_WRONLY|O_CREAT, 0000); - close(fd); - log_event_print("coldboot %ld uS\n", ((long) (t1 - t0))); - } else { - log_event_print("skipping coldboot, already done\n"); + if (access(COLDBOOT_DONE, F_OK) == 0) { + NOTICE("Skipping coldboot, already done!\n"); + return; } + + Timer t; + coldboot("/sys/class"); + coldboot("/sys/block"); + coldboot("/sys/devices"); + close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000)); + NOTICE("Coldboot took %.2fs.\n", t.duration()); } int get_device_fd() diff --git a/init/devices.h b/init/devices.h index 5d0fe88..6cb0a77 100644 --- a/init/devices.h +++ b/init/devices.h @@ -26,4 +26,5 @@ extern int add_dev_perms(const char *name, const char *attr, unsigned int gid, unsigned short prefix, unsigned short wildcard); int get_device_fd(); + #endif /* _INIT_DEVICES_H */ diff --git a/init/grab-bootchart.sh b/init/grab-bootchart.sh index 7fe8904..d6082aa 100755 --- a/init/grab-bootchart.sh +++ b/init/grab-bootchart.sh @@ -1,10 +1,9 @@ #!/bin/sh # -# this script is used to retrieve the bootchart log generated -# by init when compiled with INIT_BOOTCHART=true. -# -# for all details, see //device/system/init/README.BOOTCHART -# +# This script is used to retrieve a bootchart log generated by init. +# All options are passed to adb, for better or for worse. +# See the readme in this directory for more on bootcharting. + TMPDIR=/tmp/android-bootchart rm -rf $TMPDIR mkdir -p $TMPDIR @@ -15,8 +14,9 @@ TARBALL=bootchart.tgz FILES="header proc_stat.log proc_ps.log proc_diskstats.log kernel_pacct" for f in $FILES; do - adb pull $LOGROOT/$f $TMPDIR/$f 2>&1 > /dev/null + adb "${@}" pull $LOGROOT/$f $TMPDIR/$f 2>&1 > /dev/null done (cd $TMPDIR && tar -czf $TARBALL $FILES) -cp -f $TMPDIR/$TARBALL ./$TARBALL -echo "look at $TARBALL" +bootchart ${TMPDIR}/${TARBALL} +gnome-open ${TARBALL%.tgz}.png +echo "Clean up ${TMPDIR}/ and ./${TARBALL%.tgz}.png when done" diff --git a/init/init.c b/init/init.cpp index bd1db7a..dd74538 100644 --- a/init/init.c +++ b/init/init.cpp @@ -14,37 +14,43 @@ * limitations under the License. */ +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <libgen.h> +#include <paths.h> +#include <signal.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <ctype.h> -#include <signal.h> -#include <sys/wait.h> +#include <sys/epoll.h> #include <sys/mount.h> +#include <sys/socket.h> #include <sys/stat.h> -#include <sys/poll.h> -#include <errno.h> -#include <stdarg.h> -#include <mtd/mtd-user.h> #include <sys/types.h> -#include <sys/socket.h> #include <sys/un.h> +#include <sys/wait.h> +#include <termios.h> +#include <unistd.h> + +#include <mtd/mtd-user.h> #include <selinux/selinux.h> #include <selinux/label.h> #include <selinux/android.h> -#include <libgen.h> - -#include <cutils/list.h> +#include <base/file.h> +#include <base/stringprintf.h> #include <cutils/android_reboot.h> -#include <cutils/sockets.h> -#include <cutils/iosched_policy.h> #include <cutils/fs.h> +#include <cutils/iosched_policy.h> +#include <cutils/list.h> +#include <cutils/sockets.h> #include <private/android_filesystem_config.h> -#include <termios.h> + +#include <memory> #include "devices.h" #include "init.h" @@ -63,29 +69,10 @@ struct selabel_handle *sehandle_prop; static int property_triggers_enabled = 0; -#if BOOTCHART -static int bootchart_count; -#endif - -static char console[32]; -static char bootmode[32]; -static char hardware[32]; -static unsigned revision = 0; static char qemu[32]; static struct action *cur_action = NULL; static struct command *cur_command = NULL; -static struct listnode *command_queue = NULL; - -void notify_service_state(const char *name, const char *state) -{ - char pname[PROP_NAME_MAX]; - int len = strlen(name); - if ((len + 10) > PROP_NAME_MAX) - return; - snprintf(pname, sizeof(pname), "init.svc.%s", name); - property_set(pname, state); -} static int have_console; static char console_name[PROP_VALUE_MAX] = "/dev/console"; @@ -93,6 +80,40 @@ static time_t process_needs_restart; static const char *ENV[32]; +bool waiting_for_exec = false; + +static int epoll_fd = -1; + +void register_epoll_handler(int fd, void (*fn)()) { + epoll_event ev; + ev.events = EPOLLIN; + ev.data.ptr = reinterpret_cast<void*>(fn); + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) { + ERROR("epoll_ctl failed: %s\n", strerror(errno)); + } +} + +void service::NotifyStateChange(const char* new_state) { + if (!properties_initialized()) { + // If properties aren't available yet, we can't set them. + return; + } + + if ((flags & SVC_EXEC) != 0) { + // 'exec' commands don't have properties tracking their state. + return; + } + + char prop_name[PROP_NAME_MAX]; + if (snprintf(prop_name, sizeof(prop_name), "init.svc.%s", name) >= PROP_NAME_MAX) { + // If the property name would be too long, we can't set it. + ERROR("Property name \"init.svc.%s\" too long; not setting to %s\n", name, new_state); + return; + } + + property_set(prop_name, new_state); +} + /* add_environment - add "key=value" to the current environment */ int add_environment(const char *key, const char *val) { @@ -113,9 +134,8 @@ int add_environment(const char *key, const char *val) /* Add entry if a free slot is available */ if (ENV[n] == NULL) { - size_t len = key_len + strlen(val) + 2; - char *entry = malloc(len); - snprintf(entry, len, "%s=%s", key, val); + char* entry; + asprintf(&entry, "%s=%s", key, val); ENV[n] = entry; return 0; } @@ -126,7 +146,7 @@ int add_environment(const char *key, const char *val) return -1; } -static void zap_stdio(void) +void zap_stdio(void) { int fd; fd = open("/dev/null", O_RDWR); @@ -166,36 +186,26 @@ static void publish_socket(const char *name, int fd) void service_start(struct service *svc, const char *dynamic_args) { - struct stat s; - pid_t pid; - int needs_console; - int n; - char *scon = NULL; - int rc; - - /* starting a service removes it from the disabled or reset - * state and immediately takes it out of the restarting - * state if it was in there - */ + // Starting a service removes it from the disabled or reset state and + // immediately takes it out of the restarting state if it was in there. svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START)); svc->time_started = 0; - /* running processes require no additional work -- if - * they're in the process of exiting, we've ensured - * that they will immediately restart on exit, unless - * they are ONESHOT - */ + // Running processes require no additional work --- if they're in the + // process of exiting, we've ensured that they will immediately restart + // on exit, unless they are ONESHOT. if (svc->flags & SVC_RUNNING) { return; } - needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0; - if (needs_console && (!have_console)) { + bool needs_console = (svc->flags & SVC_CONSOLE); + if (needs_console && !have_console) { ERROR("service '%s' requires console\n", svc->name); svc->flags |= SVC_DISABLED; return; } + struct stat s; if (stat(svc->args[0], &s) != 0) { ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name); svc->flags |= SVC_DISABLED; @@ -209,6 +219,7 @@ void service_start(struct service *svc, const char *dynamic_args) return; } + char* scon = NULL; if (is_selinux_enabled() > 0) { if (svc->seclabel) { scon = strdup(svc->seclabel); @@ -220,7 +231,7 @@ void service_start(struct service *svc, const char *dynamic_args) char *mycon = NULL, *fcon = NULL; INFO("computing context for service '%s'\n", svc->args[0]); - rc = getcon(&mycon); + int rc = getcon(&mycon); if (rc < 0) { ERROR("could not get context while starting '%s'\n", svc->name); return; @@ -246,10 +257,9 @@ void service_start(struct service *svc, const char *dynamic_args) } } - NOTICE("starting '%s'\n", svc->name); - - pid = fork(); + NOTICE("Starting service '%s'...\n", svc->name); + pid_t pid = fork(); if (pid == 0) { struct socketinfo *si; struct svcenvinfo *ei; @@ -257,9 +267,9 @@ void service_start(struct service *svc, const char *dynamic_args) int fd, sz; umask(077); - if (properties_inited()) { + if (properties_initialized()) { get_property_workspace(&fd, &sz); - sprintf(tmp, "%d,%d", dup(fd), sz); + snprintf(tmp, sizeof(tmp), "%d,%d", dup(fd), sz); add_environment("ANDROID_PROPERTY_WORKSPACE", tmp); } @@ -294,18 +304,18 @@ void service_start(struct service *svc, const char *dynamic_args) zap_stdio(); } -#if 0 - for (n = 0; svc->args[n]; n++) { - INFO("args[%d] = '%s'\n", n, svc->args[n]); - } - for (n = 0; ENV[n]; n++) { - INFO("env[%d] = '%s'\n", n, ENV[n]); + if (false) { + for (size_t n = 0; svc->args[n]; n++) { + INFO("args[%zu] = '%s'\n", n, svc->args[n]); + } + for (size_t n = 0; ENV[n]; n++) { + INFO("env[%zu] = '%s'\n", n, ENV[n]); + } } -#endif setpgid(0, getpid()); - /* as requested, set our gid, supplemental gids, and uid */ + // As requested, set our gid, supplemental gids, and uid. if (svc->gid) { if (setgid(svc->gid) != 0) { ERROR("setgid failed: %s\n", strerror(errno)); @@ -350,7 +360,7 @@ void service_start(struct service *svc, const char *dynamic_args) if (arg_idx == INIT_PARSER_MAXARGS) break; } - arg_ptrs[arg_idx] = '\0'; + arg_ptrs[arg_idx] = NULL; execve(svc->args[0], (char**) arg_ptrs, (char**) ENV); } _exit(127); @@ -368,8 +378,13 @@ void service_start(struct service *svc, const char *dynamic_args) svc->pid = pid; svc->flags |= SVC_RUNNING; - if (properties_inited()) - notify_service_state(svc->name, "running"); + if ((svc->flags & SVC_EXEC) != 0) { + INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n", + svc->pid, svc->uid, svc->gid, svc->nr_supp_gids, svc->seclabel); + waiting_for_exec = true; + } + + svc->NotifyStateChange("running"); } /* The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART */ @@ -393,11 +408,11 @@ static void service_stop_or_reset(struct service *svc, int how) } if (svc->pid) { - NOTICE("service '%s' is being killed\n", svc->name); + NOTICE("Service '%s' is being killed...\n", svc->name); kill(-svc->pid, SIGKILL); - notify_service_state(svc->name, "stopping"); + svc->NotifyStateChange("stopping"); } else { - notify_service_state(svc->name, "stopped"); + svc->NotifyStateChange("stopped"); } } @@ -541,47 +556,74 @@ static int is_last_command(struct action *act, struct command *cmd) return (list_tail(&act->commands) == &cmd->clist); } -void execute_one_command(void) -{ - int ret, i; + +void build_triggers_string(char *name_str, int length, struct action *cur_action) { + struct listnode *node; + struct trigger *cur_trigger; + + list_for_each(node, &cur_action->triggers) { + cur_trigger = node_to_item(node, struct trigger, nlist); + if (node != cur_action->triggers.next) { + strlcat(name_str, " " , length); + } + strlcat(name_str, cur_trigger->name , length); + } +} + +void execute_one_command() { + Timer t; + char cmd_str[256] = ""; + char name_str[256] = ""; if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) { cur_action = action_remove_queue_head(); cur_command = NULL; - if (!cur_action) + if (!cur_action) { return; - INFO("processing action %p (%s)\n", cur_action, cur_action->name); + } + + build_triggers_string(name_str, sizeof(name_str), cur_action); + + INFO("processing action %p (%s)\n", cur_action, name_str); cur_command = get_first_command(cur_action); } else { cur_command = get_next_command(cur_action, cur_command); } - if (!cur_command) + if (!cur_command) { return; + } - ret = cur_command->func(cur_command->nargs, cur_command->args); + int result = cur_command->func(cur_command->nargs, cur_command->args); if (klog_get_level() >= KLOG_INFO_LEVEL) { - for (i = 0; i < cur_command->nargs; i++) { + for (int i = 0; i < cur_command->nargs; i++) { strlcat(cmd_str, cur_command->args[i], sizeof(cmd_str)); if (i < cur_command->nargs - 1) { strlcat(cmd_str, " ", sizeof(cmd_str)); } } - INFO("command '%s' action=%s status=%d (%s:%d)\n", - cmd_str, cur_action ? cur_action->name : "", ret, cur_command->filename, - cur_command->line); + char source[256]; + if (cur_command->filename) { + snprintf(source, sizeof(source), " (%s:%d)", cur_command->filename, cur_command->line); + } else { + *source = '\0'; + } + INFO("Command '%s' action=%s%s returned %d took %.2fs\n", + cmd_str, cur_action ? name_str : "", source, result, t.duration()); } } -static int wait_for_coldboot_done_action(int nargs, char **args) -{ - int ret; - INFO("wait for %s\n", coldboot_done); - ret = wait_for_file(coldboot_done, COMMAND_RETRY_TIMEOUT); - if (ret) - ERROR("Timed out waiting for %s\n", coldboot_done); - return ret; +static int wait_for_coldboot_done_action(int nargs, char **args) { + Timer t; + + NOTICE("Waiting for %s...\n", COLDBOOT_DONE); + if (wait_for_file(COLDBOOT_DONE, COMMAND_RETRY_TIMEOUT)) { + ERROR("Timed out waiting for %s\n", COLDBOOT_DONE); + } + + NOTICE("Waiting for %s took %.2fs.\n", COLDBOOT_DONE, t.duration()); + return 0; } /* @@ -609,7 +651,7 @@ static int mix_hwrng_into_linux_rng_action(int nargs, char **args) size_t total_bytes_written = 0; hwrandom_fd = TEMP_FAILURE_RETRY( - open("/dev/hw_random", O_RDONLY | O_NOFOLLOW)); + open("/dev/hw_random", O_RDONLY | O_NOFOLLOW | O_CLOEXEC)); if (hwrandom_fd == -1) { if (errno == ENOENT) { ERROR("/dev/hw_random not found\n"); @@ -622,7 +664,7 @@ static int mix_hwrng_into_linux_rng_action(int nargs, char **args) } urandom_fd = TEMP_FAILURE_RETRY( - open("/dev/urandom", O_WRONLY | O_NOFOLLOW)); + open("/dev/urandom", O_WRONLY | O_NOFOLLOW | O_CLOEXEC)); if (urandom_fd == -1) { ERROR("Failed to open /dev/urandom: %s\n", strerror(errno)); goto ret; @@ -658,7 +700,6 @@ ret: if (urandom_fd != -1) { close(urandom_fd); } - memset(buf, 0, sizeof(buf)); return result; } @@ -670,18 +711,17 @@ static int keychord_init_action(int nargs, char **args) static int console_init_action(int nargs, char **args) { - int fd; - - if (console[0]) { + char console[PROP_VALUE_MAX]; + if (property_get("ro.boot.console", console) > 0) { snprintf(console_name, sizeof(console_name), "/dev/%s", console); } - fd = open(console_name, O_RDWR); + int fd = open(console_name, O_RDWR | O_CLOEXEC); if (fd >= 0) have_console = 1; close(fd); - fd = open("/dev/tty0", O_WRONLY); + fd = open("/dev/tty0", O_WRONLY | O_CLOEXEC); if (fd >= 0) { const char *msg; msg = "\n" @@ -706,7 +746,7 @@ static int console_init_action(int nargs, char **args) return 0; } -static void import_kernel_nv(char *name, int for_emulator) +static void import_kernel_nv(char *name, bool for_emulator) { char *value = strchr(name, '='); int name_len = strlen(name); @@ -739,55 +779,56 @@ static void import_kernel_nv(char *name, int for_emulator) } } -static void export_kernel_boot_props(void) -{ - char tmp[PROP_VALUE_MAX]; - int ret; - unsigned i; +static void export_kernel_boot_props() { struct { const char *src_prop; - const char *dest_prop; - const char *def_val; + const char *dst_prop; + const char *default_value; } prop_map[] = { - { "ro.boot.serialno", "ro.serialno", "", }, - { "ro.boot.mode", "ro.bootmode", "unknown", }, - { "ro.boot.baseband", "ro.baseband", "unknown", }, + { "ro.boot.serialno", "ro.serialno", "", }, + { "ro.boot.mode", "ro.bootmode", "unknown", }, + { "ro.boot.baseband", "ro.baseband", "unknown", }, { "ro.boot.bootloader", "ro.bootloader", "unknown", }, + { "ro.boot.hardware", "ro.hardware", "unknown", }, + { "ro.boot.revision", "ro.revision", "0", }, }; + for (size_t i = 0; i < ARRAY_SIZE(prop_map); i++) { + char value[PROP_VALUE_MAX]; + int rc = property_get(prop_map[i].src_prop, value); + property_set(prop_map[i].dst_prop, (rc > 0) ? value : prop_map[i].default_value); + } +} - for (i = 0; i < ARRAY_SIZE(prop_map); i++) { - ret = property_get(prop_map[i].src_prop, tmp); - if (ret > 0) - property_set(prop_map[i].dest_prop, tmp); - else - property_set(prop_map[i].dest_prop, prop_map[i].def_val); +static void process_kernel_dt(void) +{ + static const char android_dir[] = "/proc/device-tree/firmware/android"; + + std::string file_name = android::base::StringPrintf("%s/compatible", android_dir); + + std::string dt_file; + android::base::ReadFileToString(file_name, &dt_file); + if (!dt_file.compare("android,firmware")) { + ERROR("firmware/android is not compatible with 'android,firmware'\n"); + return; } - ret = property_get("ro.boot.console", tmp); - if (ret) - strlcpy(console, tmp, sizeof(console)); - - /* save a copy for init's usage during boot */ - property_get("ro.bootmode", tmp); - strlcpy(bootmode, tmp, sizeof(bootmode)); - - /* if this was given on kernel command line, override what we read - * before (e.g. from /proc/cpuinfo), if anything */ - ret = property_get("ro.boot.hardware", tmp); - if (ret) - strlcpy(hardware, tmp, sizeof(hardware)); - property_set("ro.hardware", hardware); - - snprintf(tmp, PROP_VALUE_MAX, "%d", revision); - property_set("ro.revision", tmp); - - /* TODO: these are obsolete. We should delete them */ - if (!strcmp(bootmode,"factory")) - property_set("ro.factorytest", "1"); - else if (!strcmp(bootmode,"factory2")) - property_set("ro.factorytest", "2"); - else - property_set("ro.factorytest", "0"); + std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dir), closedir); + if (!dir) + return; + + struct dirent *dp; + while ((dp = readdir(dir.get())) != NULL) { + if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible")) + continue; + + file_name = android::base::StringPrintf("%s/%s", android_dir, dp->d_name); + + android::base::ReadFileToString(file_name, &dt_file); + std::replace(dt_file.begin(), dt_file.end(), ',', '.'); + + std::string property_name = android::base::StringPrintf("ro.boot.%s", dp->d_name); + property_set(property_name.c_str(), dt_file.c_str()); + } } static void process_kernel_cmdline(void) @@ -799,40 +840,9 @@ static void process_kernel_cmdline(void) * second pass is only necessary for qemu to export all kernel params * as props. */ - import_kernel_cmdline(0, import_kernel_nv); + import_kernel_cmdline(false, import_kernel_nv); if (qemu[0]) - import_kernel_cmdline(1, import_kernel_nv); - - /* now propogate the info given on command line to internal variables - * used by init as well as the current required properties - */ - export_kernel_boot_props(); -} - -static int property_service_init_action(int nargs, char **args) -{ - /* read any property files on system or data and - * fire up the property service. This must happen - * after the ro.foo properties are set above so - * that /data/local.prop cannot interfere with them. - */ - start_property_service(); - if (get_property_set_fd() < 0) { - ERROR("start_property_service() failed\n"); - exit(1); - } - - return 0; -} - -static int signal_init_action(int nargs, char **args) -{ - signal_init(); - if (get_signal_fd() < 0) { - ERROR("signal_init() failed\n"); - exit(1); - } - return 0; + import_kernel_cmdline(true, import_kernel_nv); } static int queue_property_triggers_action(int nargs, char **args) @@ -843,90 +853,55 @@ static int queue_property_triggers_action(int nargs, char **args) return 0; } -#if BOOTCHART -static int bootchart_init_action(int nargs, char **args) +static void selinux_init_all_handles(void) { - bootchart_count = bootchart_init(); - if (bootchart_count < 0) { - ERROR("bootcharting init failure\n"); - } else if (bootchart_count > 0) { - NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS); - } else { - NOTICE("bootcharting ignored\n"); - } - - return 0; + sehandle = selinux_android_file_context_handle(); + selinux_android_set_sehandle(sehandle); + sehandle_prop = selinux_android_prop_context_handle(); } -#endif -static const struct selinux_opt seopts_prop[] = { - { SELABEL_OPT_PATH, "/property_contexts" }, - { SELABEL_OPT_PATH, "/data/security/current/property_contexts" }, - { 0, NULL } -}; +enum selinux_enforcing_status { SELINUX_DISABLED, SELINUX_PERMISSIVE, SELINUX_ENFORCING }; -struct selabel_handle* selinux_android_prop_context_handle(void) -{ - int policy_index = selinux_android_use_data_policy() ? 1 : 0; - struct selabel_handle* sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP, - &seopts_prop[policy_index], 1); - if (!sehandle) { - ERROR("SELinux: Could not load property_contexts: %s\n", - strerror(errno)); - return NULL; - } - INFO("SELinux: Loaded property contexts from %s\n", seopts_prop[policy_index].value); - return sehandle; -} +static selinux_enforcing_status selinux_status_from_cmdline() { + selinux_enforcing_status status = SELINUX_ENFORCING; -void selinux_init_all_handles(void) -{ - sehandle = selinux_android_file_context_handle(); - selinux_android_set_sehandle(sehandle); - sehandle_prop = selinux_android_prop_context_handle(); + std::function<void(char*,bool)> fn = [&](char* name, bool in_qemu) { + char *value = strchr(name, '='); + if (value == nullptr) { return; } + *value++ = '\0'; + if (strcmp(name, "androidboot.selinux") == 0) { + if (strcmp(value, "disabled") == 0) { + status = SELINUX_DISABLED; + } else if (strcmp(value, "permissive") == 0) { + status = SELINUX_PERMISSIVE; + } + } + }; + import_kernel_cmdline(false, fn); + + return status; } + static bool selinux_is_disabled(void) { -#ifdef ALLOW_DISABLE_SELINUX - char tmp[PROP_VALUE_MAX]; - - if (access("/sys/fs/selinux", F_OK) != 0) { - /* SELinux is not compiled into the kernel, or has been disabled - * via the kernel command line "selinux=0". - */ - return true; - } - - if ((property_get("ro.boot.selinux", tmp) != 0) && (strcmp(tmp, "disabled") == 0)) { - /* SELinux is compiled into the kernel, but we've been told to disable it. */ - return true; + if (ALLOW_DISABLE_SELINUX) { + if (access("/sys/fs/selinux", F_OK) != 0) { + // SELinux is not compiled into the kernel, or has been disabled + // via the kernel command line "selinux=0". + return true; + } + return selinux_status_from_cmdline() == SELINUX_DISABLED; } -#endif return false; } static bool selinux_is_enforcing(void) { -#ifdef ALLOW_DISABLE_SELINUX - char tmp[PROP_VALUE_MAX]; - - if (property_get("ro.boot.selinux", tmp) == 0) { - /* Property is not set. Assume enforcing */ - return true; - } - - if (strcmp(tmp, "permissive") == 0) { - /* SELinux is in the kernel, but we've been told to go into permissive mode */ - return false; - } - - if (strcmp(tmp, "enforcing") != 0) { - ERROR("SELinux: Unknown value of ro.boot.selinux. Got: \"%s\". Assuming enforcing.\n", tmp); + if (ALLOW_DISABLE_SELINUX) { + return selinux_status_from_cmdline() == SELINUX_ENFORCING; } - -#endif return true; } @@ -952,223 +927,196 @@ int selinux_reload_policy(void) return 0; } -static int audit_callback(void *data, security_class_t cls __attribute__((unused)), char *buf, size_t len) -{ +static int audit_callback(void *data, security_class_t /*cls*/, char *buf, size_t len) { snprintf(buf, len, "property=%s", !data ? "NULL" : (char *)data); return 0; } -int log_callback(int type, const char *fmt, ...) -{ - int level; - va_list ap; - switch (type) { - case SELINUX_WARNING: - level = KLOG_WARNING_LEVEL; - break; - case SELINUX_INFO: - level = KLOG_INFO_LEVEL; - break; - default: - level = KLOG_ERROR_LEVEL; - break; - } - va_start(ap, fmt); - klog_vwrite(level, fmt, ap); - va_end(ap); - return 0; +static void security_failure() { + ERROR("Security failure; rebooting into recovery mode...\n"); + android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); + while (true) { pause(); } // never reached } -static void selinux_initialize(void) -{ +static void selinux_initialize(bool in_kernel_domain) { + Timer t; + + selinux_callback cb; + cb.func_log = selinux_klog_callback; + selinux_set_callback(SELINUX_CB_LOG, cb); + cb.func_audit = audit_callback; + selinux_set_callback(SELINUX_CB_AUDIT, cb); + if (selinux_is_disabled()) { return; } - INFO("loading selinux policy\n"); - if (selinux_android_load_policy() < 0) { - ERROR("SELinux: Failed to load policy; rebooting into recovery mode\n"); - android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); - while (1) { pause(); } // never reached - } + if (in_kernel_domain) { + INFO("Loading SELinux policy...\n"); + if (selinux_android_load_policy() < 0) { + ERROR("failed to load policy: %s\n", strerror(errno)); + security_failure(); + } - selinux_init_all_handles(); - bool is_enforcing = selinux_is_enforcing(); - INFO("SELinux: security_setenforce(%d)\n", is_enforcing); - security_setenforce(is_enforcing); + bool is_enforcing = selinux_is_enforcing(); + security_setenforce(is_enforcing); + + if (write_file("/sys/fs/selinux/checkreqprot", "0") == -1) { + security_failure(); + } + + NOTICE("(Initializing SELinux %s took %.2fs.)\n", + is_enforcing ? "enforcing" : "non-enforcing", t.duration()); + } else { + selinux_init_all_handles(); + } } -int main(int argc, char **argv) -{ - int fd_count = 0; - struct pollfd ufds[4]; - char *tmpdev; - char* debuggable; - char tmp[32]; - int property_set_fd_init = 0; - int signal_fd_init = 0; - int keychord_fd_init = 0; - bool is_charger = false; - - if (!strcmp(basename(argv[0]), "ueventd")) +int main(int argc, char** argv) { + if (!strcmp(basename(argv[0]), "ueventd")) { return ueventd_main(argc, argv); + } - if (!strcmp(basename(argv[0]), "watchdogd")) + if (!strcmp(basename(argv[0]), "watchdogd")) { return watchdogd_main(argc, argv); + } - /* clear the umask */ + // Clear the umask. umask(0); - /* Get the basic filesystem setup we need put - * together in the initramdisk on / and then we'll - * let the rc file figure out the rest. - */ - mkdir("/dev", 0755); - mkdir("/proc", 0755); - mkdir("/sys", 0755); - - mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); - mkdir("/dev/pts", 0755); - mkdir("/dev/socket", 0755); - mount("devpts", "/dev/pts", "devpts", 0, NULL); - mount("proc", "/proc", "proc", 0, NULL); - mount("sysfs", "/sys", "sysfs", 0, NULL); - - /* indicate that booting is in progress to background fw loaders, etc */ - close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000)); - - /* We must have some place other than / to create the - * device nodes for kmsg and null, otherwise we won't - * be able to remount / read-only later on. - * Now that tmpfs is mounted on /dev, we can actually - * talk to the outside world. - */ + add_environment("PATH", _PATH_DEFPATH); + + bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0); + + // Get the basic filesystem setup we need put together in the initramdisk + // on / and then we'll let the rc file figure out the rest. + if (is_first_stage) { + mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); + mkdir("/dev/pts", 0755); + mkdir("/dev/socket", 0755); + mount("devpts", "/dev/pts", "devpts", 0, NULL); + mount("proc", "/proc", "proc", 0, NULL); + mount("sysfs", "/sys", "sysfs", 0, NULL); + } + + // We must have some place other than / to create the device nodes for + // kmsg and null, otherwise we won't be able to remount / read-only + // later on. Now that tmpfs is mounted on /dev, we can actually talk + // to the outside world. open_devnull_stdio(); klog_init(); - property_init(); + klog_set_level(KLOG_NOTICE_LEVEL); - get_hardware_name(hardware, &revision); + NOTICE("init%s started!\n", is_first_stage ? "" : " second stage"); - process_kernel_cmdline(); + if (!is_first_stage) { + // Indicate that booting is in progress to background fw loaders, etc. + close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000)); - union selinux_callback cb; - cb.func_log = log_callback; - selinux_set_callback(SELINUX_CB_LOG, cb); + property_init(); - cb.func_audit = audit_callback; - selinux_set_callback(SELINUX_CB_AUDIT, cb); + // If arguments are passed both on the command line and in DT, + // properties set in DT always have priority over the command-line ones. + process_kernel_dt(); + process_kernel_cmdline(); - selinux_initialize(); - /* These directories were necessarily created before initial policy load - * and therefore need their security context restored to the proper value. - * This must happen before /dev is populated by ueventd. - */ + // Propogate the kernel variables to internal variables + // used by init as well as the current required properties. + export_kernel_boot_props(); + } + + // Set up SELinux, including loading the SELinux policy if we're in the kernel domain. + selinux_initialize(is_first_stage); + + // If we're in the kernel domain, re-exec init to transition to the init domain now + // that the SELinux policy has been loaded. + if (is_first_stage) { + if (restorecon("/init") == -1) { + ERROR("restorecon failed: %s\n", strerror(errno)); + security_failure(); + } + char* path = argv[0]; + char* args[] = { path, const_cast<char*>("--second-stage"), nullptr }; + if (execv(path, args) == -1) { + ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno)); + security_failure(); + } + } + + // These directories were necessarily created before initial policy load + // and therefore need their security context restored to the proper value. + // This must happen before /dev is populated by ueventd. + INFO("Running restorecon...\n"); restorecon("/dev"); restorecon("/dev/socket"); restorecon("/dev/__properties__"); restorecon_recursive("/sys"); - is_charger = !strcmp(bootmode, "charger"); + epoll_fd = epoll_create1(EPOLL_CLOEXEC); + if (epoll_fd == -1) { + ERROR("epoll_create1 failed: %s\n", strerror(errno)); + exit(1); + } + + signal_handler_init(); - INFO("property init\n"); property_load_boot_defaults(); + start_property_service(); - INFO("reading config file\n"); init_parse_config_file("/init.rc"); action_for_each_trigger("early-init", action_add_queue_tail); + // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev... queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done"); + // ... so that we can start queuing up actions that require stuff from /dev. queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng"); queue_builtin_action(keychord_init_action, "keychord_init"); queue_builtin_action(console_init_action, "console_init"); - /* execute all the boot actions to get us started */ + // Trigger all the boot actions to get us started. action_for_each_trigger("init", action_add_queue_tail); - /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random - * wasn't ready immediately after wait_for_coldboot_done - */ + // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random + // wasn't ready immediately after wait_for_coldboot_done queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng"); - queue_builtin_action(property_service_init_action, "property_service_init"); - queue_builtin_action(signal_init_action, "signal_init"); - /* Don't mount filesystems or start core system services if in charger mode. */ - if (is_charger) { + // Don't mount filesystems or start core system services in charger mode. + char bootmode[PROP_VALUE_MAX]; + if (property_get("ro.bootmode", bootmode) > 0 && strcmp(bootmode, "charger") == 0) { action_for_each_trigger("charger", action_add_queue_tail); } else { action_for_each_trigger("late-init", action_add_queue_tail); } - /* run all property triggers based on current state of the properties */ + // Run all property triggers based on current state of the properties. queue_builtin_action(queue_property_triggers_action, "queue_property_triggers"); - -#if BOOTCHART - queue_builtin_action(bootchart_init_action, "bootchart_init"); -#endif - - for(;;) { - int nr, i, timeout = -1; - - execute_one_command(); - restart_processes(); - - if (!property_set_fd_init && get_property_set_fd() > 0) { - ufds[fd_count].fd = get_property_set_fd(); - ufds[fd_count].events = POLLIN; - ufds[fd_count].revents = 0; - fd_count++; - property_set_fd_init = 1; - } - if (!signal_fd_init && get_signal_fd() > 0) { - ufds[fd_count].fd = get_signal_fd(); - ufds[fd_count].events = POLLIN; - ufds[fd_count].revents = 0; - fd_count++; - signal_fd_init = 1; - } - if (!keychord_fd_init && get_keychord_fd() > 0) { - ufds[fd_count].fd = get_keychord_fd(); - ufds[fd_count].events = POLLIN; - ufds[fd_count].revents = 0; - fd_count++; - keychord_fd_init = 1; + while (true) { + if (!waiting_for_exec) { + execute_one_command(); + restart_processes(); } + int timeout = -1; if (process_needs_restart) { timeout = (process_needs_restart - gettime()) * 1000; if (timeout < 0) timeout = 0; } - if (!action_queue_empty() || cur_action) + if (!action_queue_empty() || cur_action) { timeout = 0; - -#if BOOTCHART - if (bootchart_count > 0) { - if (timeout < 0 || timeout > BOOTCHART_POLLING_MS) - timeout = BOOTCHART_POLLING_MS; - if (bootchart_step() < 0 || --bootchart_count == 0) { - bootchart_finish(); - bootchart_count = 0; - } } -#endif - nr = poll(ufds, fd_count, timeout); - if (nr <= 0) - continue; + bootchart_sample(&timeout); - for (i = 0; i < fd_count; i++) { - if (ufds[i].revents & POLLIN) { - if (ufds[i].fd == get_property_set_fd()) - handle_property_set_fd(); - else if (ufds[i].fd == get_keychord_fd()) - handle_keychord(); - else if (ufds[i].fd == get_signal_fd()) - handle_signal(); - } + epoll_event ev; + int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout)); + if (nr == -1) { + ERROR("epoll_wait failed: %s\n", strerror(errno)); + } else if (nr == 1) { + ((void (*)()) ev.data.ptr)(); } } diff --git a/init/init.h b/init/init.h index a7615a3..1cabb14 100644 --- a/init/init.h +++ b/init/init.h @@ -17,11 +17,10 @@ #ifndef _INIT_INIT_H #define _INIT_INIT_H -#include <cutils/list.h> - -#include <sys/stat.h> +#include <sys/types.h> -void handle_control_message(const char *msg, const char *arg); +#include <cutils/list.h> +#include <cutils/iosched_policy.h> struct command { @@ -37,6 +36,11 @@ struct command char *args[1]; }; +struct trigger { + struct listnode nlist; + const char *name; +}; + struct action { /* node in list of all actions */ struct listnode alist; @@ -46,8 +50,9 @@ struct action { struct listnode tlist; unsigned hash; - const char *name; + /* list of actions which triggers the commands*/ + struct listnode triggers; struct listnode commands; struct command *current; }; @@ -68,27 +73,29 @@ struct svcenvinfo { const char *value; }; -#define SVC_DISABLED 0x01 /* do not autostart with class */ -#define SVC_ONESHOT 0x02 /* do not restart on exit */ -#define SVC_RUNNING 0x04 /* currently active */ -#define SVC_RESTARTING 0x08 /* waiting to restart */ -#define SVC_CONSOLE 0x10 /* requires console */ -#define SVC_CRITICAL 0x20 /* will reboot into recovery if keeps crashing */ -#define SVC_RESET 0x40 /* Use when stopping a process, but not disabling - so it can be restarted with its class */ -#define SVC_RC_DISABLED 0x80 /* Remember if the disabled flag was set in the rc script */ -#define SVC_RESTART 0x100 /* Use to safely restart (stop, wait, start) a service */ -#define SVC_DISABLED_START 0x200 /* a start was requested but it was disabled at the time */ +#define SVC_DISABLED 0x001 // do not autostart with class +#define SVC_ONESHOT 0x002 // do not restart on exit +#define SVC_RUNNING 0x004 // currently active +#define SVC_RESTARTING 0x008 // waiting to restart +#define SVC_CONSOLE 0x010 // requires console +#define SVC_CRITICAL 0x020 // will reboot into recovery if keeps crashing +#define SVC_RESET 0x040 // Use when stopping a process, but not disabling so it can be restarted with its class. +#define SVC_RC_DISABLED 0x080 // Remember if the disabled flag was set in the rc script. +#define SVC_RESTART 0x100 // Use to safely restart (stop, wait, start) a service. +#define SVC_DISABLED_START 0x200 // A start was requested but it was disabled at the time. +#define SVC_EXEC 0x400 // This synthetic service corresponds to an 'exec'. #define NR_SVC_SUPP_GIDS 12 /* twelve supplementary groups */ #define COMMAND_RETRY_TIMEOUT 5 struct service { + void NotifyStateChange(const char* new_state); + /* list of all services */ struct listnode slist; - const char *name; + char *name; const char *classname; unsigned flags; @@ -96,25 +103,25 @@ struct service { time_t time_started; /* time of last start */ time_t time_crashed; /* first crash within inspection window */ int nr_crashed; /* number of times crashed within window */ - + uid_t uid; gid_t gid; gid_t supp_gids[NR_SVC_SUPP_GIDS]; size_t nr_supp_gids; - char *seclabel; + const char* seclabel; struct socketinfo *sockets; struct svcenvinfo *envvars; struct action onrestart; /* Actions to execute on restart. */ - + /* keycodes for triggering this service via /dev/keychord */ int *keycodes; int nkeycodes; int keychord_id; - int ioprio_class; + IoSchedClass ioprio_class; int ioprio_pri; int nargs; @@ -122,7 +129,13 @@ struct service { char *args[1]; }; /* ^-------'args' MUST be at the end of this struct! */ -void notify_service_state(const char *name, const char *state); +extern bool waiting_for_exec; +extern struct selabel_handle *sehandle; +extern struct selabel_handle *sehandle_prop; + +void build_triggers_string(char *name_str, int length, struct action *cur_action); + +void handle_control_message(const char *msg, const char *arg); struct service *service_find_by_name(const char *name); struct service *service_find_by_pid(pid_t pid); @@ -138,8 +151,10 @@ void service_restart(struct service *svc); void service_start(struct service *svc, const char *dynamic_args); void property_changed(const char *name, const char *value); -extern struct selabel_handle *sehandle; -extern struct selabel_handle *sehandle_prop; -extern int selinux_reload_policy(void); +int selinux_reload_policy(void); + +void zap_stdio(void); + +void register_epoll_handler(int fd, void (*fn)()); #endif /* _INIT_INIT_H */ diff --git a/init/init_parser.c b/init/init_parser.cpp index 6466db2..b76b04e 100644 --- a/init/init_parser.c +++ b/init/init_parser.cpp @@ -14,14 +14,16 @@ * limitations under the License. */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> +#include <ctype.h> +#include <errno.h> #include <fcntl.h> +#include <inttypes.h> #include <stdarg.h> -#include <string.h> #include <stddef.h> -#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> #include "init.h" #include "parser.h" @@ -73,14 +75,53 @@ static struct { #define kw_func(kw) (keyword_info[kw].func) #define kw_nargs(kw) (keyword_info[kw].nargs) +void dump_parser_state() { + if (false) { + struct listnode* node; + list_for_each(node, &service_list) { + service* svc = node_to_item(node, struct service, slist); + INFO("service %s\n", svc->name); + INFO(" class '%s'\n", svc->classname); + INFO(" exec"); + for (int n = 0; n < svc->nargs; n++) { + INFO(" '%s'", svc->args[n]); + } + INFO("\n"); + for (socketinfo* si = svc->sockets; si; si = si->next) { + INFO(" socket %s %s 0%o\n", si->name, si->type, si->perm); + } + } + + list_for_each(node, &action_list) { + action* act = node_to_item(node, struct action, alist); + INFO("on "); + char name_str[256] = ""; + build_triggers_string(name_str, sizeof(name_str), act); + INFO("%s", name_str); + INFO("\n"); + + struct listnode* node2; + list_for_each(node2, &act->commands) { + command* cmd = node_to_item(node2, struct command, clist); + INFO(" %p", cmd->func); + for (int n = 0; n < cmd->nargs; n++) { + INFO(" %s", cmd->args[n]); + } + INFO("\n"); + } + INFO("\n"); + } + } +} + static int lookup_keyword(const char *s) { switch (*s++) { + case 'b': + if (!strcmp(s, "ootchart_init")) return K_bootchart_init; + break; case 'c': - if (!strcmp(s, "opy")) return K_copy; - if (!strcmp(s, "apability")) return K_capability; - if (!strcmp(s, "hdir")) return K_chdir; - if (!strcmp(s, "hroot")) return K_chroot; + if (!strcmp(s, "opy")) return K_copy; if (!strcmp(s, "lass")) return K_class; if (!strcmp(s, "lass_start")) return K_class_start; if (!strcmp(s, "lass_stop")) return K_class_stop; @@ -110,6 +151,7 @@ static int lookup_keyword(const char *s) if (!strcmp(s, "fup")) return K_ifup; if (!strcmp(s, "nsmod")) return K_insmod; if (!strcmp(s, "mport")) return K_import; + if (!strcmp(s, "nstallkey")) return K_installkey; break; case 'k': if (!strcmp(s, "eycodes")) return K_keycodes; @@ -131,6 +173,7 @@ static int lookup_keyword(const char *s) break; case 'p': if (!strcmp(s, "owerctl")) return K_powerctl; + break; case 'r': if (!strcmp(s, "estart")) return K_restart; if (!strcmp(s, "estorecon")) return K_restorecon; @@ -141,13 +184,9 @@ static int lookup_keyword(const char *s) case 's': if (!strcmp(s, "eclabel")) return K_seclabel; if (!strcmp(s, "ervice")) return K_service; - if (!strcmp(s, "etcon")) return K_setcon; - if (!strcmp(s, "etenforce")) return K_setenforce; if (!strcmp(s, "etenv")) return K_setenv; - if (!strcmp(s, "etkey")) return K_setkey; if (!strcmp(s, "etprop")) return K_setprop; if (!strcmp(s, "etrlimit")) return K_setrlimit; - if (!strcmp(s, "etsebool")) return K_setsebool; if (!strcmp(s, "ocket")) return K_socket; if (!strcmp(s, "tart")) return K_start; if (!strcmp(s, "top")) return K_stop; @@ -161,6 +200,10 @@ static int lookup_keyword(const char *s) case 'u': if (!strcmp(s, "ser")) return K_user; break; + case 'v': + if (!strcmp(s, "erity_load_state")) return K_verity_load_state; + if (!strcmp(s, "erity_update_state")) return K_verity_update_state; + break; case 'w': if (!strcmp(s, "rite")) return K_write; if (!strcmp(s, "ait")) return K_wait; @@ -169,8 +212,7 @@ static int lookup_keyword(const char *s) return K_UNKNOWN; } -static void parse_line_no_op(struct parse_state *state, int nargs, char **args) -{ +static void parse_line_no_op(struct parse_state*, int, char**) { } static int push_chars(char **dst, int *len, const char *chars, int cnt) @@ -187,19 +229,14 @@ static int push_chars(char **dst, int *len, const char *chars, int cnt) int expand_props(char *dst, const char *src, int dst_size) { - int cnt = 0; char *dst_ptr = dst; const char *src_ptr = src; - int src_len; - int idx = 0; int ret = 0; int left = dst_size - 1; if (!src || !dst || dst_size == 0) return -1; - src_len = strlen(src); - /* - variables can either be $x.y or ${x.y}, in case they are only part * of the string. * - will accept $$ as a literal $. @@ -294,8 +331,7 @@ err: static void parse_import(struct parse_state *state, int nargs, char **args) { - struct listnode *import_list = state->priv; - struct import *import; + struct listnode *import_list = (listnode*) state->priv; char conf_file[PATH_MAX]; int ret; @@ -311,10 +347,10 @@ static void parse_import(struct parse_state *state, int nargs, char **args) return; } - import = calloc(1, sizeof(struct import)); + struct import* import = (struct import*) calloc(1, sizeof(struct import)); import->filename = strdup(conf_file); list_add_tail(import_list, &import->list); - INFO("found import '%s', adding to import list", import->filename); + INFO("Added '%s' to import list\n", import->filename); } static void parse_new_section(struct parse_state *state, int kw, @@ -344,7 +380,7 @@ static void parse_new_section(struct parse_state *state, int kw, state->parse_line = parse_line_no_op; } -static void parse_config(const char *fn, char *s) +static void parse_config(const char *fn, const std::string& data) { struct parse_state state; struct listnode import_list; @@ -355,7 +391,7 @@ static void parse_config(const char *fn, char *s) nargs = 0; state.filename = fn; state.line = 0; - state.ptr = s; + state.ptr = strdup(data.c_str()); // TODO: fix this code! state.nexttoken = 0; state.parse_line = parse_line_no_op; @@ -393,7 +429,6 @@ parser_done: struct import *import = node_to_item(node, struct import, list); int ret; - INFO("importing '%s'", import->filename); ret = init_parse_config_file(import->filename); if (ret) ERROR("could not import file '%s' from '%s'\n", @@ -401,14 +436,18 @@ parser_done: } } -int init_parse_config_file(const char *fn) -{ - char *data; - data = read_file(fn, 0); - if (!data) return -1; +int init_parse_config_file(const char* path) { + INFO("Parsing %s...\n", path); + Timer t; + std::string data; + if (!read_file(path, &data)) { + return -1; + } + + parse_config(path, data); + dump_parser_state(); - parse_config(fn, data); - DUMP(); + NOTICE("(Parsing %s took %.2fs.)\n", path, t.duration()); return 0; } @@ -504,83 +543,94 @@ void service_for_each_flags(unsigned matchflags, void action_for_each_trigger(const char *trigger, void (*func)(struct action *act)) { - struct listnode *node; + struct listnode *node, *node2; struct action *act; + struct trigger *cur_trigger; + list_for_each(node, &action_list) { act = node_to_item(node, struct action, alist); - if (!strcmp(act->name, trigger)) { - func(act); + list_for_each(node2, &act->triggers) { + cur_trigger = node_to_item(node2, struct trigger, nlist); + if (!strcmp(cur_trigger->name, trigger)) { + func(act); + } } } } + void queue_property_triggers(const char *name, const char *value) { - struct listnode *node; + struct listnode *node, *node2; struct action *act; + struct trigger *cur_trigger; + bool match; + int name_length; + list_for_each(node, &action_list) { act = node_to_item(node, struct action, alist); - if (!strncmp(act->name, "property:", strlen("property:"))) { - const char *test = act->name + strlen("property:"); - int name_length = strlen(name); - - if (!strncmp(name, test, name_length) && - test[name_length] == '=' && - (!strcmp(test + name_length + 1, value) || - !strcmp(test + name_length + 1, "*"))) { - action_add_queue_tail(act); - } + match = !name; + list_for_each(node2, &act->triggers) { + cur_trigger = node_to_item(node2, struct trigger, nlist); + if (!strncmp(cur_trigger->name, "property:", strlen("property:"))) { + const char *test = cur_trigger->name + strlen("property:"); + if (!match) { + name_length = strlen(name); + if (!strncmp(name, test, name_length) && + test[name_length] == '=' && + (!strcmp(test + name_length + 1, value) || + !strcmp(test + name_length + 1, "*"))) { + match = true; + continue; + } + } else { + const char* equals = strchr(test, '='); + if (equals) { + char prop_name[PROP_NAME_MAX + 1]; + char value[PROP_VALUE_MAX]; + int length = equals - test; + if (length <= PROP_NAME_MAX) { + int ret; + memcpy(prop_name, test, length); + prop_name[length] = 0; + + /* does the property exist, and match the trigger value? */ + ret = property_get(prop_name, value); + if (ret > 0 && (!strcmp(equals + 1, value) || + !strcmp(equals + 1, "*"))) { + continue; + } + } + } + } + } + match = false; + break; + } + if (match) { + action_add_queue_tail(act); } } } void queue_all_property_triggers() { - struct listnode *node; - struct action *act; - list_for_each(node, &action_list) { - act = node_to_item(node, struct action, alist); - if (!strncmp(act->name, "property:", strlen("property:"))) { - /* parse property name and value - syntax is property:<name>=<value> */ - const char* name = act->name + strlen("property:"); - const char* equals = strchr(name, '='); - if (equals) { - char prop_name[PROP_NAME_MAX + 1]; - char value[PROP_VALUE_MAX]; - int length = equals - name; - if (length > PROP_NAME_MAX) { - ERROR("property name too long in trigger %s", act->name); - } else { - int ret; - memcpy(prop_name, name, length); - prop_name[length] = 0; - - /* does the property exist, and match the trigger value? */ - ret = property_get(prop_name, value); - if (ret > 0 && (!strcmp(equals + 1, value) || - !strcmp(equals + 1, "*"))) { - action_add_queue_tail(act); - } - } - } - } - } + queue_property_triggers(NULL, NULL); } -void queue_builtin_action(int (*func)(int nargs, char **args), char *name) +void queue_builtin_action(int (*func)(int nargs, char **args), const char *name) { - struct action *act; - struct command *cmd; - - act = calloc(1, sizeof(*act)); - act->name = name; + action* act = (action*) calloc(1, sizeof(*act)); + trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger)); + cur_trigger->name = name; + list_init(&act->triggers); + list_add_tail(&act->triggers, &cur_trigger->nlist); list_init(&act->commands); list_init(&act->qlist); - cmd = calloc(1, sizeof(*cmd)); + command* cmd = (command*) calloc(1, sizeof(*cmd)); cmd->func = func; - cmd->args[0] = name; + cmd->args[0] = const_cast<char*>(name); cmd->nargs = 1; list_add_tail(&act->commands, &cmd->clist); @@ -613,9 +663,67 @@ int action_queue_empty() return list_empty(&action_queue); } +service* make_exec_oneshot_service(int nargs, char** args) { + // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS... + int command_arg = 1; + for (int i = 1; i < nargs; ++i) { + if (strcmp(args[i], "--") == 0) { + command_arg = i + 1; + break; + } + } + if (command_arg > 4 + NR_SVC_SUPP_GIDS) { + ERROR("exec called with too many supplementary group ids\n"); + return NULL; + } + + int argc = nargs - command_arg; + char** argv = (args + command_arg); + if (argc < 1) { + ERROR("exec called without command\n"); + return NULL; + } + + service* svc = (service*) calloc(1, sizeof(*svc) + sizeof(char*) * argc); + if (svc == NULL) { + ERROR("Couldn't allocate service for exec of '%s': %s", argv[0], strerror(errno)); + return NULL; + } + + if (command_arg > 2) { + svc->seclabel = args[1]; + } + if (command_arg > 3) { + svc->uid = decode_uid(args[2]); + } + if (command_arg > 4) { + svc->gid = decode_uid(args[3]); + svc->nr_supp_gids = command_arg - 1 /* -- */ - 4 /* exec SECLABEL UID GID */; + for (size_t i = 0; i < svc->nr_supp_gids; ++i) { + svc->supp_gids[i] = decode_uid(args[4 + i]); + } + } + + static int exec_count; // Every service needs a unique name. + char* name = NULL; + asprintf(&name, "exec %d (%s)", exec_count++, argv[0]); + if (name == NULL) { + ERROR("Couldn't allocate name for exec service '%s'\n", argv[0]); + free(svc); + return NULL; + } + svc->name = name; + svc->classname = "default"; + svc->flags = SVC_EXEC | SVC_ONESHOT; + svc->nargs = argc; + memcpy(svc->args, argv, sizeof(char*) * svc->nargs); + svc->args[argc] = NULL; + list_add_tail(&service_list, &svc->slist); + return svc; +} + static void *parse_service(struct parse_state *state, int nargs, char **args) { - struct service *svc; if (nargs < 3) { parse_error(state, "services must have a name and a program\n"); return 0; @@ -625,24 +733,27 @@ static void *parse_service(struct parse_state *state, int nargs, char **args) return 0; } - svc = service_find_by_name(args[1]); + service* svc = (service*) service_find_by_name(args[1]); if (svc) { parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]); return 0; } nargs -= 2; - svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs); + svc = (service*) calloc(1, sizeof(*svc) + sizeof(char*) * nargs); if (!svc) { parse_error(state, "out of memory\n"); return 0; } - svc->name = args[1]; + svc->name = strdup(args[1]); svc->classname = "default"; memcpy(svc->args, args + 2, sizeof(char*) * nargs); + trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger)); svc->args[nargs] = 0; svc->nargs = nargs; - svc->onrestart.name = "onrestart"; + list_init(&svc->onrestart.triggers); + cur_trigger->name = "onrestart"; + list_add_tail(&svc->onrestart.triggers, &cur_trigger->nlist); list_init(&svc->onrestart.commands); list_add_tail(&service_list, &svc->slist); return svc; @@ -650,7 +761,7 @@ static void *parse_service(struct parse_state *state, int nargs, char **args) static void parse_line_service(struct parse_state *state, int nargs, char **args) { - struct service *svc = state->context; + struct service *svc = (service*) state->context; struct command *cmd; int i, kw, kw_nargs; @@ -662,8 +773,6 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args kw = lookup_keyword(args[0]); switch (kw) { - case K_capability: - break; case K_class: if (nargs != 2) { parse_error(state, "class option requires a classname\n"); @@ -719,7 +828,7 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args if (nargs < 2) { parse_error(state, "keycodes option requires atleast one keycode\n"); } else { - svc->keycodes = malloc((nargs - 1) * sizeof(svc->keycodes[0])); + svc->keycodes = (int*) malloc((nargs - 1) * sizeof(svc->keycodes[0])); if (!svc->keycodes) { parse_error(state, "could not allocate keycodes\n"); } else { @@ -748,7 +857,7 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args break; } - cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs); + cmd = (command*) malloc(sizeof(*cmd) + sizeof(char*) * nargs); cmd->func = kw_func(kw); cmd->nargs = nargs; memcpy(cmd->args, args, sizeof(char*) * nargs); @@ -758,12 +867,11 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args svc->flags |= SVC_CRITICAL; break; case K_setenv: { /* name value */ - struct svcenvinfo *ei; if (nargs < 3) { parse_error(state, "setenv option requires name and value arguments\n"); break; } - ei = calloc(1, sizeof(*ei)); + svcenvinfo* ei = (svcenvinfo*) calloc(1, sizeof(*ei)); if (!ei) { parse_error(state, "out of memory\n"); break; @@ -775,7 +883,6 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args break; } case K_socket: {/* name type perm [ uid gid context ] */ - struct socketinfo *si; if (nargs < 4) { parse_error(state, "socket option requires name, type, perm arguments\n"); break; @@ -785,7 +892,7 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args parse_error(state, "socket type must be 'dgram', 'stream' or 'seqpacket'\n"); break; } - si = calloc(1, sizeof(*si)); + socketinfo* si = (socketinfo*) calloc(1, sizeof(*si)); if (!si) { parse_error(state, "out of memory\n"); break; @@ -825,17 +932,36 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args static void *parse_action(struct parse_state *state, int nargs, char **args) { - struct action *act; + struct trigger *cur_trigger; + int i; if (nargs < 2) { parse_error(state, "actions must have a trigger\n"); return 0; } - if (nargs > 2) { - parse_error(state, "actions may not have extra parameters\n"); - return 0; + + action* act = (action*) calloc(1, sizeof(*act)); + list_init(&act->triggers); + + for (i = 1; i < nargs; i++) { + if (!(i % 2)) { + if (strcmp(args[i], "&&")) { + struct listnode *node; + struct listnode *node2; + parse_error(state, "& is the only symbol allowed to concatenate actions\n"); + list_for_each_safe(node, node2, &act->triggers) { + struct trigger *trigger = node_to_item(node, struct trigger, nlist); + free(trigger); + } + free(act); + return 0; + } else + continue; + } + cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger)); + cur_trigger->name = args[i]; + list_add_tail(&act->triggers, &cur_trigger->nlist); } - act = calloc(1, sizeof(*act)); - act->name = args[1]; + list_init(&act->commands); list_init(&act->qlist); list_add_tail(&action_list, &act->alist); @@ -845,9 +971,7 @@ static void *parse_action(struct parse_state *state, int nargs, char **args) static void parse_line_action(struct parse_state* state, int nargs, char **args) { - struct command *cmd; - struct action *act = state->context; - int (*func)(int nargs, char **args); + struct action *act = (action*) state->context; int kw, n; if (nargs == 0) { @@ -866,7 +990,7 @@ static void parse_line_action(struct parse_state* state, int nargs, char **args) n > 2 ? "arguments" : "argument"); return; } - cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs); + command* cmd = (command*) malloc(sizeof(*cmd) + sizeof(char*) * nargs); cmd->func = kw_func(kw); cmd->line = state->line; cmd->filename = state->filename; diff --git a/init/init_parser.h b/init/init_parser.h index b078cad..6348607 100644 --- a/init/init_parser.h +++ b/init/init_parser.h @@ -20,6 +20,7 @@ #define INIT_PARSER_MAXARGS 64 struct action; +struct service; struct action *action_remove_queue_head(void); void action_add_queue_tail(struct action *act); @@ -28,9 +29,11 @@ void action_for_each_trigger(const char *trigger, int action_queue_empty(void); void queue_property_triggers(const char *name, const char *value); void queue_all_property_triggers(); -void queue_builtin_action(int (*func)(int nargs, char **args), char *name); +void queue_builtin_action(int (*func)(int nargs, char **args), const char *name); int init_parse_config_file(const char *fn); int expand_props(char *dst, const char *src, int len); +service* make_exec_oneshot_service(int argc, char** argv); + #endif diff --git a/init/init_parser_test.cpp b/init/init_parser_test.cpp new file mode 100644 index 0000000..170a73a --- /dev/null +++ b/init/init_parser_test.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2015 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 "init_parser.h" + +#include "init.h" +#include "util.h" + +#include <errno.h> +#include <gtest/gtest.h> + +TEST(init_parser, make_exec_oneshot_service_invalid_syntax) { + char* argv[10]; + memset(argv, 0, sizeof(argv)); + + // Nothing. + ASSERT_EQ(nullptr, make_exec_oneshot_service(0, argv)); + + // No arguments to 'exec'. + argv[0] = const_cast<char*>("exec"); + ASSERT_EQ(nullptr, make_exec_oneshot_service(1, argv)); + + // No command in "exec --". + argv[1] = const_cast<char*>("--"); + ASSERT_EQ(nullptr, make_exec_oneshot_service(2, argv)); +} + +TEST(init_parser, make_exec_oneshot_service_too_many_supplementary_gids) { + int argc = 0; + char* argv[4 + NR_SVC_SUPP_GIDS + 3]; + argv[argc++] = const_cast<char*>("exec"); + argv[argc++] = const_cast<char*>("seclabel"); + argv[argc++] = const_cast<char*>("root"); // uid. + argv[argc++] = const_cast<char*>("root"); // gid. + for (int i = 0; i < NR_SVC_SUPP_GIDS; ++i) { + argv[argc++] = const_cast<char*>("root"); // Supplementary gid. + } + argv[argc++] = const_cast<char*>("--"); + argv[argc++] = const_cast<char*>("/system/bin/id"); + argv[argc] = nullptr; + ASSERT_EQ(nullptr, make_exec_oneshot_service(argc, argv)); +} + +static void Test_make_exec_oneshot_service(bool dash_dash, bool seclabel, bool uid, bool gid, bool supplementary_gids) { + int argc = 0; + char* argv[10]; + argv[argc++] = const_cast<char*>("exec"); + if (seclabel) { + argv[argc++] = const_cast<char*>("u:r:su:s0"); // seclabel + if (uid) { + argv[argc++] = const_cast<char*>("log"); // uid + if (gid) { + argv[argc++] = const_cast<char*>("shell"); // gid + if (supplementary_gids) { + argv[argc++] = const_cast<char*>("system"); // supplementary gid 0 + argv[argc++] = const_cast<char*>("adb"); // supplementary gid 1 + } + } + } + } + if (dash_dash) { + argv[argc++] = const_cast<char*>("--"); + } + argv[argc++] = const_cast<char*>("/system/bin/toybox"); + argv[argc++] = const_cast<char*>("id"); + argv[argc] = nullptr; + service* svc = make_exec_oneshot_service(argc, argv); + ASSERT_NE(nullptr, svc); + + if (seclabel) { + ASSERT_STREQ("u:r:su:s0", svc->seclabel); + } else { + ASSERT_EQ(nullptr, svc->seclabel); + } + if (uid) { + ASSERT_EQ(decode_uid("log"), svc->uid); + } else { + ASSERT_EQ(0U, svc->uid); + } + if (gid) { + ASSERT_EQ(decode_uid("shell"), svc->gid); + } else { + ASSERT_EQ(0U, svc->gid); + } + if (supplementary_gids) { + ASSERT_EQ(2U, svc->nr_supp_gids); + ASSERT_EQ(decode_uid("system"), svc->supp_gids[0]); + ASSERT_EQ(decode_uid("adb"), svc->supp_gids[1]); + } else { + ASSERT_EQ(0U, svc->nr_supp_gids); + } + + ASSERT_EQ(2, svc->nargs); + ASSERT_EQ("/system/bin/toybox", svc->args[0]); + ASSERT_EQ("id", svc->args[1]); + ASSERT_EQ(nullptr, svc->args[2]); +} + +TEST(init_parser, make_exec_oneshot_service_with_everything) { + Test_make_exec_oneshot_service(true, true, true, true, true); +} + +TEST(init_parser, make_exec_oneshot_service_with_seclabel_uid_gid) { + Test_make_exec_oneshot_service(true, true, true, true, false); +} + +TEST(init_parser, make_exec_oneshot_service_with_seclabel_uid) { + Test_make_exec_oneshot_service(true, true, true, false, false); +} + +TEST(init_parser, make_exec_oneshot_service_with_seclabel) { + Test_make_exec_oneshot_service(true, true, false, false, false); +} + +TEST(init_parser, make_exec_oneshot_service_with_just_command) { + Test_make_exec_oneshot_service(true, false, false, false, false); +} + +TEST(init_parser, make_exec_oneshot_service_with_just_command_no_dash) { + Test_make_exec_oneshot_service(false, false, false, false, false); +} diff --git a/init/keychords.c b/init/keychords.cpp index 4a64042..10d9573 100644 --- a/init/keychords.c +++ b/init/keychords.cpp @@ -40,7 +40,7 @@ void add_service_keycodes(struct service *svc) if (svc->keycodes) { /* add a new keychord to the list */ size = sizeof(*keychord) + svc->nkeycodes * sizeof(keychord->keycodes[0]); - keychords = realloc(keychords, keychords_length + size); + keychords = (input_keychord*) realloc(keychords, keychords_length + size); if (!keychords) { ERROR("could not allocate keychords\n"); keychords_length = 0; @@ -62,38 +62,7 @@ void add_service_keycodes(struct service *svc) } } -void keychord_init() -{ - int fd, ret; - - service_for_each(add_service_keycodes); - - /* nothing to do if no services require keychords */ - if (!keychords) - return; - - fd = open("/dev/keychord", O_RDWR); - if (fd < 0) { - ERROR("could not open /dev/keychord\n"); - return; - } - fcntl(fd, F_SETFD, FD_CLOEXEC); - - ret = write(fd, keychords, keychords_length); - if (ret != keychords_length) { - ERROR("could not configure /dev/keychord %d (%d)\n", ret, errno); - close(fd); - fd = -1; - } - - free(keychords); - keychords = 0; - - keychord_fd = fd; -} - -void handle_keychord() -{ +static void handle_keychord() { struct service *svc; char adb_enabled[PROP_VALUE_MAX]; int ret; @@ -110,7 +79,7 @@ void handle_keychord() if (!strcmp(adb_enabled, "running")) { svc = service_find_by_keychord(id); if (svc) { - INFO("starting service %s from keychord\n", svc->name); + INFO("Starting service %s from keychord\n", svc->name); service_start(svc, NULL); } else { ERROR("service for keychord %d not found\n", id); @@ -118,7 +87,28 @@ void handle_keychord() } } -int get_keychord_fd() -{ - return keychord_fd; +void keychord_init() { + service_for_each(add_service_keycodes); + + // Nothing to do if no services require keychords. + if (!keychords) { + return; + } + + keychord_fd = TEMP_FAILURE_RETRY(open("/dev/keychord", O_RDWR | O_CLOEXEC)); + if (keychord_fd == -1) { + ERROR("could not open /dev/keychord: %s\n", strerror(errno)); + return; + } + + int ret = write(keychord_fd, keychords, keychords_length); + if (ret != keychords_length) { + ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno)); + close(keychord_fd); + } + + free(keychords); + keychords = nullptr; + + register_epoll_handler(keychord_fd, handle_keychord); } diff --git a/init/keychords.h b/init/keychords.h index 070b858..d2723b7 100644 --- a/init/keychords.h +++ b/init/keychords.h @@ -19,9 +19,7 @@ struct service; -void add_service_keycodes(struct service *svc); -void keychord_init(void); -void handle_keychord(void); -int get_keychord_fd(void); +void add_service_keycodes(service*); +void keychord_init(); #endif diff --git a/init/keywords.h b/init/keywords.h index 2d97e5b..37f01b8 100644 --- a/init/keywords.h +++ b/init/keywords.h @@ -1,7 +1,5 @@ - #ifndef KEYWORD -int do_chroot(int nargs, char **args); -int do_chdir(int nargs, char **args); +int do_bootchart_init(int nargs, char **args); int do_class_start(int nargs, char **args); int do_class_stop(int nargs, char **args); int do_class_reset(int nargs, char **args); @@ -12,6 +10,7 @@ int do_export(int nargs, char **args); int do_hostname(int nargs, char **args); int do_ifup(int nargs, char **args); int do_insmod(int nargs, char **args); +int do_installkey(int nargs, char **args); int do_mkdir(int nargs, char **args); int do_mount_all(int nargs, char **args); int do_mount(int nargs, char **args); @@ -21,12 +20,8 @@ int do_restorecon(int nargs, char **args); int do_restorecon_recursive(int nargs, char **args); int do_rm(int nargs, char **args); int do_rmdir(int nargs, char **args); -int do_setcon(int nargs, char **args); -int do_setenforce(int nargs, char **args); -int do_setkey(int nargs, char **args); int do_setprop(int nargs, char **args); int do_setrlimit(int nargs, char **args); -int do_setsebool(int nargs, char **args); int do_start(int nargs, char **args); int do_stop(int nargs, char **args); int do_swapon_all(int nargs, char **args); @@ -40,15 +35,14 @@ int do_chmod(int nargs, char **args); int do_loglevel(int nargs, char **args); int do_load_persist_props(int nargs, char **args); int do_load_all_props(int nargs, char **args); +int do_verity_load_state(int nargs, char **args); +int do_verity_update_state(int nargs, char **args); int do_wait(int nargs, char **args); #define __MAKE_KEYWORD_ENUM__ #define KEYWORD(symbol, flags, nargs, func) K_##symbol, enum { K_UNKNOWN, #endif - KEYWORD(capability, OPTION, 0, 0) - KEYWORD(chdir, COMMAND, 1, do_chdir) - KEYWORD(chroot, COMMAND, 1, do_chroot) KEYWORD(class, OPTION, 0, 0) KEYWORD(class_start, COMMAND, 1, do_class_start) KEYWORD(class_stop, COMMAND, 1, do_class_stop) @@ -64,6 +58,7 @@ enum { KEYWORD(hostname, COMMAND, 1, do_hostname) KEYWORD(ifup, COMMAND, 1, do_ifup) KEYWORD(insmod, COMMAND, 1, do_insmod) + KEYWORD(installkey, COMMAND, 1, do_installkey) KEYWORD(import, SECTION, 1, 0) KEYWORD(keycodes, OPTION, 0, 0) KEYWORD(mkdir, COMMAND, 1, do_mkdir) @@ -80,13 +75,9 @@ enum { KEYWORD(rmdir, COMMAND, 1, do_rmdir) KEYWORD(seclabel, OPTION, 0, 0) KEYWORD(service, SECTION, 0, 0) - KEYWORD(setcon, COMMAND, 1, do_setcon) - KEYWORD(setenforce, COMMAND, 1, do_setenforce) KEYWORD(setenv, OPTION, 2, 0) - KEYWORD(setkey, COMMAND, 0, do_setkey) KEYWORD(setprop, COMMAND, 2, do_setprop) KEYWORD(setrlimit, COMMAND, 3, do_setrlimit) - KEYWORD(setsebool, COMMAND, 2, do_setsebool) KEYWORD(socket, OPTION, 0, 0) KEYWORD(start, COMMAND, 1, do_start) KEYWORD(stop, COMMAND, 1, do_stop) @@ -95,6 +86,8 @@ enum { KEYWORD(symlink, COMMAND, 1, do_symlink) KEYWORD(sysclktz, COMMAND, 1, do_sysclktz) KEYWORD(user, OPTION, 0, 0) + KEYWORD(verity_load_state, COMMAND, 0, do_verity_load_state) + KEYWORD(verity_update_state, COMMAND, 0, do_verity_update_state) KEYWORD(wait, COMMAND, 1, do_wait) KEYWORD(write, COMMAND, 2, do_write) KEYWORD(copy, COMMAND, 2, do_copy) @@ -104,10 +97,10 @@ enum { KEYWORD(load_persist_props, COMMAND, 0, do_load_persist_props) KEYWORD(load_all_props, COMMAND, 0, do_load_all_props) KEYWORD(ioprio, OPTION, 0, 0) + KEYWORD(bootchart_init, COMMAND, 0, do_bootchart_init) #ifdef __MAKE_KEYWORD_ENUM__ KEYWORD_COUNT, }; #undef __MAKE_KEYWORD_ENUM__ #undef KEYWORD #endif - diff --git a/init/log.cpp b/init/log.cpp new file mode 100644 index 0000000..d32f2da --- /dev/null +++ b/init/log.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 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 <sys/uio.h> + +#include <selinux/selinux.h> + +#include "log.h" + +static void init_klog_vwrite(int level, const char* fmt, va_list ap) { + static const char* tag = basename(getprogname()); + + char prefix[64]; + snprintf(prefix, sizeof(prefix), "<%d>%s: ", level, tag); + + char msg[512]; + vsnprintf(msg, sizeof(msg), fmt, ap); + + iovec iov[2]; + iov[0].iov_base = prefix; + iov[0].iov_len = strlen(prefix); + iov[1].iov_base = msg; + iov[1].iov_len = strlen(msg); + + klog_writev(level, iov, 2); +} + +void init_klog_write(int level, const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + init_klog_vwrite(level, fmt, ap); + va_end(ap); +} + +int selinux_klog_callback(int type, const char *fmt, ...) { + int level = KLOG_ERROR_LEVEL; + if (type == SELINUX_WARNING) { + level = KLOG_WARNING_LEVEL; + } else if (type == SELINUX_INFO) { + level = KLOG_INFO_LEVEL; + } + va_list ap; + va_start(ap, fmt); + init_klog_vwrite(level, fmt, ap); + va_end(ap); + return 0; +} @@ -19,10 +19,11 @@ #include <cutils/klog.h> -#define ERROR(x...) KLOG_ERROR("init", x) -#define NOTICE(x...) KLOG_NOTICE("init", x) -#define INFO(x...) KLOG_INFO("init", x) +#define ERROR(x...) init_klog_write(KLOG_ERROR_LEVEL, x) +#define NOTICE(x...) init_klog_write(KLOG_NOTICE_LEVEL, x) +#define INFO(x...) init_klog_write(KLOG_INFO_LEVEL, x) -extern int log_callback(int type, const char *fmt, ...); +void init_klog_write(int level, const char* fmt, ...) __printflike(2, 3); +int selinux_klog_callback(int level, const char* fmt, ...) __printflike(2, 3); #endif diff --git a/init/parser.c b/init/parser.cpp index 48e7aec..8193729 100644 --- a/init/parser.c +++ b/init/parser.cpp @@ -1,59 +1,17 @@ -#include <stdio.h> +#include "parser.h" + #include <stdarg.h> +#include <stdio.h> #include <string.h> -#include "parser.h" #include "log.h" -#define RAW(x...) log_write(6, x) - -void DUMP(void) -{ -#if 0 - struct service *svc; - struct action *act; - struct command *cmd; - struct listnode *node; - struct listnode *node2; - struct socketinfo *si; - int n; - - list_for_each(node, &service_list) { - svc = node_to_item(node, struct service, slist); - RAW("service %s\n", svc->name); - RAW(" class '%s'\n", svc->classname); - RAW(" exec"); - for (n = 0; n < svc->nargs; n++) { - RAW(" '%s'", svc->args[n]); - } - RAW("\n"); - for (si = svc->sockets; si; si = si->next) { - RAW(" socket %s %s 0%o\n", si->name, si->type, si->perm); - } - } - - list_for_each(node, &action_list) { - act = node_to_item(node, struct action, alist); - RAW("on %s\n", act->name); - list_for_each(node2, &act->commands) { - cmd = node_to_item(node2, struct command, clist); - RAW(" %p", cmd->func); - for (n = 0; n < cmd->nargs; n++) { - RAW(" %s", cmd->args[n]); - } - RAW("\n"); - } - RAW("\n"); - } -#endif -} - void parse_error(struct parse_state *state, const char *fmt, ...) { va_list ap; char buf[128]; int off; - + snprintf(buf, 128, "%s: %d: ", state->filename, state->line); buf[127] = 0; off = strlen(buf); diff --git a/init/parser.h b/init/parser.h index a58272a..95e1164 100644 --- a/init/parser.h +++ b/init/parser.h @@ -33,7 +33,7 @@ struct parse_state void *priv; }; -void DUMP(void); +void dump_parser_state(void); int next_token(struct parse_state *state); void parse_error(struct parse_state *state, const char *fmt, ...); diff --git a/init/property_service.c b/init/property_service.cpp index 91ef251..930ef82 100644 --- a/init/property_service.c +++ b/init/property_service.cpp @@ -26,6 +26,8 @@ #include <errno.h> #include <sys/poll.h> +#include <memory> + #include <cutils/misc.h> #include <cutils/sockets.h> #include <cutils/multiuser.h> @@ -52,44 +54,34 @@ #define PERSISTENT_PROPERTY_DIR "/data/property" static int persistent_properties_loaded = 0; -static int property_area_inited = 0; +static bool property_area_initialized = false; static int property_set_fd = -1; -typedef struct { +struct workspace { size_t size; int fd; -} workspace; - -static int init_workspace(workspace *w, size_t size) -{ - void *data; - int fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW); - if (fd < 0) - return -1; - - w->size = size; - w->fd = fd; - return 0; -} +}; static workspace pa_workspace; -static int init_property_area(void) -{ - if (property_area_inited) - return -1; - - if(__system_property_area_init()) - return -1; +void property_init() { + if (property_area_initialized) { + return; + } - if(init_workspace(&pa_workspace, 0)) - return -1; + property_area_initialized = true; - fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC); + if (__system_property_area_init()) { + return; + } - property_area_inited = 1; - return 0; + pa_workspace.size = 0; + pa_workspace.fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); + if (pa_workspace.fd == -1) { + ERROR("Failed to open %s: %s\n", PROP_FILENAME, strerror(errno)); + return; + } } static int check_mac_perms(const char *name, char *sctx) @@ -98,8 +90,6 @@ static int check_mac_perms(const char *name, char *sctx) return 1; char *tctx = NULL; - const char *class = "property_service"; - const char *perm = "set"; int result = 0; if (!sctx) @@ -111,7 +101,7 @@ static int check_mac_perms(const char *name, char *sctx) if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0) goto err; - if (selinux_check_access(sctx, tctx, class, perm, (void*) name) == 0) + if (selinux_check_access(sctx, tctx, "property_service", "set", (void*) name) == 0) result = 1; freecon(tctx); @@ -142,9 +132,6 @@ static int check_control_mac_perms(const char *name, char *sctx) */ static int check_perms(const char *name, char *sctx) { - int i; - unsigned int app_id; - if(!strncmp(name, "ro.", 3)) name +=3; @@ -165,7 +152,7 @@ static void write_persistent_property(const char *name, const char *value) snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR); fd = mkstemp(tempPath); if (fd < 0) { - ERROR("Unable to write persistent property to temp file %s errno: %d\n", tempPath, errno); + ERROR("Unable to write persistent property to temp file %s: %s\n", tempPath, strerror(errno)); return; } write(fd, value, strlen(value)); @@ -205,18 +192,14 @@ static bool is_legal_property_name(const char* name, size_t namelen) return true; } -int property_set(const char *name, const char *value) -{ - prop_info *pi; - int ret; - +static int property_set_impl(const char* name, const char* value) { size_t namelen = strlen(name); size_t valuelen = strlen(value); if (!is_legal_property_name(name, namelen)) return -1; if (valuelen >= PROP_VALUE_MAX) return -1; - pi = (prop_info*) __system_property_find(name); + prop_info* pi = (prop_info*) __system_property_find(name); if(pi != 0) { /* ro.* properties may NEVER be modified once set */ @@ -224,10 +207,9 @@ int property_set(const char *name, const char *value) __system_property_update(pi, value, valuelen); } else { - ret = __system_property_add(name, namelen, value, valuelen); - if (ret < 0) { - ERROR("Failed to set '%s'='%s'\n", name, value); - return ret; + int rc = __system_property_add(name, namelen, value, valuelen); + if (rc < 0) { + return rc; } } /* If name starts with "net." treat as a DNS property. */ @@ -256,12 +238,19 @@ int property_set(const char *name, const char *value) return 0; } -void handle_property_set_fd() +int property_set(const char* name, const char* value) { + int rc = property_set_impl(name, value); + if (rc == -1) { + ERROR("property_set(\"%s\", \"%s\") failed\n", name, value); + } + return rc; +} + +static void handle_property_set_fd() { prop_msg msg; int s; int r; - int res; struct ucred cr; struct sockaddr_un addr; socklen_t addr_size = sizeof(addr); @@ -291,15 +280,15 @@ void handle_property_set_fd() close(s); return; } else if (nr < 0) { - ERROR("sys_prop: error waiting for uid=%d to send property message. err=%d %s\n", cr.uid, errno, strerror(errno)); + ERROR("sys_prop: error waiting for uid=%d to send property message: %s\n", cr.uid, strerror(errno)); close(s); return; } r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT)); if(r != sizeof(prop_msg)) { - ERROR("sys_prop: mis-match msg size received: %d expected: %zu errno: %d\n", - r, sizeof(prop_msg), errno); + ERROR("sys_prop: mis-match msg size received: %d expected: %zu: %s\n", + r, sizeof(prop_msg), strerror(errno)); close(s); return; } @@ -421,126 +410,106 @@ static void load_properties(char *data, const char *filter) * Filter is used to decide which properties to load: NULL loads all keys, * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match. */ -static void load_properties_from_file(const char *fn, const char *filter) -{ - char *data; - unsigned sz; +static void load_properties_from_file(const char* filename, const char* filter) { + Timer t; + std::string data; + if (read_file(filename, &data)) { + load_properties(&data[0], filter); + } + NOTICE("(Loading properties from %s took %.2fs.)\n", filename, t.duration()); +} - data = read_file(fn, &sz); +static void load_persistent_properties() { + persistent_properties_loaded = 1; - if(data != 0) { - load_properties(data, filter); - free(data); + std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(PERSISTENT_PROPERTY_DIR), closedir); + if (!dir) { + ERROR("Unable to open persistent property directory \"%s\": %s\n", + PERSISTENT_PROPERTY_DIR, strerror(errno)); + return; } -} -static void load_persistent_properties() -{ - DIR* dir = opendir(PERSISTENT_PROPERTY_DIR); - int dir_fd; - struct dirent* entry; - char value[PROP_VALUE_MAX]; - int fd, length; - struct stat sb; - - if (dir) { - dir_fd = dirfd(dir); - while ((entry = readdir(dir)) != NULL) { - if (strncmp("persist.", entry->d_name, strlen("persist."))) - continue; -#if HAVE_DIRENT_D_TYPE - if (entry->d_type != DT_REG) - continue; -#endif - /* open the file and read the property value */ - fd = openat(dir_fd, entry->d_name, O_RDONLY | O_NOFOLLOW); - if (fd < 0) { - ERROR("Unable to open persistent property file \"%s\" errno: %d\n", - entry->d_name, errno); - continue; - } - if (fstat(fd, &sb) < 0) { - ERROR("fstat on property file \"%s\" failed errno: %d\n", entry->d_name, errno); - close(fd); - continue; - } + struct dirent* entry; + while ((entry = readdir(dir.get())) != NULL) { + if (strncmp("persist.", entry->d_name, strlen("persist."))) { + continue; + } + if (entry->d_type != DT_REG) { + continue; + } - // File must not be accessible to others, be owned by root/root, and - // not be a hard link to any other file. - if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) - || (sb.st_uid != 0) - || (sb.st_gid != 0) - || (sb.st_nlink != 1)) { - ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%d mode=%o)\n", - entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid, - sb.st_nlink, sb.st_mode); - close(fd); - continue; - } + // Open the file and read the property value. + int fd = openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW); + if (fd == -1) { + ERROR("Unable to open persistent property file \"%s\": %s\n", + entry->d_name, strerror(errno)); + continue; + } - length = read(fd, value, sizeof(value) - 1); - if (length >= 0) { - value[length] = 0; - property_set(entry->d_name, value); - } else { - ERROR("Unable to read persistent property file %s errno: %d\n", - entry->d_name, errno); - } + struct stat sb; + if (fstat(fd, &sb) == -1) { + ERROR("fstat on property file \"%s\" failed: %s\n", entry->d_name, strerror(errno)); close(fd); + continue; } - closedir(dir); - } else { - ERROR("Unable to open persistent property directory %s errno: %d\n", PERSISTENT_PROPERTY_DIR, errno); - } - persistent_properties_loaded = 1; -} + // File must not be accessible to others, be owned by root/root, and + // not be a hard link to any other file. + if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || (sb.st_uid != 0) || (sb.st_gid != 0) || + (sb.st_nlink != 1)) { + ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%u mode=%o)\n", + entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid, + (unsigned int)sb.st_nlink, sb.st_mode); + close(fd); + continue; + } -void property_init(void) -{ - init_property_area(); + char value[PROP_VALUE_MAX]; + int length = read(fd, value, sizeof(value) - 1); + if (length >= 0) { + value[length] = 0; + property_set(entry->d_name, value); + } else { + ERROR("Unable to read persistent property file %s: %s\n", + entry->d_name, strerror(errno)); + } + close(fd); + } } -void property_load_boot_defaults(void) -{ +void property_load_boot_defaults() { load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL); } -int properties_inited(void) -{ - return property_area_inited; +bool properties_initialized() { + return property_area_initialized; } static void load_override_properties() { -#ifdef ALLOW_LOCAL_PROP_OVERRIDE - char debuggable[PROP_VALUE_MAX]; - int ret; - - ret = property_get("ro.debuggable", debuggable); - if (ret && (strcmp(debuggable, "1") == 0)) { - load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL); + if (ALLOW_LOCAL_PROP_OVERRIDE) { + char debuggable[PROP_VALUE_MAX]; + int ret = property_get("ro.debuggable", debuggable); + if (ret && (strcmp(debuggable, "1") == 0)) { + load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL); + } } -#endif /* ALLOW_LOCAL_PROP_OVERRIDE */ } - /* When booting an encrypted system, /data is not mounted when the * property service is started, so any properties stored there are * not loaded. Vold triggers init to load these properties once it * has mounted /data. */ -void load_persist_props(void) -{ +void load_persist_props(void) { load_override_properties(); /* Read persistent properties after all default values have been loaded. */ load_persistent_properties(); } -void load_all_props(void) -{ +void load_all_props() { load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL); - load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL); load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL); + load_properties_from_file(PROP_PATH_BOOTIMAGE_BUILD, NULL); load_properties_from_file(PROP_PATH_FACTORY, "ro.*"); load_override_properties(); @@ -549,20 +518,15 @@ void load_all_props(void) load_persistent_properties(); } -void start_property_service(void) -{ - int fd; - - fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL); - if(fd < 0) return; - fcntl(fd, F_SETFD, FD_CLOEXEC); - fcntl(fd, F_SETFL, O_NONBLOCK); +void start_property_service() { + property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + 0666, 0, 0, NULL); + if (property_set_fd == -1) { + ERROR("start_property_service socket creation failed: %s\n", strerror(errno)); + exit(1); + } - listen(fd, 8); - property_set_fd = fd; -} + listen(property_set_fd, 8); -int get_property_set_fd() -{ - return property_set_fd; + register_epoll_handler(property_set_fd, handle_property_set_fd); } diff --git a/init/property_service.h b/init/property_service.h index 730495e..a27053d 100644 --- a/init/property_service.h +++ b/init/property_service.h @@ -17,10 +17,9 @@ #ifndef _INIT_PROPERTY_H #define _INIT_PROPERTY_H -#include <stdbool.h> +#include <stddef.h> #include <sys/system_properties.h> -extern void handle_property_set_fd(void); extern void property_init(void); extern void property_load_boot_defaults(void); extern void load_persist_props(void); @@ -29,16 +28,21 @@ extern void start_property_service(void); void get_property_workspace(int *fd, int *sz); extern int __property_get(const char *name, char *value); extern int property_set(const char *name, const char *value); -extern int properties_inited(); -int get_property_set_fd(void); +extern bool properties_initialized(); +#ifndef __clang__ extern void __property_get_size_error() __attribute__((__error__("property_get called with too small buffer"))); +#else +extern void __property_get_size_error(); +#endif static inline __attribute__ ((always_inline)) __attribute__ ((gnu_inline)) +#ifndef __clang__ __attribute__ ((artificial)) +#endif int property_get(const char *name, char *value) { size_t value_len = __builtin_object_size(value, 0); diff --git a/init/readme.txt b/init/readme.txt index 26be536..6b9c42d 100644 --- a/init/readme.txt +++ b/init/readme.txt @@ -70,11 +70,11 @@ disabled setenv <name> <value> Set the environment variable <name> to <value> in the launched process. -socket <name> <type> <perm> [ <user> [ <group> [ <context> ] ] ] +socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ] Create a unix domain socket named /dev/socket/<name> and pass its fd to the launched process. <type> must be "dgram", "stream" or "seqpacket". User and group default to 0. - Context is the SELinux security context for the socket. + 'seclabel' is the SELinux security context for the socket. It defaults to the service security context, as specified by seclabel or computed based on the service executable file security context. @@ -91,8 +91,8 @@ group <groupname> [ <groupname> ]* supplemental groups of the process (via setgroups()). Currently defaults to root. (??? probably should default to nobody) -seclabel <securitycontext> - Change to securitycontext before exec'ing this service. +seclabel <seclabel> + Change to 'seclabel' before exec'ing this service. Primarily for use by services run from the rootfs, e.g. ueventd, adbd. Services on the system partition can instead use policy-defined transitions based on their file security context. @@ -110,6 +110,7 @@ class <name> onrestart Execute a Command (see below) when service restarts. + Triggers -------- Triggers are strings which can be used to match certain kinds @@ -123,40 +124,22 @@ boot Triggers of this form occur when the property <name> is set to the specific value <value>. -device-added-<path> -device-removed-<path> - Triggers of these forms occur when a device node is added - or removed. + One can also test multiple properties to execute a group + of commands. For example: + + on property:test.a=1 && property:test.b=1 + setprop test.c 1 -service-exited-<name> - Triggers of this form occur when the specified service exits. + The above stub sets test.c to 1 only when + both test.a=1 and test.b=1 Commands -------- -exec <path> [ <argument> ]* - Fork and execute a program (<path>). This will block until - the program completes execution. It is best to avoid exec - as unlike the builtin commands, it runs the risk of getting - init "stuck". (??? maybe there should be a timeout?) - -export <name> <value> - Set the environment variable <name> equal to <value> in the - global environment (which will be inherited by all processes - started after this command is executed) - -ifup <interface> - Bring the network interface <interface> online. - -import <filename> - Parse an init config file, extending the current configuration. - -hostname <name> - Set the host name. - -chdir <directory> - Change working directory. +bootchart_init + Start bootcharting if configured (see below). + This is included in the default init.rc. chmod <octal-mode> <path> Change file access permissions. @@ -164,17 +147,23 @@ chmod <octal-mode> <path> chown <owner> <group> <path> Change file owner and group. -chroot <directory> - Change process root directory. - class_start <serviceclass> Start all services of the specified class if they are not already running. class_stop <serviceclass> - Stop all services of the specified class if they are + Stop and disable all services of the specified class if they are currently running. +class_reset <serviceclass> + Stop all services of the specified class if they are + currently running, without disabling them. They can be restarted + later using class_start. + +copy <src> <dst> + Copies a file. Similar to write, but useful for binary/large + amounts of data. + domainname <name> Set the domain name. @@ -187,20 +176,63 @@ enable <servicename> on property:ro.boot.myfancyhardware=1 enable my_fancy_service_for_my_fancy_hardware +exec [ <seclabel> [ <user> [ <group> ]* ] ] -- <command> [ <argument> ]* + Fork and execute command with the given arguments. The command starts + after "--" so that an optional security context, user, and supplementary + groups can be provided. No other commands will be run until this one + finishes. + +export <name> <value> + Set the environment variable <name> equal to <value> in the + global environment (which will be inherited by all processes + started after this command is executed) + +hostname <name> + Set the host name. + +ifup <interface> + Bring the network interface <interface> online. + +import <filename> + Parse an init config file, extending the current configuration. insmod <path> Install the module at <path> +load_all_props + Loads properties from /system, /vendor, et cetera. + This is included in the default init.rc. + +load_persist_props + Loads persistent properties when /data has been decrypted. + This is included in the default init.rc. + +loglevel <level> + Sets the kernel log level to level. Properties are expanded within <level>. + mkdir <path> [mode] [owner] [group] Create a directory at <path>, optionally with the given mode, owner, and group. If not provided, the directory is created with permissions 755 and - owned by the root user and root group. + owned by the root user and root group. If provided, the mode, owner and group + will be updated if the directory exists already. -mount <type> <device> <dir> [ <mountoption> ]* +mount_all <fstab> + Calls fs_mgr_mount_all on the given fs_mgr-format fstab. + +mount <type> <device> <dir> [ <flag> ]* [<options>] Attempt to mount the named device at the directory <dir> <device> may be of the form mtd@name to specify a mtd block device by name. - <mountoption>s include "ro", "rw", "remount", "noatime", ... + <flag>s include "ro", "rw", "remount", "noatime", ... + <options> include "barrier=1", "noauto_da_alloc", "discard", ... as + a comma separated string, eg: barrier=1,noauto_da_alloc + +powerctl + Internal implementation detail used to respond to changes to the + "sys.powerctl" system property, used to implement rebooting. + +restart <service> + Like stop, but doesn't disable the service. restorecon <path> [ <path> ]* Restore the file named by <path> to the security context specified @@ -211,37 +243,31 @@ restorecon <path> [ <path> ]* restorecon_recursive <path> [ <path> ]* Recursively restore the directory tree named by <path> to the security contexts specified in the file_contexts configuration. - Do NOT use this with paths leading to shell-writable or app-writable - directories, e.g. /data/local/tmp, /data/data or any prefix thereof. - -setcon <securitycontext> - Set the current process security context to the specified string. - This is typically only used from early-init to set the init context - before any other process is started. -setenforce 0|1 - Set the SELinux system-wide enforcing status. - 0 is permissive (i.e. log but do not deny), 1 is enforcing. +rm <path> + Calls unlink(2) on the given path. You might want to + use "exec -- rm ..." instead (provided the system partition is + already mounted). -setkey - TBD +rmdir <path> + Calls rmdir(2) on the given path. setprop <name> <value> - Set system property <name> to <value>. + Set system property <name> to <value>. Properties are expanded + within <value>. setrlimit <resource> <cur> <max> Set the rlimit for a resource. -setsebool <name> <value> - Set SELinux boolean <name> to <value>. - <value> may be 1|true|on or 0|false|off - start <service> Start a service running if it is not already running. stop <service> Stop a service from running if it is currently running. +swapon_all <fstab> + Calls fs_mgr_swapon_all on the given fstab file. + symlink <target> <path> Create a symbolic link at <path> with the value <target> @@ -252,14 +278,23 @@ trigger <event> Trigger an event. Used to queue an action from another action. +verity_load_state + Internal implementation detail used to load dm-verity state. + +verity_update_state <mount_point> + Internal implementation detail used to update dm-verity state and + set the partition.<mount_point>.verified properties used by adb remount + because fs_mgr can't set them directly itself. + wait <path> [ <timeout> ] - Poll for the existence of the given file and return when found, - or the timeout has been reached. If timeout is not specified it - currently defaults to five seconds. + Poll for the existence of the given file and return when found, + or the timeout has been reached. If timeout is not specified it + currently defaults to five seconds. -write <path> <string> - Open the file at <path> and write a string to it with write(2) - without appending. +write <path> <content> + Open the file at <path> and write a string to it with write(2). + If the file does not exist, it will be created. If it does exist, + it will be truncated. Properties are expanded within <content>. Properties @@ -267,7 +302,7 @@ Properties Init updates some system properties to provide some insight into what it's doing: -init.action +init.action Equal to the name of the action currently being executed or "" if none init.command @@ -277,73 +312,62 @@ init.svc.<name> State of a named service ("stopped", "running", "restarting") -Example init.conf ------------------ - -# not complete -- just providing some examples of usage -# -on boot - export PATH /sbin:/system/sbin:/system/bin - export LD_LIBRARY_PATH /system/lib - - mkdir /dev - mkdir /proc - mkdir /sys - - mount tmpfs tmpfs /dev - mkdir /dev/pts - mkdir /dev/socket - mount devpts devpts /dev/pts - mount proc proc /proc - mount sysfs sysfs /sys - - write /proc/cpu/alignment 4 +Bootcharting +------------ +This version of init contains code to perform "bootcharting": generating log +files that can be later processed by the tools provided by www.bootchart.org. - ifup lo +On the emulator, use the -bootchart <timeout> option to boot with bootcharting +activated for <timeout> seconds. - hostname localhost - domainname localhost +On a device, create /data/bootchart/start with a command like the following: - mount yaffs2 mtd@system /system - mount yaffs2 mtd@userdata /data + adb shell 'echo $TIMEOUT > /data/bootchart/start' - import /system/etc/init.conf +Where the value of $TIMEOUT corresponds to the desired bootcharted period in +seconds. Bootcharting will stop after that many seconds have elapsed. +You can also stop the bootcharting at any moment by doing the following: - class_start default + adb shell 'echo 1 > /data/bootchart/stop' -service adbd /sbin/adbd - user adb - group adb +Note that /data/bootchart/stop is deleted automatically by init at the end of +the bootcharting. This is not the case with /data/bootchart/start, so don't +forget to delete it when you're done collecting data. -service usbd /system/bin/usbd -r - user usbd - group usbd - socket usbd 666 +The log files are written to /data/bootchart/. A script is provided to +retrieve them and create a bootchart.tgz file that can be used with the +bootchart command-line utility: -service zygote /system/bin/app_process -Xzygote /system/bin --zygote - socket zygote 666 + sudo apt-get install pybootchartgui + # grab-bootchart.sh uses $ANDROID_SERIAL. + $ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh -service runtime /system/bin/runtime - user system - group system +One thing to watch for is that the bootchart will show init as if it started +running at 0s. You'll have to look at dmesg to work out when the kernel +actually started init. -on device-added-/dev/compass - start akmd -on device-removed-/dev/compass - stop akmd - -service akmd /sbin/akmd - disabled - user akmd - group akmd - -Debugging notes ---------------- +Debugging init +-------------- By default, programs executed by init will drop stdout and stderr into /dev/null. To help with debugging, you can execute your program via the -Andoird program logwrapper. This will redirect stdout/stderr into the +Android program logwrapper. This will redirect stdout/stderr into the Android logging system (accessed via logcat). For example service akmd /system/bin/logwrapper /sbin/akmd + +For quicker turnaround when working on init itself, use: + + mm -j + m ramdisk-nodeps + m bootimage-nodeps + adb reboot bootloader + fastboot boot $ANDROID_PRODUCT_OUT/boot.img + +Alternatively, use the emulator: + + emulator -partition-size 1024 -verbose -show-kernel -no-window + +You might want to call klog_set_level(6) after the klog_init() call +so you see the kernel logging in dmesg (or the emulator output). diff --git a/init/signal_handler.c b/init/signal_handler.c deleted file mode 100644 index 7e8e1a7..0000000 --- a/init/signal_handler.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 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 <stdio.h> -#include <errno.h> -#include <signal.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/wait.h> -#include <cutils/sockets.h> -#include <cutils/android_reboot.h> -#include <cutils/list.h> - -#include "init.h" -#include "util.h" -#include "log.h" - -static int signal_fd = -1; -static int signal_recv_fd = -1; - -static void sigchld_handler(int s) -{ - write(signal_fd, &s, 1); -} - -#define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */ -#define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery*/ - -static int wait_for_one_process(int block) -{ - pid_t pid; - int status; - struct service *svc; - struct socketinfo *si; - time_t now; - struct listnode *node; - struct command *cmd; - - while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR ); - if (pid <= 0) return -1; - INFO("waitpid returned pid %d, status = %08x\n", pid, status); - - svc = service_find_by_pid(pid); - if (!svc) { - if (WIFEXITED(status)) { - ERROR("untracked pid %d exited with status %d\n", pid, WEXITSTATUS(status)); - } else if (WIFSIGNALED(status)) { - ERROR("untracked pid %d killed by signal %d\n", pid, WTERMSIG(status)); - } else if (WIFSTOPPED(status)) { - ERROR("untracked pid %d stopped by signal %d\n", pid, WSTOPSIG(status)); - } else { - ERROR("untracked pid %d state changed\n", pid); - } - return 0; - } - - NOTICE("process '%s', pid %d exited\n", svc->name, pid); - - if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) { - kill(-pid, SIGKILL); - NOTICE("process '%s' killing any children in process group\n", svc->name); - } - - /* remove any sockets we may have created */ - for (si = svc->sockets; si; si = si->next) { - char tmp[128]; - snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name); - unlink(tmp); - } - - svc->pid = 0; - svc->flags &= (~SVC_RUNNING); - - /* oneshot processes go into the disabled state on exit, - * except when manually restarted. */ - if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) { - svc->flags |= SVC_DISABLED; - } - - /* disabled and reset processes do not get restarted automatically */ - if (svc->flags & (SVC_DISABLED | SVC_RESET) ) { - notify_service_state(svc->name, "stopped"); - return 0; - } - - now = gettime(); - if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) { - if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) { - if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) { - ERROR("critical process '%s' exited %d times in %d minutes; " - "rebooting into recovery mode\n", svc->name, - CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60); - android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); - return 0; - } - } else { - svc->time_crashed = now; - svc->nr_crashed = 1; - } - } - - svc->flags &= (~SVC_RESTART); - svc->flags |= SVC_RESTARTING; - - /* Execute all onrestart commands for this service. */ - list_for_each(node, &svc->onrestart.commands) { - cmd = node_to_item(node, struct command, clist); - cmd->func(cmd->nargs, cmd->args); - } - notify_service_state(svc->name, "restarting"); - return 0; -} - -void handle_signal(void) -{ - char tmp[32]; - - /* we got a SIGCHLD - reap and restart as needed */ - read(signal_recv_fd, tmp, sizeof(tmp)); - while (!wait_for_one_process(0)) - ; -} - -void signal_init(void) -{ - int s[2]; - - struct sigaction act; - memset(&act, 0, sizeof(act)); - act.sa_handler = sigchld_handler; - act.sa_flags = SA_NOCLDSTOP; - sigaction(SIGCHLD, &act, 0); - - /* create a signalling mechanism for the sigchld handler */ - if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) { - signal_fd = s[0]; - signal_recv_fd = s[1]; - fcntl(s[0], F_SETFD, FD_CLOEXEC); - fcntl(s[0], F_SETFL, O_NONBLOCK); - fcntl(s[1], F_SETFD, FD_CLOEXEC); - fcntl(s[1], F_SETFL, O_NONBLOCK); - } - - handle_signal(); -} - -int get_signal_fd() -{ - return signal_recv_fd; -} diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp new file mode 100644 index 0000000..39a466d --- /dev/null +++ b/init/signal_handler.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (C) 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 <signal.h> +#include <stdio.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include <base/stringprintf.h> +#include <cutils/android_reboot.h> +#include <cutils/list.h> +#include <cutils/sockets.h> + +#include "init.h" +#include "log.h" +#include "util.h" + +#define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */ +#define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery */ + +static int signal_write_fd = -1; +static int signal_read_fd = -1; + +static std::string DescribeStatus(int status) { + if (WIFEXITED(status)) { + return android::base::StringPrintf("exited with status %d", WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + return android::base::StringPrintf("killed by signal %d", WTERMSIG(status)); + } else if (WIFSTOPPED(status)) { + return android::base::StringPrintf("stopped by signal %d", WSTOPSIG(status)); + } else { + return "state changed"; + } +} + +static bool wait_for_one_process() { + int status; + pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG)); + if (pid == 0) { + return false; + } else if (pid == -1) { + ERROR("waitpid failed: %s\n", strerror(errno)); + return false; + } + + service* svc = service_find_by_pid(pid); + + std::string name; + if (svc) { + name = android::base::StringPrintf("Service '%s' (pid %d)", svc->name, pid); + } else { + name = android::base::StringPrintf("Untracked pid %d", pid); + } + + NOTICE("%s %s\n", name.c_str(), DescribeStatus(status).c_str()); + + if (!svc) { + return true; + } + + // TODO: all the code from here down should be a member function on service. + + if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) { + NOTICE("Service '%s' (pid %d) killing any children in process group\n", svc->name, pid); + kill(-pid, SIGKILL); + } + + // Remove any sockets we may have created. + for (socketinfo* si = svc->sockets; si; si = si->next) { + char tmp[128]; + snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name); + unlink(tmp); + } + + if (svc->flags & SVC_EXEC) { + INFO("SVC_EXEC pid %d finished...\n", svc->pid); + waiting_for_exec = false; + list_remove(&svc->slist); + free(svc->name); + free(svc); + return true; + } + + svc->pid = 0; + svc->flags &= (~SVC_RUNNING); + + // Oneshot processes go into the disabled state on exit, + // except when manually restarted. + if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) { + svc->flags |= SVC_DISABLED; + } + + // Disabled and reset processes do not get restarted automatically. + if (svc->flags & (SVC_DISABLED | SVC_RESET)) { + svc->NotifyStateChange("stopped"); + return true; + } + + time_t now = gettime(); + if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) { + if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) { + if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) { + ERROR("critical process '%s' exited %d times in %d minutes; " + "rebooting into recovery mode\n", svc->name, + CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60); + android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); + return true; + } + } else { + svc->time_crashed = now; + svc->nr_crashed = 1; + } + } + + svc->flags &= (~SVC_RESTART); + svc->flags |= SVC_RESTARTING; + + // Execute all onrestart commands for this service. + struct listnode* node; + list_for_each(node, &svc->onrestart.commands) { + command* cmd = node_to_item(node, struct command, clist); + cmd->func(cmd->nargs, cmd->args); + } + svc->NotifyStateChange("restarting"); + return true; +} + +static void reap_any_outstanding_children() { + while (wait_for_one_process()) { + } +} + +static void handle_signal() { + // Clear outstanding requests. + char buf[32]; + read(signal_read_fd, buf, sizeof(buf)); + + reap_any_outstanding_children(); +} + +static void SIGCHLD_handler(int) { + if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) { + ERROR("write(signal_write_fd) failed: %s\n", strerror(errno)); + } +} + +void signal_handler_init() { + // Create a signalling mechanism for SIGCHLD. + int s[2]; + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) { + ERROR("socketpair failed: %s\n", strerror(errno)); + exit(1); + } + + signal_write_fd = s[0]; + signal_read_fd = s[1]; + + // Write to signal_write_fd if we catch SIGCHLD. + struct sigaction act; + memset(&act, 0, sizeof(act)); + act.sa_handler = SIGCHLD_handler; + act.sa_flags = SA_NOCLDSTOP; + sigaction(SIGCHLD, &act, 0); + + reap_any_outstanding_children(); + + register_epoll_handler(signal_read_fd, handle_signal); +} diff --git a/init/signal_handler.h b/init/signal_handler.h index b092ccb..449b4af 100644 --- a/init/signal_handler.h +++ b/init/signal_handler.h @@ -17,8 +17,6 @@ #ifndef _INIT_SIGNAL_HANDLER_H_ #define _INIT_SIGNAL_HANDLER_H_ -void signal_init(void); -void handle_signal(void); -int get_signal_fd(void); +void signal_handler_init(void); #endif diff --git a/init/ueventd.c b/init/ueventd.cpp index 833e4fd..c63fdaa 100644 --- a/init/ueventd.c +++ b/init/ueventd.cpp @@ -14,46 +14,27 @@ * limitations under the License. */ -#include <poll.h> -#include <fcntl.h> -#include <string.h> -#include <stdlib.h> -#include <stdio.h> #include <ctype.h> +#include <fcntl.h> +#include <poll.h> #include <signal.h> -#include <selinux/selinux.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <base/stringprintf.h> #include <private/android_filesystem_config.h> +#include <selinux/selinux.h> #include "ueventd.h" #include "log.h" #include "util.h" #include "devices.h" #include "ueventd_parser.h" - -static char hardware[32]; -static unsigned revision = 0; - -static void import_kernel_nv(char *name, int in_qemu) -{ - if (*name != '\0') { - char *value = strchr(name, '='); - if (value != NULL) { - *value++ = 0; - if (!strcmp(name,"androidboot.hardware")) - { - strlcpy(hardware, value, sizeof(hardware)); - } - } - } -} +#include "property_service.h" int ueventd_main(int argc, char **argv) { - struct pollfd ufd; - int nr; - char tmp[32]; - /* * init sets the umask to 077 for forked processes. We need to * create files with exact permissions, without modification by @@ -70,44 +51,38 @@ int ueventd_main(int argc, char **argv) open_devnull_stdio(); klog_init(); -#if LOG_UEVENTS - /* Ensure we're at a logging level that will show the events */ - if (klog_get_level() < KLOG_INFO_LEVEL) { - klog_set_level(KLOG_INFO_LEVEL); - } -#endif + klog_set_level(KLOG_NOTICE_LEVEL); - union selinux_callback cb; - cb.func_log = log_callback; - selinux_set_callback(SELINUX_CB_LOG, cb); + NOTICE("ueventd started!\n"); - INFO("starting ueventd\n"); - - /* Respect hardware passed in through the kernel cmd line. Here we will look - * for androidboot.hardware param in kernel cmdline, and save its value in - * hardware[]. */ - import_kernel_cmdline(0, import_kernel_nv); + selinux_callback cb; + cb.func_log = selinux_klog_callback; + selinux_set_callback(SELINUX_CB_LOG, cb); - get_hardware_name(hardware, &revision); + char hardware[PROP_VALUE_MAX]; + property_get("ro.hardware", hardware); ueventd_parse_config_file("/ueventd.rc"); - - snprintf(tmp, sizeof(tmp), "/ueventd.%s.rc", hardware); - ueventd_parse_config_file(tmp); + ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware).c_str()); device_init(); + pollfd ufd; ufd.events = POLLIN; ufd.fd = get_device_fd(); - while(1) { + while (true) { ufd.revents = 0; - nr = poll(&ufd, 1, -1); - if (nr <= 0) + int nr = poll(&ufd, 1, -1); + if (nr <= 0) { continue; - if (ufd.revents & POLLIN) - handle_device_fd(); + } + if (ufd.revents & POLLIN) { + handle_device_fd(); + } } + + return 0; } static int get_android_id(const char *id) diff --git a/init/ueventd.h b/init/ueventd.h index 0a454c5..d12d7fe 100644 --- a/init/ueventd.h +++ b/init/ueventd.h @@ -20,16 +20,18 @@ #include <cutils/list.h> #include <sys/types.h> +enum devname_src_t { + DEVNAME_UNKNOWN = 0, + DEVNAME_UEVENT_DEVNAME, + DEVNAME_UEVENT_DEVPATH, +}; + struct ueventd_subsystem { struct listnode slist; const char *name; - enum { - DEVNAME_UNKNOWN = 0, - DEVNAME_UEVENT_DEVNAME, - DEVNAME_UEVENT_DEVPATH, - } devname_src; const char *dirname; + devname_src_t devname_src; }; int ueventd_main(int argc, char **argv); diff --git a/init/ueventd_parser.c b/init/ueventd_parser.cpp index e447006..7a4841f 100644 --- a/init/ueventd_parser.c +++ b/init/ueventd_parser.cpp @@ -67,9 +67,7 @@ static int lookup_keyword(const char *s) return K_UNKNOWN; } -static void parse_line_no_op(struct parse_state *state __attribute__((unused)), - int nargs __attribute__((unused)), char **args __attribute__((unused))) -{ +static void parse_line_no_op(struct parse_state*, int, char**) { } static int valid_name(const char *name) @@ -97,24 +95,20 @@ struct ueventd_subsystem *ueventd_subsystem_find_by_name(const char *name) return 0; } -static void *parse_subsystem(struct parse_state *state, - int nargs __attribute__((unused)), char **args) -{ - struct ueventd_subsystem *s; - +static void *parse_subsystem(parse_state* state, int /*nargs*/, char** args) { if (!valid_name(args[1])) { parse_error(state, "invalid subsystem name '%s'\n", args[1]); return 0; } - s = ueventd_subsystem_find_by_name(args[1]); + ueventd_subsystem* s = ueventd_subsystem_find_by_name(args[1]); if (s) { parse_error(state, "ignored duplicate definition of subsystem '%s'\n", args[1]); return 0; } - s = calloc(1, sizeof(*s)); + s = (ueventd_subsystem*) calloc(1, sizeof(*s)); if (!s) { parse_error(state, "out of memory\n"); return 0; @@ -128,7 +122,7 @@ static void *parse_subsystem(struct parse_state *state, static void parse_line_subsystem(struct parse_state *state, int nargs, char **args) { - struct ueventd_subsystem *s = state->context; + struct ueventd_subsystem *s = (ueventd_subsystem*) state->context; int kw; if (nargs == 0) { @@ -197,7 +191,7 @@ static void parse_line(struct parse_state *state, char **args, int nargs) } } -static void parse_config(const char *fn, char *s) +static void parse_config(const char *fn, const std::string& data) { struct parse_state state; char *args[UEVENTD_PARSER_MAXARGS]; @@ -205,7 +199,7 @@ static void parse_config(const char *fn, char *s) nargs = 0; state.filename = fn; state.line = 1; - state.ptr = s; + state.ptr = strdup(data.c_str()); // TODO: fix this code! state.nexttoken = 0; state.parse_line = parse_line_no_op; for (;;) { @@ -232,17 +226,16 @@ static void parse_config(const char *fn, char *s) int ueventd_parse_config_file(const char *fn) { - char *data; - data = read_file(fn, 0); - if (!data) return -1; + std::string data; + if (!read_file(fn, &data)) { + return -1; + } parse_config(fn, data); - DUMP(); + dump_parser_state(); return 0; } -static void parse_line_device(struct parse_state *state __attribute__((unused)), - int nargs, char **args) -{ +static void parse_line_device(parse_state*, int nargs, char** args) { set_device_permission(nargs, args); } diff --git a/init/util.c b/init/util.cpp index 12cb11d..20ce806 100644 --- a/init/util.c +++ b/init/util.cpp @@ -32,6 +32,8 @@ #include <sys/socket.h> #include <sys/un.h> +#include <base/file.h> + /* for ANDROID_SOCKET_* */ #include <cutils/sockets.h> @@ -146,48 +148,46 @@ out_close: return -1; } -/* reads a file, making sure it is terminated with \n \0 */ -void *read_file(const char *fn, unsigned *_sz) -{ - char *data; - int sz; - int fd; - struct stat sb; +bool read_file(const char* path, std::string* content) { + content->clear(); - data = 0; - fd = open(fn, O_RDONLY); - if(fd < 0) return 0; + int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC)); + if (fd == -1) { + return false; + } - // for security reasons, disallow world-writable - // or group-writable files - if (fstat(fd, &sb) < 0) { - ERROR("fstat failed for '%s'\n", fn); - goto oops; + // For security reasons, disallow world-writable + // or group-writable files. + struct stat sb; + if (fstat(fd, &sb) == -1) { + ERROR("fstat failed for '%s': %s\n", path, strerror(errno)); + return false; } if ((sb.st_mode & (S_IWGRP | S_IWOTH)) != 0) { - ERROR("skipping insecure file '%s'\n", fn); - goto oops; + ERROR("skipping insecure file '%s'\n", path); + return false; } - sz = lseek(fd, 0, SEEK_END); - if(sz < 0) goto oops; - - if(lseek(fd, 0, SEEK_SET) != 0) goto oops; - - data = (char*) malloc(sz + 2); - if(data == 0) goto oops; - - if(read(fd, data, sz) != sz) goto oops; - close(fd); - data[sz] = '\n'; - data[sz+1] = 0; - if(_sz) *_sz = sz; - return data; + bool okay = android::base::ReadFdToString(fd, content); + TEMP_FAILURE_RETRY(close(fd)); + if (okay) { + content->append("\n", 1); + } + return okay; +} -oops: - close(fd); - if(data != 0) free(data); - return 0; +int write_file(const char* path, const char* content) { + int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0600)); + if (fd == -1) { + NOTICE("write_file: Unable to open '%s': %s\n", path, strerror(errno)); + return -1; + } + int result = android::base::WriteStringToFd(content, fd) ? 0 : -1; + if (result == -1) { + NOTICE("write_file: Unable to write to '%s': %s\n", path, strerror(errno)); + } + TEMP_FAILURE_RETRY(close(fd)); + return result; } #define MAX_MTD_PARTITIONS 16 @@ -207,7 +207,7 @@ static void find_mtd_partitions(void) ssize_t pmtdsize; int r; - fd = open("/proc/mtd", O_RDONLY); + fd = open("/proc/mtd", O_RDONLY|O_CLOEXEC); if (fd < 0) return; @@ -262,22 +262,16 @@ int mtd_name_to_number(const char *name) return -1; } -/* - * gettime() - returns the time in seconds of the system's monotonic clock or - * zero on error. - */ -time_t gettime(void) -{ - struct timespec ts; - int ret; - - ret = clock_gettime(CLOCK_MONOTONIC, &ts); - if (ret < 0) { - ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno)); - return 0; - } +time_t gettime() { + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return now.tv_sec; +} - return ts.tv_sec; +uint64_t gettime_ns() { + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec; } int mkdir_recursive(const char *pathname, mode_t mode) @@ -385,101 +379,37 @@ int wait_for_file(const char *filename, int timeout) void open_devnull_stdio(void) { - int fd; - static const char *name = "/dev/__null__"; - if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) { - fd = open(name, O_RDWR); - unlink(name); - if (fd >= 0) { - dup2(fd, 0); - dup2(fd, 1); - dup2(fd, 2); - if (fd > 2) { - close(fd); - } - return; - } - } - - exit(1); -} - -void get_hardware_name(char *hardware, unsigned int *revision) -{ - const char *cpuinfo = "/proc/cpuinfo"; - char *data = NULL; - size_t len = 0, limit = 1024; - int fd, n; - char *x, *hw, *rev; - - /* Hardware string was provided on kernel command line */ - if (hardware[0]) - return; - - fd = open(cpuinfo, O_RDONLY); - if (fd < 0) return; - - for (;;) { - x = realloc(data, limit); - if (!x) { - ERROR("Failed to allocate memory to read %s\n", cpuinfo); - goto done; + // Try to avoid the mknod() call if we can. Since SELinux makes + // a /dev/null replacement available for free, let's use it. + int fd = open("/sys/fs/selinux/null", O_RDWR); + if (fd == -1) { + // OOPS, /sys/fs/selinux/null isn't available, likely because + // /sys/fs/selinux isn't mounted. Fall back to mknod. + static const char *name = "/dev/__null__"; + if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) { + fd = open(name, O_RDWR); + unlink(name); } - data = x; - - n = read(fd, data + len, limit - len); - if (n < 0) { - ERROR("Failed reading %s: %s (%d)\n", cpuinfo, strerror(errno), errno); - goto done; + if (fd == -1) { + exit(1); } - len += n; - - if (len < limit) - break; - - /* We filled the buffer, so increase size and loop to read more */ - limit *= 2; } - data[len] = 0; - hw = strstr(data, "\nHardware"); - rev = strstr(data, "\nRevision"); - - if (hw) { - x = strstr(hw, ": "); - if (x) { - x += 2; - n = 0; - while (*x && *x != '\n') { - if (!isspace(*x)) - hardware[n++] = tolower(*x); - x++; - if (n == 31) break; - } - hardware[n] = 0; - } - } - - if (rev) { - x = strstr(rev, ": "); - if (x) { - *revision = strtoul(x + 2, 0, 16); - } + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + if (fd > 2) { + close(fd); } - -done: - close(fd); - free(data); } -void import_kernel_cmdline(int in_qemu, - void (*import_kernel_nv)(char *name, int in_qemu)) +void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)> import_kernel_nv) { char cmdline[2048]; char *ptr; int fd; - fd = open("/proc/cmdline", O_RDONLY); + fd = open("/proc/cmdline", O_RDONLY | O_CLOEXEC); if (fd >= 0) { int n = read(fd, cmdline, sizeof(cmdline) - 1); if (n < 0) n = 0; diff --git a/init/util.h b/init/util.h index a7e7c8b..1c947ec 100644 --- a/init/util.h +++ b/init/util.h @@ -20,15 +20,36 @@ #include <sys/stat.h> #include <sys/types.h> +#include <string> +#include <functional> + #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) -static const char *coldboot_done = "/dev/.coldboot_done"; +#define COLDBOOT_DONE "/dev/.coldboot_done" int mtd_name_to_number(const char *name); int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid, const char *socketcon); -void *read_file(const char *fn, unsigned *_sz); -time_t gettime(void); + +bool read_file(const char* path, std::string* content); +int write_file(const char* path, const char* content); + +time_t gettime(); +uint64_t gettime_ns(); + +class Timer { + public: + Timer() : t0(gettime_ns()) { + } + + double duration() { + return static_cast<double>(gettime_ns() - t0) / 1000000000.0; + } + + private: + uint64_t t0; +}; + unsigned int decode_uid(const char *s); int mkdir_recursive(const char *pathname, mode_t mode); @@ -37,8 +58,7 @@ void make_link_init(const char *oldpath, const char *newpath); void remove_link(const char *oldpath, const char *newpath); int wait_for_file(const char *filename, int timeout); void open_devnull_stdio(void); -void get_hardware_name(char *hardware, unsigned int *revision); -void import_kernel_cmdline(int in_qemu, void (*import_kernel_nv)(char *name, int in_qemu)); +void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)>); int make_dir(const char *path, mode_t mode); int restorecon(const char *pathname); int restorecon_recursive(const char *pathname); diff --git a/init/util_test.cpp b/init/util_test.cpp new file mode 100644 index 0000000..5b3ab50 --- /dev/null +++ b/init/util_test.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 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 "util.h" + +#include <errno.h> +#include <gtest/gtest.h> + +TEST(util, read_file_ENOENT) { + std::string s("hello"); + errno = 0; + EXPECT_FALSE(read_file("/proc/does-not-exist", &s)); + EXPECT_EQ(ENOENT, errno); + EXPECT_EQ("", s); // s was cleared. +} + +TEST(util, read_file_success) { + std::string s("hello"); + EXPECT_TRUE(read_file("/proc/version", &s)); + EXPECT_GT(s.length(), 6U); + EXPECT_EQ('\n', s[s.length() - 1]); + s[5] = 0; + EXPECT_STREQ("Linux", s.c_str()); +} + +TEST(util, decode_uid) { + EXPECT_EQ(0U, decode_uid("root")); + EXPECT_EQ(-1U, decode_uid("toot")); + EXPECT_EQ(123U, decode_uid("123")); +} diff --git a/init/watchdogd.c b/init/watchdogd.cpp index fb53836..881a4df 100644 --- a/init/watchdogd.c +++ b/init/watchdogd.cpp @@ -18,6 +18,7 @@ #include <fcntl.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #include <linux/watchdog.h> @@ -26,52 +27,45 @@ #define DEV_NAME "/dev/watchdog" -int watchdogd_main(int argc, char **argv) -{ - int fd; - int ret; - int interval = 10; - int margin = 10; - int timeout; - +int watchdogd_main(int argc, char **argv) { open_devnull_stdio(); klog_init(); + klog_set_level(KLOG_NOTICE_LEVEL); - INFO("Starting watchdogd\n"); - - if (argc >= 2) - interval = atoi(argv[1]); + int interval = 10; + if (argc >= 2) interval = atoi(argv[1]); - if (argc >= 3) - margin = atoi(argv[2]); + int margin = 10; + if (argc >= 3) margin = atoi(argv[2]); - timeout = interval + margin; + NOTICE("watchdogd started (interval %d, margin %d)!\n", interval, margin); - fd = open(DEV_NAME, O_RDWR); - if (fd < 0) { + int fd = open(DEV_NAME, O_RDWR|O_CLOEXEC); + if (fd == -1) { ERROR("watchdogd: Failed to open %s: %s\n", DEV_NAME, strerror(errno)); return 1; } - ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout); + int timeout = interval + margin; + int ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout); if (ret) { ERROR("watchdogd: Failed to set timeout to %d: %s\n", timeout, strerror(errno)); ret = ioctl(fd, WDIOC_GETTIMEOUT, &timeout); if (ret) { ERROR("watchdogd: Failed to get timeout: %s\n", strerror(errno)); } else { - if (timeout > margin) + if (timeout > margin) { interval = timeout - margin; - else + } else { interval = 1; + } ERROR("watchdogd: Adjusted interval to timeout returned by driver: timeout %d, interval %d, margin %d\n", timeout, interval, margin); } } - while(1) { + while (true) { write(fd, "", 1); sleep(interval); } } - diff --git a/libbacktrace/Android.build.mk b/libbacktrace/Android.build.mk index 2f55645..35fed6d 100644 --- a/libbacktrace/Android.build.mk +++ b/libbacktrace/Android.build.mk @@ -19,28 +19,37 @@ include $(CLEAR_VARS) LOCAL_MODULE := $(module) LOCAL_MODULE_TAGS := $(module_tag) LOCAL_MULTILIB := $($(module)_multilib) +ifeq ($(LOCAL_MULTILIB),both) +ifneq ($(build_target),$(filter $(build_target),SHARED_LIBRARY STATIC_LIBRRARY)) + LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 + LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 +endif +endif LOCAL_ADDITIONAL_DEPENDENCIES := \ $(LOCAL_PATH)/Android.mk \ $(LOCAL_PATH)/Android.build.mk \ LOCAL_CFLAGS := \ - $(common_cflags) \ + $(libbacktrace_common_cflags) \ $($(module)_cflags) \ $($(module)_cflags_$(build_type)) \ +LOCAL_CLANG_CFLAGS += \ + $(libbacktrace_common_clang_cflags) \ + LOCAL_CONLYFLAGS += \ - $(common_conlyflags) \ + $(libbacktrace_common_conlyflags) \ $($(module)_conlyflags) \ $($(module)_conlyflags_$(build_type)) \ LOCAL_CPPFLAGS += \ - $(common_cppflags) \ + $(libbacktrace_common_cppflags) \ $($(module)_cppflags) \ $($(module)_cppflags_$(build_type)) \ LOCAL_C_INCLUDES := \ - $(common_c_includes) \ + $(libbacktrace_common_c_includes) \ $($(module)_c_includes) \ $($(module)_c_includes_$(build_type)) \ @@ -61,21 +70,13 @@ LOCAL_LDLIBS := \ $($(module)_ldlibs_$(build_type)) \ ifeq ($(build_type),target) - ifneq ($($(module)_libc++),) - include external/libcxx/libcxx.mk - else - include external/stlport/libstlport.mk - endif - include $(BUILD_$(build_target)) endif ifeq ($(build_type),host) # Only build if host builds are supported. ifeq ($(build_host),true) - ifneq ($($(module)_libc++),) - include external/libcxx/libcxx.mk - endif + LOCAL_CFLAGS += -Wno-extern-c-compat -fno-omit-frame-pointer include $(BUILD_HOST_$(build_target)) endif endif diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk index 9588dd6..54cace9 100755..100644 --- a/libbacktrace/Android.mk +++ b/libbacktrace/Android.mk @@ -16,16 +16,20 @@ LOCAL_PATH:= $(call my-dir) -common_cflags := \ +libbacktrace_common_cflags := \ -Wall \ -Werror \ -common_conlyflags := \ +libbacktrace_common_conlyflags := \ -std=gnu99 \ -common_cppflags := \ +libbacktrace_common_cppflags := \ -std=gnu++11 \ +# The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists. +libbacktrace_common_clang_cflags += \ + -Wno-inline-asm + build_host := false ifeq ($(HOST_OS),linux) ifeq ($(HOST_ARCH),$(filter $(HOST_ARCH),x86 x86_64)) @@ -37,26 +41,22 @@ endif # The libbacktrace library. #------------------------------------------------------------------------- libbacktrace_src_files := \ - BacktraceImpl.cpp \ + Backtrace.cpp \ + BacktraceCurrent.cpp \ BacktraceMap.cpp \ - BacktraceThread.cpp \ + BacktracePtrace.cpp \ thread_utils.c \ - -libbacktrace_shared_libraries_target := \ - libcutils \ - libgccdemangle \ - -libbacktrace_src_files += \ + ThreadEntry.cpp \ UnwindCurrent.cpp \ UnwindMap.cpp \ UnwindPtrace.cpp \ -libbacktrace_c_includes := \ - external/libunwind/include \ +libbacktrace_shared_libraries_target := \ + libcutils \ libbacktrace_shared_libraries := \ + libbase \ libunwind \ - libunwind-ptrace \ libbacktrace_shared_libraries_host := \ liblog \ @@ -74,58 +74,9 @@ build_type := target build_target := SHARED_LIBRARY include $(LOCAL_PATH)/Android.build.mk build_type := host +libbacktrace_multilib := both include $(LOCAL_PATH)/Android.build.mk -# Don't build for unbundled branches -ifeq (,$(TARGET_BUILD_APPS)) -#------------------------------------------------------------------------- -# The libbacktrace library (libc++) -#------------------------------------------------------------------------- -libbacktrace_libc++_src_files := \ - BacktraceImpl.cpp \ - BacktraceMap.cpp \ - BacktraceThread.cpp \ - thread_utils.c \ - -libbacktrace_libc++_shared_libraries_target := \ - libcutils \ - libgccdemangle \ - -libbacktrace_libc++_src_files += \ - UnwindCurrent.cpp \ - UnwindMap.cpp \ - UnwindPtrace.cpp \ - -libbacktrace_libc++_c_includes := \ - external/libunwind/include \ - -libbacktrace_libc++_shared_libraries := \ - libunwind \ - libunwind-ptrace \ - -libbacktrace_libc++_shared_libraries_host := \ - liblog \ - -libbacktrace_libc++_static_libraries_host := \ - libcutils \ - -libbacktrace_libc++_ldlibs_host := \ - -lpthread \ - -lrt \ - -libbacktrace_libc++_libc++ := true - -module := libbacktrace_libc++ -module_tag := optional -build_type := target -build_target := SHARED_LIBRARY -include $(LOCAL_PATH)/Android.build.mk -build_type := host -libbacktrace_libc++_multilib := both -include $(LOCAL_PATH)/Android.build.mk -libbacktrace_libc++_multilib := -endif - #------------------------------------------------------------------------- # The libbacktrace_test library needed by backtrace_test. #------------------------------------------------------------------------- @@ -139,6 +90,7 @@ module := libbacktrace_test module_tag := debug build_type := target build_target := SHARED_LIBRARY +libbacktrace_test_multilib := both include $(LOCAL_PATH)/Android.build.mk build_type := host include $(LOCAL_PATH)/Android.build.mk @@ -177,6 +129,7 @@ module := backtrace_test module_tag := debug build_type := target build_target := NATIVE_TEST +backtrace_test_multilib := both include $(LOCAL_PATH)/Android.build.mk build_type := host include $(LOCAL_PATH)/Android.build.mk @@ -194,25 +147,8 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := \ BacktraceMap.cpp \ -include $(BUILD_HOST_SHARED_LIBRARY) - -# Don't build for unbundled branches -ifeq (,$(TARGET_BUILD_APPS)) -#------------------------------------------------------------------------- -# The libbacktrace library (libc++) -#------------------------------------------------------------------------- -include $(CLEAR_VARS) - -LOCAL_MODULE := libbacktrace_libc++ -LOCAL_MODULE_TAGS := optional - -LOCAL_SRC_FILES := \ - BacktraceMap.cpp \ - LOCAL_MULTILIB := both include $(BUILD_HOST_SHARED_LIBRARY) -endif # TARGET_BUILD_APPS - endif # HOST_OS-darwin diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp new file mode 100644 index 0000000..91ca8b7 --- /dev/null +++ b/libbacktrace/Backtrace.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2013 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 <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/types.h> +#include <ucontext.h> + +#include <string> + +#include <base/stringprintf.h> + +#include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> + +#include "BacktraceLog.h" +#include "thread_utils.h" +#include "UnwindCurrent.h" +#include "UnwindPtrace.h" + +using android::base::StringPrintf; + +//------------------------------------------------------------------------- +// Backtrace functions. +//------------------------------------------------------------------------- +Backtrace::Backtrace(pid_t pid, pid_t tid, BacktraceMap* map) + : pid_(pid), tid_(tid), map_(map), map_shared_(true) { + if (map_ == nullptr) { + map_ = BacktraceMap::Create(pid); + map_shared_ = false; + } +} + +Backtrace::~Backtrace() { + if (map_ && !map_shared_) { + delete map_; + map_ = nullptr; + } +} + +extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len, + int* status); + +std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) { + std::string func_name = GetFunctionNameRaw(pc, offset); + if (!func_name.empty()) { +#if defined(__APPLE__) + // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7. + if (func_name[0] != '_') { + return func_name; + } +#endif + char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0); + if (name) { + func_name = name; + free(name); + } + } + return func_name; +} + +bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) { + if (ptr & (sizeof(word_t)-1)) { + BACK_LOGW("invalid pointer %p", reinterpret_cast<void*>(ptr)); + *out_value = static_cast<word_t>(-1); + return false; + } + return true; +} + +std::string Backtrace::FormatFrameData(size_t frame_num) { + if (frame_num >= frames_.size()) { + return ""; + } + return FormatFrameData(&frames_[frame_num]); +} + +std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) { + const char* map_name; + if (BacktraceMap::IsValid(frame->map) && !frame->map.name.empty()) { + map_name = frame->map.name.c_str(); + } else { + map_name = "<unknown>"; + } + + uintptr_t relative_pc; + if (BacktraceMap::IsValid(frame->map)) { + relative_pc = frame->pc - frame->map.start; + } else { + relative_pc = frame->pc; + } + + std::string line(StringPrintf("#%02zu pc %" PRIPTR " %s", frame->num, relative_pc, map_name)); + if (!frame->func_name.empty()) { + line += " (" + frame->func_name; + if (frame->func_offset) { + line += StringPrintf("+%" PRIuPTR, frame->func_offset); + } + line += ')'; + } + + return line; +} + +void Backtrace::FillInMap(uintptr_t pc, backtrace_map_t* map) { + map_->FillIn(pc, map); +} + +Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) { + if (pid == BACKTRACE_CURRENT_PROCESS) { + pid = getpid(); + if (tid == BACKTRACE_CURRENT_THREAD) { + tid = gettid(); + } + } else if (tid == BACKTRACE_CURRENT_THREAD) { + tid = pid; + } + + if (pid == getpid()) { + return new UnwindCurrent(pid, tid, map); + } else { + return new UnwindPtrace(pid, tid, map); + } +} diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp new file mode 100644 index 0000000..fd1f4da --- /dev/null +++ b/libbacktrace/BacktraceCurrent.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2013 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 _GNU_SOURCE 1 +#include <errno.h> +#include <stdint.h> +#include <string.h> +#include <sys/param.h> +#include <sys/ptrace.h> +#include <sys/types.h> +#include <ucontext.h> +#include <unistd.h> + +#include <string> + +#include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> + +#include "BacktraceCurrent.h" +#include "BacktraceLog.h" +#include "ThreadEntry.h" +#include "thread_utils.h" + +bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) { + if (!VerifyReadWordArgs(ptr, out_value)) { + return false; + } + + backtrace_map_t map; + FillInMap(ptr, &map); + if (BacktraceMap::IsValid(map) && map.flags & PROT_READ) { + *out_value = *reinterpret_cast<word_t*>(ptr); + return true; + } else { + BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr)); + *out_value = static_cast<word_t>(-1); + return false; + } +} + +size_t BacktraceCurrent::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) { + backtrace_map_t map; + FillInMap(addr, &map); + if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) { + return 0; + } + bytes = MIN(map.end - addr, bytes); + memcpy(buffer, reinterpret_cast<uint8_t*>(addr), bytes); + return bytes; +} + +bool BacktraceCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { + if (ucontext) { + return UnwindFromContext(num_ignore_frames, ucontext); + } + + if (Tid() != gettid()) { + return UnwindThread(num_ignore_frames); + } + + return UnwindFromContext(num_ignore_frames, nullptr); +} + +bool BacktraceCurrent::DiscardFrame(const backtrace_frame_data_t& frame) { + if (BacktraceMap::IsValid(frame.map)) { + const std::string library = basename(frame.map.name.c_str()); + if (library == "libunwind.so" || library == "libbacktrace.so") { + return true; + } + } + return false; +} + +static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER; + +static void SignalHandler(int, siginfo_t*, void* sigcontext) { + ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false); + if (!entry) { + BACK_LOGW("Unable to find pid %d tid %d information", getpid(), gettid()); + return; + } + + entry->CopyUcontextFromSigcontext(sigcontext); + + // Indicate the ucontext is now valid. + entry->Wake(); + + // Pause the thread until the unwind is complete. This avoids having + // the thread run ahead causing problems. + // The number indicates that we are waiting for the second Wake() call + // overall which is made by the thread requesting an unwind. + entry->Wait(2); + + ThreadEntry::Remove(entry); +} + +bool BacktraceCurrent::UnwindThread(size_t num_ignore_frames) { + // Prevent multiple threads trying to set the trigger action on different + // threads at the same time. + pthread_mutex_lock(&g_sigaction_mutex); + + ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid()); + entry->Lock(); + + struct sigaction act, oldact; + memset(&act, 0, sizeof(act)); + act.sa_sigaction = SignalHandler; + act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; + sigemptyset(&act.sa_mask); + if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) { + BACK_LOGW("sigaction failed %s", strerror(errno)); + entry->Unlock(); + ThreadEntry::Remove(entry); + pthread_mutex_unlock(&g_sigaction_mutex); + return false; + } + + if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) { + BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno)); + sigaction(THREAD_SIGNAL, &oldact, nullptr); + entry->Unlock(); + ThreadEntry::Remove(entry); + pthread_mutex_unlock(&g_sigaction_mutex); + return false; + } + + // Wait for the thread to get the ucontext. The number indicates + // that we are waiting for the first Wake() call made by the thread. + entry->Wait(1); + + // After the thread has received the signal, allow other unwinders to + // continue. + sigaction(THREAD_SIGNAL, &oldact, nullptr); + pthread_mutex_unlock(&g_sigaction_mutex); + + bool unwind_done = UnwindFromContext(num_ignore_frames, entry->GetUcontext()); + + // Tell the signal handler to exit and release the entry. + entry->Wake(); + + return unwind_done; +} diff --git a/libbacktrace/BacktraceCurrent.h b/libbacktrace/BacktraceCurrent.h new file mode 100644 index 0000000..8aad36d --- /dev/null +++ b/libbacktrace/BacktraceCurrent.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 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 _LIBBACKTRACE_BACKTRACE_CURRENT_H +#define _LIBBACKTRACE_BACKTRACE_CURRENT_H + +#include <stdint.h> +#include <sys/types.h> +#include <ucontext.h> + +#include <backtrace/Backtrace.h> + +// The signal used to cause a thread to dump the stack. +#if defined(__GLIBC__) +// In order to run the backtrace_tests on the host, we can't use +// the internal real time signals used by GLIBC. To avoid this, +// use SIGRTMIN for the signal to dump the stack. +#define THREAD_SIGNAL SIGRTMIN +#else +#define THREAD_SIGNAL (__SIGRTMIN+1) +#endif + +class BacktraceMap; + +class BacktraceCurrent : public Backtrace { +public: + BacktraceCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {} + virtual ~BacktraceCurrent() {} + + size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override; + + bool ReadWord(uintptr_t ptr, word_t* out_value) override; + + bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override; + +protected: + bool DiscardFrame(const backtrace_frame_data_t& frame); + +private: + bool UnwindThread(size_t num_ignore_frames); + + virtual bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) = 0; +}; + +#endif // _LIBBACKTRACE_BACKTRACE_CURRENT_H diff --git a/libbacktrace/BacktraceImpl.cpp b/libbacktrace/BacktraceImpl.cpp deleted file mode 100644 index 405b042..0000000 --- a/libbacktrace/BacktraceImpl.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) 2013 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 <stdlib.h> -#include <string.h> -#include <sys/ptrace.h> -#include <sys/types.h> -#include <ucontext.h> -#include <unistd.h> - -#include <string> - -#include <backtrace/Backtrace.h> -#include <backtrace/BacktraceMap.h> - -#include "BacktraceImpl.h" -#include "BacktraceLog.h" -#include "thread_utils.h" - -//------------------------------------------------------------------------- -// Backtrace functions. -//------------------------------------------------------------------------- -Backtrace::Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map) - : pid_(pid), tid_(-1), map_(map), map_shared_(true), impl_(impl) { - impl_->SetParent(this); - - if (map_ == NULL) { - map_ = BacktraceMap::Create(pid); - map_shared_ = false; - } -} - -Backtrace::~Backtrace() { - if (impl_) { - delete impl_; - impl_ = NULL; - } - - if (map_ && !map_shared_) { - delete map_; - map_ = NULL; - } -} - -bool Backtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { - return impl_->Unwind(num_ignore_frames, ucontext); -} - -extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len, - int* status); - -std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) { - std::string func_name = impl_->GetFunctionNameRaw(pc, offset); - if (!func_name.empty()) { -#if defined(__APPLE__) - // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7. - if (func_name[0] != '_') { - return func_name; - } -#endif - char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0); - if (name) { - func_name = name; - free(name); - } - } - return func_name; -} - -bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) { - if (ptr & (sizeof(word_t)-1)) { - BACK_LOGW("invalid pointer %p", (void*)ptr); - *out_value = (word_t)-1; - return false; - } - return true; -} - -std::string Backtrace::FormatFrameData(size_t frame_num) { - if (frame_num >= frames_.size()) { - return ""; - } - return FormatFrameData(&frames_[frame_num]); -} - -std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) { - const char* map_name; - if (frame->map && !frame->map->name.empty()) { - map_name = frame->map->name.c_str(); - } else { - map_name = "<unknown>"; - } - - uintptr_t relative_pc; - if (frame->map) { - relative_pc = frame->pc - frame->map->start; - } else { - relative_pc = frame->pc; - } - - char buf[512]; - if (!frame->func_name.empty() && frame->func_offset) { - snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s+%" PRIuPTR ")", - frame->num, (int)sizeof(uintptr_t)*2, relative_pc, map_name, - frame->func_name.c_str(), frame->func_offset); - } else if (!frame->func_name.empty()) { - snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s)", frame->num, - (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name.c_str()); - } else { - snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s", frame->num, - (int)sizeof(uintptr_t)*2, relative_pc, map_name); - } - - return buf; -} - -const backtrace_map_t* Backtrace::FindMap(uintptr_t pc) { - return map_->Find(pc); -} - -//------------------------------------------------------------------------- -// BacktraceCurrent functions. -//------------------------------------------------------------------------- -BacktraceCurrent::BacktraceCurrent( - BacktraceImpl* impl, BacktraceMap* map) : Backtrace(impl, getpid(), map) { -} - -BacktraceCurrent::~BacktraceCurrent() { -} - -bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) { - if (!VerifyReadWordArgs(ptr, out_value)) { - return false; - } - - const backtrace_map_t* map = FindMap(ptr); - if (map && map->flags & PROT_READ) { - *out_value = *reinterpret_cast<word_t*>(ptr); - return true; - } else { - BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr)); - *out_value = static_cast<word_t>(-1); - return false; - } -} - -//------------------------------------------------------------------------- -// BacktracePtrace functions. -//------------------------------------------------------------------------- -BacktracePtrace::BacktracePtrace( - BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map) - : Backtrace(impl, pid, map) { - tid_ = tid; -} - -BacktracePtrace::~BacktracePtrace() { -} - -bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) { - if (!VerifyReadWordArgs(ptr, out_value)) { - return false; - } - -#if defined(__APPLE__) - BACK_LOGW("MacOS does not support reading from another pid."); - return false; -#else - // ptrace() returns -1 and sets errno when the operation fails. - // To disambiguate -1 from a valid result, we clear errno beforehand. - errno = 0; - *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL); - if (*out_value == static_cast<word_t>(-1) && errno) { - BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s", - reinterpret_cast<void*>(ptr), Tid(), strerror(errno)); - return false; - } - return true; -#endif -} - -Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) { - if (pid == BACKTRACE_CURRENT_PROCESS || pid == getpid()) { - if (tid == BACKTRACE_CURRENT_THREAD || tid == gettid()) { - return CreateCurrentObj(map); - } else { - return CreateThreadObj(tid, map); - } - } else if (tid == BACKTRACE_CURRENT_THREAD) { - return CreatePtraceObj(pid, pid, map); - } else { - return CreatePtraceObj(pid, tid, map); - } -} diff --git a/libbacktrace/BacktraceImpl.h b/libbacktrace/BacktraceImpl.h deleted file mode 100755 index d34ad05..0000000 --- a/libbacktrace/BacktraceImpl.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2013 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 _LIBBACKTRACE_BACKTRACE_IMPL_H -#define _LIBBACKTRACE_BACKTRACE_IMPL_H - -#include <backtrace/Backtrace.h> -#include <backtrace/BacktraceMap.h> - -#include <sys/types.h> - -class BacktraceImpl { -public: - virtual ~BacktraceImpl() { } - - virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) = 0; - - // The name returned is not demangled, Backtrace::GetFunctionName() - // takes care of demangling the name. - virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) = 0; - - void SetParent(Backtrace* backtrace) { backtrace_obj_ = backtrace; } - - inline pid_t Pid() { return backtrace_obj_->Pid(); } - inline pid_t Tid() { return backtrace_obj_->Tid(); } - - inline const backtrace_map_t* FindMap(uintptr_t addr) { - return backtrace_obj_->FindMap(addr); - } - inline std::string GetFunctionName(uintptr_t pc, uintptr_t* offset) { - return backtrace_obj_->GetFunctionName(pc, offset); - } - inline BacktraceMap* GetMap() { return backtrace_obj_->GetMap(); } - -protected: - inline std::vector<backtrace_frame_data_t>* GetFrames() { return &backtrace_obj_->frames_; } - - Backtrace* backtrace_obj_; -}; - -class BacktraceCurrent : public Backtrace { -public: - BacktraceCurrent(BacktraceImpl* impl, BacktraceMap* map); - virtual ~BacktraceCurrent(); - - bool ReadWord(uintptr_t ptr, word_t* out_value); -}; - -class BacktracePtrace : public Backtrace { -public: - BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map); - virtual ~BacktracePtrace(); - - bool ReadWord(uintptr_t ptr, word_t* out_value); -}; - -Backtrace* CreateCurrentObj(BacktraceMap* map); -Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map); -Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map); - -#endif // _LIBBACKTRACE_BACKTRACE_IMPL_H diff --git a/libbacktrace/BacktraceLog.h b/libbacktrace/BacktraceLog.h index 1632ec2..1632ec2 100755..100644 --- a/libbacktrace/BacktraceLog.h +++ b/libbacktrace/BacktraceLog.h diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp index f38e484..b0ada46 100644 --- a/libbacktrace/BacktraceMap.cpp +++ b/libbacktrace/BacktraceMap.cpp @@ -15,18 +15,15 @@ */ #include <ctype.h> +#include <stdint.h> #include <sys/types.h> #include <unistd.h> -#include <string> -#include <vector> - #include <backtrace/backtrace_constants.h> #include <backtrace/BacktraceMap.h> #include <log/log.h> #include "thread_utils.h" -#include "BacktraceImpl.h" BacktraceMap::BacktraceMap(pid_t pid) : pid_(pid) { if (pid_ < 0) { @@ -37,14 +34,15 @@ BacktraceMap::BacktraceMap(pid_t pid) : pid_(pid) { BacktraceMap::~BacktraceMap() { } -const backtrace_map_t* BacktraceMap::Find(uintptr_t addr) { +void BacktraceMap::FillIn(uintptr_t addr, backtrace_map_t* map) { for (BacktraceMap::const_iterator it = begin(); it != end(); ++it) { if (addr >= it->start && addr < it->end) { - return &*it; + *map = *it; + return; } } - return NULL; + *map = {}; } bool BacktraceMap::ParseLine(const char* line, backtrace_map_t* map) { @@ -115,7 +113,7 @@ bool BacktraceMap::Build() { snprintf(path, sizeof(path), "/proc/%d/maps", pid_); FILE* fp = fopen(path, "r"); #endif - if (fp == NULL) { + if (fp == nullptr) { return false; } @@ -141,7 +139,7 @@ BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) { BacktraceMap* map = new BacktraceMap(pid); if (!map->Build()) { delete map; - return NULL; + return nullptr; } return map; } diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp new file mode 100644 index 0000000..6134438 --- /dev/null +++ b/libbacktrace/BacktracePtrace.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2013 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 <stdint.h> +#include <string.h> +#include <sys/param.h> +#include <sys/ptrace.h> +#include <sys/types.h> +#include <ucontext.h> +#include <unistd.h> + +#include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> + +#include "BacktraceLog.h" +#include "BacktracePtrace.h" +#include "thread_utils.h" + +#if !defined(__APPLE__) +static bool PtraceRead(pid_t tid, uintptr_t addr, word_t* out_value) { + // ptrace() returns -1 and sets errno when the operation fails. + // To disambiguate -1 from a valid result, we clear errno beforehand. + errno = 0; + *out_value = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(addr), nullptr); + if (*out_value == static_cast<word_t>(-1) && errno) { + BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s", + reinterpret_cast<void*>(addr), tid, strerror(errno)); + return false; + } + return true; +} +#endif + +bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) { +#if defined(__APPLE__) + BACK_LOGW("MacOS does not support reading from another pid."); + return false; +#else + if (!VerifyReadWordArgs(ptr, out_value)) { + return false; + } + + backtrace_map_t map; + FillInMap(ptr, &map); + if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) { + return false; + } + + return PtraceRead(Tid(), ptr, out_value); +#endif +} + +size_t BacktracePtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) { +#if defined(__APPLE__) + BACK_LOGW("MacOS does not support reading from another pid."); + return 0; +#else + backtrace_map_t map; + FillInMap(addr, &map); + if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) { + return 0; + } + + bytes = MIN(map.end - addr, bytes); + size_t bytes_read = 0; + word_t data_word; + size_t align_bytes = addr & (sizeof(word_t) - 1); + if (align_bytes != 0) { + if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) { + return 0; + } + align_bytes = sizeof(word_t) - align_bytes; + memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + sizeof(word_t) - align_bytes, + align_bytes); + addr += align_bytes; + buffer += align_bytes; + bytes -= align_bytes; + bytes_read += align_bytes; + } + + size_t num_words = bytes / sizeof(word_t); + for (size_t i = 0; i < num_words; i++) { + if (!PtraceRead(Tid(), addr, &data_word)) { + return bytes_read; + } + memcpy(buffer, &data_word, sizeof(word_t)); + buffer += sizeof(word_t); + addr += sizeof(word_t); + bytes_read += sizeof(word_t); + } + + size_t left_over = bytes & (sizeof(word_t) - 1); + if (left_over) { + if (!PtraceRead(Tid(), addr, &data_word)) { + return bytes_read; + } + memcpy(buffer, &data_word, left_over); + bytes_read += left_over; + } + return bytes_read; +#endif +} diff --git a/fastbootd/debug.h b/libbacktrace/BacktracePtrace.h index 74620b8..1d49811 100644 --- a/fastbootd/debug.h +++ b/libbacktrace/BacktracePtrace.h @@ -14,29 +14,24 @@ * limitations under the License. */ -#ifndef _FASTBOOTD_DEBUG_H_ -#define _FASTBOOTD_DEBUG_H_ +#ifndef _LIBBACKTRACE_BACKTRACE_PTRACE_H +#define _LIBBACKTRACE_BACKTRACE_PTRACE_H -#include <stdio.h> +#include <stdint.h> +#include <sys/types.h> -#include <cutils/klog.h> +#include <backtrace/Backtrace.h> -#define ERR 0 -#define WARN 1 -#define INFO 2 -#define VERBOSE 3 -#define DEBUG 4 +class BacktraceMap; -extern unsigned int debug_level; +class BacktracePtrace : public Backtrace { +public: + BacktracePtrace(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {} + virtual ~BacktracePtrace() {} -//#define DLOG(fmt, ...) printf(fmt, ##__VA_ARGS__) -#define DLOG(fmt, ...) KLOG_INFO("fastbootd", fmt, ##__VA_ARGS__) + size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes); -#define D(level, fmt, ...) \ - do { \ - if (debug_level == level || debug_level > level) { \ - DLOG("%s:%d " fmt "\n", __BASE_FILE__, __LINE__, ##__VA_ARGS__); \ - } \ - } while (0) + bool ReadWord(uintptr_t ptr, word_t* out_value); +}; -#endif +#endif // _LIBBACKTRACE_BACKTRACE_PTRACE_H diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp deleted file mode 100644 index 439cc3b..0000000 --- a/libbacktrace/BacktraceThread.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2013 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 <inttypes.h> -#include <limits.h> -#include <pthread.h> -#include <signal.h> -#include <stdlib.h> -#include <string.h> -#include <sys/syscall.h> -#include <sys/time.h> -#include <sys/types.h> -#include <ucontext.h> -#include <unistd.h> - -#include <cutils/atomic.h> - -#include "BacktraceLog.h" -#include "BacktraceThread.h" -#include "thread_utils.h" - -//------------------------------------------------------------------------- -// ThreadEntry implementation. -//------------------------------------------------------------------------- -ThreadEntry* ThreadEntry::list_ = NULL; -pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER; - -// Assumes that ThreadEntry::list_mutex_ has already been locked before -// creating a ThreadEntry object. -ThreadEntry::ThreadEntry(pid_t pid, pid_t tid) - : pid_(pid), tid_(tid), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), - wait_mutex_(PTHREAD_MUTEX_INITIALIZER), wait_value_(0), - next_(ThreadEntry::list_), prev_(NULL) { - pthread_condattr_t attr; - pthread_condattr_init(&attr); - pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); - pthread_cond_init(&wait_cond_, &attr); - - // Add ourselves to the list. - if (ThreadEntry::list_) { - ThreadEntry::list_->prev_ = this; - } - ThreadEntry::list_ = this; -} - -ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) { - pthread_mutex_lock(&ThreadEntry::list_mutex_); - ThreadEntry* entry = list_; - while (entry != NULL) { - if (entry->Match(pid, tid)) { - break; - } - entry = entry->next_; - } - - if (!entry) { - if (create) { - entry = new ThreadEntry(pid, tid); - } - } else { - entry->ref_count_++; - } - pthread_mutex_unlock(&ThreadEntry::list_mutex_); - - return entry; -} - -void ThreadEntry::Remove(ThreadEntry* entry) { - pthread_mutex_unlock(&entry->mutex_); - - pthread_mutex_lock(&ThreadEntry::list_mutex_); - if (--entry->ref_count_ == 0) { - delete entry; - } - pthread_mutex_unlock(&ThreadEntry::list_mutex_); -} - -// Assumes that ThreadEntry::list_mutex_ has already been locked before -// deleting a ThreadEntry object. -ThreadEntry::~ThreadEntry() { - if (list_ == this) { - list_ = next_; - } else { - if (next_) { - next_->prev_ = prev_; - } - prev_->next_ = next_; - } - - next_ = NULL; - prev_ = NULL; - - pthread_cond_destroy(&wait_cond_); -} - -void ThreadEntry::Wait(int value) { - timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) { - BACK_LOGW("clock_gettime failed: %s", strerror(errno)); - abort(); - } - ts.tv_sec += 10; - - pthread_mutex_lock(&wait_mutex_); - while (wait_value_ != value) { - int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts); - if (ret != 0) { - BACK_LOGW("pthread_cond_timedwait failed: %s", strerror(ret)); - break; - } - } - pthread_mutex_unlock(&wait_mutex_); -} - -void ThreadEntry::Wake() { - pthread_mutex_lock(&wait_mutex_); - wait_value_++; - pthread_mutex_unlock(&wait_mutex_); - - pthread_cond_signal(&wait_cond_); -} - -void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) { - ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext); - // The only thing the unwinder cares about is the mcontext data. - memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext)); -} - -//------------------------------------------------------------------------- -// BacktraceThread functions. -//------------------------------------------------------------------------- -static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER; - -static void SignalHandler(int, siginfo_t*, void* sigcontext) { - ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false); - if (!entry) { - BACK_LOGW("Unable to find pid %d tid %d information", getpid(), gettid()); - return; - } - - entry->CopyUcontextFromSigcontext(sigcontext); - - // Indicate the ucontext is now valid. - entry->Wake(); - - // Pause the thread until the unwind is complete. This avoids having - // the thread run ahead causing problems. - entry->Wait(2); - - ThreadEntry::Remove(entry); -} - -BacktraceThread::BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map) - : BacktraceCurrent(impl, map) { - tid_ = tid; -} - -BacktraceThread::~BacktraceThread() { -} - -bool BacktraceThread::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { - if (ucontext) { - // Unwind using an already existing ucontext. - return impl_->Unwind(num_ignore_frames, ucontext); - } - - // Prevent multiple threads trying to set the trigger action on different - // threads at the same time. - if (pthread_mutex_lock(&g_sigaction_mutex) < 0) { - BACK_LOGW("sigaction failed: %s", strerror(errno)); - return false; - } - - ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid()); - entry->Lock(); - - struct sigaction act, oldact; - memset(&act, 0, sizeof(act)); - act.sa_sigaction = SignalHandler; - act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; - sigemptyset(&act.sa_mask); - if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) { - BACK_LOGW("sigaction failed %s", strerror(errno)); - entry->Unlock(); - ThreadEntry::Remove(entry); - pthread_mutex_unlock(&g_sigaction_mutex); - return false; - } - - if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) { - BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno)); - sigaction(THREAD_SIGNAL, &oldact, NULL); - entry->Unlock(); - ThreadEntry::Remove(entry); - pthread_mutex_unlock(&g_sigaction_mutex); - return false; - } - - // Wait for the thread to get the ucontext. - entry->Wait(1); - - // After the thread has received the signal, allow other unwinders to - // continue. - sigaction(THREAD_SIGNAL, &oldact, NULL); - pthread_mutex_unlock(&g_sigaction_mutex); - - bool unwind_done = impl_->Unwind(num_ignore_frames, entry->GetUcontext()); - - // Tell the signal handler to exit and release the entry. - entry->Wake(); - - return unwind_done; -} diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp index 442383b..09a721d 100644 --- a/libbacktrace/GetPss.cpp +++ b/libbacktrace/GetPss.cpp @@ -14,11 +14,10 @@ * limitations under the License. */ -#include <assert.h> #include <inttypes.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> -#include <stdint.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> @@ -46,13 +45,22 @@ static bool ReadData(int fd, unsigned long place, uint64_t *data) { size_t GetPssBytes() { FILE* maps = fopen("/proc/self/maps", "r"); - assert(maps != NULL); + if (maps == nullptr) { + return 0; + } int pagecount_fd = open("/proc/kpagecount", O_RDONLY); - assert(pagecount_fd >= 0); + if (pagecount_fd == -1) { + fclose(maps); + return 0; + } int pagemap_fd = open("/proc/self/pagemap", O_RDONLY); - assert(pagemap_fd >= 0); + if (pagemap_fd == -1) { + fclose(maps); + close(pagecount_fd); + return 0; + } char line[4096]; size_t total_pss = 0; diff --git a/libbacktrace/ThreadEntry.cpp b/libbacktrace/ThreadEntry.cpp new file mode 100644 index 0000000..e8b60c8 --- /dev/null +++ b/libbacktrace/ThreadEntry.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2015 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 <pthread.h> +#include <stdint.h> +#include <string.h> +#include <sys/types.h> +#include <time.h> +#include <ucontext.h> + +#include "BacktraceLog.h" +#include "ThreadEntry.h" + +// Initialize static member variables. +ThreadEntry* ThreadEntry::list_ = nullptr; +pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER; + +// Assumes that ThreadEntry::list_mutex_ has already been locked before +// creating a ThreadEntry object. +ThreadEntry::ThreadEntry(pid_t pid, pid_t tid) + : pid_(pid), tid_(tid), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), + wait_mutex_(PTHREAD_MUTEX_INITIALIZER), wait_value_(0), + next_(ThreadEntry::list_), prev_(nullptr) { + pthread_condattr_t attr; + pthread_condattr_init(&attr); + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + pthread_cond_init(&wait_cond_, &attr); + + // Add ourselves to the list. + if (ThreadEntry::list_) { + ThreadEntry::list_->prev_ = this; + } + ThreadEntry::list_ = this; +} + +ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) { + pthread_mutex_lock(&ThreadEntry::list_mutex_); + ThreadEntry* entry = list_; + while (entry != nullptr) { + if (entry->Match(pid, tid)) { + break; + } + entry = entry->next_; + } + + if (!entry) { + if (create) { + entry = new ThreadEntry(pid, tid); + } + } else { + entry->ref_count_++; + } + pthread_mutex_unlock(&ThreadEntry::list_mutex_); + + return entry; +} + +void ThreadEntry::Remove(ThreadEntry* entry) { + pthread_mutex_unlock(&entry->mutex_); + + pthread_mutex_lock(&ThreadEntry::list_mutex_); + if (--entry->ref_count_ == 0) { + delete entry; + } + pthread_mutex_unlock(&ThreadEntry::list_mutex_); +} + +// Assumes that ThreadEntry::list_mutex_ has already been locked before +// deleting a ThreadEntry object. +ThreadEntry::~ThreadEntry() { + if (list_ == this) { + list_ = next_; + } else { + if (next_) { + next_->prev_ = prev_; + } + prev_->next_ = next_; + } + + next_ = nullptr; + prev_ = nullptr; + + pthread_cond_destroy(&wait_cond_); +} + +void ThreadEntry::Wait(int value) { + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + ts.tv_sec += 10; + + pthread_mutex_lock(&wait_mutex_); + while (wait_value_ != value) { + int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts); + if (ret != 0) { + BACK_LOGW("pthread_cond_timedwait failed: %s", strerror(ret)); + break; + } + } + pthread_mutex_unlock(&wait_mutex_); +} + +void ThreadEntry::Wake() { + pthread_mutex_lock(&wait_mutex_); + wait_value_++; + pthread_mutex_unlock(&wait_mutex_); + + pthread_cond_signal(&wait_cond_); +} + +void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) { + ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext); + // The only thing the unwinder cares about is the mcontext data. + memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext)); +} diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/ThreadEntry.h index 99a8638..94becf2 100644 --- a/libbacktrace/BacktraceThread.h +++ b/libbacktrace/ThreadEntry.h @@ -14,26 +14,13 @@ * limitations under the License. */ -#ifndef _LIBBACKTRACE_BACKTRACE_THREAD_H -#define _LIBBACKTRACE_BACKTRACE_THREAD_H +#ifndef _LIBBACKTRACE_THREAD_ENTRY_H +#define _LIBBACKTRACE_THREAD_ENTRY_H -#include <inttypes.h> #include <pthread.h> -#include <signal.h> -#include <string.h> #include <sys/types.h> #include <ucontext.h> -#include "BacktraceImpl.h" - -// The signal used to cause a thread to dump the stack. -#if defined(__GLIBC__) -// GLIBC reserves __SIGRTMIN signals, so use SIGRTMIN to avoid errors. -#define THREAD_SIGNAL SIGRTMIN -#else -#define THREAD_SIGNAL (__SIGRTMIN+1) -#endif - class ThreadEntry { public: static ThreadEntry* Get(pid_t pid, pid_t tid, bool create = true); @@ -81,12 +68,4 @@ private: static pthread_mutex_t list_mutex_; }; -class BacktraceThread : public BacktraceCurrent { -public: - BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map); - virtual ~BacktraceThread(); - - virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext); -}; - -#endif // _LIBBACKTRACE_BACKTRACE_THREAD_H +#endif // _LIBBACKTRACE_THREAD_ENTRY_H diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp index b176aaf..67e583f 100755..100644 --- a/libbacktrace/UnwindCurrent.cpp +++ b/libbacktrace/UnwindCurrent.cpp @@ -14,41 +14,30 @@ * limitations under the License. */ -#include <sys/types.h> +#include <stdint.h> #include <ucontext.h> -#include <backtrace/Backtrace.h> -#include <backtrace/BacktraceMap.h> +#include <memory> +#include <string> #define UNW_LOCAL_ONLY #include <libunwind.h> +#include <backtrace/Backtrace.h> + #include "BacktraceLog.h" -#include "BacktraceThread.h" #include "UnwindCurrent.h" -#include "UnwindMap.h" - -//------------------------------------------------------------------------- -// UnwindCurrent functions. -//------------------------------------------------------------------------- -UnwindCurrent::UnwindCurrent() { -} - -UnwindCurrent::~UnwindCurrent() { -} -bool UnwindCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { - if (!ucontext) { - int ret = unw_getcontext(&context_); - if (ret < 0) { - BACK_LOGW("unw_getcontext failed %d", ret); - return false; - } - } - else { - GetUnwContextFromUcontext(ucontext); +std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { + *offset = 0; + char buf[512]; + unw_word_t value; + if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf), + &value, &context_) >= 0 && buf[0] != '\0') { + *offset = static_cast<uintptr_t>(value); + return buf; } - return UnwindFromContext(num_ignore_frames, false); + return ""; } void UnwindCurrent::GetUnwContextFromUcontext(const ucontext_t* ucontext) { @@ -76,90 +65,67 @@ void UnwindCurrent::GetUnwContextFromUcontext(const ucontext_t* ucontext) { #endif } -std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { - *offset = 0; - char buf[512]; - unw_word_t value; - if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf), - &value, &context_) >= 0 && buf[0] != '\0') { - *offset = static_cast<uintptr_t>(value); - return buf; +bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) { + if (ucontext == nullptr) { + int ret = unw_getcontext(&context_); + if (ret < 0) { + BACK_LOGW("unw_getcontext failed %d", ret); + return false; + } + } else { + GetUnwContextFromUcontext(ucontext); } - return ""; -} -bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool within_handler) { // The cursor structure is pretty large, do not put it on the stack. - unw_cursor_t* cursor = new unw_cursor_t; - int ret = unw_init_local(cursor, &context_); + std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t); + int ret = unw_init_local(cursor.get(), &context_); if (ret < 0) { - if (!within_handler) { - BACK_LOGW("unw_init_local failed %d", ret); - } - delete cursor; + BACK_LOGW("unw_init_local failed %d", ret); return false; } - std::vector<backtrace_frame_data_t>* frames = GetFrames(); - frames->reserve(MAX_BACKTRACE_FRAMES); size_t num_frames = 0; do { unw_word_t pc; - ret = unw_get_reg(cursor, UNW_REG_IP, &pc); + ret = unw_get_reg(cursor.get(), UNW_REG_IP, &pc); if (ret < 0) { - if (!within_handler) { - BACK_LOGW("Failed to read IP %d", ret); - } + BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; - ret = unw_get_reg(cursor, UNW_REG_SP, &sp); + ret = unw_get_reg(cursor.get(), UNW_REG_SP, &sp); if (ret < 0) { - if (!within_handler) { - BACK_LOGW("Failed to read SP %d", ret); - } + BACK_LOGW("Failed to read SP %d", ret); break; } - if (num_ignore_frames == 0) { - frames->resize(num_frames+1); - backtrace_frame_data_t* frame = &frames->at(num_frames); - frame->num = num_frames; - frame->pc = static_cast<uintptr_t>(pc); - frame->sp = static_cast<uintptr_t>(sp); - frame->stack_size = 0; - - if (num_frames > 0) { - // Set the stack size for the previous frame. - backtrace_frame_data_t* prev = &frames->at(num_frames-1); - prev->stack_size = frame->sp - prev->sp; - } - - if (!within_handler) { + frames_.resize(num_frames+1); + backtrace_frame_data_t* frame = &frames_.at(num_frames); + frame->num = num_frames; + frame->pc = static_cast<uintptr_t>(pc); + frame->sp = static_cast<uintptr_t>(sp); + frame->stack_size = 0; + + FillInMap(frame->pc, &frame->map); + // Check to see if we should skip this frame because it's coming + // from within the library, and we are doing a local unwind. + if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) { + if (num_ignore_frames == 0) { + // GetFunctionName is an expensive call, only do it if we are + // keeping the frame. frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); - frame->map = FindMap(frame->pc); + if (num_frames > 0) { + // Set the stack size for the previous frame. + backtrace_frame_data_t* prev = &frames_.at(num_frames-1); + prev->stack_size = frame->sp - prev->sp; + } + num_frames++; } else { - frame->map = NULL; - frame->func_offset = 0; + num_ignore_frames--; } - num_frames++; - } else { - num_ignore_frames--; } - ret = unw_step (cursor); + ret = unw_step (cursor.get()); } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); - delete cursor; return true; } - -//------------------------------------------------------------------------- -// C++ object creation function. -//------------------------------------------------------------------------- -Backtrace* CreateCurrentObj(BacktraceMap* map) { - return new BacktraceCurrent(new UnwindCurrent(), map); -} - -Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) { - return new BacktraceThread(new UnwindCurrent(), tid, map); -} diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h index 2375e6e..3023996 100644 --- a/libbacktrace/UnwindCurrent.h +++ b/libbacktrace/UnwindCurrent.h @@ -17,27 +17,32 @@ #ifndef _LIBBACKTRACE_UNWIND_CURRENT_H #define _LIBBACKTRACE_UNWIND_CURRENT_H +#include <stdint.h> +#include <sys/types.h> +#include <ucontext.h> + #include <string> -#include "BacktraceImpl.h" +#include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> + +#include "BacktraceCurrent.h" #define UNW_LOCAL_ONLY #include <libunwind.h> -class UnwindCurrent : public BacktraceImpl { +class UnwindCurrent : public BacktraceCurrent { public: - UnwindCurrent(); - virtual ~UnwindCurrent(); - - virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext); + UnwindCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : BacktraceCurrent(pid, tid, map) {} + virtual ~UnwindCurrent() {} - virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset); + std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override; - bool UnwindFromContext(size_t num_ignore_frames, bool within_handler); +private: + void GetUnwContextFromUcontext(const ucontext_t* ucontext); - void GetUnwContextFromUcontext(const ucontext_t* context); + bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override; -protected: unw_context_t context_; }; diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp index 387d768..fa59d07 100644 --- a/libbacktrace/UnwindMap.cpp +++ b/libbacktrace/UnwindMap.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <pthread.h> +#include <stdint.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> @@ -113,18 +113,17 @@ bool UnwindMapLocal::Build() { return (map_created_ = (unw_map_local_create() == 0)) && GenerateMap();; } -const backtrace_map_t* UnwindMapLocal::Find(uintptr_t addr) { - const backtrace_map_t* map = BacktraceMap::Find(addr); - if (!map) { +void UnwindMapLocal::FillIn(uintptr_t addr, backtrace_map_t* map) { + BacktraceMap::FillIn(addr, map); + if (!IsValid(*map)) { // Check to see if the underlying map changed and regenerate the map // if it did. if (unw_map_local_cursor_valid(&map_cursor_) < 0) { if (GenerateMap()) { - map = BacktraceMap::Find(addr); + BacktraceMap::FillIn(addr, map); } } } - return map; } //------------------------------------------------------------------------- @@ -143,7 +142,7 @@ BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) { } if (!map->Build()) { delete map; - return NULL; + return nullptr; } return map; } diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h index 2fdb29f..e292016 100644 --- a/libbacktrace/UnwindMap.h +++ b/libbacktrace/UnwindMap.h @@ -17,6 +17,9 @@ #ifndef _LIBBACKTRACE_UNWIND_MAP_H #define _LIBBACKTRACE_UNWIND_MAP_H +#include <stdint.h> +#include <sys/types.h> + #include <backtrace/BacktraceMap.h> // The unw_map_cursor_t structure is different depending on whether it is @@ -45,7 +48,7 @@ public: virtual bool Build(); - virtual const backtrace_map_t* Find(uintptr_t addr); + virtual void FillIn(uintptr_t addr, backtrace_map_t* map); protected: virtual bool GenerateMap(); diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp index 7ba8775..a7c3de5 100644 --- a/libbacktrace/UnwindPtrace.cpp +++ b/libbacktrace/UnwindPtrace.cpp @@ -14,35 +14,36 @@ * limitations under the License. */ -#include <backtrace/Backtrace.h> -#include <backtrace/BacktraceMap.h> - +#include <stdint.h> #include <sys/types.h> -#include <string.h> #include <ucontext.h> #include <libunwind.h> #include <libunwind-ptrace.h> +#include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> + #include "BacktraceLog.h" #include "UnwindMap.h" #include "UnwindPtrace.h" -UnwindPtrace::UnwindPtrace() : addr_space_(NULL), upt_info_(NULL) { +UnwindPtrace::UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map) + : BacktracePtrace(pid, tid, map), addr_space_(nullptr), upt_info_(nullptr) { } UnwindPtrace::~UnwindPtrace() { if (upt_info_) { _UPT_destroy(upt_info_); - upt_info_ = NULL; + upt_info_ = nullptr; } if (addr_space_) { // Remove the map from the address space before destroying it. // It will be freed in the UnwindMap destructor. - unw_map_set(addr_space_, NULL); + unw_map_set(addr_space_, nullptr); unw_destroy_addr_space(addr_space_); - addr_space_ = NULL; + addr_space_ = nullptr; } } @@ -74,8 +75,6 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { return false; } - std::vector<backtrace_frame_data_t>* frames = GetFrames(); - frames->reserve(MAX_BACKTRACE_FRAMES); size_t num_frames = 0; do { unw_word_t pc; @@ -92,21 +91,21 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { } if (num_ignore_frames == 0) { - frames->resize(num_frames+1); - backtrace_frame_data_t* frame = &frames->at(num_frames); + frames_.resize(num_frames+1); + backtrace_frame_data_t* frame = &frames_.at(num_frames); frame->num = num_frames; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; if (num_frames > 0) { - backtrace_frame_data_t* prev = &frames->at(num_frames-1); + backtrace_frame_data_t* prev = &frames_.at(num_frames-1); prev->stack_size = frame->sp - prev->sp; } frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); - frame->map = FindMap(frame->pc); + FillInMap(frame->pc, &frame->map); num_frames++; } else { @@ -129,10 +128,3 @@ std::string UnwindPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { } return ""; } - -//------------------------------------------------------------------------- -// C++ object creation function. -//------------------------------------------------------------------------- -Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map) { - return new BacktracePtrace(new UnwindPtrace(), pid, tid, map); -} diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h index 2fb7967..ab04abf 100644 --- a/libbacktrace/UnwindPtrace.h +++ b/libbacktrace/UnwindPtrace.h @@ -17,20 +17,26 @@ #ifndef _LIBBACKTRACE_UNWIND_PTRACE_H #define _LIBBACKTRACE_UNWIND_PTRACE_H -#include <string> +#include <stdint.h> +#include <sys/types.h> -#include "BacktraceImpl.h" +#include <string> +#ifdef UNW_LOCAL_ONLY +#undef UNW_LOCAL_ONLY +#endif #include <libunwind.h> -class UnwindPtrace : public BacktraceImpl { +#include "BacktracePtrace.h" + +class UnwindPtrace : public BacktracePtrace { public: - UnwindPtrace(); + UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map); virtual ~UnwindPtrace(); - virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext); + bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override; - virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset); + std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override; private: unw_addr_space_t addr_space_; diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp index 8002ed6..4af6592 100644 --- a/libbacktrace/backtrace_test.cpp +++ b/libbacktrace/backtrace_test.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#define _GNU_SOURCE 1 #include <dirent.h> #include <errno.h> #include <inttypes.h> @@ -31,15 +32,16 @@ #include <backtrace/Backtrace.h> #include <backtrace/BacktraceMap.h> -#include <UniquePtr.h> // For the THREAD_SIGNAL definition. -#include "BacktraceThread.h" +#include "BacktraceCurrent.h" #include <cutils/atomic.h> #include <gtest/gtest.h> #include <algorithm> +#include <memory> +#include <string> #include <vector> #include "thread_utils.h" @@ -60,6 +62,7 @@ struct thread_t { pid_t tid; int32_t state; pthread_t threadId; + void* data; }; struct dump_thread_t { @@ -82,15 +85,16 @@ uint64_t NanoTime() { return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec); } -void DumpFrames(Backtrace* backtrace) { +std::string DumpFrames(Backtrace* backtrace) { if (backtrace->NumFrames() == 0) { - printf(" No frames to dump\n"); - return; + return " No frames to dump.\n"; } + std::string frame; for (size_t i = 0; i < backtrace->NumFrames(); i++) { - printf(" %s\n", backtrace->FormatFrameData(i).c_str()); + frame += " " + backtrace->FormatFrameData(i) + '\n'; } + return frame; } void WaitForStop(pid_t pid) { @@ -120,8 +124,10 @@ bool ReadyLevelBacktrace(Backtrace* backtrace) { } void VerifyLevelDump(Backtrace* backtrace) { - ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0)); - ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)); + ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0)) + << DumpFrames(backtrace); + ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)) + << DumpFrames(backtrace); // Look through the frames starting at the highest to find the // frame we want. @@ -132,19 +138,23 @@ void VerifyLevelDump(Backtrace* backtrace) { break; } } - ASSERT_LT(static_cast<size_t>(0), frame_num); - ASSERT_LE(static_cast<size_t>(3), frame_num); - - ASSERT_EQ(backtrace->GetFrame(frame_num)->func_name, "test_level_one"); - ASSERT_EQ(backtrace->GetFrame(frame_num-1)->func_name, "test_level_two"); - ASSERT_EQ(backtrace->GetFrame(frame_num-2)->func_name, "test_level_three"); - ASSERT_EQ(backtrace->GetFrame(frame_num-3)->func_name, "test_level_four"); + ASSERT_LT(static_cast<size_t>(0), frame_num) << DumpFrames(backtrace); + ASSERT_LE(static_cast<size_t>(3), frame_num) << DumpFrames(backtrace); + + ASSERT_EQ(backtrace->GetFrame(frame_num)->func_name, "test_level_one") + << DumpFrames(backtrace); + ASSERT_EQ(backtrace->GetFrame(frame_num-1)->func_name, "test_level_two") + << DumpFrames(backtrace); + ASSERT_EQ(backtrace->GetFrame(frame_num-2)->func_name, "test_level_three") + << DumpFrames(backtrace); + ASSERT_EQ(backtrace->GetFrame(frame_num-3)->func_name, "test_level_four") + << DumpFrames(backtrace); } void VerifyLevelBacktrace(void*) { - UniquePtr<Backtrace> backtrace( + std::unique_ptr<Backtrace> backtrace( Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); - ASSERT_TRUE(backtrace.get() != NULL); + ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); VerifyLevelDump(backtrace.get()); @@ -155,16 +165,17 @@ bool ReadyMaxBacktrace(Backtrace* backtrace) { } void VerifyMaxDump(Backtrace* backtrace) { - ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)); + ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)) + << DumpFrames(backtrace); // Verify that the last frame is our recursive call. - ASSERT_EQ(backtrace->GetFrame(MAX_BACKTRACE_FRAMES-1)->func_name, - "test_recursive_call"); + ASSERT_EQ(backtrace->GetFrame(MAX_BACKTRACE_FRAMES-1)->func_name, "test_recursive_call") + << DumpFrames(backtrace); } void VerifyMaxBacktrace(void*) { - UniquePtr<Backtrace> backtrace( + std::unique_ptr<Backtrace> backtrace( Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); - ASSERT_TRUE(backtrace.get() != NULL); + ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); VerifyMaxDump(backtrace.get()); @@ -180,8 +191,8 @@ void ThreadSetState(void* data) { } void VerifyThreadTest(pid_t tid, void (*VerifyFunc)(Backtrace*)) { - UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), tid)); - ASSERT_TRUE(backtrace.get() != NULL); + std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), tid)); + ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); VerifyFunc(backtrace.get()); @@ -197,18 +208,38 @@ bool WaitForNonZero(int32_t* value, uint64_t seconds) { return false; } +TEST(libbacktrace, local_no_unwind_frames) { + // Verify that a local unwind does not include any frames within + // libunwind or libbacktrace. + std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid())); + ASSERT_TRUE(backtrace.get() != nullptr); + ASSERT_TRUE(backtrace->Unwind(0)); + + ASSERT_TRUE(backtrace->NumFrames() != 0); + for (const auto& frame : *backtrace ) { + if (BacktraceMap::IsValid(frame.map)) { + const std::string name = basename(frame.map.name.c_str()); + ASSERT_TRUE(name != "libunwind.so" && name != "libbacktrace.so") + << DumpFrames(backtrace.get()); + } + break; + } +} + TEST(libbacktrace, local_trace) { - ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, NULL), 0); + ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0); } void VerifyIgnoreFrames( Backtrace* bt_all, Backtrace* bt_ign1, Backtrace* bt_ign2, const char* cur_proc) { - EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1); - EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2); + EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1) + << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 1 backtrace:\n" << DumpFrames(bt_ign1); + EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2) + << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 2 backtrace:\n" << DumpFrames(bt_ign2); // Check all of the frames are the same > the current frame. - bool check = (cur_proc == NULL); + bool check = (cur_proc == nullptr); for (size_t i = 0; i < bt_ign2->NumFrames(); i++) { if (check) { EXPECT_EQ(bt_ign2->GetFrame(i)->pc, bt_ign1->GetFrame(i+1)->pc); @@ -226,30 +257,30 @@ void VerifyIgnoreFrames( } void VerifyLevelIgnoreFrames(void*) { - UniquePtr<Backtrace> all( + std::unique_ptr<Backtrace> all( Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); - ASSERT_TRUE(all.get() != NULL); + ASSERT_TRUE(all.get() != nullptr); ASSERT_TRUE(all->Unwind(0)); - UniquePtr<Backtrace> ign1( + std::unique_ptr<Backtrace> ign1( Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); - ASSERT_TRUE(ign1.get() != NULL); + ASSERT_TRUE(ign1.get() != nullptr); ASSERT_TRUE(ign1->Unwind(1)); - UniquePtr<Backtrace> ign2( + std::unique_ptr<Backtrace> ign2( Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); - ASSERT_TRUE(ign2.get() != NULL); + ASSERT_TRUE(ign2.get() != nullptr); ASSERT_TRUE(ign2->Unwind(2)); VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), "VerifyLevelIgnoreFrames"); } TEST(libbacktrace, local_trace_ignore_frames) { - ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelIgnoreFrames, NULL), 0); + ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelIgnoreFrames, nullptr), 0); } TEST(libbacktrace, local_max_trace) { - ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, NULL), 0); + ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, nullptr), 0); } void VerifyProcTest(pid_t pid, pid_t tid, bool share_map, @@ -263,35 +294,38 @@ void VerifyProcTest(pid_t pid, pid_t tid, bool share_map, } uint64_t start = NanoTime(); bool verified = false; + std::string last_dump; do { usleep(US_PER_MSEC); if (ptrace(PTRACE_ATTACH, ptrace_tid, 0, 0) == 0) { // Wait for the process to get to a stopping point. WaitForStop(ptrace_tid); - UniquePtr<BacktraceMap> map; + std::unique_ptr<BacktraceMap> map; if (share_map) { map.reset(BacktraceMap::Create(pid)); } - UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get())); + std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get())); + ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); - ASSERT_TRUE(backtrace.get() != NULL); if (ReadyFunc(backtrace.get())) { VerifyFunc(backtrace.get()); verified = true; + } else { + last_dump = DumpFrames(backtrace.get()); } ASSERT_TRUE(ptrace(PTRACE_DETACH, ptrace_tid, 0, 0) == 0); } // If 5 seconds have passed, then we are done. } while (!verified && (NanoTime() - start) <= 5 * NS_PER_SEC); - ASSERT_TRUE(verified); + ASSERT_TRUE(verified) << "Last backtrace:\n" << last_dump; } TEST(libbacktrace, ptrace_trace) { pid_t pid; if ((pid = fork()) == 0) { - ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0); + ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0); _exit(1); } VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyLevelDump); @@ -304,7 +338,7 @@ TEST(libbacktrace, ptrace_trace) { TEST(libbacktrace, ptrace_trace_shared_map) { pid_t pid; if ((pid = fork()) == 0) { - ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0); + ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0); _exit(1); } @@ -318,7 +352,7 @@ TEST(libbacktrace, ptrace_trace_shared_map) { TEST(libbacktrace, ptrace_max_trace) { pid_t pid; if ((pid = fork()) == 0) { - ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL, NULL), 0); + ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, nullptr, nullptr), 0); _exit(1); } VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyMaxBacktrace, VerifyMaxDump); @@ -329,21 +363,21 @@ TEST(libbacktrace, ptrace_max_trace) { } void VerifyProcessIgnoreFrames(Backtrace* bt_all) { - UniquePtr<Backtrace> ign1(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD)); - ASSERT_TRUE(ign1.get() != NULL); + std::unique_ptr<Backtrace> ign1(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD)); + ASSERT_TRUE(ign1.get() != nullptr); ASSERT_TRUE(ign1->Unwind(1)); - UniquePtr<Backtrace> ign2(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD)); - ASSERT_TRUE(ign2.get() != NULL); + std::unique_ptr<Backtrace> ign2(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD)); + ASSERT_TRUE(ign2.get() != nullptr); ASSERT_TRUE(ign2->Unwind(2)); - VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), NULL); + VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), nullptr); } TEST(libbacktrace, ptrace_ignore_frames) { pid_t pid; if ((pid = fork()) == 0) { - ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0); + ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0); _exit(1); } VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyProcessIgnoreFrames); @@ -355,8 +389,8 @@ TEST(libbacktrace, ptrace_ignore_frames) { // Create a process with multiple threads and dump all of the threads. void* PtraceThreadLevelRun(void*) { - EXPECT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0); - return NULL; + EXPECT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0); + return nullptr; } void GetThreads(pid_t pid, std::vector<pid_t>* threads) { @@ -365,9 +399,9 @@ void GetThreads(pid_t pid, std::vector<pid_t>* threads) { snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid); DIR* tasks_dir = opendir(task_path); - ASSERT_TRUE(tasks_dir != NULL); + ASSERT_TRUE(tasks_dir != nullptr); struct dirent* entry; - while ((entry = readdir(tasks_dir)) != NULL) { + while ((entry = readdir(tasks_dir)) != nullptr) { char* end; pid_t tid = strtoul(entry->d_name, &end, 10); if (*end == '\0') { @@ -386,9 +420,9 @@ TEST(libbacktrace, ptrace_threads) { pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_t thread; - ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, NULL) == 0); + ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, nullptr) == 0); } - ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0); + ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0); _exit(1); } @@ -420,27 +454,27 @@ TEST(libbacktrace, ptrace_threads) { } void VerifyLevelThread(void*) { - UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid())); - ASSERT_TRUE(backtrace.get() != NULL); + std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid())); + ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); VerifyLevelDump(backtrace.get()); } TEST(libbacktrace, thread_current_level) { - ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, NULL), 0); + ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, nullptr), 0); } void VerifyMaxThread(void*) { - UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid())); - ASSERT_TRUE(backtrace.get() != NULL); + std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid())); + ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); VerifyMaxDump(backtrace.get()); } TEST(libbacktrace, thread_current_max) { - ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, NULL), 0); + ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, nullptr), 0); } void* ThreadLevelRun(void* data) { @@ -448,7 +482,7 @@ void* ThreadLevelRun(void* data) { thread->tid = gettid(); EXPECT_NE(test_level_one(1, 2, 3, 4, ThreadSetState, data), 0); - return NULL; + return nullptr; } TEST(libbacktrace, thread_level_trace) { @@ -456,7 +490,7 @@ TEST(libbacktrace, thread_level_trace) { pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - thread_t thread_data = { 0, 0, 0 }; + thread_t thread_data = { 0, 0, 0, nullptr }; pthread_t thread; ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0); @@ -471,10 +505,10 @@ TEST(libbacktrace, thread_level_trace) { // Save the current signal action and make sure it is restored afterwards. struct sigaction cur_action; - ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &cur_action) == 0); + ASSERT_TRUE(sigaction(THREAD_SIGNAL, nullptr, &cur_action) == 0); - UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid)); - ASSERT_TRUE(backtrace.get() != NULL); + std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid)); + ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); VerifyLevelDump(backtrace.get()); @@ -484,14 +518,18 @@ TEST(libbacktrace, thread_level_trace) { // Verify that the old action was restored. struct sigaction new_action; - ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &new_action) == 0); + ASSERT_TRUE(sigaction(THREAD_SIGNAL, nullptr, &new_action) == 0); EXPECT_EQ(cur_action.sa_sigaction, new_action.sa_sigaction); // The SA_RESTORER flag gets set behind our back, so a direct comparison // doesn't work unless we mask the value off. Mips doesn't have this // flag, so skip this on that platform. -#ifdef SA_RESTORER +#if defined(SA_RESTORER) cur_action.sa_flags &= ~SA_RESTORER; new_action.sa_flags &= ~SA_RESTORER; +#elif defined(__GLIBC__) + // Our host compiler doesn't appear to define this flag for some reason. + cur_action.sa_flags &= ~0x04000000; + new_action.sa_flags &= ~0x04000000; #endif EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags); } @@ -501,26 +539,26 @@ TEST(libbacktrace, thread_ignore_frames) { pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - thread_t thread_data = { 0, 0, 0 }; + thread_t thread_data = { 0, 0, 0, nullptr }; pthread_t thread; ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0); // Wait up to 2 seconds for the tid to be set. ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2)); - UniquePtr<Backtrace> all(Backtrace::Create(getpid(), thread_data.tid)); - ASSERT_TRUE(all.get() != NULL); + std::unique_ptr<Backtrace> all(Backtrace::Create(getpid(), thread_data.tid)); + ASSERT_TRUE(all.get() != nullptr); ASSERT_TRUE(all->Unwind(0)); - UniquePtr<Backtrace> ign1(Backtrace::Create(getpid(), thread_data.tid)); - ASSERT_TRUE(ign1.get() != NULL); + std::unique_ptr<Backtrace> ign1(Backtrace::Create(getpid(), thread_data.tid)); + ASSERT_TRUE(ign1.get() != nullptr); ASSERT_TRUE(ign1->Unwind(1)); - UniquePtr<Backtrace> ign2(Backtrace::Create(getpid(), thread_data.tid)); - ASSERT_TRUE(ign2.get() != NULL); + std::unique_ptr<Backtrace> ign2(Backtrace::Create(getpid(), thread_data.tid)); + ASSERT_TRUE(ign2.get() != nullptr); ASSERT_TRUE(ign2->Unwind(2)); - VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), NULL); + VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), nullptr); // Tell the thread to exit its infinite loop. android_atomic_acquire_store(0, &thread_data.state); @@ -531,7 +569,7 @@ void* ThreadMaxRun(void* data) { thread->tid = gettid(); EXPECT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, ThreadSetState, data), 0); - return NULL; + return nullptr; } TEST(libbacktrace, thread_max_trace) { @@ -539,15 +577,15 @@ TEST(libbacktrace, thread_max_trace) { pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - thread_t thread_data = { 0, 0, 0 }; + thread_t thread_data = { 0, 0, 0, nullptr }; pthread_t thread; ASSERT_TRUE(pthread_create(&thread, &attr, ThreadMaxRun, &thread_data) == 0); // Wait for the tid to be set. ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2)); - UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid)); - ASSERT_TRUE(backtrace.get() != NULL); + std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid)); + ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); VerifyMaxDump(backtrace.get()); @@ -570,7 +608,7 @@ void* ThreadDump(void* data) { android_atomic_acquire_store(1, &dump->done); - return NULL; + return nullptr; } TEST(libbacktrace, thread_multiple_dump) { @@ -614,11 +652,11 @@ TEST(libbacktrace, thread_multiple_dump) { // Tell the runner thread to exit its infinite loop. android_atomic_acquire_store(0, &runners[i].state); - ASSERT_TRUE(dumpers[i].backtrace != NULL); + ASSERT_TRUE(dumpers[i].backtrace != nullptr); VerifyMaxDump(dumpers[i].backtrace); delete dumpers[i].backtrace; - dumpers[i].backtrace = NULL; + dumpers[i].backtrace = nullptr; } } @@ -654,11 +692,11 @@ TEST(libbacktrace, thread_multiple_dump_same_thread) { for (size_t i = 0; i < NUM_THREADS; i++) { ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 30)); - ASSERT_TRUE(dumpers[i].backtrace != NULL); + ASSERT_TRUE(dumpers[i].backtrace != nullptr); VerifyMaxDump(dumpers[i].backtrace); delete dumpers[i].backtrace; - dumpers[i].backtrace = NULL; + dumpers[i].backtrace = nullptr; } // Tell the runner thread to exit its infinite loop. @@ -673,37 +711,54 @@ TEST(libbacktrace, simultaneous_maps) { BacktraceMap* map3 = BacktraceMap::Create(getpid()); Backtrace* back1 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map1); + ASSERT_TRUE(back1 != nullptr); EXPECT_TRUE(back1->Unwind(0)); delete back1; delete map1; Backtrace* back2 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map2); + ASSERT_TRUE(back2 != nullptr); EXPECT_TRUE(back2->Unwind(0)); delete back2; delete map2; Backtrace* back3 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map3); + ASSERT_TRUE(back3 != nullptr); EXPECT_TRUE(back3->Unwind(0)); delete back3; delete map3; } +TEST(libbacktrace, fillin_erases) { + BacktraceMap* back_map = BacktraceMap::Create(getpid()); + + backtrace_map_t map; + + map.start = 1; + map.end = 3; + map.flags = 1; + map.name = "Initialized"; + back_map->FillIn(0, &map); + delete back_map; + + ASSERT_FALSE(BacktraceMap::IsValid(map)); + ASSERT_EQ(static_cast<uintptr_t>(0), map.start); + ASSERT_EQ(static_cast<uintptr_t>(0), map.end); + ASSERT_EQ(0, map.flags); + ASSERT_EQ("", map.name); +} + TEST(libbacktrace, format_test) { - UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD)); - ASSERT_TRUE(backtrace.get() != NULL); + std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD)); + ASSERT_TRUE(backtrace.get() != nullptr); backtrace_frame_data_t frame; frame.num = 1; frame.pc = 2; frame.sp = 0; frame.stack_size = 0; - frame.map = NULL; frame.func_offset = 0; - backtrace_map_t map; - map.start = 0; - map.end = 0; - // Check no map set. frame.num = 1; #if defined(__LP64__) @@ -714,8 +769,8 @@ TEST(libbacktrace, format_test) { backtrace->FormatFrameData(&frame)); // Check map name empty, but exists. - frame.map = ↦ - map.start = 1; + frame.map.start = 1; + frame.map.end = 1; #if defined(__LP64__) EXPECT_EQ("#01 pc 0000000000000001 <unknown>", #else @@ -726,9 +781,9 @@ TEST(libbacktrace, format_test) { // Check relative pc is set and map name is set. frame.pc = 0x12345679; - frame.map = ↦ - map.name = "MapFake"; - map.start = 1; + frame.map.name = "MapFake"; + frame.map.start = 1; + frame.map.end = 1; #if defined(__LP64__) EXPECT_EQ("#01 pc 0000000012345678 MapFake", #else @@ -764,12 +819,12 @@ bool map_sort(map_test_t i, map_test_t j) { return i.start < j.start; } -static void VerifyMap(pid_t pid) { +void VerifyMap(pid_t pid) { char buffer[4096]; snprintf(buffer, sizeof(buffer), "/proc/%d/maps", pid); FILE* map_file = fopen(buffer, "r"); - ASSERT_TRUE(map_file != NULL); + ASSERT_TRUE(map_file != nullptr); std::vector<map_test_t> test_maps; while (fgets(buffer, sizeof(buffer), map_file)) { map_test_t map; @@ -779,7 +834,7 @@ static void VerifyMap(pid_t pid) { fclose(map_file); std::sort(test_maps.begin(), test_maps.end(), map_sort); - UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid)); + std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid)); // Basic test that verifies that the map is in the expected order. std::vector<map_test_t>::const_iterator test_it = test_maps.begin(); @@ -813,7 +868,173 @@ TEST(libbacktrace, verify_map_remote) { ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0); kill(pid, SIGKILL); - ASSERT_EQ(waitpid(pid, NULL, 0), pid); + ASSERT_EQ(waitpid(pid, nullptr, 0), pid); +} + +void* ThreadReadTest(void* data) { + thread_t* thread_data = reinterpret_cast<thread_t*>(data); + + thread_data->tid = gettid(); + + // Create two map pages. + // Mark the second page as not-readable. + size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE)); + uint8_t* memory; + if (posix_memalign(reinterpret_cast<void**>(&memory), pagesize, 2 * pagesize) != 0) { + return reinterpret_cast<void*>(-1); + } + + if (mprotect(&memory[pagesize], pagesize, PROT_NONE) != 0) { + return reinterpret_cast<void*>(-1); + } + + // Set up a simple pattern in memory. + for (size_t i = 0; i < pagesize; i++) { + memory[i] = i; + } + + thread_data->data = memory; + + // Tell the caller it's okay to start reading memory. + android_atomic_acquire_store(1, &thread_data->state); + + // Loop waiting for the caller to finish reading the memory. + while (thread_data->state) { + } + + // Re-enable read-write on the page so that we don't crash if we try + // and access data on this page when freeing the memory. + if (mprotect(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) != 0) { + return reinterpret_cast<void*>(-1); + } + free(memory); + + android_atomic_acquire_store(1, &thread_data->state); + + return nullptr; +} + +void RunReadTest(Backtrace* backtrace, uintptr_t read_addr) { + size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE)); + + // Create a page of data to use to do quick compares. + uint8_t* expected = new uint8_t[pagesize]; + for (size_t i = 0; i < pagesize; i++) { + expected[i] = i; + } + uint8_t* data = new uint8_t[2*pagesize]; + // Verify that we can only read one page worth of data. + size_t bytes_read = backtrace->Read(read_addr, data, 2 * pagesize); + ASSERT_EQ(pagesize, bytes_read); + ASSERT_TRUE(memcmp(data, expected, pagesize) == 0); + + // Verify unaligned reads. + for (size_t i = 1; i < sizeof(word_t); i++) { + bytes_read = backtrace->Read(read_addr + i, data, 2 * sizeof(word_t)); + ASSERT_EQ(2 * sizeof(word_t), bytes_read); + ASSERT_TRUE(memcmp(data, &expected[i], 2 * sizeof(word_t)) == 0) + << "Offset at " << i << " failed"; + } + delete data; + delete expected; +} + +TEST(libbacktrace, thread_read) { + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_t thread; + thread_t thread_data = { 0, 0, 0, nullptr }; + ASSERT_TRUE(pthread_create(&thread, &attr, ThreadReadTest, &thread_data) == 0); + + ASSERT_TRUE(WaitForNonZero(&thread_data.state, 10)); + + std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid)); + ASSERT_TRUE(backtrace.get() != nullptr); + + RunReadTest(backtrace.get(), reinterpret_cast<uintptr_t>(thread_data.data)); + + android_atomic_acquire_store(0, &thread_data.state); + + ASSERT_TRUE(WaitForNonZero(&thread_data.state, 10)); +} + +volatile uintptr_t g_ready = 0; +volatile uintptr_t g_addr = 0; + +void ForkedReadTest() { + // Create two map pages. + size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE)); + uint8_t* memory; + if (posix_memalign(reinterpret_cast<void**>(&memory), pagesize, 2 * pagesize) != 0) { + perror("Failed to allocate memory\n"); + exit(1); + } + + // Mark the second page as not-readable. + if (mprotect(&memory[pagesize], pagesize, PROT_NONE) != 0) { + perror("Failed to mprotect memory\n"); + exit(1); + } + + // Set up a simple pattern in memory. + for (size_t i = 0; i < pagesize; i++) { + memory[i] = i; + } + + g_addr = reinterpret_cast<uintptr_t>(memory); + g_ready = 1; + + while (1) { + usleep(US_PER_MSEC); + } +} + +TEST(libbacktrace, process_read) { + pid_t pid; + if ((pid = fork()) == 0) { + ForkedReadTest(); + exit(0); + } + ASSERT_NE(-1, pid); + + bool test_executed = false; + uint64_t start = NanoTime(); + while (1) { + if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) { + WaitForStop(pid); + + std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid)); + ASSERT_TRUE(backtrace.get() != nullptr); + + uintptr_t read_addr; + size_t bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(&g_ready), + reinterpret_cast<uint8_t*>(&read_addr), + sizeof(uintptr_t)); + ASSERT_EQ(sizeof(uintptr_t), bytes_read); + if (read_addr) { + // The forked process is ready to be read. + bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(&g_addr), + reinterpret_cast<uint8_t*>(&read_addr), + sizeof(uintptr_t)); + ASSERT_EQ(sizeof(uintptr_t), bytes_read); + + RunReadTest(backtrace.get(), read_addr); + + test_executed = true; + break; + } + ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0); + } + if ((NanoTime() - start) > 5 * NS_PER_SEC) { + break; + } + usleep(US_PER_MSEC); + } + kill(pid, SIGKILL); + ASSERT_EQ(waitpid(pid, nullptr, 0), pid); + + ASSERT_TRUE(test_executed); } #if defined(ENABLE_PSS_TESTS) @@ -821,24 +1042,26 @@ TEST(libbacktrace, verify_map_remote) { #define MAX_LEAK_BYTES 32*1024UL -static void CheckForLeak(pid_t pid, pid_t tid) { +void CheckForLeak(pid_t pid, pid_t tid) { // Do a few runs to get the PSS stable. for (size_t i = 0; i < 100; i++) { Backtrace* backtrace = Backtrace::Create(pid, tid); - ASSERT_TRUE(backtrace != NULL); + ASSERT_TRUE(backtrace != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); delete backtrace; } size_t stable_pss = GetPssBytes(); + ASSERT_TRUE(stable_pss != 0); // Loop enough that even a small leak should be detectable. for (size_t i = 0; i < 4096; i++) { Backtrace* backtrace = Backtrace::Create(pid, tid); - ASSERT_TRUE(backtrace != NULL); + ASSERT_TRUE(backtrace != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); delete backtrace; } size_t new_pss = GetPssBytes(); + ASSERT_TRUE(new_pss != 0); size_t abs_diff = (new_pss > stable_pss) ? new_pss - stable_pss : stable_pss - new_pss; // As long as the new pss is within a certain amount, consider everything okay. ASSERT_LE(abs_diff, MAX_LEAK_BYTES); @@ -849,9 +1072,9 @@ TEST(libbacktrace, check_for_leak_local) { } TEST(libbacktrace, check_for_leak_local_thread) { - thread_t thread_data = { 0, 0, 0 }; + thread_t thread_data = { 0, 0, 0, nullptr }; pthread_t thread; - ASSERT_TRUE(pthread_create(&thread, NULL, ThreadLevelRun, &thread_data) == 0); + ASSERT_TRUE(pthread_create(&thread, nullptr, ThreadLevelRun, &thread_data) == 0); // Wait up to 2 seconds for the tid to be set. ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2)); @@ -861,7 +1084,7 @@ TEST(libbacktrace, check_for_leak_local_thread) { // Tell the thread to exit its infinite loop. android_atomic_acquire_store(0, &thread_data.state); - ASSERT_TRUE(pthread_join(thread, NULL) == 0); + ASSERT_TRUE(pthread_join(thread, nullptr) == 0); } TEST(libbacktrace, check_for_leak_remote) { @@ -884,6 +1107,6 @@ TEST(libbacktrace, check_for_leak_remote) { ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0); kill(pid, SIGKILL); - ASSERT_EQ(waitpid(pid, NULL, 0), pid); + ASSERT_EQ(waitpid(pid, nullptr, 0), pid); } #endif diff --git a/libcutils/Android.mk b/libcutils/Android.mk index b016a42..9dc15d1 100644 --- a/libcutils/Android.mk +++ b/libcutils/Android.mk @@ -16,20 +16,13 @@ LOCAL_PATH := $(my-dir) include $(CLEAR_VARS) -ifeq ($(TARGET_CPU_SMP),true) - targetSmpFlag := -DANDROID_SMP=1 -else - targetSmpFlag := -DANDROID_SMP=0 -endif -hostSmpFlag := -DANDROID_SMP=0 - commonSources := \ hashmap.c \ atomic.c.arm \ native_handle.c \ config_utils.c \ - cpu_info.c \ load_file.c \ + strlcpy.c \ open_memstream.c \ strdup16to8.c \ strdup8to16.c \ @@ -39,6 +32,7 @@ commonSources := \ sched_policy.c \ iosched_policy.c \ str_parms.c \ + fs_config.c # some files must not be compiled when building against Mingw # they correspond to features not used by our host development tools @@ -67,38 +61,33 @@ ifneq ($(WINDOWS_HOST_ONLY),1) sockets.c \ commonHostSources += \ - ashmem-host.c + ashmem-host.c \ + trace-host.c endif -# Static library for host +# Shared and static library for host # ======================================================== LOCAL_MODULE := libcutils LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c LOCAL_STATIC_LIBRARIES := liblog -LOCAL_CFLAGS += $(hostSmpFlag) ifneq ($(HOST_OS),windows) LOCAL_CFLAGS += -Werror endif LOCAL_MULTILIB := both -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_HOST_STATIC_LIBRARY) - -# Tests for host -# ======================================================== include $(CLEAR_VARS) -LOCAL_MODULE := tst_str_parms -LOCAL_CFLAGS += -DTEST_STR_PARMS +LOCAL_MODULE := libcutils +LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c +LOCAL_SHARED_LIBRARIES := liblog ifneq ($(HOST_OS),windows) LOCAL_CFLAGS += -Werror endif -LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c -LOCAL_STATIC_LIBRARIES := liblog -LOCAL_MODULE_TAGS := optional -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -include $(BUILD_HOST_EXECUTABLE) +LOCAL_MULTILIB := both +include $(BUILD_HOST_SHARED_LIBRARY) + # Shared and static library for target @@ -111,40 +100,32 @@ LOCAL_SRC_FILES := $(commonSources) \ ashmem-dev.c \ debugger.c \ klog.c \ - memory.c \ partition_utils.c \ properties.c \ qtaguid.c \ - trace.c \ + trace-dev.c \ uevent.c \ -LOCAL_SRC_FILES_arm += \ - arch-arm/memset32.S \ +# arch-arm/memset32.S does not compile with Clang. +LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as -LOCAL_SRC_FILES_arm64 += \ - arch-arm64/android_memset.S \ +LOCAL_SRC_FILES_arm += arch-arm/memset32.S +LOCAL_SRC_FILES_arm64 += arch-arm64/android_memset.S -LOCAL_SRC_FILES_mips += \ - arch-mips/android_memset.c \ +LOCAL_SRC_FILES_mips += arch-mips/android_memset.c +LOCAL_SRC_FILES_mips64 += arch-mips/android_memset.c LOCAL_SRC_FILES_x86 += \ arch-x86/android_memset16.S \ arch-x86/android_memset32.S \ LOCAL_SRC_FILES_x86_64 += \ - arch-x86_64/android_memset16_SSE2-atom.S \ - arch-x86_64/android_memset32_SSE2-atom.S \ - -LOCAL_CFLAGS_arm += -DHAVE_MEMSET16 -DHAVE_MEMSET32 -LOCAL_CFLAGS_arm64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32 -LOCAL_CFLAGS_mips += -DHAVE_MEMSET16 -DHAVE_MEMSET32 -LOCAL_CFLAGS_x86 += -DHAVE_MEMSET16 -DHAVE_MEMSET32 -LOCAL_CFLAGS_x86_64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32 + arch-x86_64/android_memset16.S \ + arch-x86_64/android_memset32.S \ LOCAL_C_INCLUDES := $(libcutils_c_includes) LOCAL_STATIC_LIBRARIES := liblog -LOCAL_CFLAGS += $(targetSmpFlag) -Werror -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_CFLAGS += -Werror -std=gnu90 include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) @@ -153,18 +134,8 @@ LOCAL_MODULE := libcutils # liblog symbols present in libcutils. LOCAL_WHOLE_STATIC_LIBRARIES := libcutils liblog LOCAL_SHARED_LIBRARIES := liblog -LOCAL_CFLAGS += $(targetSmpFlag) -Werror +LOCAL_CFLAGS += -Werror LOCAL_C_INCLUDES := $(libcutils_c_includes) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_SHARED_LIBRARY) -include $(CLEAR_VARS) -LOCAL_MODULE := tst_str_parms -LOCAL_CFLAGS += -DTEST_STR_PARMS -Werror -LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c -LOCAL_SHARED_LIBRARIES := liblog -LOCAL_MODULE_TAGS := optional -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -include $(BUILD_EXECUTABLE) - include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c index 5d98295..6ae23c1 100644 --- a/libcutils/android_reboot.c +++ b/libcutils/android_reboot.c @@ -20,6 +20,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <mntent.h> #include <stdio.h> #include <string.h> @@ -33,37 +34,21 @@ */ static int remount_ro_done(void) { - FILE *f; - char mount_dev[256]; - char mount_dir[256]; - char mount_type[256]; - char mount_opts[256]; - int mount_freq; - int mount_passno; - int match; + FILE* fp; + struct mntent* mentry; int found_rw_fs = 0; - f = fopen("/proc/mounts", "r"); - if (! f) { - /* If we can't read /proc/mounts, just give up */ + if ((fp = setmntent("/proc/mounts", "r")) == NULL) { + /* If we can't read /proc/mounts, just give up. */ return 1; } - - do { - match = fscanf(f, "%255s %255s %255s %255s %d %d\n", - mount_dev, mount_dir, mount_type, - mount_opts, &mount_freq, &mount_passno); - mount_dev[255] = 0; - mount_dir[255] = 0; - mount_type[255] = 0; - mount_opts[255] = 0; - if ((match == 6) && !strncmp(mount_dev, "/dev/block", 10) && strstr(mount_opts, "rw,")) { + while ((mentry = getmntent(fp)) != NULL) { + if (!strncmp(mentry->mnt_fsname, "/dev/block", 10) && strstr(mentry->mnt_opts, "rw,")) { found_rw_fs = 1; break; } - } while (match != EOF); - - fclose(f); + } + endmntent(fp); return !found_rw_fs; } @@ -104,7 +89,7 @@ static void remount_ro(void) } -int android_reboot(int cmd, int flags UNUSED, char *arg) +int android_reboot(int cmd, int flags UNUSED, const char *arg) { int ret; diff --git a/libcutils/arch-mips/android_memset.c b/libcutils/arch-mips/android_memset.c index bbc99fe..a6b7496 100644 --- a/libcutils/arch-mips/android_memset.c +++ b/libcutils/arch-mips/android_memset.c @@ -1,31 +1,93 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2015 The Android Open Source Project + * All rights reserved. * - * 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 + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. * - * 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. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. */ -#include <cutils/memory.h> +/* generic C version for any machine */ -/* Use mips-assembler versions supplied by bionic/libc/arch-mips/string/memset.S: */ -void _memset16(uint16_t* dst, uint16_t value, size_t size); -void _memset32(uint32_t* dst, uint32_t value, size_t size); +#include <cutils/memory.h> void android_memset16(uint16_t* dst, uint16_t value, size_t size) { - _memset16(dst, value, size); + /* optimized version of + size >>= 1; + while (size--) + *dst++ = value; + */ + + size >>= 1; + if (((uintptr_t)dst & 2) && size) { + /* fill unpaired first elem separately */ + *dst++ = value; + size--; + } + /* dst is now 32-bit-aligned */ + /* fill body with 32-bit pairs */ + uint32_t value32 = (value << 16) | value; + android_memset32((uint32_t*) dst, value32, size<<1); + if (size & 1) { + dst[size-1] = value; /* fill unpaired last elem */ + } } + void android_memset32(uint32_t* dst, uint32_t value, size_t size) { - _memset32(dst, value, size); + /* optimized version of + size >>= 2; + while (size--) + *dst++ = value; + */ + + size >>= 2; + if (((uintptr_t)dst & 4) && size) { + /* fill unpaired first 32-bit elem separately */ + *dst++ = value; + size--; + } + /* dst is now 64-bit aligned */ + /* fill body with 64-bit pairs */ + uint64_t value64 = (((uint64_t)value)<<32) | value; + uint64_t* dst64 = (uint64_t*)dst; + + while (size >= 12) { + dst64[0] = value64; + dst64[1] = value64; + dst64[2] = value64; + dst64[3] = value64; + dst64[4] = value64; + dst64[5] = value64; + size -= 12; + dst64 += 6; + } + + /* fill remainder with original 32-bit single-elem loop */ + dst = (uint32_t*) dst64; + while (size--) { + *dst++ = value; + } + } diff --git a/libcutils/arch-x86/android_memset16.S b/libcutils/arch-x86/android_memset16.S index f8b79bd..cb2ff14 100644..100755 --- a/libcutils/arch-x86/android_memset16.S +++ b/libcutils/arch-x86/android_memset16.S @@ -13,13 +13,707 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * Contributed by: Intel Corporation - */ -# include "cache_wrapper.S" -# undef __i686 -# define USE_AS_ANDROID -# define sse2_memset16_atom android_memset16 -# include "sse2-memset16-atom.S" +#include "cache.h" + +#ifndef MEMSET +# define MEMSET android_memset16 +#endif + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef ALIGN +# define ALIGN(n) .p2align n +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#ifdef USE_AS_BZERO16 +# define DEST PARMS +# define LEN DEST+4 +# define SETRTNVAL +#else +# define DEST PARMS +# define CHR DEST+4 +# define LEN CHR+4 +# define SETRTNVAL movl DEST(%esp), %eax +#endif + +#if (defined SHARED || defined __PIC__) +# define ENTRANCE PUSH (%ebx); +# define RETURN_END POP (%ebx); ret +# define RETURN RETURN_END; CFI_PUSH (%ebx) +# define PARMS 8 /* Preserve EBX. */ +# define JMPTBL(I, B) I - B + +/* Load an entry in a jump table into EBX and branch to it. TABLE is a + jump table with relative offsets. */ +# define BRANCH_TO_JMPTBL_ENTRY(TABLE) \ + /* We first load PC into EBX. */ \ + call __x86.get_pc_thunk.bx; \ + /* Get the address of the jump table. */ \ + add $(TABLE - .), %ebx; \ + /* Get the entry and convert the relative offset to the \ + absolute address. */ \ + add (%ebx,%ecx,4), %ebx; \ + /* We loaded the jump table and adjuested EDX. Go. */ \ + jmp *%ebx + + .section .gnu.linkonce.t.__x86.get_pc_thunk.bx,"ax",@progbits + .globl __x86.get_pc_thunk.bx + .hidden __x86.get_pc_thunk.bx + ALIGN (4) + .type __x86.get_pc_thunk.bx,@function +__x86.get_pc_thunk.bx: + movl (%esp), %ebx + ret +#else +# define ENTRANCE +# define RETURN_END ret +# define RETURN RETURN_END +# define PARMS 4 +# define JMPTBL(I, B) I + +/* Branch to an entry in a jump table. TABLE is a jump table with + absolute offsets. */ +# define BRANCH_TO_JMPTBL_ENTRY(TABLE) \ + jmp *TABLE(,%ecx,4) +#endif + + .section .text.sse2,"ax",@progbits + ALIGN (4) +ENTRY (MEMSET) + ENTRANCE + + movl LEN(%esp), %ecx + shr $1, %ecx +#ifdef USE_AS_BZERO16 + xor %eax, %eax +#else + movzwl CHR(%esp), %eax + mov %eax, %edx + shl $16, %eax + or %edx, %eax +#endif + movl DEST(%esp), %edx + cmp $32, %ecx + jae L(32wordsormore) + +L(write_less32words): + lea (%edx, %ecx, 2), %edx + BRANCH_TO_JMPTBL_ENTRY (L(table_less32words)) + + + .pushsection .rodata.sse2,"a",@progbits + ALIGN (2) +L(table_less32words): + .int JMPTBL (L(write_0words), L(table_less32words)) + .int JMPTBL (L(write_1words), L(table_less32words)) + .int JMPTBL (L(write_2words), L(table_less32words)) + .int JMPTBL (L(write_3words), L(table_less32words)) + .int JMPTBL (L(write_4words), L(table_less32words)) + .int JMPTBL (L(write_5words), L(table_less32words)) + .int JMPTBL (L(write_6words), L(table_less32words)) + .int JMPTBL (L(write_7words), L(table_less32words)) + .int JMPTBL (L(write_8words), L(table_less32words)) + .int JMPTBL (L(write_9words), L(table_less32words)) + .int JMPTBL (L(write_10words), L(table_less32words)) + .int JMPTBL (L(write_11words), L(table_less32words)) + .int JMPTBL (L(write_12words), L(table_less32words)) + .int JMPTBL (L(write_13words), L(table_less32words)) + .int JMPTBL (L(write_14words), L(table_less32words)) + .int JMPTBL (L(write_15words), L(table_less32words)) + .int JMPTBL (L(write_16words), L(table_less32words)) + .int JMPTBL (L(write_17words), L(table_less32words)) + .int JMPTBL (L(write_18words), L(table_less32words)) + .int JMPTBL (L(write_19words), L(table_less32words)) + .int JMPTBL (L(write_20words), L(table_less32words)) + .int JMPTBL (L(write_21words), L(table_less32words)) + .int JMPTBL (L(write_22words), L(table_less32words)) + .int JMPTBL (L(write_23words), L(table_less32words)) + .int JMPTBL (L(write_24words), L(table_less32words)) + .int JMPTBL (L(write_25words), L(table_less32words)) + .int JMPTBL (L(write_26words), L(table_less32words)) + .int JMPTBL (L(write_27words), L(table_less32words)) + .int JMPTBL (L(write_28words), L(table_less32words)) + .int JMPTBL (L(write_29words), L(table_less32words)) + .int JMPTBL (L(write_30words), L(table_less32words)) + .int JMPTBL (L(write_31words), L(table_less32words)) + .popsection + + ALIGN (4) +L(write_28words): + movl %eax, -56(%edx) + movl %eax, -52(%edx) +L(write_24words): + movl %eax, -48(%edx) + movl %eax, -44(%edx) +L(write_20words): + movl %eax, -40(%edx) + movl %eax, -36(%edx) +L(write_16words): + movl %eax, -32(%edx) + movl %eax, -28(%edx) +L(write_12words): + movl %eax, -24(%edx) + movl %eax, -20(%edx) +L(write_8words): + movl %eax, -16(%edx) + movl %eax, -12(%edx) +L(write_4words): + movl %eax, -8(%edx) + movl %eax, -4(%edx) +L(write_0words): + SETRTNVAL + RETURN + + ALIGN (4) +L(write_29words): + movl %eax, -58(%edx) + movl %eax, -54(%edx) +L(write_25words): + movl %eax, -50(%edx) + movl %eax, -46(%edx) +L(write_21words): + movl %eax, -42(%edx) + movl %eax, -38(%edx) +L(write_17words): + movl %eax, -34(%edx) + movl %eax, -30(%edx) +L(write_13words): + movl %eax, -26(%edx) + movl %eax, -22(%edx) +L(write_9words): + movl %eax, -18(%edx) + movl %eax, -14(%edx) +L(write_5words): + movl %eax, -10(%edx) + movl %eax, -6(%edx) +L(write_1words): + mov %ax, -2(%edx) + SETRTNVAL + RETURN + + ALIGN (4) +L(write_30words): + movl %eax, -60(%edx) + movl %eax, -56(%edx) +L(write_26words): + movl %eax, -52(%edx) + movl %eax, -48(%edx) +L(write_22words): + movl %eax, -44(%edx) + movl %eax, -40(%edx) +L(write_18words): + movl %eax, -36(%edx) + movl %eax, -32(%edx) +L(write_14words): + movl %eax, -28(%edx) + movl %eax, -24(%edx) +L(write_10words): + movl %eax, -20(%edx) + movl %eax, -16(%edx) +L(write_6words): + movl %eax, -12(%edx) + movl %eax, -8(%edx) +L(write_2words): + movl %eax, -4(%edx) + SETRTNVAL + RETURN + + ALIGN (4) +L(write_31words): + movl %eax, -62(%edx) + movl %eax, -58(%edx) +L(write_27words): + movl %eax, -54(%edx) + movl %eax, -50(%edx) +L(write_23words): + movl %eax, -46(%edx) + movl %eax, -42(%edx) +L(write_19words): + movl %eax, -38(%edx) + movl %eax, -34(%edx) +L(write_15words): + movl %eax, -30(%edx) + movl %eax, -26(%edx) +L(write_11words): + movl %eax, -22(%edx) + movl %eax, -18(%edx) +L(write_7words): + movl %eax, -14(%edx) + movl %eax, -10(%edx) +L(write_3words): + movl %eax, -6(%edx) + movw %ax, -2(%edx) + SETRTNVAL + RETURN + + ALIGN (4) + +L(32wordsormore): + shl $1, %ecx + test $0x01, %edx + jz L(aligned2bytes) + mov %eax, (%edx) + mov %eax, -4(%edx, %ecx) + sub $2, %ecx + add $1, %edx + rol $8, %eax +L(aligned2bytes): +#ifdef USE_AS_BZERO16 + pxor %xmm0, %xmm0 +#else + movd %eax, %xmm0 + pshufd $0, %xmm0, %xmm0 +#endif + testl $0xf, %edx + jz L(aligned_16) +/* ECX > 32 and EDX is not 16 byte aligned. */ +L(not_aligned_16): + movdqu %xmm0, (%edx) + movl %edx, %eax + and $-16, %edx + add $16, %edx + sub %edx, %eax + add %eax, %ecx + movd %xmm0, %eax + + ALIGN (4) +L(aligned_16): + cmp $128, %ecx + jae L(128bytesormore) + +L(aligned_16_less128bytes): + add %ecx, %edx + shr $1, %ecx + BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) + + ALIGN (4) +L(128bytesormore): +#ifdef SHARED_CACHE_SIZE + PUSH (%ebx) + mov $SHARED_CACHE_SIZE, %ebx +#else +# if (defined SHARED || defined __PIC__) + call __x86.get_pc_thunk.bx + add $_GLOBAL_OFFSET_TABLE_, %ebx + mov __x86_shared_cache_size@GOTOFF(%ebx), %ebx +# else + PUSH (%ebx) + mov __x86_shared_cache_size, %ebx +# endif +#endif + cmp %ebx, %ecx + jae L(128bytesormore_nt_start) + + +#ifdef DATA_CACHE_SIZE + POP (%ebx) +# define RESTORE_EBX_STATE CFI_PUSH (%ebx) + cmp $DATA_CACHE_SIZE, %ecx +#else +# if (defined SHARED || defined __PIC__) +# define RESTORE_EBX_STATE + call __x86.get_pc_thunk.bx + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size@GOTOFF(%ebx), %ecx +# else + POP (%ebx) +# define RESTORE_EBX_STATE CFI_PUSH (%ebx) + cmp __x86_data_cache_size, %ecx +# endif +#endif + + jae L(128bytes_L2_normal) + subl $128, %ecx +L(128bytesormore_normal): + sub $128, %ecx + movdqa %xmm0, (%edx) + movdqa %xmm0, 0x10(%edx) + movdqa %xmm0, 0x20(%edx) + movdqa %xmm0, 0x30(%edx) + movdqa %xmm0, 0x40(%edx) + movdqa %xmm0, 0x50(%edx) + movdqa %xmm0, 0x60(%edx) + movdqa %xmm0, 0x70(%edx) + lea 128(%edx), %edx + jb L(128bytesless_normal) + + + sub $128, %ecx + movdqa %xmm0, (%edx) + movdqa %xmm0, 0x10(%edx) + movdqa %xmm0, 0x20(%edx) + movdqa %xmm0, 0x30(%edx) + movdqa %xmm0, 0x40(%edx) + movdqa %xmm0, 0x50(%edx) + movdqa %xmm0, 0x60(%edx) + movdqa %xmm0, 0x70(%edx) + lea 128(%edx), %edx + jae L(128bytesormore_normal) + +L(128bytesless_normal): + lea 128(%ecx), %ecx + add %ecx, %edx + shr $1, %ecx + BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) + + ALIGN (4) +L(128bytes_L2_normal): + prefetcht0 0x380(%edx) + prefetcht0 0x3c0(%edx) + sub $128, %ecx + movdqa %xmm0, (%edx) + movaps %xmm0, 0x10(%edx) + movaps %xmm0, 0x20(%edx) + movaps %xmm0, 0x30(%edx) + movaps %xmm0, 0x40(%edx) + movaps %xmm0, 0x50(%edx) + movaps %xmm0, 0x60(%edx) + movaps %xmm0, 0x70(%edx) + add $128, %edx + cmp $128, %ecx + jae L(128bytes_L2_normal) + +L(128bytesless_L2_normal): + add %ecx, %edx + shr $1, %ecx + BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) + + RESTORE_EBX_STATE +L(128bytesormore_nt_start): + sub %ebx, %ecx + mov %ebx, %eax + and $0x7f, %eax + add %eax, %ecx + movd %xmm0, %eax + ALIGN (4) +L(128bytesormore_shared_cache_loop): + prefetcht0 0x3c0(%edx) + prefetcht0 0x380(%edx) + sub $0x80, %ebx + movdqa %xmm0, (%edx) + movdqa %xmm0, 0x10(%edx) + movdqa %xmm0, 0x20(%edx) + movdqa %xmm0, 0x30(%edx) + movdqa %xmm0, 0x40(%edx) + movdqa %xmm0, 0x50(%edx) + movdqa %xmm0, 0x60(%edx) + movdqa %xmm0, 0x70(%edx) + add $0x80, %edx + cmp $0x80, %ebx + jae L(128bytesormore_shared_cache_loop) + cmp $0x80, %ecx + jb L(shared_cache_loop_end) + ALIGN (4) +L(128bytesormore_nt): + sub $0x80, %ecx + movntdq %xmm0, (%edx) + movntdq %xmm0, 0x10(%edx) + movntdq %xmm0, 0x20(%edx) + movntdq %xmm0, 0x30(%edx) + movntdq %xmm0, 0x40(%edx) + movntdq %xmm0, 0x50(%edx) + movntdq %xmm0, 0x60(%edx) + movntdq %xmm0, 0x70(%edx) + add $0x80, %edx + cmp $0x80, %ecx + jae L(128bytesormore_nt) + sfence +L(shared_cache_loop_end): +#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__) + POP (%ebx) +#endif + add %ecx, %edx + shr $1, %ecx + BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) + + + .pushsection .rodata.sse2,"a",@progbits + ALIGN (2) +L(table_16_128bytes): + .int JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_2bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_6bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_10bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_14bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_18bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_22bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_26bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_30bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_34bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_38bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_42bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_46bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_50bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_54bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_58bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_62bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_66bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_70bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_74bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_78bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_82bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_86bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_90bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_94bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_98bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_102bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_106bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_110bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_114bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_118bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_122bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_126bytes), L(table_16_128bytes)) + .popsection + + + ALIGN (4) +L(aligned_16_112bytes): + movdqa %xmm0, -112(%edx) +L(aligned_16_96bytes): + movdqa %xmm0, -96(%edx) +L(aligned_16_80bytes): + movdqa %xmm0, -80(%edx) +L(aligned_16_64bytes): + movdqa %xmm0, -64(%edx) +L(aligned_16_48bytes): + movdqa %xmm0, -48(%edx) +L(aligned_16_32bytes): + movdqa %xmm0, -32(%edx) +L(aligned_16_16bytes): + movdqa %xmm0, -16(%edx) +L(aligned_16_0bytes): + SETRTNVAL + RETURN + + + ALIGN (4) +L(aligned_16_114bytes): + movdqa %xmm0, -114(%edx) +L(aligned_16_98bytes): + movdqa %xmm0, -98(%edx) +L(aligned_16_82bytes): + movdqa %xmm0, -82(%edx) +L(aligned_16_66bytes): + movdqa %xmm0, -66(%edx) +L(aligned_16_50bytes): + movdqa %xmm0, -50(%edx) +L(aligned_16_34bytes): + movdqa %xmm0, -34(%edx) +L(aligned_16_18bytes): + movdqa %xmm0, -18(%edx) +L(aligned_16_2bytes): + movw %ax, -2(%edx) + SETRTNVAL + RETURN + + ALIGN (4) +L(aligned_16_116bytes): + movdqa %xmm0, -116(%edx) +L(aligned_16_100bytes): + movdqa %xmm0, -100(%edx) +L(aligned_16_84bytes): + movdqa %xmm0, -84(%edx) +L(aligned_16_68bytes): + movdqa %xmm0, -68(%edx) +L(aligned_16_52bytes): + movdqa %xmm0, -52(%edx) +L(aligned_16_36bytes): + movdqa %xmm0, -36(%edx) +L(aligned_16_20bytes): + movdqa %xmm0, -20(%edx) +L(aligned_16_4bytes): + movl %eax, -4(%edx) + SETRTNVAL + RETURN + + + ALIGN (4) +L(aligned_16_118bytes): + movdqa %xmm0, -118(%edx) +L(aligned_16_102bytes): + movdqa %xmm0, -102(%edx) +L(aligned_16_86bytes): + movdqa %xmm0, -86(%edx) +L(aligned_16_70bytes): + movdqa %xmm0, -70(%edx) +L(aligned_16_54bytes): + movdqa %xmm0, -54(%edx) +L(aligned_16_38bytes): + movdqa %xmm0, -38(%edx) +L(aligned_16_22bytes): + movdqa %xmm0, -22(%edx) +L(aligned_16_6bytes): + movl %eax, -6(%edx) + movw %ax, -2(%edx) + SETRTNVAL + RETURN + + + ALIGN (4) +L(aligned_16_120bytes): + movdqa %xmm0, -120(%edx) +L(aligned_16_104bytes): + movdqa %xmm0, -104(%edx) +L(aligned_16_88bytes): + movdqa %xmm0, -88(%edx) +L(aligned_16_72bytes): + movdqa %xmm0, -72(%edx) +L(aligned_16_56bytes): + movdqa %xmm0, -56(%edx) +L(aligned_16_40bytes): + movdqa %xmm0, -40(%edx) +L(aligned_16_24bytes): + movdqa %xmm0, -24(%edx) +L(aligned_16_8bytes): + movq %xmm0, -8(%edx) + SETRTNVAL + RETURN + + + ALIGN (4) +L(aligned_16_122bytes): + movdqa %xmm0, -122(%edx) +L(aligned_16_106bytes): + movdqa %xmm0, -106(%edx) +L(aligned_16_90bytes): + movdqa %xmm0, -90(%edx) +L(aligned_16_74bytes): + movdqa %xmm0, -74(%edx) +L(aligned_16_58bytes): + movdqa %xmm0, -58(%edx) +L(aligned_16_42bytes): + movdqa %xmm0, -42(%edx) +L(aligned_16_26bytes): + movdqa %xmm0, -26(%edx) +L(aligned_16_10bytes): + movq %xmm0, -10(%edx) + movw %ax, -2(%edx) + SETRTNVAL + RETURN + + + ALIGN (4) +L(aligned_16_124bytes): + movdqa %xmm0, -124(%edx) +L(aligned_16_108bytes): + movdqa %xmm0, -108(%edx) +L(aligned_16_92bytes): + movdqa %xmm0, -92(%edx) +L(aligned_16_76bytes): + movdqa %xmm0, -76(%edx) +L(aligned_16_60bytes): + movdqa %xmm0, -60(%edx) +L(aligned_16_44bytes): + movdqa %xmm0, -44(%edx) +L(aligned_16_28bytes): + movdqa %xmm0, -28(%edx) +L(aligned_16_12bytes): + movq %xmm0, -12(%edx) + movl %eax, -4(%edx) + SETRTNVAL + RETURN + + + ALIGN (4) +L(aligned_16_126bytes): + movdqa %xmm0, -126(%edx) +L(aligned_16_110bytes): + movdqa %xmm0, -110(%edx) +L(aligned_16_94bytes): + movdqa %xmm0, -94(%edx) +L(aligned_16_78bytes): + movdqa %xmm0, -78(%edx) +L(aligned_16_62bytes): + movdqa %xmm0, -62(%edx) +L(aligned_16_46bytes): + movdqa %xmm0, -46(%edx) +L(aligned_16_30bytes): + movdqa %xmm0, -30(%edx) +L(aligned_16_14bytes): + movq %xmm0, -14(%edx) + movl %eax, -6(%edx) + movw %ax, -2(%edx) + SETRTNVAL + RETURN +END (MEMSET) diff --git a/libcutils/arch-x86/android_memset32.S b/libcutils/arch-x86/android_memset32.S index 6249fce..f4326dc 100644..100755 --- a/libcutils/arch-x86/android_memset32.S +++ b/libcutils/arch-x86/android_memset32.S @@ -13,13 +13,498 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * Contributed by: Intel Corporation - */ -# include "cache_wrapper.S" -# undef __i686 -# define USE_AS_ANDROID -# define sse2_memset32_atom android_memset32 -# include "sse2-memset32-atom.S" +#include "cache.h" + +#ifndef MEMSET +# define MEMSET android_memset32 +#endif + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef ALIGN +# define ALIGN(n) .p2align n +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#ifdef USE_AS_BZERO32 +# define DEST PARMS +# define LEN DEST+4 +# define SETRTNVAL +#else +# define DEST PARMS +# define DWDS DEST+4 +# define LEN DWDS+4 +# define SETRTNVAL movl DEST(%esp), %eax +#endif + +#if (defined SHARED || defined __PIC__) +# define ENTRANCE PUSH (%ebx); +# define RETURN_END POP (%ebx); ret +# define RETURN RETURN_END; CFI_PUSH (%ebx) +# define PARMS 8 /* Preserve EBX. */ +# define JMPTBL(I, B) I - B + +/* Load an entry in a jump table into EBX and branch to it. TABLE is a + jump table with relative offsets. */ +# define BRANCH_TO_JMPTBL_ENTRY(TABLE) \ + /* We first load PC into EBX. */ \ + call __x86.get_pc_thunk.bx; \ + /* Get the address of the jump table. */ \ + add $(TABLE - .), %ebx; \ + /* Get the entry and convert the relative offset to the \ + absolute address. */ \ + add (%ebx,%ecx,4), %ebx; \ + /* We loaded the jump table and adjuested EDX. Go. */ \ + jmp *%ebx + + .section .gnu.linkonce.t.__x86.get_pc_thunk.bx,"ax",@progbits + .globl __x86.get_pc_thunk.bx + .hidden __x86.get_pc_thunk.bx + ALIGN (4) + .type __x86.get_pc_thunk.bx,@function +__x86.get_pc_thunk.bx: + movl (%esp), %ebx + ret +#else +# define ENTRANCE +# define RETURN_END ret +# define RETURN RETURN_END +# define PARMS 4 +# define JMPTBL(I, B) I + +/* Branch to an entry in a jump table. TABLE is a jump table with + absolute offsets. */ +# define BRANCH_TO_JMPTBL_ENTRY(TABLE) \ + jmp *TABLE(,%ecx,4) +#endif + + .section .text.sse2,"ax",@progbits + ALIGN (4) +ENTRY (MEMSET) + ENTRANCE + + movl LEN(%esp), %ecx + shr $2, %ecx +#ifdef USE_AS_BZERO32 + xor %eax, %eax +#else + mov DWDS(%esp), %eax + mov %eax, %edx +#endif + movl DEST(%esp), %edx + cmp $16, %ecx + jae L(16dbwordsormore) + +L(write_less16dbwords): + lea (%edx, %ecx, 4), %edx + BRANCH_TO_JMPTBL_ENTRY (L(table_less16dbwords)) + + .pushsection .rodata.sse2,"a",@progbits + ALIGN (2) +L(table_less16dbwords): + .int JMPTBL (L(write_0dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_1dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_2dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_3dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_4dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_5dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_6dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_7dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_8dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_9dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_10dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_11dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_12dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_13dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_14dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_15dbwords), L(table_less16dbwords)) + .popsection + + ALIGN (4) +L(write_15dbwords): + movl %eax, -60(%edx) +L(write_14dbwords): + movl %eax, -56(%edx) +L(write_13dbwords): + movl %eax, -52(%edx) +L(write_12dbwords): + movl %eax, -48(%edx) +L(write_11dbwords): + movl %eax, -44(%edx) +L(write_10dbwords): + movl %eax, -40(%edx) +L(write_9dbwords): + movl %eax, -36(%edx) +L(write_8dbwords): + movl %eax, -32(%edx) +L(write_7dbwords): + movl %eax, -28(%edx) +L(write_6dbwords): + movl %eax, -24(%edx) +L(write_5dbwords): + movl %eax, -20(%edx) +L(write_4dbwords): + movl %eax, -16(%edx) +L(write_3dbwords): + movl %eax, -12(%edx) +L(write_2dbwords): + movl %eax, -8(%edx) +L(write_1dbwords): + movl %eax, -4(%edx) +L(write_0dbwords): + SETRTNVAL + RETURN + + ALIGN (4) +L(16dbwordsormore): + test $3, %edx + jz L(aligned4bytes) + mov %eax, (%edx) + mov %eax, -4(%edx, %ecx, 4) + sub $1, %ecx + rol $24, %eax + add $1, %edx + test $3, %edx + jz L(aligned4bytes) + ror $8, %eax + add $1, %edx + test $3, %edx + jz L(aligned4bytes) + ror $8, %eax + add $1, %edx +L(aligned4bytes): + shl $2, %ecx + +#ifdef USE_AS_BZERO32 + pxor %xmm0, %xmm0 +#else + movd %eax, %xmm0 + pshufd $0, %xmm0, %xmm0 +#endif + testl $0xf, %edx + jz L(aligned_16) +/* ECX > 32 and EDX is not 16 byte aligned. */ +L(not_aligned_16): + movdqu %xmm0, (%edx) + movl %edx, %eax + and $-16, %edx + add $16, %edx + sub %edx, %eax + add %eax, %ecx + movd %xmm0, %eax + ALIGN (4) +L(aligned_16): + cmp $128, %ecx + jae L(128bytesormore) + +L(aligned_16_less128bytes): + add %ecx, %edx + shr $2, %ecx + BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) + + ALIGN (4) +L(128bytesormore): +#ifdef SHARED_CACHE_SIZE + PUSH (%ebx) + mov $SHARED_CACHE_SIZE, %ebx +#else +# if (defined SHARED || defined __PIC__) + call __x86.get_pc_thunk.bx + add $_GLOBAL_OFFSET_TABLE_, %ebx + mov __x86_shared_cache_size@GOTOFF(%ebx), %ebx +# else + PUSH (%ebx) + mov __x86_shared_cache_size, %ebx +# endif +#endif + cmp %ebx, %ecx + jae L(128bytesormore_nt_start) + +#ifdef DATA_CACHE_SIZE + POP (%ebx) +# define RESTORE_EBX_STATE CFI_PUSH (%ebx) + cmp $DATA_CACHE_SIZE, %ecx +#else +# if (defined SHARED || defined __PIC__) +# define RESTORE_EBX_STATE + call __x86.get_pc_thunk.bx + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size@GOTOFF(%ebx), %ecx +# else + POP (%ebx) +# define RESTORE_EBX_STATE CFI_PUSH (%ebx) + cmp __x86_data_cache_size, %ecx +# endif +#endif + + jae L(128bytes_L2_normal) + subl $128, %ecx +L(128bytesormore_normal): + sub $128, %ecx + movdqa %xmm0, (%edx) + movdqa %xmm0, 0x10(%edx) + movdqa %xmm0, 0x20(%edx) + movdqa %xmm0, 0x30(%edx) + movdqa %xmm0, 0x40(%edx) + movdqa %xmm0, 0x50(%edx) + movdqa %xmm0, 0x60(%edx) + movdqa %xmm0, 0x70(%edx) + lea 128(%edx), %edx + jb L(128bytesless_normal) + + + sub $128, %ecx + movdqa %xmm0, (%edx) + movdqa %xmm0, 0x10(%edx) + movdqa %xmm0, 0x20(%edx) + movdqa %xmm0, 0x30(%edx) + movdqa %xmm0, 0x40(%edx) + movdqa %xmm0, 0x50(%edx) + movdqa %xmm0, 0x60(%edx) + movdqa %xmm0, 0x70(%edx) + lea 128(%edx), %edx + jae L(128bytesormore_normal) + +L(128bytesless_normal): + lea 128(%ecx), %ecx + add %ecx, %edx + shr $2, %ecx + BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) + + ALIGN (4) +L(128bytes_L2_normal): + prefetcht0 0x380(%edx) + prefetcht0 0x3c0(%edx) + sub $128, %ecx + movdqa %xmm0, (%edx) + movaps %xmm0, 0x10(%edx) + movaps %xmm0, 0x20(%edx) + movaps %xmm0, 0x30(%edx) + movaps %xmm0, 0x40(%edx) + movaps %xmm0, 0x50(%edx) + movaps %xmm0, 0x60(%edx) + movaps %xmm0, 0x70(%edx) + add $128, %edx + cmp $128, %ecx + jae L(128bytes_L2_normal) + +L(128bytesless_L2_normal): + add %ecx, %edx + shr $2, %ecx + BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) + + RESTORE_EBX_STATE +L(128bytesormore_nt_start): + sub %ebx, %ecx + mov %ebx, %eax + and $0x7f, %eax + add %eax, %ecx + movd %xmm0, %eax + ALIGN (4) +L(128bytesormore_shared_cache_loop): + prefetcht0 0x3c0(%edx) + prefetcht0 0x380(%edx) + sub $0x80, %ebx + movdqa %xmm0, (%edx) + movdqa %xmm0, 0x10(%edx) + movdqa %xmm0, 0x20(%edx) + movdqa %xmm0, 0x30(%edx) + movdqa %xmm0, 0x40(%edx) + movdqa %xmm0, 0x50(%edx) + movdqa %xmm0, 0x60(%edx) + movdqa %xmm0, 0x70(%edx) + add $0x80, %edx + cmp $0x80, %ebx + jae L(128bytesormore_shared_cache_loop) + cmp $0x80, %ecx + jb L(shared_cache_loop_end) + + ALIGN (4) +L(128bytesormore_nt): + sub $0x80, %ecx + movntdq %xmm0, (%edx) + movntdq %xmm0, 0x10(%edx) + movntdq %xmm0, 0x20(%edx) + movntdq %xmm0, 0x30(%edx) + movntdq %xmm0, 0x40(%edx) + movntdq %xmm0, 0x50(%edx) + movntdq %xmm0, 0x60(%edx) + movntdq %xmm0, 0x70(%edx) + add $0x80, %edx + cmp $0x80, %ecx + jae L(128bytesormore_nt) + sfence +L(shared_cache_loop_end): +#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__) + POP (%ebx) +#endif + add %ecx, %edx + shr $2, %ecx + BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) + + .pushsection .rodata.sse2,"a",@progbits + ALIGN (2) +L(table_16_128bytes): + .int JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes)) + .popsection + + ALIGN (4) +L(aligned_16_112bytes): + movdqa %xmm0, -112(%edx) +L(aligned_16_96bytes): + movdqa %xmm0, -96(%edx) +L(aligned_16_80bytes): + movdqa %xmm0, -80(%edx) +L(aligned_16_64bytes): + movdqa %xmm0, -64(%edx) +L(aligned_16_48bytes): + movdqa %xmm0, -48(%edx) +L(aligned_16_32bytes): + movdqa %xmm0, -32(%edx) +L(aligned_16_16bytes): + movdqa %xmm0, -16(%edx) +L(aligned_16_0bytes): + SETRTNVAL + RETURN + + ALIGN (4) +L(aligned_16_116bytes): + movdqa %xmm0, -116(%edx) +L(aligned_16_100bytes): + movdqa %xmm0, -100(%edx) +L(aligned_16_84bytes): + movdqa %xmm0, -84(%edx) +L(aligned_16_68bytes): + movdqa %xmm0, -68(%edx) +L(aligned_16_52bytes): + movdqa %xmm0, -52(%edx) +L(aligned_16_36bytes): + movdqa %xmm0, -36(%edx) +L(aligned_16_20bytes): + movdqa %xmm0, -20(%edx) +L(aligned_16_4bytes): + movl %eax, -4(%edx) + SETRTNVAL + RETURN + + ALIGN (4) +L(aligned_16_120bytes): + movdqa %xmm0, -120(%edx) +L(aligned_16_104bytes): + movdqa %xmm0, -104(%edx) +L(aligned_16_88bytes): + movdqa %xmm0, -88(%edx) +L(aligned_16_72bytes): + movdqa %xmm0, -72(%edx) +L(aligned_16_56bytes): + movdqa %xmm0, -56(%edx) +L(aligned_16_40bytes): + movdqa %xmm0, -40(%edx) +L(aligned_16_24bytes): + movdqa %xmm0, -24(%edx) +L(aligned_16_8bytes): + movq %xmm0, -8(%edx) + SETRTNVAL + RETURN + + ALIGN (4) +L(aligned_16_124bytes): + movdqa %xmm0, -124(%edx) +L(aligned_16_108bytes): + movdqa %xmm0, -108(%edx) +L(aligned_16_92bytes): + movdqa %xmm0, -92(%edx) +L(aligned_16_76bytes): + movdqa %xmm0, -76(%edx) +L(aligned_16_60bytes): + movdqa %xmm0, -60(%edx) +L(aligned_16_44bytes): + movdqa %xmm0, -44(%edx) +L(aligned_16_28bytes): + movdqa %xmm0, -28(%edx) +L(aligned_16_12bytes): + movq %xmm0, -12(%edx) + movl %eax, -4(%edx) + SETRTNVAL + RETURN +END (MEMSET) diff --git a/libcutils/arch-x86/cache_wrapper.S b/libcutils/arch-x86/cache.h index 9eee25c..1c22fea 100644 --- a/libcutils/arch-x86/cache_wrapper.S +++ b/libcutils/arch-x86/cache.h @@ -13,9 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * Contributed by: Intel Corporation - */ #if defined(__slm__) /* Values are optimized for Silvermont */ diff --git a/libcutils/arch-x86/sse2-memset16-atom.S b/libcutils/arch-x86/sse2-memset16-atom.S deleted file mode 100755 index c2a762b..0000000 --- a/libcutils/arch-x86/sse2-memset16-atom.S +++ /dev/null @@ -1,722 +0,0 @@ -/* - * Copyright (C) 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. - */ -/* - * Contributed by: Intel Corporation - */ - -#ifndef L -# define L(label) .L##label -#endif - -#ifndef ALIGN -# define ALIGN(n) .p2align n -#endif - -#ifndef cfi_startproc -# define cfi_startproc .cfi_startproc -#endif - -#ifndef cfi_endproc -# define cfi_endproc .cfi_endproc -#endif - -#ifndef cfi_rel_offset -# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off -#endif - -#ifndef cfi_restore -# define cfi_restore(reg) .cfi_restore reg -#endif - -#ifndef cfi_adjust_cfa_offset -# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off -#endif - -#ifndef ENTRY -# define ENTRY(name) \ - .type name, @function; \ - .globl name; \ - .p2align 4; \ -name: \ - cfi_startproc -#endif - -#ifndef END -# define END(name) \ - cfi_endproc; \ - .size name, .-name -#endif - -#define CFI_PUSH(REG) \ - cfi_adjust_cfa_offset (4); \ - cfi_rel_offset (REG, 0) - -#define CFI_POP(REG) \ - cfi_adjust_cfa_offset (-4); \ - cfi_restore (REG) - -#define PUSH(REG) pushl REG; CFI_PUSH (REG) -#define POP(REG) popl REG; CFI_POP (REG) - -#ifdef USE_AS_BZERO16 -# define DEST PARMS -# define LEN DEST+4 -#else -# define DEST PARMS -# define CHR DEST+4 -# define LEN CHR+4 -#endif - -#if 1 -# define SETRTNVAL -#else -# define SETRTNVAL movl DEST(%esp), %eax -#endif - -#if (defined SHARED || defined __PIC__) -# define ENTRANCE PUSH (%ebx); -# define RETURN_END POP (%ebx); ret -# define RETURN RETURN_END; CFI_PUSH (%ebx) -# define PARMS 8 /* Preserve EBX. */ -# define JMPTBL(I, B) I - B - -/* Load an entry in a jump table into EBX and branch to it. TABLE is a - jump table with relative offsets. */ -# define BRANCH_TO_JMPTBL_ENTRY(TABLE) \ - /* We first load PC into EBX. */ \ - call __i686.get_pc_thunk.bx; \ - /* Get the address of the jump table. */ \ - add $(TABLE - .), %ebx; \ - /* Get the entry and convert the relative offset to the \ - absolute address. */ \ - add (%ebx,%ecx,4), %ebx; \ - /* We loaded the jump table and adjuested EDX. Go. */ \ - jmp *%ebx - - .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits - .globl __i686.get_pc_thunk.bx - .hidden __i686.get_pc_thunk.bx - ALIGN (4) - .type __i686.get_pc_thunk.bx,@function -__i686.get_pc_thunk.bx: - movl (%esp), %ebx - ret -#else -# define ENTRANCE -# define RETURN_END ret -# define RETURN RETURN_END -# define PARMS 4 -# define JMPTBL(I, B) I - -/* Branch to an entry in a jump table. TABLE is a jump table with - absolute offsets. */ -# define BRANCH_TO_JMPTBL_ENTRY(TABLE) \ - jmp *TABLE(,%ecx,4) -#endif - - .section .text.sse2,"ax",@progbits - ALIGN (4) -ENTRY (sse2_memset16_atom) - ENTRANCE - - movl LEN(%esp), %ecx -#ifdef USE_AS_ANDROID - shr $1, %ecx -#endif -#ifdef USE_AS_BZERO16 - xor %eax, %eax -#else - movzwl CHR(%esp), %eax - mov %eax, %edx - shl $16, %eax - or %edx, %eax -#endif - movl DEST(%esp), %edx - cmp $32, %ecx - jae L(32wordsormore) - -L(write_less32words): - lea (%edx, %ecx, 2), %edx - BRANCH_TO_JMPTBL_ENTRY (L(table_less32words)) - - - .pushsection .rodata.sse2,"a",@progbits - ALIGN (2) -L(table_less32words): - .int JMPTBL (L(write_0words), L(table_less32words)) - .int JMPTBL (L(write_1words), L(table_less32words)) - .int JMPTBL (L(write_2words), L(table_less32words)) - .int JMPTBL (L(write_3words), L(table_less32words)) - .int JMPTBL (L(write_4words), L(table_less32words)) - .int JMPTBL (L(write_5words), L(table_less32words)) - .int JMPTBL (L(write_6words), L(table_less32words)) - .int JMPTBL (L(write_7words), L(table_less32words)) - .int JMPTBL (L(write_8words), L(table_less32words)) - .int JMPTBL (L(write_9words), L(table_less32words)) - .int JMPTBL (L(write_10words), L(table_less32words)) - .int JMPTBL (L(write_11words), L(table_less32words)) - .int JMPTBL (L(write_12words), L(table_less32words)) - .int JMPTBL (L(write_13words), L(table_less32words)) - .int JMPTBL (L(write_14words), L(table_less32words)) - .int JMPTBL (L(write_15words), L(table_less32words)) - .int JMPTBL (L(write_16words), L(table_less32words)) - .int JMPTBL (L(write_17words), L(table_less32words)) - .int JMPTBL (L(write_18words), L(table_less32words)) - .int JMPTBL (L(write_19words), L(table_less32words)) - .int JMPTBL (L(write_20words), L(table_less32words)) - .int JMPTBL (L(write_21words), L(table_less32words)) - .int JMPTBL (L(write_22words), L(table_less32words)) - .int JMPTBL (L(write_23words), L(table_less32words)) - .int JMPTBL (L(write_24words), L(table_less32words)) - .int JMPTBL (L(write_25words), L(table_less32words)) - .int JMPTBL (L(write_26words), L(table_less32words)) - .int JMPTBL (L(write_27words), L(table_less32words)) - .int JMPTBL (L(write_28words), L(table_less32words)) - .int JMPTBL (L(write_29words), L(table_less32words)) - .int JMPTBL (L(write_30words), L(table_less32words)) - .int JMPTBL (L(write_31words), L(table_less32words)) - .popsection - - ALIGN (4) -L(write_28words): - movl %eax, -56(%edx) - movl %eax, -52(%edx) -L(write_24words): - movl %eax, -48(%edx) - movl %eax, -44(%edx) -L(write_20words): - movl %eax, -40(%edx) - movl %eax, -36(%edx) -L(write_16words): - movl %eax, -32(%edx) - movl %eax, -28(%edx) -L(write_12words): - movl %eax, -24(%edx) - movl %eax, -20(%edx) -L(write_8words): - movl %eax, -16(%edx) - movl %eax, -12(%edx) -L(write_4words): - movl %eax, -8(%edx) - movl %eax, -4(%edx) -L(write_0words): - SETRTNVAL - RETURN - - ALIGN (4) -L(write_29words): - movl %eax, -58(%edx) - movl %eax, -54(%edx) -L(write_25words): - movl %eax, -50(%edx) - movl %eax, -46(%edx) -L(write_21words): - movl %eax, -42(%edx) - movl %eax, -38(%edx) -L(write_17words): - movl %eax, -34(%edx) - movl %eax, -30(%edx) -L(write_13words): - movl %eax, -26(%edx) - movl %eax, -22(%edx) -L(write_9words): - movl %eax, -18(%edx) - movl %eax, -14(%edx) -L(write_5words): - movl %eax, -10(%edx) - movl %eax, -6(%edx) -L(write_1words): - mov %ax, -2(%edx) - SETRTNVAL - RETURN - - ALIGN (4) -L(write_30words): - movl %eax, -60(%edx) - movl %eax, -56(%edx) -L(write_26words): - movl %eax, -52(%edx) - movl %eax, -48(%edx) -L(write_22words): - movl %eax, -44(%edx) - movl %eax, -40(%edx) -L(write_18words): - movl %eax, -36(%edx) - movl %eax, -32(%edx) -L(write_14words): - movl %eax, -28(%edx) - movl %eax, -24(%edx) -L(write_10words): - movl %eax, -20(%edx) - movl %eax, -16(%edx) -L(write_6words): - movl %eax, -12(%edx) - movl %eax, -8(%edx) -L(write_2words): - movl %eax, -4(%edx) - SETRTNVAL - RETURN - - ALIGN (4) -L(write_31words): - movl %eax, -62(%edx) - movl %eax, -58(%edx) -L(write_27words): - movl %eax, -54(%edx) - movl %eax, -50(%edx) -L(write_23words): - movl %eax, -46(%edx) - movl %eax, -42(%edx) -L(write_19words): - movl %eax, -38(%edx) - movl %eax, -34(%edx) -L(write_15words): - movl %eax, -30(%edx) - movl %eax, -26(%edx) -L(write_11words): - movl %eax, -22(%edx) - movl %eax, -18(%edx) -L(write_7words): - movl %eax, -14(%edx) - movl %eax, -10(%edx) -L(write_3words): - movl %eax, -6(%edx) - movw %ax, -2(%edx) - SETRTNVAL - RETURN - - ALIGN (4) - -L(32wordsormore): - shl $1, %ecx - test $0x01, %edx - jz L(aligned2bytes) - mov %eax, (%edx) - mov %eax, -4(%edx, %ecx) - sub $2, %ecx - add $1, %edx - rol $8, %eax -L(aligned2bytes): -#ifdef USE_AS_BZERO16 - pxor %xmm0, %xmm0 -#else - movd %eax, %xmm0 - pshufd $0, %xmm0, %xmm0 -#endif - testl $0xf, %edx - jz L(aligned_16) -/* ECX > 32 and EDX is not 16 byte aligned. */ -L(not_aligned_16): - movdqu %xmm0, (%edx) - movl %edx, %eax - and $-16, %edx - add $16, %edx - sub %edx, %eax - add %eax, %ecx - movd %xmm0, %eax - - ALIGN (4) -L(aligned_16): - cmp $128, %ecx - jae L(128bytesormore) - -L(aligned_16_less128bytes): - add %ecx, %edx - shr $1, %ecx - BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) - - ALIGN (4) -L(128bytesormore): -#ifdef SHARED_CACHE_SIZE - PUSH (%ebx) - mov $SHARED_CACHE_SIZE, %ebx -#else -# if (defined SHARED || defined __PIC__) - call __i686.get_pc_thunk.bx - add $_GLOBAL_OFFSET_TABLE_, %ebx - mov __x86_shared_cache_size@GOTOFF(%ebx), %ebx -# else - PUSH (%ebx) - mov __x86_shared_cache_size, %ebx -# endif -#endif - cmp %ebx, %ecx - jae L(128bytesormore_nt_start) - - -#ifdef DATA_CACHE_SIZE - POP (%ebx) -# define RESTORE_EBX_STATE CFI_PUSH (%ebx) - cmp $DATA_CACHE_SIZE, %ecx -#else -# if (defined SHARED || defined __PIC__) -# define RESTORE_EBX_STATE - call __i686.get_pc_thunk.bx - add $_GLOBAL_OFFSET_TABLE_, %ebx - cmp __x86_data_cache_size@GOTOFF(%ebx), %ecx -# else - POP (%ebx) -# define RESTORE_EBX_STATE CFI_PUSH (%ebx) - cmp __x86_data_cache_size, %ecx -# endif -#endif - - jae L(128bytes_L2_normal) - subl $128, %ecx -L(128bytesormore_normal): - sub $128, %ecx - movdqa %xmm0, (%edx) - movdqa %xmm0, 0x10(%edx) - movdqa %xmm0, 0x20(%edx) - movdqa %xmm0, 0x30(%edx) - movdqa %xmm0, 0x40(%edx) - movdqa %xmm0, 0x50(%edx) - movdqa %xmm0, 0x60(%edx) - movdqa %xmm0, 0x70(%edx) - lea 128(%edx), %edx - jb L(128bytesless_normal) - - - sub $128, %ecx - movdqa %xmm0, (%edx) - movdqa %xmm0, 0x10(%edx) - movdqa %xmm0, 0x20(%edx) - movdqa %xmm0, 0x30(%edx) - movdqa %xmm0, 0x40(%edx) - movdqa %xmm0, 0x50(%edx) - movdqa %xmm0, 0x60(%edx) - movdqa %xmm0, 0x70(%edx) - lea 128(%edx), %edx - jae L(128bytesormore_normal) - -L(128bytesless_normal): - lea 128(%ecx), %ecx - add %ecx, %edx - shr $1, %ecx - BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) - - ALIGN (4) -L(128bytes_L2_normal): - prefetcht0 0x380(%edx) - prefetcht0 0x3c0(%edx) - sub $128, %ecx - movdqa %xmm0, (%edx) - movaps %xmm0, 0x10(%edx) - movaps %xmm0, 0x20(%edx) - movaps %xmm0, 0x30(%edx) - movaps %xmm0, 0x40(%edx) - movaps %xmm0, 0x50(%edx) - movaps %xmm0, 0x60(%edx) - movaps %xmm0, 0x70(%edx) - add $128, %edx - cmp $128, %ecx - jae L(128bytes_L2_normal) - -L(128bytesless_L2_normal): - add %ecx, %edx - shr $1, %ecx - BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) - - RESTORE_EBX_STATE -L(128bytesormore_nt_start): - sub %ebx, %ecx - mov %ebx, %eax - and $0x7f, %eax - add %eax, %ecx - movd %xmm0, %eax - ALIGN (4) -L(128bytesormore_shared_cache_loop): - prefetcht0 0x3c0(%edx) - prefetcht0 0x380(%edx) - sub $0x80, %ebx - movdqa %xmm0, (%edx) - movdqa %xmm0, 0x10(%edx) - movdqa %xmm0, 0x20(%edx) - movdqa %xmm0, 0x30(%edx) - movdqa %xmm0, 0x40(%edx) - movdqa %xmm0, 0x50(%edx) - movdqa %xmm0, 0x60(%edx) - movdqa %xmm0, 0x70(%edx) - add $0x80, %edx - cmp $0x80, %ebx - jae L(128bytesormore_shared_cache_loop) - cmp $0x80, %ecx - jb L(shared_cache_loop_end) - ALIGN (4) -L(128bytesormore_nt): - sub $0x80, %ecx - movntdq %xmm0, (%edx) - movntdq %xmm0, 0x10(%edx) - movntdq %xmm0, 0x20(%edx) - movntdq %xmm0, 0x30(%edx) - movntdq %xmm0, 0x40(%edx) - movntdq %xmm0, 0x50(%edx) - movntdq %xmm0, 0x60(%edx) - movntdq %xmm0, 0x70(%edx) - add $0x80, %edx - cmp $0x80, %ecx - jae L(128bytesormore_nt) - sfence -L(shared_cache_loop_end): -#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__) - POP (%ebx) -#endif - add %ecx, %edx - shr $1, %ecx - BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) - - - .pushsection .rodata.sse2,"a",@progbits - ALIGN (2) -L(table_16_128bytes): - .int JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_2bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_6bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_10bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_14bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_18bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_22bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_26bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_30bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_34bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_38bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_42bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_46bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_50bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_54bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_58bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_62bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_66bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_70bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_74bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_78bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_82bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_86bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_90bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_94bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_98bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_102bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_106bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_110bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_114bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_118bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_122bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_126bytes), L(table_16_128bytes)) - .popsection - - - ALIGN (4) -L(aligned_16_112bytes): - movdqa %xmm0, -112(%edx) -L(aligned_16_96bytes): - movdqa %xmm0, -96(%edx) -L(aligned_16_80bytes): - movdqa %xmm0, -80(%edx) -L(aligned_16_64bytes): - movdqa %xmm0, -64(%edx) -L(aligned_16_48bytes): - movdqa %xmm0, -48(%edx) -L(aligned_16_32bytes): - movdqa %xmm0, -32(%edx) -L(aligned_16_16bytes): - movdqa %xmm0, -16(%edx) -L(aligned_16_0bytes): - SETRTNVAL - RETURN - - - ALIGN (4) -L(aligned_16_114bytes): - movdqa %xmm0, -114(%edx) -L(aligned_16_98bytes): - movdqa %xmm0, -98(%edx) -L(aligned_16_82bytes): - movdqa %xmm0, -82(%edx) -L(aligned_16_66bytes): - movdqa %xmm0, -66(%edx) -L(aligned_16_50bytes): - movdqa %xmm0, -50(%edx) -L(aligned_16_34bytes): - movdqa %xmm0, -34(%edx) -L(aligned_16_18bytes): - movdqa %xmm0, -18(%edx) -L(aligned_16_2bytes): - movw %ax, -2(%edx) - SETRTNVAL - RETURN - - ALIGN (4) -L(aligned_16_116bytes): - movdqa %xmm0, -116(%edx) -L(aligned_16_100bytes): - movdqa %xmm0, -100(%edx) -L(aligned_16_84bytes): - movdqa %xmm0, -84(%edx) -L(aligned_16_68bytes): - movdqa %xmm0, -68(%edx) -L(aligned_16_52bytes): - movdqa %xmm0, -52(%edx) -L(aligned_16_36bytes): - movdqa %xmm0, -36(%edx) -L(aligned_16_20bytes): - movdqa %xmm0, -20(%edx) -L(aligned_16_4bytes): - movl %eax, -4(%edx) - SETRTNVAL - RETURN - - - ALIGN (4) -L(aligned_16_118bytes): - movdqa %xmm0, -118(%edx) -L(aligned_16_102bytes): - movdqa %xmm0, -102(%edx) -L(aligned_16_86bytes): - movdqa %xmm0, -86(%edx) -L(aligned_16_70bytes): - movdqa %xmm0, -70(%edx) -L(aligned_16_54bytes): - movdqa %xmm0, -54(%edx) -L(aligned_16_38bytes): - movdqa %xmm0, -38(%edx) -L(aligned_16_22bytes): - movdqa %xmm0, -22(%edx) -L(aligned_16_6bytes): - movl %eax, -6(%edx) - movw %ax, -2(%edx) - SETRTNVAL - RETURN - - - ALIGN (4) -L(aligned_16_120bytes): - movdqa %xmm0, -120(%edx) -L(aligned_16_104bytes): - movdqa %xmm0, -104(%edx) -L(aligned_16_88bytes): - movdqa %xmm0, -88(%edx) -L(aligned_16_72bytes): - movdqa %xmm0, -72(%edx) -L(aligned_16_56bytes): - movdqa %xmm0, -56(%edx) -L(aligned_16_40bytes): - movdqa %xmm0, -40(%edx) -L(aligned_16_24bytes): - movdqa %xmm0, -24(%edx) -L(aligned_16_8bytes): - movq %xmm0, -8(%edx) - SETRTNVAL - RETURN - - - ALIGN (4) -L(aligned_16_122bytes): - movdqa %xmm0, -122(%edx) -L(aligned_16_106bytes): - movdqa %xmm0, -106(%edx) -L(aligned_16_90bytes): - movdqa %xmm0, -90(%edx) -L(aligned_16_74bytes): - movdqa %xmm0, -74(%edx) -L(aligned_16_58bytes): - movdqa %xmm0, -58(%edx) -L(aligned_16_42bytes): - movdqa %xmm0, -42(%edx) -L(aligned_16_26bytes): - movdqa %xmm0, -26(%edx) -L(aligned_16_10bytes): - movq %xmm0, -10(%edx) - movw %ax, -2(%edx) - SETRTNVAL - RETURN - - - ALIGN (4) -L(aligned_16_124bytes): - movdqa %xmm0, -124(%edx) -L(aligned_16_108bytes): - movdqa %xmm0, -108(%edx) -L(aligned_16_92bytes): - movdqa %xmm0, -92(%edx) -L(aligned_16_76bytes): - movdqa %xmm0, -76(%edx) -L(aligned_16_60bytes): - movdqa %xmm0, -60(%edx) -L(aligned_16_44bytes): - movdqa %xmm0, -44(%edx) -L(aligned_16_28bytes): - movdqa %xmm0, -28(%edx) -L(aligned_16_12bytes): - movq %xmm0, -12(%edx) - movl %eax, -4(%edx) - SETRTNVAL - RETURN - - - ALIGN (4) -L(aligned_16_126bytes): - movdqa %xmm0, -126(%edx) -L(aligned_16_110bytes): - movdqa %xmm0, -110(%edx) -L(aligned_16_94bytes): - movdqa %xmm0, -94(%edx) -L(aligned_16_78bytes): - movdqa %xmm0, -78(%edx) -L(aligned_16_62bytes): - movdqa %xmm0, -62(%edx) -L(aligned_16_46bytes): - movdqa %xmm0, -46(%edx) -L(aligned_16_30bytes): - movdqa %xmm0, -30(%edx) -L(aligned_16_14bytes): - movq %xmm0, -14(%edx) - movl %eax, -6(%edx) - movw %ax, -2(%edx) - SETRTNVAL - RETURN - -END (sse2_memset16_atom) diff --git a/libcutils/arch-x86/sse2-memset32-atom.S b/libcutils/arch-x86/sse2-memset32-atom.S deleted file mode 100755 index 05eb64f..0000000 --- a/libcutils/arch-x86/sse2-memset32-atom.S +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Copyright (C) 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. - */ -/* - * Contributed by: Intel Corporation - */ - -#ifndef L -# define L(label) .L##label -#endif - -#ifndef ALIGN -# define ALIGN(n) .p2align n -#endif - -#ifndef cfi_startproc -# define cfi_startproc .cfi_startproc -#endif - -#ifndef cfi_endproc -# define cfi_endproc .cfi_endproc -#endif - -#ifndef cfi_rel_offset -# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off -#endif - -#ifndef cfi_restore -# define cfi_restore(reg) .cfi_restore reg -#endif - -#ifndef cfi_adjust_cfa_offset -# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off -#endif - -#ifndef ENTRY -# define ENTRY(name) \ - .type name, @function; \ - .globl name; \ - .p2align 4; \ -name: \ - cfi_startproc -#endif - -#ifndef END -# define END(name) \ - cfi_endproc; \ - .size name, .-name -#endif - -#define CFI_PUSH(REG) \ - cfi_adjust_cfa_offset (4); \ - cfi_rel_offset (REG, 0) - -#define CFI_POP(REG) \ - cfi_adjust_cfa_offset (-4); \ - cfi_restore (REG) - -#define PUSH(REG) pushl REG; CFI_PUSH (REG) -#define POP(REG) popl REG; CFI_POP (REG) - -#ifdef USE_AS_BZERO32 -# define DEST PARMS -# define LEN DEST+4 -#else -# define DEST PARMS -# define DWDS DEST+4 -# define LEN DWDS+4 -#endif - -#ifdef USE_AS_WMEMSET32 -# define SETRTNVAL movl DEST(%esp), %eax -#else -# define SETRTNVAL -#endif - -#if (defined SHARED || defined __PIC__) -# define ENTRANCE PUSH (%ebx); -# define RETURN_END POP (%ebx); ret -# define RETURN RETURN_END; CFI_PUSH (%ebx) -# define PARMS 8 /* Preserve EBX. */ -# define JMPTBL(I, B) I - B - -/* Load an entry in a jump table into EBX and branch to it. TABLE is a - jump table with relative offsets. */ -# define BRANCH_TO_JMPTBL_ENTRY(TABLE) \ - /* We first load PC into EBX. */ \ - call __i686.get_pc_thunk.bx; \ - /* Get the address of the jump table. */ \ - add $(TABLE - .), %ebx; \ - /* Get the entry and convert the relative offset to the \ - absolute address. */ \ - add (%ebx,%ecx,4), %ebx; \ - /* We loaded the jump table and adjuested EDX. Go. */ \ - jmp *%ebx - - .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits - .globl __i686.get_pc_thunk.bx - .hidden __i686.get_pc_thunk.bx - ALIGN (4) - .type __i686.get_pc_thunk.bx,@function -__i686.get_pc_thunk.bx: - movl (%esp), %ebx - ret -#else -# define ENTRANCE -# define RETURN_END ret -# define RETURN RETURN_END -# define PARMS 4 -# define JMPTBL(I, B) I - -/* Branch to an entry in a jump table. TABLE is a jump table with - absolute offsets. */ -# define BRANCH_TO_JMPTBL_ENTRY(TABLE) \ - jmp *TABLE(,%ecx,4) -#endif - - .section .text.sse2,"ax",@progbits - ALIGN (4) -ENTRY (sse2_memset32_atom) - ENTRANCE - - movl LEN(%esp), %ecx -#ifdef USE_AS_ANDROID - shr $2, %ecx -#endif -#ifdef USE_AS_BZERO32 - xor %eax, %eax -#else - mov DWDS(%esp), %eax - mov %eax, %edx -#endif - movl DEST(%esp), %edx - cmp $16, %ecx - jae L(16dbwordsormore) - -L(write_less16dbwords): - lea (%edx, %ecx, 4), %edx - BRANCH_TO_JMPTBL_ENTRY (L(table_less16dbwords)) - - .pushsection .rodata.sse2,"a",@progbits - ALIGN (2) -L(table_less16dbwords): - .int JMPTBL (L(write_0dbwords), L(table_less16dbwords)) - .int JMPTBL (L(write_1dbwords), L(table_less16dbwords)) - .int JMPTBL (L(write_2dbwords), L(table_less16dbwords)) - .int JMPTBL (L(write_3dbwords), L(table_less16dbwords)) - .int JMPTBL (L(write_4dbwords), L(table_less16dbwords)) - .int JMPTBL (L(write_5dbwords), L(table_less16dbwords)) - .int JMPTBL (L(write_6dbwords), L(table_less16dbwords)) - .int JMPTBL (L(write_7dbwords), L(table_less16dbwords)) - .int JMPTBL (L(write_8dbwords), L(table_less16dbwords)) - .int JMPTBL (L(write_9dbwords), L(table_less16dbwords)) - .int JMPTBL (L(write_10dbwords), L(table_less16dbwords)) - .int JMPTBL (L(write_11dbwords), L(table_less16dbwords)) - .int JMPTBL (L(write_12dbwords), L(table_less16dbwords)) - .int JMPTBL (L(write_13dbwords), L(table_less16dbwords)) - .int JMPTBL (L(write_14dbwords), L(table_less16dbwords)) - .int JMPTBL (L(write_15dbwords), L(table_less16dbwords)) - .popsection - - ALIGN (4) -L(write_15dbwords): - movl %eax, -60(%edx) -L(write_14dbwords): - movl %eax, -56(%edx) -L(write_13dbwords): - movl %eax, -52(%edx) -L(write_12dbwords): - movl %eax, -48(%edx) -L(write_11dbwords): - movl %eax, -44(%edx) -L(write_10dbwords): - movl %eax, -40(%edx) -L(write_9dbwords): - movl %eax, -36(%edx) -L(write_8dbwords): - movl %eax, -32(%edx) -L(write_7dbwords): - movl %eax, -28(%edx) -L(write_6dbwords): - movl %eax, -24(%edx) -L(write_5dbwords): - movl %eax, -20(%edx) -L(write_4dbwords): - movl %eax, -16(%edx) -L(write_3dbwords): - movl %eax, -12(%edx) -L(write_2dbwords): - movl %eax, -8(%edx) -L(write_1dbwords): - movl %eax, -4(%edx) -L(write_0dbwords): - SETRTNVAL - RETURN - - ALIGN (4) -L(16dbwordsormore): - test $3, %edx - jz L(aligned4bytes) - mov %eax, (%edx) - mov %eax, -4(%edx, %ecx, 4) - sub $1, %ecx - rol $24, %eax - add $1, %edx - test $3, %edx - jz L(aligned4bytes) - ror $8, %eax - add $1, %edx - test $3, %edx - jz L(aligned4bytes) - ror $8, %eax - add $1, %edx -L(aligned4bytes): - shl $2, %ecx - -#ifdef USE_AS_BZERO32 - pxor %xmm0, %xmm0 -#else - movd %eax, %xmm0 - pshufd $0, %xmm0, %xmm0 -#endif - testl $0xf, %edx - jz L(aligned_16) -/* ECX > 32 and EDX is not 16 byte aligned. */ -L(not_aligned_16): - movdqu %xmm0, (%edx) - movl %edx, %eax - and $-16, %edx - add $16, %edx - sub %edx, %eax - add %eax, %ecx - movd %xmm0, %eax - ALIGN (4) -L(aligned_16): - cmp $128, %ecx - jae L(128bytesormore) - -L(aligned_16_less128bytes): - add %ecx, %edx - shr $2, %ecx - BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) - - ALIGN (4) -L(128bytesormore): -#ifdef SHARED_CACHE_SIZE - PUSH (%ebx) - mov $SHARED_CACHE_SIZE, %ebx -#else -# if (defined SHARED || defined __PIC__) - call __i686.get_pc_thunk.bx - add $_GLOBAL_OFFSET_TABLE_, %ebx - mov __x86_shared_cache_size@GOTOFF(%ebx), %ebx -# else - PUSH (%ebx) - mov __x86_shared_cache_size, %ebx -# endif -#endif - cmp %ebx, %ecx - jae L(128bytesormore_nt_start) - -#ifdef DATA_CACHE_SIZE - POP (%ebx) -# define RESTORE_EBX_STATE CFI_PUSH (%ebx) - cmp $DATA_CACHE_SIZE, %ecx -#else -# if (defined SHARED || defined __PIC__) -# define RESTORE_EBX_STATE - call __i686.get_pc_thunk.bx - add $_GLOBAL_OFFSET_TABLE_, %ebx - cmp __x86_data_cache_size@GOTOFF(%ebx), %ecx -# else - POP (%ebx) -# define RESTORE_EBX_STATE CFI_PUSH (%ebx) - cmp __x86_data_cache_size, %ecx -# endif -#endif - - jae L(128bytes_L2_normal) - subl $128, %ecx -L(128bytesormore_normal): - sub $128, %ecx - movdqa %xmm0, (%edx) - movdqa %xmm0, 0x10(%edx) - movdqa %xmm0, 0x20(%edx) - movdqa %xmm0, 0x30(%edx) - movdqa %xmm0, 0x40(%edx) - movdqa %xmm0, 0x50(%edx) - movdqa %xmm0, 0x60(%edx) - movdqa %xmm0, 0x70(%edx) - lea 128(%edx), %edx - jb L(128bytesless_normal) - - - sub $128, %ecx - movdqa %xmm0, (%edx) - movdqa %xmm0, 0x10(%edx) - movdqa %xmm0, 0x20(%edx) - movdqa %xmm0, 0x30(%edx) - movdqa %xmm0, 0x40(%edx) - movdqa %xmm0, 0x50(%edx) - movdqa %xmm0, 0x60(%edx) - movdqa %xmm0, 0x70(%edx) - lea 128(%edx), %edx - jae L(128bytesormore_normal) - -L(128bytesless_normal): - lea 128(%ecx), %ecx - add %ecx, %edx - shr $2, %ecx - BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) - - ALIGN (4) -L(128bytes_L2_normal): - prefetcht0 0x380(%edx) - prefetcht0 0x3c0(%edx) - sub $128, %ecx - movdqa %xmm0, (%edx) - movaps %xmm0, 0x10(%edx) - movaps %xmm0, 0x20(%edx) - movaps %xmm0, 0x30(%edx) - movaps %xmm0, 0x40(%edx) - movaps %xmm0, 0x50(%edx) - movaps %xmm0, 0x60(%edx) - movaps %xmm0, 0x70(%edx) - add $128, %edx - cmp $128, %ecx - jae L(128bytes_L2_normal) - -L(128bytesless_L2_normal): - add %ecx, %edx - shr $2, %ecx - BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) - - RESTORE_EBX_STATE -L(128bytesormore_nt_start): - sub %ebx, %ecx - mov %ebx, %eax - and $0x7f, %eax - add %eax, %ecx - movd %xmm0, %eax - ALIGN (4) -L(128bytesormore_shared_cache_loop): - prefetcht0 0x3c0(%edx) - prefetcht0 0x380(%edx) - sub $0x80, %ebx - movdqa %xmm0, (%edx) - movdqa %xmm0, 0x10(%edx) - movdqa %xmm0, 0x20(%edx) - movdqa %xmm0, 0x30(%edx) - movdqa %xmm0, 0x40(%edx) - movdqa %xmm0, 0x50(%edx) - movdqa %xmm0, 0x60(%edx) - movdqa %xmm0, 0x70(%edx) - add $0x80, %edx - cmp $0x80, %ebx - jae L(128bytesormore_shared_cache_loop) - cmp $0x80, %ecx - jb L(shared_cache_loop_end) - - ALIGN (4) -L(128bytesormore_nt): - sub $0x80, %ecx - movntdq %xmm0, (%edx) - movntdq %xmm0, 0x10(%edx) - movntdq %xmm0, 0x20(%edx) - movntdq %xmm0, 0x30(%edx) - movntdq %xmm0, 0x40(%edx) - movntdq %xmm0, 0x50(%edx) - movntdq %xmm0, 0x60(%edx) - movntdq %xmm0, 0x70(%edx) - add $0x80, %edx - cmp $0x80, %ecx - jae L(128bytesormore_nt) - sfence -L(shared_cache_loop_end): -#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__) - POP (%ebx) -#endif - add %ecx, %edx - shr $2, %ecx - BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes)) - - .pushsection .rodata.sse2,"a",@progbits - ALIGN (2) -L(table_16_128bytes): - .int JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes)) - .int JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes)) - .popsection - - ALIGN (4) -L(aligned_16_112bytes): - movdqa %xmm0, -112(%edx) -L(aligned_16_96bytes): - movdqa %xmm0, -96(%edx) -L(aligned_16_80bytes): - movdqa %xmm0, -80(%edx) -L(aligned_16_64bytes): - movdqa %xmm0, -64(%edx) -L(aligned_16_48bytes): - movdqa %xmm0, -48(%edx) -L(aligned_16_32bytes): - movdqa %xmm0, -32(%edx) -L(aligned_16_16bytes): - movdqa %xmm0, -16(%edx) -L(aligned_16_0bytes): - SETRTNVAL - RETURN - - ALIGN (4) -L(aligned_16_116bytes): - movdqa %xmm0, -116(%edx) -L(aligned_16_100bytes): - movdqa %xmm0, -100(%edx) -L(aligned_16_84bytes): - movdqa %xmm0, -84(%edx) -L(aligned_16_68bytes): - movdqa %xmm0, -68(%edx) -L(aligned_16_52bytes): - movdqa %xmm0, -52(%edx) -L(aligned_16_36bytes): - movdqa %xmm0, -36(%edx) -L(aligned_16_20bytes): - movdqa %xmm0, -20(%edx) -L(aligned_16_4bytes): - movl %eax, -4(%edx) - SETRTNVAL - RETURN - - ALIGN (4) -L(aligned_16_120bytes): - movdqa %xmm0, -120(%edx) -L(aligned_16_104bytes): - movdqa %xmm0, -104(%edx) -L(aligned_16_88bytes): - movdqa %xmm0, -88(%edx) -L(aligned_16_72bytes): - movdqa %xmm0, -72(%edx) -L(aligned_16_56bytes): - movdqa %xmm0, -56(%edx) -L(aligned_16_40bytes): - movdqa %xmm0, -40(%edx) -L(aligned_16_24bytes): - movdqa %xmm0, -24(%edx) -L(aligned_16_8bytes): - movq %xmm0, -8(%edx) - SETRTNVAL - RETURN - - ALIGN (4) -L(aligned_16_124bytes): - movdqa %xmm0, -124(%edx) -L(aligned_16_108bytes): - movdqa %xmm0, -108(%edx) -L(aligned_16_92bytes): - movdqa %xmm0, -92(%edx) -L(aligned_16_76bytes): - movdqa %xmm0, -76(%edx) -L(aligned_16_60bytes): - movdqa %xmm0, -60(%edx) -L(aligned_16_44bytes): - movdqa %xmm0, -44(%edx) -L(aligned_16_28bytes): - movdqa %xmm0, -28(%edx) -L(aligned_16_12bytes): - movq %xmm0, -12(%edx) - movl %eax, -4(%edx) - SETRTNVAL - RETURN - -END (sse2_memset32_atom) diff --git a/libcutils/arch-x86_64/android_memset16_SSE2-atom.S b/libcutils/arch-x86_64/android_memset16.S index 48a10ed..cb6d4a3 100644 --- a/libcutils/arch-x86_64/android_memset16_SSE2-atom.S +++ b/libcutils/arch-x86_64/android_memset16.S @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * Contributed by: Intel Corporation - */ #include "cache.h" +#ifndef MEMSET +# define MEMSET android_memset16 +#endif + #ifndef L # define L(label) .L##label #endif @@ -63,7 +64,7 @@ name: \ .section .text.sse2,"ax",@progbits ALIGN (4) -ENTRY (android_memset16) // Address in rdi +ENTRY (MEMSET) // Address in rdi shr $1, %rdx // Count in rdx movzwl %si, %ecx /* Fill the whole ECX with pattern. */ @@ -561,4 +562,4 @@ L(aligned_16_14bytes): movw %cx, -2(%rdi) ret -END (android_memset16) +END (MEMSET) diff --git a/libcutils/arch-x86_64/android_memset32_SSE2-atom.S b/libcutils/arch-x86_64/android_memset32.S index 4bdea8e..1514aa2 100644 --- a/libcutils/arch-x86_64/android_memset32_SSE2-atom.S +++ b/libcutils/arch-x86_64/android_memset32.S @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * Contributed by: Intel Corporation - */ #include "cache.h" +#ifndef MEMSET +# define MEMSET android_memset32 +#endif + #ifndef L # define L(label) .L##label #endif @@ -63,7 +64,7 @@ name: \ .section .text.sse2,"ax",@progbits ALIGN (4) -ENTRY (android_memset32) // Address in rdi +ENTRY (MEMSET) // Address in rdi shr $2, %rdx // Count in rdx movl %esi, %ecx // Pattern in ecx @@ -369,4 +370,4 @@ L(aligned_16_12bytes): movl %ecx, -4(%rdi) ret -END (android_memset32) +END (MEMSET) diff --git a/libcutils/arch-x86_64/cache.h b/libcutils/arch-x86_64/cache.h index ab5dd2f..f144309 100644 --- a/libcutils/arch-x86_64/cache.h +++ b/libcutils/arch-x86_64/cache.h @@ -13,19 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * Contributed by: Intel Corporation - */ -#if defined(__slm__) /* Values are optimized for Silvermont */ #define SHARED_CACHE_SIZE (1024*1024) /* Silvermont L2 Cache */ #define DATA_CACHE_SIZE (24*1024) /* Silvermont L1 Data Cache */ -#else -/* Values are optimized for Atom */ -#define SHARED_CACHE_SIZE (512*1024) /* Atom L2 Cache */ -#define DATA_CACHE_SIZE (24*1024) /* Atom L1 Data Cache */ -#endif #define SHARED_CACHE_SIZE_HALF (SHARED_CACHE_SIZE / 2) #define DATA_CACHE_SIZE_HALF (DATA_CACHE_SIZE / 2) diff --git a/libcutils/ashmem-host.c b/libcutils/ashmem-host.c index 4ac4f57..abc4f94 100644 --- a/libcutils/ashmem-host.c +++ b/libcutils/ashmem-host.c @@ -22,7 +22,6 @@ #include <errno.h> #include <fcntl.h> #include <limits.h> -#include <pthread.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -33,51 +32,18 @@ #include <unistd.h> #include <cutils/ashmem.h> +#include <utils/Compat.h> #ifndef __unused #define __unused __attribute__((__unused__)) #endif -static pthread_once_t seed_initialized = PTHREAD_ONCE_INIT; -static void initialize_random() { - srand(time(NULL) + getpid()); -} - int ashmem_create_region(const char *ignored __unused, size_t size) { - static const char txt[] = "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - char name[64]; - unsigned int retries = 0; - pid_t pid = getpid(); - int fd; - if (pthread_once(&seed_initialized, &initialize_random) != 0) { - return -1; - } - do { - /* not beautiful, its just wolf-like loop unrolling */ - snprintf(name, sizeof(name), "/tmp/android-ashmem-%d-%c%c%c%c%c%c%c%c", - pid, - txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))], - txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))], - txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))], - txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))], - txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))], - txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))], - txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))], - txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))]); - - /* open O_EXCL & O_CREAT: we are either the sole owner or we fail */ - fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0600); - if (fd == -1) { - /* unlikely, but if we failed because `name' exists, retry */ - if (errno != EEXIST || ++retries >= 6) { - return -1; - } - } - } while (fd == -1); - /* truncate the file to `len' bytes */ - if (ftruncate(fd, size) != -1 && unlink(name) != -1) { + char template[PATH_MAX]; + snprintf(template, sizeof(template), "/tmp/android-ashmem-%d-XXXXXXXXX", getpid()); + int fd = mkstemp(template); + if (fd != -1 && TEMP_FAILURE_RETRY(ftruncate(fd, size)) != -1 && unlink(template) != -1) { return fd; } close(fd); @@ -102,9 +68,7 @@ int ashmem_unpin_region(int fd __unused, size_t offset __unused, size_t len __un int ashmem_get_size_region(int fd) { struct stat buf; - int result; - - result = fstat(fd, &buf); + int result = fstat(fd, &buf); if (result == -1) { return -1; } @@ -116,5 +80,5 @@ int ashmem_get_size_region(int fd) return -1; } - return (int)buf.st_size; // TODO: care about overflow (> 2GB file)? + return buf.st_size; } diff --git a/libcutils/atomic.c b/libcutils/atomic.c index 1484ef8..d34aa00 100644 --- a/libcutils/atomic.c +++ b/libcutils/atomic.c @@ -14,6 +14,13 @@ * limitations under the License. */ +/* + * Generate non-inlined versions of android_atomic functions. + * Nobody should be using these, but some binary blobs currently (late 2014) + * are. + * If you read this in 2015 or later, please try to delete this file. + */ + #define ANDROID_ATOMIC_INLINE -#include <cutils/atomic-inline.h> +#include <cutils/atomic.h> diff --git a/libcutils/cpu_info.c b/libcutils/cpu_info.c deleted file mode 100644 index 21fa1dc..0000000 --- a/libcutils/cpu_info.c +++ /dev/null @@ -1,82 +0,0 @@ -/* -** 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 <string.h> - -#include <cutils/cpu_info.h> - -// we cache the serial number here. -// this is also used as a fgets() line buffer when we are reading /proc/cpuinfo -static char serial_number[100] = { 0 }; - -extern const char* get_cpu_serial_number(void) -{ - if (serial_number[0] == 0) - { - FILE* file; - char* chp, *end; - char* whitespace; - - // read serial number from /proc/cpuinfo - file = fopen("proc/cpuinfo", "r"); - if (! file) - return NULL; - - while ((chp = fgets(serial_number, sizeof(serial_number), file)) != NULL) - { - // look for something like "Serial : 999206122a03591c" - - if (strncmp(chp, "Serial", 6) != 0) - continue; - - chp = strchr(chp, ':'); - if (!chp) - continue; - - // skip colon and whitespace - while ( *(++chp) == ' ') {} - - // truncate trailing whitespace - end = chp; - while (*end && *end != ' ' && *end != '\t' && *end != '\n' && *end != '\r') - ++end; - *end = 0; - - whitespace = strchr(chp, ' '); - if (whitespace) - *whitespace = 0; - whitespace = strchr(chp, '\t'); - if (whitespace) - *whitespace = 0; - whitespace = strchr(chp, '\r'); - if (whitespace) - *whitespace = 0; - whitespace = strchr(chp, '\n'); - if (whitespace) - *whitespace = 0; - - // shift serial number to beginning of the buffer - memmove(serial_number, chp, strlen(chp) + 1); - break; - } - - fclose(file); - } - - return (serial_number[0] ? serial_number : NULL); -} diff --git a/libcutils/debugger.c b/libcutils/debugger.c index b8a2efc..4558719 100644 --- a/libcutils/debugger.c +++ b/libcutils/debugger.c @@ -29,33 +29,6 @@ #define LOG_TAG "DEBUG" #include <log/log.h> -#if defined(__LP64__) -#include <elf.h> - -static bool is32bit(pid_t tid) { - char* exeline; - if (asprintf(&exeline, "/proc/%d/exe", tid) == -1) { - return false; - } - int fd = open(exeline, O_RDONLY | O_CLOEXEC); - free(exeline); - if (fd == -1) { - return false; - } - - char ehdr[EI_NIDENT]; - ssize_t bytes = read(fd, &ehdr, sizeof(ehdr)); - close(fd); - if (bytes != (ssize_t) sizeof(ehdr) || memcmp(ELFMAG, ehdr, SELFMAG) != 0) { - return false; - } - if (ehdr[EI_CLASS] == ELFCLASS32) { - return true; - } - return false; -} -#endif - static int send_request(int sock_fd, void* msg_ptr, size_t msg_len) { int result = 0; if (TEMP_FAILURE_RETRY(write(sock_fd, msg_ptr, msg_len)) != (ssize_t) msg_len) { @@ -70,34 +43,12 @@ static int send_request(int sock_fd, void* msg_ptr, size_t msg_len) { } static int make_dump_request(debugger_action_t action, pid_t tid, int timeout_secs) { - const char* socket_name; debugger_msg_t msg; - size_t msg_len; - void* msg_ptr; - -#if defined(__LP64__) - debugger32_msg_t msg32; - if (is32bit(tid)) { - msg_len = sizeof(debugger32_msg_t); - memset(&msg32, 0, msg_len); - msg32.tid = tid; - msg32.action = action; - msg_ptr = &msg32; - - socket_name = DEBUGGER32_SOCKET_NAME; - } else -#endif - { - msg_len = sizeof(debugger_msg_t); - memset(&msg, 0, msg_len); - msg.tid = tid; - msg.action = action; - msg_ptr = &msg; - - socket_name = DEBUGGER_SOCKET_NAME; - } + memset(&msg, 0, sizeof(msg)); + msg.tid = tid; + msg.action = action; - int sock_fd = socket_local_client(socket_name, ANDROID_SOCKET_NAMESPACE_ABSTRACT, + int sock_fd = socket_local_client(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM | SOCK_CLOEXEC); if (sock_fd < 0) { return -1; @@ -116,7 +67,7 @@ static int make_dump_request(debugger_action_t action, pid_t tid, int timeout_se } } - if (send_request(sock_fd, msg_ptr, msg_len) < 0) { + if (send_request(sock_fd, &msg, sizeof(msg)) < 0) { TEMP_FAILURE_RETRY(close(sock_fd)); return -1; } diff --git a/libcutils/dir_hash.c b/libcutils/dir_hash.c deleted file mode 100644 index 098b5db..0000000 --- a/libcutils/dir_hash.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * 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. - */ - -#include <dirent.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sha1.h> -#include <unistd.h> -#include <limits.h> - -#include <sys/stat.h> - -#include <netinet/in.h> -#include <resolv.h> - -#include <cutils/dir_hash.h> - -/** - * Copies, if it fits within max_output_string bytes, into output_string - * a hash of the contents, size, permissions, uid, and gid of the file - * specified by path, using the specified algorithm. Returns the length - * of the output string, or a negative number if the buffer is too short. - */ -int get_file_hash(HashAlgorithm algorithm, const char *path, - char *output_string, size_t max_output_string) { - SHA1_CTX context; - struct stat sb; - unsigned char md[SHA1_DIGEST_LENGTH]; - int used; - size_t n; - - if (algorithm != SHA_1) { - errno = EINVAL; - return -1; - } - - if (stat(path, &sb) != 0) { - return -1; - } - - if (S_ISLNK(sb.st_mode)) { - char buf[PATH_MAX]; - int len; - - len = readlink(path, buf, sizeof(buf)); - if (len < 0) { - return -1; - } - - SHA1Init(&context); - SHA1Update(&context, (unsigned char *) buf, len); - SHA1Final(md, &context); - } else if (S_ISREG(sb.st_mode)) { - char buf[10000]; - FILE *f = fopen(path, "rb"); - int len; - - if (f == NULL) { - return -1; - } - - SHA1Init(&context); - - while ((len = fread(buf, 1, sizeof(buf), f)) > 0) { - SHA1Update(&context, (unsigned char *) buf, len); - } - - if (ferror(f)) { - fclose(f); - return -1; - } - - fclose(f); - SHA1Final(md, &context); - } - - if (S_ISLNK(sb.st_mode) || S_ISREG(sb.st_mode)) { - used = b64_ntop(md, SHA1_DIGEST_LENGTH, - output_string, max_output_string); - if (used < 0) { - errno = ENOSPC; - return -1; - } - - n = snprintf(output_string + used, max_output_string - used, - " %d 0%o %d %d", (int) sb.st_size, sb.st_mode, - (int) sb.st_uid, (int) sb.st_gid); - } else { - n = snprintf(output_string, max_output_string, - "- - 0%o %d %d", sb.st_mode, - (int) sb.st_uid, (int) sb.st_gid); - } - - if (n >= max_output_string - used) { - errno = ENOSPC; - return -(used + n); - } - - return used + n; -} - -struct list { - char *name; - struct list *next; -}; - -static int cmp(const void *a, const void *b) { - struct list *const *ra = a; - struct list *const *rb = b; - - return strcmp((*ra)->name, (*rb)->name); -} - -static int recurse(HashAlgorithm algorithm, const char *directory_path, - struct list **out) { - struct list *list = NULL; - struct list *f; - - struct dirent *de; - DIR *d = opendir(directory_path); - - if (d == NULL) { - return -1; - } - - while ((de = readdir(d)) != NULL) { - if (strcmp(de->d_name, ".") == 0) { - continue; - } - if (strcmp(de->d_name, "..") == 0) { - continue; - } - - char *name = malloc(strlen(de->d_name) + 1); - struct list *node = malloc(sizeof(struct list)); - - if (name == NULL || node == NULL) { - struct list *next; - for (f = list; f != NULL; f = next) { - next = f->next; - free(f->name); - free(f); - } - - free(name); - free(node); - closedir(d); - return -1; - } - - strcpy(name, de->d_name); - - node->name = name; - node->next = list; - list = node; - } - - closedir(d); - - for (f = list; f != NULL; f = f->next) { - struct stat sb; - char *name; - char outstr[NAME_MAX + 100]; - char *keep; - struct list *res; - - name = malloc(strlen(f->name) + strlen(directory_path) + 2); - if (name == NULL) { - struct list *next; - for (f = list; f != NULL; f = f->next) { - next = f->next; - free(f->name); - free(f); - } - for (f = *out; f != NULL; f = f->next) { - next = f->next; - free(f->name); - free(f); - } - *out = NULL; - return -1; - } - - sprintf(name, "%s/%s", directory_path, f->name); - - int len = get_file_hash(algorithm, name, - outstr, sizeof(outstr)); - if (len < 0) { - // should not happen - return -1; - } - - keep = malloc(len + strlen(name) + 3); - res = malloc(sizeof(struct list)); - - if (keep == NULL || res == NULL) { - struct list *next; - for (f = list; f != NULL; f = f->next) { - next = f->next; - free(f->name); - free(f); - } - for (f = *out; f != NULL; f = f->next) { - next = f->next; - free(f->name); - free(f); - } - *out = NULL; - - free(keep); - free(res); - return -1; - } - - sprintf(keep, "%s %s\n", name, outstr); - - res->name = keep; - res->next = *out; - *out = res; - - if ((stat(name, &sb) == 0) && S_ISDIR(sb.st_mode)) { - if (recurse(algorithm, name, out) < 0) { - struct list *next; - for (f = list; f != NULL; f = next) { - next = f->next; - free(f->name); - free(f); - } - - return -1; - } - } - } - - struct list *next; - for (f = list; f != NULL; f = next) { - next = f->next; - - free(f->name); - free(f); - } -} - -/** - * Allocates a string containing the names and hashes of all files recursively - * reached under the specified directory_path, using the specified algorithm. - * The string is returned as *output_string; the return value is the length - * of the string, or a negative number if there was a failure. - */ -int get_recursive_hash_manifest(HashAlgorithm algorithm, - const char *directory_path, - char **output_string) { - struct list *out = NULL; - struct list *r; - struct list **list; - int count = 0; - int len = 0; - int retlen = 0; - int i; - char *buf; - - if (recurse(algorithm, directory_path, &out) < 0) { - return -1; - } - - for (r = out; r != NULL; r = r->next) { - count++; - len += strlen(r->name); - } - - list = malloc(count * sizeof(struct list *)); - if (list == NULL) { - struct list *next; - for (r = out; r != NULL; r = next) { - next = r->next; - free(r->name); - free(r); - } - return -1; - } - - count = 0; - for (r = out; r != NULL; r = r->next) { - list[count++] = r; - } - - qsort(list, count, sizeof(struct list *), cmp); - - buf = malloc(len + 1); - if (buf == NULL) { - struct list *next; - for (r = out; r != NULL; r = next) { - next = r->next; - free(r->name); - free(r); - } - free(list); - return -1; - } - - for (i = 0; i < count; i++) { - int n = strlen(list[i]->name); - - strcpy(buf + retlen, list[i]->name); - retlen += n; - } - - free(list); - - struct list *next; - for (r = out; r != NULL; r = next) { - next = r->next; - - free(r->name); - free(r); - } - - *output_string = buf; - return retlen; -} diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c new file mode 100644 index 0000000..9f8023e --- /dev/null +++ b/libcutils/fs_config.c @@ -0,0 +1,273 @@ +/* + * 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. + */ + +/* This file is used to define the properties of the filesystem +** images generated by build tools (mkbootfs and mkyaffs2image) and +** by the device side of adb. +*/ + +#define LOG_TAG "fs_config" + +#define _GNU_SOURCE + +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <log/log.h> +#include <private/android_filesystem_config.h> +#include <utils/Compat.h> + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +/* The following structure is stored little endian */ +struct fs_path_config_from_file { + uint16_t len; + uint16_t mode; + uint16_t uid; + uint16_t gid; + uint64_t capabilities; + char prefix[]; +} __attribute__((__aligned__(sizeof(uint64_t)))); + +/* My kingdom for <endian.h> */ +static inline uint16_t get2LE(const uint8_t* src) +{ + return src[0] | (src[1] << 8); +} + +static inline uint64_t get8LE(const uint8_t* src) +{ + uint32_t low, high; + + low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); + high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24); + return ((uint64_t) high << 32) | (uint64_t) low; +} + +#define ALIGN(x, alignment) ( ((x) + ((alignment) - 1)) & ~((alignment) - 1) ) + +/* Rules for directories. +** These rules are applied based on "first match", so they +** should start with the most specific path and work their +** way up to the root. +*/ + +static const struct fs_path_config android_dirs[] = { + { 00770, AID_SYSTEM, AID_CACHE, 0, "cache" }, + { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" }, + { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" }, + { 00771, AID_ROOT, AID_ROOT, 0, "data/dalvik-cache" }, + { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" }, + { 00771, AID_SHELL, AID_SHELL, 0, "data/local/tmp" }, + { 00771, AID_SHELL, AID_SHELL, 0, "data/local" }, + { 01771, AID_SYSTEM, AID_MISC, 0, "data/misc" }, + { 00770, AID_DHCP, AID_DHCP, 0, "data/misc/dhcp" }, + { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" }, + { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" }, + { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" }, + { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" }, + { 00750, AID_ROOT, AID_SHELL, 0, "sbin" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/bin" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin" }, + { 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" }, + { 00755, AID_ROOT, AID_SHELL, 0, "vendor" }, + { 00777, AID_ROOT, AID_ROOT, 0, "sdcard" }, + { 00755, AID_ROOT, AID_ROOT, 0, 0 }, +}; + +/* Rules for files. +** These rules are applied based on "first match", so they +** should start with the most specific path and work their +** way up to the root. Prefixes ending in * denotes wildcard +** and will allow partial matches. +*/ +static const char conf_dir[] = "/system/etc/fs_config_dirs"; +static const char conf_file[] = "/system/etc/fs_config_files"; + +static const struct fs_path_config android_files[] = { + { 00440, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.rc" }, + { 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.sh" }, + { 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.ril" }, + { 00550, AID_DHCP, AID_SHELL, 0, "system/etc/dhcpcd/dhcpcd-run-hooks" }, + { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/ppp/*" }, + { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/rc.*" }, + { 00444, AID_ROOT, AID_ROOT, 0, conf_dir + 1 }, + { 00444, AID_ROOT, AID_ROOT, 0, conf_file + 1 }, + { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app/*" }, + { 00644, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/*" }, + { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private/*" }, + { 00644, AID_APP, AID_APP, 0, "data/data/*" }, + + /* the following five files are INTENTIONALLY set-uid, but they + * are NOT included on user builds. */ + { 04750, AID_ROOT, AID_SHELL, 0, "system/xbin/su" }, + { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/librank" }, + { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procrank" }, + { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" }, + { 04770, AID_ROOT, AID_RADIO, 0, "system/bin/pppd-ril" }, + + /* the following files have enhanced capabilities and ARE included in user builds. */ + { 00750, AID_ROOT, AID_SHELL, (1ULL << CAP_SETUID) | (1ULL << CAP_SETGID), "system/bin/run-as" }, + { 00700, AID_SYSTEM, AID_SHELL, (1ULL << CAP_BLOCK_SUSPEND), "system/bin/inputflinger" }, + + { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" }, + { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" }, + { 00755, AID_ROOT, AID_ROOT, 0, "system/lib/valgrind/*" }, + { 00755, AID_ROOT, AID_ROOT, 0, "system/lib64/valgrind/*" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor/bin/*" }, + { 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" }, + { 00750, AID_ROOT, AID_SHELL, 0, "sbin/*" }, + { 00755, AID_ROOT, AID_ROOT, 0, "bin/*" }, + { 00750, AID_ROOT, AID_SHELL, 0, "init*" }, + { 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" }, + { 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" }, + { 00644, AID_ROOT, AID_ROOT, 0, 0 }, +}; + +static int fs_config_open(int dir) +{ + int fd = -1; + + const char *out = getenv("OUT"); + if (out && *out) { + char *name = NULL; + asprintf(&name, "%s%s", out, dir ? conf_dir : conf_file); + if (name) { + fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_BINARY)); + free(name); + } + } + if (fd < 0) { + fd = TEMP_FAILURE_RETRY(open(dir ? conf_dir : conf_file, O_RDONLY | O_BINARY)); + } + return fd; +} + +static bool fs_config_cmp(bool dir, const char *prefix, size_t len, + const char *path, size_t plen) +{ + if (dir) { + if (plen < len) { + return false; + } + } else { + /* If name ends in * then allow partial matches. */ + if (prefix[len - 1] == '*') { + return !strncmp(prefix, path, len - 1); + } + if (plen != len) { + return false; + } + } + return !strncmp(prefix, path, len); +} + +void fs_config(const char *path, int dir, + unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities) +{ + const struct fs_path_config *pc; + int fd, plen; + + if (path[0] == '/') { + path++; + } + + plen = strlen(path); + + fd = fs_config_open(dir); + if (fd >= 0) { + struct fs_path_config_from_file header; + + while (TEMP_FAILURE_RETRY(read(fd, &header, sizeof(header))) == sizeof(header)) { + char *prefix; + uint16_t host_len = get2LE((const uint8_t *)&header.len); + ssize_t len, remainder = host_len - sizeof(header); + if (remainder <= 0) { + ALOGE("%s len is corrupted", dir ? conf_dir : conf_file); + break; + } + prefix = calloc(1, remainder); + if (!prefix) { + ALOGE("%s out of memory", dir ? conf_dir : conf_file); + break; + } + if (TEMP_FAILURE_RETRY(read(fd, prefix, remainder)) != remainder) { + free(prefix); + ALOGE("%s prefix is truncated", dir ? conf_dir : conf_file); + break; + } + len = strnlen(prefix, remainder); + if (len >= remainder) { /* missing a terminating null */ + free(prefix); + ALOGE("%s is corrupted", dir ? conf_dir : conf_file); + break; + } + if (fs_config_cmp(dir, prefix, len, path, plen)) { + free(prefix); + close(fd); + *uid = get2LE((const uint8_t *)&(header.uid)); + *gid = get2LE((const uint8_t *)&(header.gid)); + *mode = (*mode & (~07777)) | get2LE((const uint8_t *)&(header.mode)); + *capabilities = get8LE((const uint8_t *)&(header.capabilities)); + return; + } + free(prefix); + } + close(fd); + } + + pc = dir ? android_dirs : android_files; + for(; pc->prefix; pc++){ + if (fs_config_cmp(dir, pc->prefix, strlen(pc->prefix), path, plen)) { + break; + } + } + *uid = pc->uid; + *gid = pc->gid; + *mode = (*mode & (~07777)) | pc->mode; + *capabilities = pc->capabilities; +} + +ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc) +{ + struct fs_path_config_from_file *p = (struct fs_path_config_from_file *)buffer; + size_t len = ALIGN(sizeof(*p) + strlen(pc->prefix) + 1, sizeof(uint64_t)); + + if ((length < len) || (len > UINT16_MAX)) { + return -ENOSPC; + } + memset(p, 0, len); + uint16_t host_len = len; + p->len = get2LE((const uint8_t *)&host_len); + p->mode = get2LE((const uint8_t *)&(pc->mode)); + p->uid = get2LE((const uint8_t *)&(pc->uid)); + p->gid = get2LE((const uint8_t *)&(pc->gid)); + p->capabilities = get8LE((const uint8_t *)&(pc->capabilities)); + strcpy(p->prefix, pc->prefix); + return len; +} diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c index a6da9ca..8946d3c 100644 --- a/libcutils/iosched_policy.c +++ b/libcutils/iosched_policy.c @@ -1,5 +1,5 @@ /* -** Copyright 2007-2014, The Android Open Source Project +** 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. diff --git a/libcutils/klog.c b/libcutils/klog.c index fbb7b72..f574f08 100644 --- a/libcutils/klog.c +++ b/libcutils/klog.c @@ -14,13 +14,14 @@ * limitations under the License. */ -#include <sys/stat.h> -#include <sys/types.h> +#include <errno.h> #include <fcntl.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/stat.h> +#include <sys/types.h> #include <unistd.h> #include <cutils/klog.h> @@ -36,41 +37,36 @@ void klog_set_level(int level) { klog_level = level; } -void klog_init(void) -{ - static const char *name = "/dev/__kmsg__"; - +void klog_init(void) { if (klog_fd >= 0) return; /* Already initialized */ + static const char* name = "/dev/__kmsg__"; if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) { - klog_fd = open(name, O_WRONLY); - if (klog_fd < 0) - return; - fcntl(klog_fd, F_SETFD, FD_CLOEXEC); + klog_fd = open(name, O_WRONLY | O_CLOEXEC); unlink(name); } } #define LOG_BUF_MAX 512 -void klog_vwrite(int level, const char *fmt, va_list ap) -{ - char buf[LOG_BUF_MAX]; - +void klog_writev(int level, const struct iovec* iov, int iov_count) { if (level > klog_level) return; if (klog_fd < 0) klog_init(); if (klog_fd < 0) return; - - vsnprintf(buf, LOG_BUF_MAX, fmt, ap); - buf[LOG_BUF_MAX - 1] = 0; - - write(klog_fd, buf, strlen(buf)); + TEMP_FAILURE_RETRY(writev(klog_fd, iov, iov_count)); } -void klog_write(int level, const char *fmt, ...) -{ +void klog_write(int level, const char* fmt, ...) { + char buf[LOG_BUF_MAX]; va_list ap; va_start(ap, fmt); - klog_vwrite(level, fmt, ap); + vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); + + buf[LOG_BUF_MAX - 1] = 0; + + struct iovec iov[1]; + iov[0].iov_base = buf; + iov[0].iov_len = strlen(buf); + klog_writev(level, iov, 1); } diff --git a/libcutils/loghack.h b/libcutils/loghack.h deleted file mode 100644 index 750cab0..0000000 --- a/libcutils/loghack.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - */ - -/** - * This is a temporary hack to enable logging from cutils. - */ - -#ifndef _CUTILS_LOGHACK_H -#define _CUTILS_LOGHACK_H - -#ifdef HAVE_ANDROID_OS -#include <cutils/log.h> -#else -#include <stdio.h> -#define ALOG(level, ...) \ - ((void)printf("cutils:" level "/" LOG_TAG ": " __VA_ARGS__)) -#define ALOGV(...) ALOG("V", __VA_ARGS__) -#define ALOGD(...) ALOG("D", __VA_ARGS__) -#define ALOGI(...) ALOG("I", __VA_ARGS__) -#define ALOGW(...) ALOG("W", __VA_ARGS__) -#define ALOGE(...) ALOG("E", __VA_ARGS__) -#define LOG_ALWAYS_FATAL(...) do { ALOGE(__VA_ARGS__); exit(1); } while (0) -#endif - -#endif // _CUTILS_LOGHACK_H diff --git a/libcutils/open_memstream.c b/libcutils/open_memstream.c index 5b4388a..9183266 100644 --- a/libcutils/open_memstream.c +++ b/libcutils/open_memstream.c @@ -14,7 +14,7 @@ * limitations under the License. */ -#ifndef HAVE_OPEN_MEMSTREAM +#if defined(__APPLE__) /* * Implementation of the POSIX open_memstream() function, which Linux has @@ -59,8 +59,6 @@ # define DBUG(x) ((void)0) #endif -#ifdef HAVE_FUNOPEN - /* * Definition of a seekable, write-only memory stream. */ @@ -251,12 +249,6 @@ FILE* open_memstream(char** bufp, size_t* sizep) return fp; } -#else /*not HAVE_FUNOPEN*/ -FILE* open_memstream(char** bufp, size_t* sizep) -{ - abort(); -} -#endif /*HAVE_FUNOPEN*/ @@ -378,4 +370,4 @@ DONE #endif -#endif /*!HAVE_OPEN_MEMSTREAM*/ +#endif /* __APPLE__ */ diff --git a/libcutils/process_name.c b/libcutils/process_name.c index 9c3dfb8..cc931eb 100644 --- a/libcutils/process_name.c +++ b/libcutils/process_name.c @@ -17,7 +17,7 @@ #include <fcntl.h> #include <stdlib.h> #include <string.h> -#if defined(HAVE_PRCTL) +#if defined(__linux__) #include <sys/prctl.h> #endif #include <sys/stat.h> @@ -51,7 +51,7 @@ void set_process_name(const char* new_name) { strcpy(copy, new_name); process_name = (const char*) copy; -#if defined(HAVE_PRCTL) +#if defined(__linux__) if (len < 16) { prctl(PR_SET_NAME, (unsigned long) new_name, 0, 0, 0); } else { diff --git a/libcutils/properties.c b/libcutils/properties.c index b283658..4e46e02 100644 --- a/libcutils/properties.c +++ b/libcutils/properties.c @@ -28,7 +28,7 @@ #include <cutils/properties.h> #include <stdbool.h> #include <inttypes.h> -#include "loghack.h" +#include <log/log.h> int8_t property_get_bool(const char *key, int8_t default_value) { if (!key) { @@ -104,8 +104,6 @@ int32_t property_get_int32(const char *key, int32_t default_value) { return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value); } -#ifdef HAVE_LIBC_SYSTEM_PROPERTIES - #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #include <sys/_system_properties.h> @@ -156,265 +154,3 @@ int property_list( struct property_list_callback_data data = { propfn, cookie }; return __system_property_foreach(property_list_callback, &data); } - -#elif defined(HAVE_SYSTEM_PROPERTY_SERVER) - -/* - * The Linux simulator provides a "system property server" that uses IPC - * to set/get/list properties. The file descriptor is shared by all - * threads in the process, so we use a mutex to ensure that requests - * from multiple threads don't get interleaved. - */ -#include <stdio.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <pthread.h> - -static pthread_once_t gInitOnce = PTHREAD_ONCE_INIT; -static pthread_mutex_t gPropertyFdLock = PTHREAD_MUTEX_INITIALIZER; -static int gPropFd = -1; - -/* - * Connect to the properties server. - * - * Returns the socket descriptor on success. - */ -static int connectToServer(const char* fileName) -{ - int sock = -1; - int cc; - - struct sockaddr_un addr; - - sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { - ALOGW("UNIX domain socket create failed (errno=%d)\n", errno); - return -1; - } - - /* connect to socket; fails if file doesn't exist */ - strcpy(addr.sun_path, fileName); // max 108 bytes - addr.sun_family = AF_UNIX; - cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr)); - if (cc < 0) { - // ENOENT means socket file doesn't exist - // ECONNREFUSED means socket exists but nobody is listening - //ALOGW("AF_UNIX connect failed for '%s': %s\n", - // fileName, strerror(errno)); - close(sock); - return -1; - } - - return sock; -} - -/* - * Perform one-time initialization. - */ -static void init(void) -{ - assert(gPropFd == -1); - - gPropFd = connectToServer(SYSTEM_PROPERTY_PIPE_NAME); - if (gPropFd < 0) { - //ALOGW("not connected to system property server\n"); - } else { - //ALOGV("Connected to system property server\n"); - } -} - -int property_get(const char *key, char *value, const char *default_value) -{ - char sendBuf[1+PROPERTY_KEY_MAX]; - char recvBuf[1+PROPERTY_VALUE_MAX]; - int len = -1; - - //ALOGV("PROPERTY GET [%s]\n", key); - - pthread_once(&gInitOnce, init); - if (gPropFd < 0) { - /* this mimics the behavior of the device implementation */ - if (default_value != NULL) { - strcpy(value, default_value); - len = strlen(value); - } - return len; - } - - if (strlen(key) >= PROPERTY_KEY_MAX) return -1; - - memset(sendBuf, 0xdd, sizeof(sendBuf)); // placate valgrind - - sendBuf[0] = (char) kSystemPropertyGet; - strcpy(sendBuf+1, key); - - pthread_mutex_lock(&gPropertyFdLock); - if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) { - pthread_mutex_unlock(&gPropertyFdLock); - return -1; - } - if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) { - pthread_mutex_unlock(&gPropertyFdLock); - return -1; - } - pthread_mutex_unlock(&gPropertyFdLock); - - /* first byte is 0 if value not defined, 1 if found */ - if (recvBuf[0] == 0) { - if (default_value != NULL) { - strcpy(value, default_value); - len = strlen(value); - } else { - /* - * If the value isn't defined, hand back an empty string and - * a zero length, rather than a failure. This seems wrong, - * since you can't tell the difference between "undefined" and - * "defined but empty", but it's what the device does. - */ - value[0] = '\0'; - len = 0; - } - } else if (recvBuf[0] == 1) { - strcpy(value, recvBuf+1); - len = strlen(value); - } else { - ALOGE("Got strange response to property_get request (%d)\n", - recvBuf[0]); - assert(0); - return -1; - } - //ALOGV("PROP [found=%d def='%s'] (%d) [%s]: [%s]\n", - // recvBuf[0], default_value, len, key, value); - - return len; -} - - -int property_set(const char *key, const char *value) -{ - char sendBuf[1+PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX]; - char recvBuf[1]; - int result = -1; - - //ALOGV("PROPERTY SET [%s]: [%s]\n", key, value); - - pthread_once(&gInitOnce, init); - if (gPropFd < 0) - return -1; - - if (strlen(key) >= PROPERTY_KEY_MAX) return -1; - if (strlen(value) >= PROPERTY_VALUE_MAX) return -1; - - memset(sendBuf, 0xdd, sizeof(sendBuf)); // placate valgrind - - sendBuf[0] = (char) kSystemPropertySet; - strcpy(sendBuf+1, key); - strcpy(sendBuf+1+PROPERTY_KEY_MAX, value); - - pthread_mutex_lock(&gPropertyFdLock); - if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) { - pthread_mutex_unlock(&gPropertyFdLock); - return -1; - } - if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) { - pthread_mutex_unlock(&gPropertyFdLock); - return -1; - } - pthread_mutex_unlock(&gPropertyFdLock); - - if (recvBuf[0] != 1) - return -1; - return 0; -} - -int property_list(void (*propfn)(const char *key, const char *value, void *cookie), - void *cookie) -{ - //ALOGV("PROPERTY LIST\n"); - pthread_once(&gInitOnce, init); - if (gPropFd < 0) - return -1; - - return 0; -} - -#else - -/* SUPER-cheesy place-holder implementation for Win32 */ - -#include <cutils/threads.h> - -static mutex_t env_lock = MUTEX_INITIALIZER; - -int property_get(const char *key, char *value, const char *default_value) -{ - char ename[PROPERTY_KEY_MAX + 6]; - char *p; - int len; - - len = strlen(key); - if(len >= PROPERTY_KEY_MAX) return -1; - memcpy(ename, "PROP_", 5); - memcpy(ename + 5, key, len + 1); - - mutex_lock(&env_lock); - - p = getenv(ename); - if(p == 0) p = ""; - len = strlen(p); - if(len >= PROPERTY_VALUE_MAX) { - len = PROPERTY_VALUE_MAX - 1; - } - - if((len == 0) && default_value) { - len = strlen(default_value); - memcpy(value, default_value, len + 1); - } else { - memcpy(value, p, len); - value[len] = 0; - } - - mutex_unlock(&env_lock); - - return len; -} - - -int property_set(const char *key, const char *value) -{ - char ename[PROPERTY_KEY_MAX + 6]; - char *p; - int len; - int r; - - if(strlen(value) >= PROPERTY_VALUE_MAX) return -1; - - len = strlen(key); - if(len >= PROPERTY_KEY_MAX) return -1; - memcpy(ename, "PROP_", 5); - memcpy(ename + 5, key, len + 1); - - mutex_lock(&env_lock); -#ifdef HAVE_MS_C_RUNTIME - { - char temp[256]; - snprintf( temp, sizeof(temp), "%s=%s", ename, value); - putenv(temp); - r = 0; - } -#else - r = setenv(ename, value, 1); -#endif - mutex_unlock(&env_lock); - - return r; -} - -int property_list(void (*propfn)(const char *key, const char *value, void *cookie), - void *cookie) -{ - return 0; -} - -#endif diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c index 493511e..dfc8777 100644 --- a/libcutils/sched_policy.c +++ b/libcutils/sched_policy.c @@ -37,7 +37,7 @@ static inline SchedPolicy _policy(SchedPolicy p) return p == SP_DEFAULT ? SP_SYSTEM_DEFAULT : p; } -#if defined(HAVE_ANDROID_OS) && defined(HAVE_SCHED_H) && defined(HAVE_PTHREADS) +#if defined(HAVE_ANDROID_OS) #include <pthread.h> #include <sched.h> @@ -203,11 +203,9 @@ static int getSchedulerGroup(int tid, char* buf, size_t bufLen) int get_sched_policy(int tid, SchedPolicy *policy) { -#ifdef HAVE_GETTID if (tid == 0) { tid = gettid(); } -#endif pthread_once(&the_once, __initialize); if (__sys_supports_schedgroups) { @@ -240,11 +238,9 @@ int get_sched_policy(int tid, SchedPolicy *policy) int set_sched_policy(int tid, SchedPolicy policy) { -#ifdef HAVE_GETTID if (tid == 0) { tid = gettid(); } -#endif policy = _policy(policy); pthread_once(&the_once, __initialize); diff --git a/libcutils/socket_local_client.c b/libcutils/socket_local_client.c index ddcc2da..7b42daa 100644 --- a/libcutils/socket_local_client.c +++ b/libcutils/socket_local_client.c @@ -52,7 +52,7 @@ int socket_make_sockaddr_un(const char *name, int namespaceId, switch (namespaceId) { case ANDROID_SOCKET_NAMESPACE_ABSTRACT: -#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE +#if defined(__linux__) namelen = strlen(name); // Test with length +1 for the *initial* '\0'. @@ -67,7 +67,7 @@ int socket_make_sockaddr_un(const char *name, int namespaceId, p_addr->sun_path[0] = 0; memcpy(p_addr->sun_path + 1, name, namelen); -#else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/ +#else /* this OS doesn't have the Linux abstract namespace */ namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX); @@ -79,7 +79,7 @@ int socket_make_sockaddr_un(const char *name, int namespaceId, strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX); strcat(p_addr->sun_path, name); -#endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/ +#endif break; case ANDROID_SOCKET_NAMESPACE_RESERVED: diff --git a/libcutils/socket_local_server.c b/libcutils/socket_local_server.c index 7628fe4..60eb86b 100644 --- a/libcutils/socket_local_server.c +++ b/libcutils/socket_local_server.c @@ -66,7 +66,7 @@ int socket_local_server_bind(int s, const char *name, int namespaceId) } /* basically: if this is a filesystem path, unlink first */ -#ifndef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE +#if !defined(__linux__) if (1) { #else if (namespaceId == ANDROID_SOCKET_NAMESPACE_RESERVED diff --git a/libcutils/socket_network_client.c b/libcutils/socket_network_client.c index 4826033..e0031ba 100644 --- a/libcutils/socket_network_client.c +++ b/libcutils/socket_network_client.c @@ -45,7 +45,6 @@ int socket_network_client_timeout(const char *host, int port, int type, int time { struct hostent *hp; struct sockaddr_in addr; - socklen_t alen; int s; int flags = 0, error = 0, ret = 0; fd_set rset, wset; diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c index dfe8c4b..924289a 100644 --- a/libcutils/str_parms.c +++ b/libcutils/str_parms.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 The Android Open Source Project + * Copyright (C) 2011 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. @@ -357,51 +357,3 @@ void str_parms_dump(struct str_parms *str_parms) { hashmapForEach(str_parms->map, dump_entry, str_parms); } - -#ifdef TEST_STR_PARMS -static void test_str_parms_str(const char *str) -{ - struct str_parms *str_parms; - char *out_str; - - str_parms = str_parms_create_str(str); - str_parms_add_str(str_parms, "dude", "woah"); - str_parms_add_str(str_parms, "dude", "woah"); - str_parms_del(str_parms, "dude"); - str_parms_dump(str_parms); - out_str = str_parms_to_str(str_parms); - str_parms_destroy(str_parms); - ALOGI("%s: '%s' stringified is '%s'", __func__, str, out_str); - free(out_str); -} - -int main(void) -{ - test_str_parms_str(""); - test_str_parms_str(";"); - test_str_parms_str("="); - test_str_parms_str("=;"); - test_str_parms_str("=bar"); - test_str_parms_str("=bar;"); - test_str_parms_str("foo="); - test_str_parms_str("foo=;"); - test_str_parms_str("foo=bar"); - test_str_parms_str("foo=bar;"); - test_str_parms_str("foo=bar;baz"); - test_str_parms_str("foo=bar;baz="); - test_str_parms_str("foo=bar;baz=bat"); - test_str_parms_str("foo=bar;baz=bat;"); - test_str_parms_str("foo=bar;baz=bat;foo=bar"); - - // hashmapPut reports errors by setting errno to ENOMEM. - // Test that we're not confused by running in an environment where this is already true. - errno = ENOMEM; - test_str_parms_str("foo=bar;baz="); - if (errno != ENOMEM) { - abort(); - } - test_str_parms_str("foo=bar;baz="); - - return 0; -} -#endif diff --git a/libcutils/memory.c b/libcutils/strlcpy.c index 6486b45..c66246c 100644 --- a/libcutils/memory.c +++ b/libcutils/strlcpy.c @@ -1,43 +1,4 @@ /* - * 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. - */ - -#include <cutils/memory.h> - -#if !HAVE_MEMSET16 -void android_memset16(uint16_t* dst, uint16_t value, size_t size) -{ - size >>= 1; - while (size--) { - *dst++ = value; - } -} -#endif - -#if !HAVE_MEMSET32 -void android_memset32(uint32_t* dst, uint32_t value, size_t size) -{ - size >>= 2; - while (size--) { - *dst++ = value; - } -} -#endif - -#if !HAVE_STRLCPY -/* * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> * * Permission to use, copy, modify, and distribute this software for any @@ -54,8 +15,13 @@ void android_memset32(uint32_t* dst, uint32_t value, size_t size) */ #include <sys/types.h> + +#if defined(__GLIBC__) || defined(_WIN32) + #include <string.h> +#include <cutils/memory.h> + /* Implementation of strlcpy() for platforms that don't already have it. */ /* @@ -88,4 +54,5 @@ strlcpy(char *dst, const char *src, size_t siz) return(s - src - 1); /* count does not include NUL */ } + #endif diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk index 8e65310..cf70345 100644 --- a/libcutils/tests/Android.mk +++ b/libcutils/tests/Android.mk @@ -15,17 +15,23 @@ LOCAL_PATH := $(call my-dir) test_src_files := \ + test_str_parms.cpp \ + +test_target_only_src_files := \ MemsetTest.cpp \ PropertiesTest.cpp \ +test_libraries := libcutils liblog + + +# +# Target. +# + include $(CLEAR_VARS) LOCAL_MODULE := libcutils_test -LOCAL_SRC_FILES := $(test_src_files) -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - liblog \ - libutils \ - +LOCAL_SRC_FILES := $(test_src_files) $(test_target_only_src_files) +LOCAL_SHARED_LIBRARIES := $(test_libraries) LOCAL_MULTILIB := both LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 @@ -34,15 +40,34 @@ include $(BUILD_NATIVE_TEST) include $(CLEAR_VARS) LOCAL_MODULE := libcutils_test_static LOCAL_FORCE_STATIC_EXECUTABLE := true +LOCAL_SRC_FILES := $(test_src_files) $(test_target_only_src_files) +LOCAL_STATIC_LIBRARIES := libc $(test_libraries) +LOCAL_CXX_STL := libc++_static +LOCAL_MULTILIB := both +LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 +LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 +include $(BUILD_NATIVE_TEST) + + +# +# Host. +# + +include $(CLEAR_VARS) +LOCAL_MODULE := libcutils_test LOCAL_SRC_FILES := $(test_src_files) -LOCAL_STATIC_LIBRARIES := \ - libc \ - libcutils \ - liblog \ - libstlport_static \ - libutils \ +LOCAL_SHARED_LIBRARIES := $(test_libraries) +LOCAL_MULTILIB := both +LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 +LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 +include $(BUILD_HOST_NATIVE_TEST) +include $(CLEAR_VARS) +LOCAL_MODULE := libcutils_test_static +LOCAL_SRC_FILES := $(test_src_files) +LOCAL_STATIC_LIBRARIES := $(test_libraries) +LOCAL_CXX_STL := libc++_static LOCAL_MULTILIB := both LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 -include $(BUILD_NATIVE_TEST) +include $(BUILD_HOST_NATIVE_TEST) diff --git a/libcutils/tests/test_str_parms.cpp b/libcutils/tests/test_str_parms.cpp new file mode 100644 index 0000000..d8f639b --- /dev/null +++ b/libcutils/tests/test_str_parms.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 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 <cutils/str_parms.h> +#include <gtest/gtest.h> + +static void test_str_parms_str(const char* str, const char* expected) { + str_parms* str_parms = str_parms_create_str(str); + str_parms_add_str(str_parms, "dude", "woah"); + str_parms_add_str(str_parms, "dude", "woah"); + str_parms_del(str_parms, "dude"); + str_parms_dump(str_parms); + char* out_str = str_parms_to_str(str_parms); + str_parms_destroy(str_parms); + ASSERT_STREQ(expected, out_str) << str; + free(out_str); +} + +TEST(str_parms, smoke) { + test_str_parms_str("", ""); + test_str_parms_str(";", ""); + test_str_parms_str("=", ""); + test_str_parms_str("=;", ""); + test_str_parms_str("=bar", ""); + test_str_parms_str("=bar;", ""); + test_str_parms_str("foo=", "foo="); + test_str_parms_str("foo=;", "foo="); + test_str_parms_str("foo=bar", "foo=bar"); + test_str_parms_str("foo=bar;", "foo=bar"); + test_str_parms_str("foo=bar;baz", "foo=bar;baz="); + test_str_parms_str("foo=bar;baz=", "foo=bar;baz="); + test_str_parms_str("foo=bar;baz=bat", "foo=bar;baz=bat"); + test_str_parms_str("foo=bar;baz=bat;", "foo=bar;baz=bat"); + test_str_parms_str("foo=bar1;baz=bat;foo=bar2", "foo=bar2;baz=bat"); +} + +TEST(str_parms, put_ENOMEM) { + // hashmapPut reports errors by setting errno to ENOMEM. + // Test that we're not confused by running in an environment where this is already true. + errno = ENOMEM; + test_str_parms_str("foo=bar;baz=", "foo=bar;baz="); + ASSERT_EQ(ENOMEM, errno); + test_str_parms_str("foo=bar;baz=", "foo=bar;baz="); +} diff --git a/libcutils/threads.c b/libcutils/threads.c index bf182f0..5f5577b 100644 --- a/libcutils/threads.c +++ b/libcutils/threads.c @@ -1,22 +1,38 @@ /* ** 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 +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at ** -** http://www.apache.org/licenses/LICENSE-2.0 +** http://www.apache.org/licenses/LICENSE-2.0 ** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and ** limitations under the License. */ -#include <cutils/threads.h> +#include "cutils/threads.h" + +#if !defined(_WIN32) + +// For gettid. +#if defined(__APPLE__) +#include "AvailabilityMacros.h" // For MAC_OS_X_VERSION_MAX_ALLOWED +#include <stdint.h> +#include <stdlib.h> +#include <sys/syscall.h> +#include <sys/time.h> +#include <unistd.h> +#elif defined(__linux__) && !defined(__ANDROID__) +#include <syscall.h> +#include <unistd.h> +#elif defined(_WIN32) +#include <Windows.h> +#endif -#ifdef HAVE_PTHREADS void* thread_store_get( thread_store_t* store ) { if (!store->has_tls) @@ -24,8 +40,8 @@ void* thread_store_get( thread_store_t* store ) return pthread_getspecific( store->tls ); } - -extern void thread_store_set( thread_store_t* store, + +extern void thread_store_set( thread_store_t* store, void* value, thread_store_destruct_t destroy) { @@ -42,14 +58,30 @@ extern void thread_store_set( thread_store_t* store, pthread_setspecific( store->tls, value ); } +// No definition needed for Android because we'll just pick up bionic's copy. +#ifndef __ANDROID__ +pid_t gettid() { +#if defined(__APPLE__) + uint64_t owner; + int rc = pthread_threadid_np(NULL, &owner); + if (rc != 0) { + abort(); + } + return owner; +#elif defined(__linux__) + return syscall(__NR_gettid); +#elif defined(_WIN32) + return (pid_t)GetCurrentThreadId(); #endif +} +#endif // __ANDROID__ -#ifdef HAVE_WIN32_THREADS +#else /* !defined(_WIN32) */ void* thread_store_get( thread_store_t* store ) { if (!store->has_tls) return NULL; - + return (void*) TlsGetValue( store->tls ); } @@ -65,7 +97,7 @@ void thread_store_set( thread_store_t* store, } else while (store->lock_init != -2) { Sleep(10); /* 10ms */ } - + EnterCriticalSection( &store->lock ); if (!store->has_tls) { store->tls = TlsAlloc(); @@ -76,7 +108,7 @@ void thread_store_set( thread_store_t* store, store->has_tls = 1; } LeaveCriticalSection( &store->lock ); - + TlsSetValue( store->tls, value ); } -#endif +#endif /* !defined(_WIN32) */ diff --git a/libcutils/trace.c b/libcutils/trace-dev.c index f57aac2..a06987e 100644 --- a/libcutils/trace.c +++ b/libcutils/trace-dev.c @@ -18,11 +18,11 @@ #include <fcntl.h> #include <limits.h> #include <pthread.h> +#include <stdatomic.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> -#include <cutils/atomic.h> #include <cutils/compiler.h> #include <cutils/properties.h> #include <cutils/trace.h> @@ -30,11 +30,18 @@ #define LOG_TAG "cutils-trace" #include <log/log.h> -volatile int32_t atrace_is_ready = 0; +/** + * Maximum size of a message that can be logged to the trace buffer. + * Note this message includes a tag, the pid, and the string given as the name. + * Names should be kept short to get the most use of the trace buffer. + */ +#define ATRACE_MESSAGE_LENGTH 1024 + +atomic_bool atrace_is_ready = ATOMIC_VAR_INIT(false); int atrace_marker_fd = -1; uint64_t atrace_enabled_tags = ATRACE_TAG_NOT_READY; static bool atrace_is_debuggable = false; -static volatile int32_t atrace_is_enabled = 1; +static atomic_bool atrace_is_enabled = ATOMIC_VAR_INIT(true); static pthread_once_t atrace_once_control = PTHREAD_ONCE_INIT; static pthread_mutex_t atrace_tags_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -51,7 +58,7 @@ void atrace_set_debuggable(bool debuggable) // the Zygote process from tracing. void atrace_set_tracing_enabled(bool enabled) { - android_atomic_release_store(enabled ? 1 : 0, &atrace_is_enabled); + atomic_store_explicit(&atrace_is_enabled, enabled, memory_order_release); atrace_update_tags(); } @@ -148,8 +155,8 @@ static uint64_t atrace_get_property() void atrace_update_tags() { uint64_t tags; - if (CC_UNLIKELY(android_atomic_acquire_load(&atrace_is_ready))) { - if (android_atomic_acquire_load(&atrace_is_enabled)) { + if (CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) { + if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) { tags = atrace_get_property(); pthread_mutex_lock(&atrace_tags_mutex); atrace_enabled_tags = tags; @@ -176,10 +183,60 @@ static void atrace_init_once() atrace_enabled_tags = atrace_get_property(); done: - android_atomic_release_store(1, &atrace_is_ready); + atomic_store_explicit(&atrace_is_ready, true, memory_order_release); } void atrace_setup() { pthread_once(&atrace_once_control, atrace_init_once); } + +void atrace_begin_body(const char* name) +{ + char buf[ATRACE_MESSAGE_LENGTH]; + size_t len; + + len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "B|%d|%s", getpid(), name); + write(atrace_marker_fd, buf, len); +} + + +void atrace_async_begin_body(const char* name, int32_t cookie) +{ + char buf[ATRACE_MESSAGE_LENGTH]; + size_t len; + + len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "S|%d|%s|%" PRId32, + getpid(), name, cookie); + write(atrace_marker_fd, buf, len); +} + +void atrace_async_end_body(const char* name, int32_t cookie) +{ + char buf[ATRACE_MESSAGE_LENGTH]; + size_t len; + + len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "F|%d|%s|%" PRId32, + getpid(), name, cookie); + write(atrace_marker_fd, buf, len); +} + +void atrace_int_body(const char* name, int32_t value) +{ + char buf[ATRACE_MESSAGE_LENGTH]; + size_t len; + + len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId32, + getpid(), name, value); + write(atrace_marker_fd, buf, len); +} + +void atrace_int64_body(const char* name, int64_t value) +{ + char buf[ATRACE_MESSAGE_LENGTH]; + size_t len; + + len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId64, + getpid(), name, value); + write(atrace_marker_fd, buf, len); +} diff --git a/libcutils/trace-host.c b/libcutils/trace-host.c new file mode 100644 index 0000000..6478e3e --- /dev/null +++ b/libcutils/trace-host.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 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 <cutils/trace.h> + +#ifndef __unused +#define __unused __attribute__((__unused__)) +#endif + +atomic_bool atrace_is_ready = ATOMIC_VAR_INIT(true); +int atrace_marker_fd = -1; +uint64_t atrace_enabled_tags = 0; + +void atrace_set_debuggable(bool debuggable __unused) { } +void atrace_set_tracing_enabled(bool enabled __unused) { } +void atrace_update_tags() { } +void atrace_setup() { } +void atrace_begin_body(const char* name __unused) { } +void atrace_async_begin_body(const char* name __unused, int32_t cookie __unused) { } +void atrace_async_end_body(const char* name __unused, int32_t cookie __unused) { } +void atrace_int_body(const char* name __unused, int32_t value __unused) { } +void atrace_int64_body(const char* name __unused, int64_t value __unused) { } diff --git a/libcutils/uevent.c b/libcutils/uevent.c index 97a81e3..de5d227 100644 --- a/libcutils/uevent.c +++ b/libcutils/uevent.c @@ -31,12 +31,12 @@ */ ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length) { - uid_t user = -1; - return uevent_kernel_multicast_uid_recv(socket, buffer, length, &user); + uid_t uid = -1; + return uevent_kernel_multicast_uid_recv(socket, buffer, length, &uid); } /** - * Like the above, but passes a uid_t in by reference. In the event that this + * Like the above, but passes a uid_t in by pointer. In the event that this * fails due to a bad uid check, the uid_t will be set to the uid of the * socket's peer. * @@ -44,8 +44,12 @@ ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length) * returns -1, sets errno to EIO, and sets "user" to the UID associated with the * message. If the peer UID cannot be determined, "user" is set to -1." */ -ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer, - size_t length, uid_t *user) +ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer, size_t length, uid_t *uid) +{ + return uevent_kernel_recv(socket, buffer, length, true, uid); +} + +ssize_t uevent_kernel_recv(int socket, void *buffer, size_t length, bool require_group, uid_t *uid) { struct iovec iov = { buffer, length }; struct sockaddr_nl addr; @@ -60,7 +64,7 @@ ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer, 0, }; - *user = -1; + *uid = -1; ssize_t n = recvmsg(socket, &hdr, 0); if (n <= 0) { return n; @@ -73,14 +77,18 @@ ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer, } struct ucred *cred = (struct ucred *)CMSG_DATA(cmsg); - *user = cred->uid; + *uid = cred->uid; if (cred->uid != 0) { /* ignoring netlink message from non-root user */ goto out; } - if (addr.nl_groups == 0 || addr.nl_pid != 0) { - /* ignoring non-kernel or unicast netlink message */ + if (addr.nl_pid != 0) { + /* ignore non-kernel */ + goto out; + } + if (require_group && addr.nl_groups == 0) { + /* ignore unicast messages when requested */ goto out; } @@ -104,7 +112,7 @@ int uevent_open_socket(int buf_sz, bool passcred) addr.nl_pid = getpid(); addr.nl_groups = 0xffffffff; - s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); + s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT); if(s < 0) return -1; diff --git a/libion/ion.c b/libion/ion.c index 80bdc2a..4908932 100644 --- a/libion/ion.c +++ b/libion/ion.c @@ -23,6 +23,7 @@ #include <errno.h> #include <fcntl.h> #include <stdio.h> +#include <string.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/types.h> @@ -117,7 +118,6 @@ int ion_map(int fd, ion_user_handle_t handle, size_t length, int prot, int ion_share(int fd, ion_user_handle_t handle, int *share_fd) { - int map_fd; int ret; struct ion_fd_data data = { .handle = handle, diff --git a/libion/ion_test.c b/libion/ion_test.c index 8872282..b7d5583 100644 --- a/libion/ion_test.c +++ b/libion/ion_test.c @@ -164,8 +164,9 @@ void ion_share_test() printf("master->master? [%10s]\n", ptr); if (recvmsg(sd[0], &msg, 0) < 0) perror("master recv 1"); + close(fd); + _exit(0); } else { - struct msghdr msg; struct cmsghdr *cmsg; char* ptr; int fd, recv_fd; @@ -205,6 +206,7 @@ void ion_share_test() strcpy(ptr, "child"); printf("child sending msg 2\n"); sendmsg(sd[1], &child_msg, 0); + close(fd); } } diff --git a/libion/tests/Android.mk b/libion/tests/Android.mk index 8dc7f9d..894f90e 100644 --- a/libion/tests/Android.mk +++ b/libion/tests/Android.mk @@ -18,10 +18,8 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := ion-unit-tests -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers LOCAL_SHARED_LIBRARIES += libion -LOCAL_STATIC_LIBRARIES += libgtest_main LOCAL_C_INCLUDES := $(LOCAL_PATH)/../kernel-headers LOCAL_SRC_FILES := \ ion_test_fixture.cpp \ diff --git a/liblog/Android.mk b/liblog/Android.mk index a4e5f5e..70aff83 100644 --- a/liblog/Android.mk +++ b/liblog/Android.mk @@ -16,6 +16,14 @@ LOCAL_PATH := $(my-dir) include $(CLEAR_VARS) +# This is what we want to do: +# liblog_cflags := $(shell \ +# sed -n \ +# 's/^\([0-9]*\)[ \t]*liblog[ \t].*/-DLIBLOG_LOG_TAG=\1/p' \ +# $(LOCAL_PATH)/event.logtags) +# so make sure we do not regret hard-coding it as follows: +liblog_cflags := -DLIBLOG_LOG_TAG=1005 + ifneq ($(TARGET_USES_LOGD),false) liblog_sources := logd_write.c else @@ -25,28 +33,20 @@ endif # some files must not be compiled when building against Mingw # they correspond to features not used by our host development tools # which are also hard or even impossible to port to native Win32 -WITH_MINGW := -ifeq ($(HOST_OS),windows) - ifeq ($(strip $(USE_CYGWIN)),) - WITH_MINGW := true - endif -endif -# USE_MINGW is defined when we build against Mingw on Linux -ifneq ($(strip $(USE_MINGW)),) - WITH_MINGW := true -endif -ifndef WITH_MINGW +ifeq ($(strip $(USE_MINGW)),) liblog_sources += \ - logprint.c \ event_tag_map.c else liblog_sources += \ uio.c endif -liblog_host_sources := $(liblog_sources) fake_log_device.c -liblog_target_sources := $(liblog_sources) log_time.cpp +liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags +liblog_target_sources := $(liblog_sources) log_time.cpp log_is_loggable.c +ifeq ($(strip $(USE_MINGW)),) +liblog_target_sources += logprint.c +endif ifneq ($(TARGET_USES_LOGD),false) liblog_target_sources += log_read.c else @@ -57,7 +57,7 @@ endif # ======================================================== LOCAL_MODULE := liblog LOCAL_SRC_FILES := $(liblog_host_sources) -LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror +LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror $(liblog_cflags) LOCAL_MULTILIB := both include $(BUILD_HOST_STATIC_LIBRARY) @@ -76,13 +76,17 @@ include $(BUILD_HOST_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := liblog LOCAL_SRC_FILES := $(liblog_target_sources) -LOCAL_CFLAGS := -Werror +LOCAL_CFLAGS := -Werror $(liblog_cflags) include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := liblog LOCAL_WHOLE_STATIC_LIBRARIES := liblog -LOCAL_CFLAGS := -Werror +LOCAL_CFLAGS := -Werror $(liblog_cflags) + +# TODO: This is to work around b/19059885. Remove after root cause is fixed +LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv + include $(BUILD_SHARED_LIBRARY) include $(call first-makefiles-under,$(LOCAL_PATH)) diff --git a/liblog/README b/liblog/README index d7472e4..f29ac04 100644 --- a/liblog/README +++ b/liblog/README @@ -111,24 +111,56 @@ DESCRIPTION ger_list_alloc, calling in turn the android_logger_open for each log id. Each entry can be retrieved with android_logger_list_read. The log(s) can be closed with android_logger_list_free. The logs should be - opened with an O_RDONLY mode. O_NDELAY mode will report when the log - reading is done with an EAGAIN error return code, otherwise the - android_logger_list_read call will block for new entries. + opened with an ANDROID_LOG_RDONLY mode. ANDROID_LOG_NONBLOCK mode + will report when the log reading is done with an EAGAIN error return + code, otherwise the android_logger_list_read call will block for new + entries. + + The ANDROID_LOG_PSTORE mode flag to the android_logger_open is used to + switch from the active logs to the persistent logs from before the last + reboot. The value returned by android_logger_open can be used as a parameter to the android_logger_clear function to empty the sub-log. It is recom‐ - mended to only open log O_WRONLY. + mended to only open log ANDROID_LOG_WRONLY in that case. The value returned by android_logger_open can be used as a parameter to the android_logger_get_log_(size|readable_size|version) to retrieve the sub-log maximum size, readable size and log buffer format protocol ver‐ sion respectively. android_logger_get_id returns the id that was used - when opening the sub-log. It is recommended to open the log O_RDONLY - in these cases. + when opening the sub-log. It is recommended to open the log + ANDROID_LOG_RDONLY in these cases. + +ERRORS + If messages fail, a negative error code will be returned to the caller. + + The -ENOTCONN return code indicates that the logger daemon is stopped. + + The -EBADF return code indicates that the log access point can not be + opened, or the log buffer id is out of range. + + For the -EAGAIN return code, this means that the logging message was + temporarily backed-up either because of Denial Of Service (DOS) logging + pressure from some chatty application or service in the Android system, + or if too small of a value is set in /proc/sys/net/unix/max_dgram_qlen. + To aid in diagnosing the occurence of this, a binary event from liblog + will be sent to the log daemon once a new message can get through + indicating how many messages were dropped as a result. Please take + action to resolve the structural problems at the source. + + It is generally not advised for the caller to retry the -EAGAIN return + code as this will only make the problem(s) worse and cause your + application to temporarily drop to the logger daemon priority, BATCH + scheduling policy and background task cgroup. If you require a group of + messages to be passed atomically, merge them into one message with + embedded newlines to the maximum length LOGGER_ENTRY_MAX_PAYLOAD. + + Other return codes from writing operation can be returned. Since the + library retries on EINTR, -EINTR should never be returned. SEE ALSO syslogd(8) - 17 Dec 2013 LIBLOG(3) + 24 Jan 2014 LIBLOG(3) diff --git a/liblog/event.logtags b/liblog/event.logtags new file mode 100644 index 0000000..72ecab1 --- /dev/null +++ b/liblog/event.logtags @@ -0,0 +1,36 @@ +# The entries in this file map a sparse set of log tag numbers to tag names. +# This is installed on the device, in /system/etc, and parsed by logcat. +# +# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the +# negative values alone for now.) +# +# Tag names are one or more ASCII letters and numbers or underscores, i.e. +# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former +# impacts log readability, the latter makes regex searches more annoying). +# +# Tag numbers and names are separated by whitespace. Blank lines and lines +# starting with '#' are ignored. +# +# Optionally, after the tag names can be put a description for the value(s) +# of the tag. Description are in the format +# (<name>|data type[|data unit]) +# Multiple values are separated by commas. +# +# The data type is a number from the following values: +# 1: int +# 2: long +# 3: string +# 4: list +# +# The data unit is a number taken from the following list: +# 1: Number of objects +# 2: Number of bytes +# 3: Number of milliseconds +# 4: Number of allocations +# 5: Id +# 6: Percent +# Default value for data of type int/long is 2 (bytes). +# +# TODO: generate ".java" and ".h" files with integer constants from this file. + +1005 liblog (dropped|1) diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c index 136792d..8a8ece2 100644 --- a/liblog/fake_log_device.c +++ b/liblog/fake_log_device.c @@ -29,7 +29,7 @@ #include <log/logd.h> -#ifdef HAVE_PTHREADS +#if !defined(_WIN32) #include <pthread.h> #endif @@ -88,7 +88,7 @@ typedef struct LogState { } LogState; -#ifdef HAVE_PTHREADS +#if !defined(_WIN32) /* * Locking. Since we're emulating a device, we need to be prepared * to have multiple callers at the same time. This lock is used @@ -106,10 +106,10 @@ static void unlock() { pthread_mutex_unlock(&fakeLogDeviceLock); } -#else // !HAVE_PTHREADS +#else // !defined(_WIN32) #define lock() ((void)0) #define unlock() ((void)0) -#endif // !HAVE_PTHREADS +#endif // !defined(_WIN32) /* @@ -320,9 +320,9 @@ static const char* getPriorityString(int priority) return priorityStrings[idx]; } -#ifndef HAVE_WRITEV +#if defined(_WIN32) /* - * Some platforms like WIN32 do not have writev(). + * WIN32 does not have writev(). * Make up something to replace it. */ static ssize_t fake_writev(int fd, const struct iovec *iov, int iovcnt) { @@ -352,7 +352,7 @@ static ssize_t fake_writev(int fd, const struct iovec *iov, int iovcnt) { static void showLog(LogState *state, int logPrio, const char* tag, const char* msg) { -#if defined(HAVE_LOCALTIME_R) +#if !defined(_WIN32) struct tm tmBuf; #endif struct tm* ptm; @@ -377,7 +377,7 @@ static void showLog(LogState *state, * in the time stamp. Don't use forward slashes, parenthesis, * brackets, asterisks, or other special chars here. */ -#if defined(HAVE_LOCALTIME_R) +#if !defined(_WIN32) ptm = localtime_r(&when, &tmBuf); #else ptm = localtime(&when); @@ -689,3 +689,9 @@ ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count) /* Assume that open() was called first. */ return redirectWritev(fd, vector, count); } + +int __android_log_is_loggable(int prio, const char *tag __unused, int def) +{ + int logLevel = def; + return logLevel >= 0 && prio >= logLevel; +} diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c new file mode 100644 index 0000000..2e09192 --- /dev/null +++ b/liblog/log_is_loggable.c @@ -0,0 +1,61 @@ +/* +** Copyright 2014, 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 <ctype.h> +#include <string.h> +#include <sys/system_properties.h> + +#include <android/log.h> + +static int __android_log_level(const char *tag, int def) +{ + char buf[PROP_VALUE_MAX]; + + if (!tag || !*tag) { + return def; + } + { + static const char log_namespace[] = "persist.log.tag."; + char key[sizeof(log_namespace) + strlen(tag)]; + + strcpy(key, log_namespace); + strcpy(key + sizeof(log_namespace) - 1, tag); + + if (__system_property_get(key + 8, buf) <= 0) { + buf[0] = '\0'; + } + if (!buf[0] && __system_property_get(key, buf) <= 0) { + buf[0] = '\0'; + } + } + switch (toupper(buf[0])) { + case 'V': return ANDROID_LOG_VERBOSE; + case 'D': return ANDROID_LOG_DEBUG; + case 'I': return ANDROID_LOG_INFO; + case 'W': return ANDROID_LOG_WARN; + case 'E': return ANDROID_LOG_ERROR; + case 'F': /* FALLTHRU */ /* Not officially supported */ + case 'A': return ANDROID_LOG_FATAL; + case 'S': return -1; /* ANDROID_LOG_SUPPRESS */ + } + return def; +} + +int __android_log_is_loggable(int prio, const char *tag, int def) +{ + int logLevel = __android_log_level(tag, def); + return logLevel >= 0 && prio >= logLevel; +} diff --git a/liblog/log_read.c b/liblog/log_read.c index ca5a1a7..5364e4f 100644 --- a/liblog/log_read.c +++ b/liblog/log_read.c @@ -19,6 +19,7 @@ #include <inttypes.h> #include <poll.h> #include <signal.h> +#include <stdbool.h> #include <stddef.h> #define NOMINMAX /* for windows to suppress definition of min in stdlib.h */ #include <stdlib.h> @@ -30,11 +31,17 @@ #include <cutils/sockets.h> #include <log/log.h> #include <log/logger.h> +#include <private/android_filesystem_config.h> +#include <private/android_logger.h> /* branchless on many architectures. */ #define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y)))) +#if (defined(USE_MINGW) || defined(HAVE_WINSOCK)) +#define WEAK static +#else #define WEAK __attribute__((weak)) +#endif #ifndef __unused #define __unused __attribute__((unused)) #endif @@ -72,7 +79,7 @@ int WEAK socket_make_sockaddr_un(const char *name, int namespaceId, switch (namespaceId) { case ANDROID_SOCKET_NAMESPACE_ABSTRACT: -#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE +#if defined(__linux__) namelen = strlen(name); /* Test with length +1 for the *initial* '\0'. */ @@ -87,7 +94,7 @@ int WEAK socket_make_sockaddr_un(const char *name, int namespaceId, p_addr->sun_path[0] = 0; memcpy(p_addr->sun_path + 1, name, namelen); -#else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/ +#else /* this OS doesn't have the Linux abstract namespace */ namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX); @@ -99,7 +106,7 @@ int WEAK socket_make_sockaddr_un(const char *name, int namespaceId, strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX); strcat(p_addr->sun_path, name); -#endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/ +#endif break; case ANDROID_SOCKET_NAMESPACE_RESERVED: @@ -353,10 +360,64 @@ static int check_log_success(char *buf, ssize_t ret) return 0; } +/* Determine the credentials of the caller */ +static bool uid_has_log_permission(uid_t uid) +{ + return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT); +} + +static uid_t get_best_effective_uid() +{ + uid_t euid; + uid_t uid; + gid_t gid; + ssize_t i; + static uid_t last_uid = (uid_t) -1; + + if (last_uid != (uid_t) -1) { + return last_uid; + } + uid = getuid(); + if (uid_has_log_permission(uid)) { + return last_uid = uid; + } + euid = geteuid(); + if (uid_has_log_permission(euid)) { + return last_uid = euid; + } + gid = getgid(); + if (uid_has_log_permission(gid)) { + return last_uid = gid; + } + gid = getegid(); + if (uid_has_log_permission(gid)) { + return last_uid = gid; + } + i = getgroups((size_t) 0, NULL); + if (i > 0) { + gid_t list[i]; + + getgroups(i, list); + while (--i >= 0) { + if (uid_has_log_permission(list[i])) { + return last_uid = list[i]; + } + } + } + return last_uid = uid; +} + int android_logger_clear(struct logger *logger) { char buf[512]; + if (logger->top->mode & ANDROID_LOG_PSTORE) { + if (uid_has_log_permission(get_best_effective_uid())) { + return unlink("/sys/fs/pstore/pmsg-ramoops-0"); + } + errno = EPERM; + return -1; + } return check_log_success(buf, send_log_msg(logger, "clear %d", buf, sizeof(buf))); } @@ -560,6 +621,116 @@ struct logger_list *android_logger_list_open(log_id_t id, return logger_list; } +static int android_logger_list_read_pstore(struct logger_list *logger_list, + struct log_msg *log_msg) +{ + ssize_t ret; + off_t current, next; + uid_t uid; + struct logger *logger; + struct __attribute__((__packed__)) { + android_pmsg_log_header_t p; + android_log_header_t l; + } buf; + static uint8_t preread_count; + + memset(log_msg, 0, sizeof(*log_msg)); + + if (logger_list->sock < 0) { + int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY); + + if (fd < 0) { + return -errno; + } + logger_list->sock = fd; + preread_count = 0; + } + + ret = 0; + while(1) { + if (preread_count < sizeof(buf)) { + ret = TEMP_FAILURE_RETRY(read(logger_list->sock, + &buf.p.magic + preread_count, + sizeof(buf) - preread_count)); + if (ret < 0) { + return -errno; + } + preread_count += ret; + } + if (preread_count != sizeof(buf)) { + return preread_count ? -EIO : -EAGAIN; + } + if ((buf.p.magic != LOGGER_MAGIC) + || (buf.p.len <= sizeof(buf)) + || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD)) + || (buf.l.id >= LOG_ID_MAX) + || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) { + do { + memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count); + } while (preread_count && (buf.p.magic != LOGGER_MAGIC)); + continue; + } + preread_count = 0; + + logger_for_each(logger, logger_list) { + if (buf.l.id != logger->id) { + continue; + } + + if ((logger_list->start.tv_sec || logger_list->start.tv_nsec) + && ((logger_list->start.tv_sec > buf.l.realtime.tv_sec) + || ((logger_list->start.tv_sec == buf.l.realtime.tv_sec) + && (logger_list->start.tv_nsec > buf.l.realtime.tv_nsec)))) { + break; + } + + if (logger_list->pid && (logger_list->pid != buf.p.pid)) { + break; + } + + uid = get_best_effective_uid(); + if (!uid_has_log_permission(uid) && (uid != buf.p.uid)) { + break; + } + + ret = TEMP_FAILURE_RETRY(read(logger_list->sock, + log_msg->entry_v3.msg, + buf.p.len - sizeof(buf))); + if (ret < 0) { + return -errno; + } + if (ret != (ssize_t)(buf.p.len - sizeof(buf))) { + return -EIO; + } + + log_msg->entry_v3.len = buf.p.len - sizeof(buf); + log_msg->entry_v3.hdr_size = sizeof(log_msg->entry_v3); + log_msg->entry_v3.pid = buf.p.pid; + log_msg->entry_v3.tid = buf.l.tid; + log_msg->entry_v3.sec = buf.l.realtime.tv_sec; + log_msg->entry_v3.nsec = buf.l.realtime.tv_nsec; + log_msg->entry_v3.lid = buf.l.id; + + return ret; + } + + current = TEMP_FAILURE_RETRY(lseek(logger_list->sock, + (off_t)0, SEEK_CUR)); + if (current < 0) { + return -errno; + } + next = TEMP_FAILURE_RETRY(lseek(logger_list->sock, + (off_t)(buf.p.len - sizeof(buf)), + SEEK_CUR)); + if (next < 0) { + return -errno; + } + if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) { + return -EIO; + } + } +} + static void caught_signal(int signum __unused) { } @@ -578,7 +749,11 @@ int android_logger_list_read(struct logger_list *logger_list, return -EINVAL; } - if (logger_list->mode & O_NONBLOCK) { + if (logger_list->mode & ANDROID_LOG_PSTORE) { + return android_logger_list_read_pstore(logger_list, log_msg); + } + + if (logger_list->mode & ANDROID_LOG_NONBLOCK) { memset(&ignore, 0, sizeof(ignore)); ignore.sa_handler = caught_signal; sigemptyset(&ignore.sa_mask); @@ -598,7 +773,7 @@ int android_logger_list_read(struct logger_list *logger_list, } strcpy(buffer, - (logger_list->mode & O_NONBLOCK) ? "dumpAndClose" : "stream"); + (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose" : "stream"); cp = buffer + strlen(buffer); strcpy(cp, " lids"); @@ -636,14 +811,14 @@ int android_logger_list_read(struct logger_list *logger_list, cp += ret; } - if (logger_list->mode & O_NONBLOCK) { + if (logger_list->mode & ANDROID_LOG_NONBLOCK) { /* Deal with an unresponsive logd */ sigaction(SIGALRM, &ignore, &old_sigaction); old_alarm = alarm(30); } ret = write(sock, buffer, cp - buffer); e = errno; - if (logger_list->mode & O_NONBLOCK) { + if (logger_list->mode & ANDROID_LOG_NONBLOCK) { if (e == EINTR) { e = ETIMEDOUT; } @@ -669,7 +844,7 @@ int android_logger_list_read(struct logger_list *logger_list, while(1) { memset(log_msg, 0, sizeof(*log_msg)); - if (logger_list->mode & O_NONBLOCK) { + if (logger_list->mode & ANDROID_LOG_NONBLOCK) { /* particularily useful if tombstone is reporting for logd */ sigaction(SIGALRM, &ignore, &old_sigaction); old_alarm = alarm(30); @@ -677,7 +852,7 @@ int android_logger_list_read(struct logger_list *logger_list, /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */ ret = recv(logger_list->sock, log_msg, LOGGER_ENTRY_MAX_LEN, 0); e = errno; - if (logger_list->mode & O_NONBLOCK) { + if (logger_list->mode & ANDROID_LOG_NONBLOCK) { if ((ret == 0) || (e == EINTR)) { e = EAGAIN; ret = -1; diff --git a/liblog/log_read_kern.c b/liblog/log_read_kern.c index 41b8a51..bdc7b18 100644 --- a/liblog/log_read_kern.c +++ b/liblog/log_read_kern.c @@ -75,10 +75,10 @@ const char *android_log_id_to_name(log_id_t log_id) static int accessmode(int mode) { - if ((mode & O_ACCMODE) == O_WRONLY) { + if ((mode & ANDROID_LOG_ACCMODE) == ANDROID_LOG_WRONLY) { return W_OK; } - if ((mode & O_ACCMODE) == O_RDWR) { + if ((mode & ANDROID_LOG_ACCMODE) == ANDROID_LOG_RDWR) { return R_OK | W_OK; } return R_OK; @@ -117,7 +117,7 @@ log_id_t android_name_to_log_id(const char *logName) ++b; } - ret = check_allocate_accessible(&n, b, O_RDONLY); + ret = check_allocate_accessible(&n, b, ANDROID_LOG_RDONLY); free(n); if (ret) { return ret; @@ -201,8 +201,8 @@ static int logger_ioctl(struct logger *logger, int cmd, int mode) return -EFAULT; } - if (((mode & O_ACCMODE) == O_RDWR) - || (((mode ^ logger->top->mode) & O_ACCMODE) == 0)) { + if (((mode & ANDROID_LOG_ACCMODE) == ANDROID_LOG_RDWR) + || (((mode ^ logger->top->mode) & ANDROID_LOG_ACCMODE) == 0)) { return ioctl(logger->fd, cmd); } @@ -227,13 +227,13 @@ static int logger_ioctl(struct logger *logger, int cmd, int mode) int android_logger_clear(struct logger *logger) { - return logger_ioctl(logger, LOGGER_FLUSH_LOG, O_WRONLY); + return logger_ioctl(logger, LOGGER_FLUSH_LOG, ANDROID_LOG_WRONLY); } /* returns the total size of the log's ring buffer */ long android_logger_get_log_size(struct logger *logger) { - return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR); + return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, ANDROID_LOG_RDWR); } int android_logger_set_log_size(struct logger *logger __unused, @@ -248,7 +248,7 @@ int android_logger_set_log_size(struct logger *logger __unused, */ long android_logger_get_log_readable_size(struct logger *logger) { - return logger_ioctl(logger, LOGGER_GET_LOG_LEN, O_RDONLY); + return logger_ioctl(logger, LOGGER_GET_LOG_LEN, ANDROID_LOG_RDONLY); } /* @@ -256,7 +256,7 @@ long android_logger_get_log_readable_size(struct logger *logger) */ int android_logger_get_log_version(struct logger *logger) { - int ret = logger_ioctl(logger, LOGGER_GET_VERSION, O_RDWR); + int ret = logger_ioctl(logger, LOGGER_GET_VERSION, ANDROID_LOG_RDWR); return (ret < 0) ? 1 : ret; } @@ -342,7 +342,7 @@ struct logger *android_logger_open(struct logger_list *logger_list, goto err_name; } - logger->fd = open(n, logger_list->mode); + logger->fd = open(n, logger_list->mode & (ANDROID_LOG_ACCMODE | ANDROID_LOG_NONBLOCK)); if (logger->fd < 0) { goto err_name; } @@ -565,7 +565,7 @@ int android_logger_list_read(struct logger_list *logger_list, if (result <= 0) { if (result) { error = errno; - } else if (logger_list->mode & O_NDELAY) { + } else if (logger_list->mode & ANDROID_LOG_NONBLOCK) { error = EAGAIN; } else { logger_list->timeout_ms = LOG_TIMEOUT_NEVER; diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp index 755c2d9..50742df 100644 --- a/liblog/log_time.cpp +++ b/liblog/log_time.cpp @@ -39,7 +39,7 @@ char *log_time::strptime(const char *s, const char *format) { #endif struct tm *ptm; -#if (defined(HAVE_LOCALTIME_R)) +#if !defined(_WIN32) struct tm tmBuf; ptm = localtime_r(&now, &tmBuf); #else @@ -78,7 +78,7 @@ char *log_time::strptime(const char *s, const char *format) { ++ret; } now = tv_sec; -#if (defined(HAVE_LOCALTIME_R)) +#if !defined(_WIN32) ptm = localtime_r(&now, &tmBuf); #else ptm = localtime(&now); @@ -150,6 +150,17 @@ log_time log_time::operator-= (const timespec &T) { return *this; } +log_time log_time::operator+= (const timespec &T) { + this->tv_nsec += (unsigned long int)T.tv_nsec; + if (this->tv_nsec >= NS_PER_SEC) { + this->tv_nsec -= NS_PER_SEC; + ++this->tv_sec; + } + this->tv_sec += T.tv_sec; + + return *this; +} + log_time log_time::operator-= (const log_time &T) { // No concept of negative time, clamp to EPOCH if (*this <= T) { @@ -166,3 +177,14 @@ log_time log_time::operator-= (const log_time &T) { return *this; } + +log_time log_time::operator+= (const log_time &T) { + this->tv_nsec += T.tv_nsec; + if (this->tv_nsec >= NS_PER_SEC) { + this->tv_nsec -= NS_PER_SEC; + ++this->tv_sec; + } + this->tv_sec += T.tv_sec; + + return *this; +} diff --git a/liblog/logd_write.c b/liblog/logd_write.c index b2668ce..c62a246 100644 --- a/liblog/logd_write.c +++ b/liblog/logd_write.c @@ -13,12 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#if (FAKE_LOG_DEVICE == 0) +#include <endian.h> +#endif #include <errno.h> #include <fcntl.h> -#ifdef HAVE_PTHREADS +#if !defined(_WIN32) #include <pthread.h> #endif #include <stdarg.h> +#include <stdatomic.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -39,6 +43,7 @@ #include <log/logger.h> #include <log/log_read.h> #include <private/android_filesystem_config.h> +#include <private/android_logger.h> #define LOG_BUF_SIZE 1024 @@ -49,7 +54,7 @@ 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; -#ifdef HAVE_PTHREADS +#if !defined(_WIN32) static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER; #endif @@ -61,6 +66,7 @@ static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER; static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 }; #else static int logd_fd = -1; +static int pstore_fd = -1; #endif /* @@ -71,6 +77,7 @@ static int logd_fd = -1; static enum { kLogUninitialized, kLogNotAvailable, kLogAvailable } g_log_status = kLogUninitialized; + int __android_log_dev_available(void) { if (g_log_status == kLogUninitialized) { @@ -83,15 +90,6 @@ int __android_log_dev_available(void) return (g_log_status == kLogAvailable); } -#if !FAKE_LOG_DEVICE -/* give up, resources too limited */ -static int __write_to_log_null(log_id_t log_fd __unused, struct iovec *vec __unused, - size_t nr __unused) -{ - return -1; -} -#endif - /* log_init_lock assumed */ static int __write_to_log_initialize() { @@ -104,40 +102,38 @@ static int __write_to_log_initialize() log_fds[i] = fakeLogOpen(buf, O_WRONLY); } #else - if (logd_fd >= 0) { - i = logd_fd; - logd_fd = -1; - close(i); + if (pstore_fd < 0) { + pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY)); } - i = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (i < 0) { - ret = -errno; - write_to_log = __write_to_log_null; - } else if (fcntl(i, F_SETFL, O_NONBLOCK) < 0) { - ret = -errno; - close(i); - i = -1; - write_to_log = __write_to_log_null; - } else { - struct sockaddr_un un; - memset(&un, 0, sizeof(struct sockaddr_un)); - un.sun_family = AF_UNIX; - strcpy(un.sun_path, "/dev/socket/logdw"); - - if (connect(i, (struct sockaddr *)&un, sizeof(struct sockaddr_un)) < 0) { + if (logd_fd < 0) { + i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)); + if (i < 0) { + ret = -errno; + } else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < 0) { ret = -errno; close(i); - i = -1; + } else { + struct sockaddr_un un; + memset(&un, 0, sizeof(struct sockaddr_un)); + un.sun_family = AF_UNIX; + strcpy(un.sun_path, "/dev/socket/logdw"); + + if (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un, + sizeof(struct sockaddr_un))) < 0) { + ret = -errno; + close(i); + } else { + logd_fd = i; + } } } - logd_fd = i; #endif return ret; } -static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr) +static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr) { ssize_t ret; #if FAKE_LOG_DEVICE @@ -155,37 +151,32 @@ static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr) } } while (ret == -EINTR); #else - static const unsigned header_length = 3; + static const unsigned header_length = 2; struct iovec newVec[nr + header_length]; - typeof_log_id_t log_id_buf; - uint16_t tid; + android_log_header_t header; + android_pmsg_log_header_t pmsg_header; struct timespec ts; - log_time realtime_ts; size_t i, payload_size; static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */ + static pid_t last_pid = (pid_t) -1; + static atomic_int_fast32_t dropped; + + if (!nr) { + return -EINVAL; + } if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */ last_uid = getuid(); } - if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */ - /* - * ignore log messages we send to ourself (logd). - * Such log messages are often generated by libraries we depend on - * which use standard Android logging. - */ - return 0; - } - - if (logd_fd < 0) { - return -EBADF; + if (last_pid == (pid_t) -1) { + last_pid = getpid(); } - /* * struct { - * // what we provide - * typeof_log_id_t log_id; - * u16 tid; - * log_time realtime; + * // what we provide to pstore + * android_pmsg_log_header_t pmsg_header; + * // what we provide to socket + * android_log_header_t header; * // caller provides * union { * struct { @@ -201,18 +192,42 @@ static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr) */ clock_gettime(CLOCK_REALTIME, &ts); - realtime_ts.tv_sec = ts.tv_sec; - realtime_ts.tv_nsec = ts.tv_nsec; - log_id_buf = log_id; - tid = gettid(); + pmsg_header.magic = LOGGER_MAGIC; + pmsg_header.len = sizeof(pmsg_header) + sizeof(header); + pmsg_header.uid = last_uid; + pmsg_header.pid = last_pid; + + header.tid = gettid(); + header.realtime.tv_sec = ts.tv_sec; + header.realtime.tv_nsec = ts.tv_nsec; + + newVec[0].iov_base = (unsigned char *) &pmsg_header; + newVec[0].iov_len = sizeof(pmsg_header); + newVec[1].iov_base = (unsigned char *) &header; + newVec[1].iov_len = sizeof(header); + + if (logd_fd > 0) { + int32_t snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed); + if (snapshot) { + android_log_event_int_t buffer; + + header.id = LOG_ID_EVENTS; + buffer.header.tag = htole32(LIBLOG_LOG_TAG); + buffer.payload.type = EVENT_TYPE_INT; + buffer.payload.data = htole32(snapshot); + + newVec[2].iov_base = &buffer; + newVec[2].iov_len = sizeof(buffer); + + ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2)); + if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) { + atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed); + } + } + } - newVec[0].iov_base = (unsigned char *) &log_id_buf; - newVec[0].iov_len = sizeof_log_id_t; - newVec[1].iov_base = (unsigned char *) &tid; - newVec[1].iov_len = sizeof(tid); - newVec[2].iov_base = (unsigned char *) &realtime_ts; - newVec[2].iov_len = sizeof(log_time); + header.id = log_id; for (payload_size = 0, i = header_length; i < nr + header_length; i++) { newVec[i].iov_base = vec[i - header_length].iov_base; @@ -223,25 +238,48 @@ static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr) if (newVec[i].iov_len) { ++i; } + payload_size = LOGGER_ENTRY_MAX_PAYLOAD; break; } } + pmsg_header.len += payload_size; + + if (pstore_fd >= 0) { + TEMP_FAILURE_RETRY(writev(pstore_fd, newVec, i)); + } + + if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */ + /* + * ignore log messages we send to ourself (logd). + * Such log messages are often generated by libraries we depend on + * which use standard Android logging. + */ + return 0; + } + + if (logd_fd < 0) { + return -EBADF; + } /* * The write below could be lost, but will never block. * + * To logd, we drop the pmsg_header + * * ENOTCONN occurs if logd dies. * EAGAIN occurs if logd is overloaded. */ - ret = writev(logd_fd, newVec, i); + ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1)); if (ret < 0) { ret = -errno; if (ret == -ENOTCONN) { -#ifdef HAVE_PTHREADS +#if !defined(_WIN32) pthread_mutex_lock(&log_init_lock); #endif + close(logd_fd); + logd_fd = -1; ret = __write_to_log_initialize(); -#ifdef HAVE_PTHREADS +#if !defined(_WIN32) pthread_mutex_unlock(&log_init_lock); #endif @@ -249,15 +287,17 @@ static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr) return ret; } - ret = writev(logd_fd, newVec, nr + header_length); + ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1)); if (ret < 0) { ret = -errno; } } } - if (ret > (ssize_t)(sizeof_log_id_t + sizeof(tid) + sizeof(log_time))) { - ret -= sizeof_log_id_t + sizeof(tid) + sizeof(log_time); + if (ret > (ssize_t)sizeof(header)) { + ret -= sizeof(header); + } else if (ret == -EAGAIN) { + atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed); } #endif @@ -284,7 +324,7 @@ const char *android_log_id_to_name(log_id_t log_id) static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) { -#ifdef HAVE_PTHREADS +#if !defined(_WIN32) pthread_mutex_lock(&log_init_lock); #endif @@ -293,16 +333,21 @@ static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) ret = __write_to_log_initialize(); if (ret < 0) { -#ifdef HAVE_PTHREADS +#if !defined(_WIN32) pthread_mutex_unlock(&log_init_lock); #endif +#if (FAKE_LOG_DEVICE == 0) + if (pstore_fd >= 0) { + __write_to_log_daemon(log_id, vec, nr); + } +#endif return ret; } - write_to_log = __write_to_log_kernel; + write_to_log = __write_to_log_daemon; } -#ifdef HAVE_PTHREADS +#if !defined(_WIN32) pthread_mutex_unlock(&log_init_lock); #endif @@ -311,43 +356,7 @@ static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) int __android_log_write(int prio, const char *tag, const char *msg) { - struct iovec vec[3]; - log_id_t log_id = LOG_ID_MAIN; - char tmp_tag[32]; - - 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 */ - !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */ - !strcmp(tag, "AT") || - !strcmp(tag, "GSM") || - !strcmp(tag, "STK") || - !strcmp(tag, "CDMA") || - !strcmp(tag, "PHONE") || - !strcmp(tag, "SMS")) { - log_id = LOG_ID_RADIO; - /* Inform third party apps/ril/radio.. to use Rlog or RLOG */ - snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag); - tag = tmp_tag; - } - -#if __BIONIC__ - if (prio == ANDROID_LOG_FATAL) { - android_set_abort_message(msg); - } -#endif - - 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(log_id, vec, 3); + return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg); } int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg) @@ -375,6 +384,12 @@ int __android_log_buf_write(int bufID, int prio, const char *tag, const char *ms tag = tmp_tag; } +#if __BIONIC__ + if (prio == ANDROID_LOG_FATAL) { + android_set_abort_message(msg); + } +#endif + vec[0].iov_base = (unsigned char *) &prio; vec[0].iov_len = 1; vec[1].iov_base = (void *) tag; @@ -440,7 +455,7 @@ void __android_log_assert(const char *cond, const char *tag, } __android_log_write(ANDROID_LOG_FATAL, tag, buf); - __builtin_trap(); /* trap so we have a chance to debug the situation */ + abort(); /* abort so we have a chance to debug the situation */ /* NOTREACHED */ } diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c index ae621cb..8742b34 100644 --- a/liblog/logd_write_kern.c +++ b/liblog/logd_write_kern.c @@ -16,9 +16,7 @@ #include <errno.h> #include <fcntl.h> -#ifdef HAVE_PTHREADS #include <pthread.h> -#endif #include <stdarg.h> #include <stdio.h> #include <stdlib.h> @@ -28,9 +26,7 @@ #include <time.h> #include <unistd.h> -#ifdef __BIONIC__ #include <android/set_abort_message.h> -#endif #include <log/log.h> #include <log/logd.h> @@ -43,23 +39,14 @@ #define LOG_BUF_SIZE 1024 -#if FAKE_LOG_DEVICE -/* This will be defined when building for the host. */ -#include "fake_log_device.h" -#define log_open(pathname, flags) fakeLogOpen(pathname, flags) -#define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count) -#define log_close(filedes) fakeLogClose(filedes) -#else #define log_open(pathname, flags) open(pathname, (flags) | O_CLOEXEC) #define log_writev(filedes, vector, count) writev(filedes, vector, count) #define log_close(filedes) close(filedes) -#endif 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; -#ifdef HAVE_PTHREADS + static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER; -#endif #ifndef __unused #define __unused __attribute__((__unused__)) @@ -119,9 +106,7 @@ static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr) static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) { -#ifdef HAVE_PTHREADS pthread_mutex_lock(&log_init_lock); -#endif if (write_to_log == __write_to_log_init) { log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY); @@ -147,52 +132,14 @@ static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) } } -#ifdef HAVE_PTHREADS pthread_mutex_unlock(&log_init_lock); -#endif return write_to_log(log_id, vec, nr); } int __android_log_write(int prio, const char *tag, const char *msg) { - struct iovec vec[3]; - log_id_t log_id = LOG_ID_MAIN; - char tmp_tag[32]; - - 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 */ - !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */ - !strcmp(tag, "AT") || - !strcmp(tag, "GSM") || - !strcmp(tag, "STK") || - !strcmp(tag, "CDMA") || - !strcmp(tag, "PHONE") || - !strcmp(tag, "SMS")) { - log_id = LOG_ID_RADIO; - /* Inform third party apps/ril/radio.. to use Rlog or RLOG */ - snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag); - tag = tmp_tag; - } - -#if __BIONIC__ - if (prio == ANDROID_LOG_FATAL) { - android_set_abort_message(msg); - } -#endif - - 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(log_id, vec, 3); + return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg); } int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg) @@ -220,6 +167,10 @@ int __android_log_buf_write(int bufID, int prio, const char *tag, const char *ms tag = tmp_tag; } + if (prio == ANDROID_LOG_FATAL) { + android_set_abort_message(msg); + } + vec[0].iov_base = (unsigned char *) &prio; vec[0].iov_len = 1; vec[1].iov_base = (void *) tag; @@ -285,7 +236,7 @@ void __android_log_assert(const char *cond, const char *tag, } __android_log_write(ANDROID_LOG_FATAL, tag, buf); - __builtin_trap(); /* trap so we have a chance to debug the situation */ + abort(); /* abort so we have a chance to debug the situation */ /* NOTREACHED */ } diff --git a/liblog/logprint.c b/liblog/logprint.c index 08e830a..7ba4c8e 100644 --- a/liblog/logprint.c +++ b/liblog/logprint.c @@ -21,10 +21,12 @@ #include <assert.h> #include <ctype.h> #include <errno.h> +#include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/param.h> #include <log/logd.h> #include <log/logprint.h> @@ -39,8 +41,23 @@ struct AndroidLogFormat_t { android_LogPriority global_pri; FilterInfo *filters; AndroidLogPrintFormat format; + bool colored_output; }; +/* + * gnome-terminal color tags + * See http://misc.flogisoft.com/bash/tip_colors_and_formatting + * for ideas on how to set the forground color of the text for xterm. + * The color manipulation character stream is defined as: + * ESC [ 3 8 ; 5 ; <color#> m + */ +#define ANDROID_COLOR_BLUE 75 +#define ANDROID_COLOR_DEFAULT 231 +#define ANDROID_COLOR_GREEN 40 +#define ANDROID_COLOR_ORANGE 166 +#define ANDROID_COLOR_RED 196 +#define ANDROID_COLOR_YELLOW 226 + static FilterInfo * filterinfo_new(const char * tag, android_LogPriority pri) { FilterInfo *p_ret; @@ -110,6 +127,23 @@ static char filterPriToChar (android_LogPriority pri) } } +static int colorFromPri (android_LogPriority pri) +{ + switch (pri) { + case ANDROID_LOG_VERBOSE: return ANDROID_COLOR_DEFAULT; + case ANDROID_LOG_DEBUG: return ANDROID_COLOR_BLUE; + case ANDROID_LOG_INFO: return ANDROID_COLOR_GREEN; + case ANDROID_LOG_WARN: return ANDROID_COLOR_ORANGE; + case ANDROID_LOG_ERROR: return ANDROID_COLOR_RED; + case ANDROID_LOG_FATAL: return ANDROID_COLOR_RED; + case ANDROID_LOG_SILENT: return ANDROID_COLOR_DEFAULT; + + case ANDROID_LOG_DEFAULT: + case ANDROID_LOG_UNKNOWN: + default: return ANDROID_COLOR_DEFAULT; + } +} + static android_LogPriority filterPriForTag( AndroidLogFormat *p_format, const char *tag) { @@ -149,6 +183,7 @@ AndroidLogFormat *android_log_format_new() p_ret->global_pri = ANDROID_LOG_VERBOSE; p_ret->format = FORMAT_BRIEF; + p_ret->colored_output = false; return p_ret; } @@ -174,7 +209,10 @@ void android_log_format_free(AndroidLogFormat *p_format) void android_log_setPrintFormat(AndroidLogFormat *p_format, AndroidLogPrintFormat format) { - p_format->format=format; + if (format == FORMAT_COLOR) + p_format->colored_output = true; + else + p_format->format = format; } /** @@ -192,6 +230,7 @@ AndroidLogPrintFormat android_log_formatFromString(const char * formatString) else if (strcmp(formatString, "time") == 0) format = FORMAT_TIME; else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME; else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG; + else if (strcmp(formatString, "color") == 0) format = FORMAT_COLOR; else format = FORMAT_OFF; return format; @@ -305,15 +344,6 @@ error: return -1; } -static inline char * strip_end(char *str) -{ - char *end = str + strlen(str) - 1; - - while (end >= str && isspace(*end)) - *end-- = '\0'; - return str; -} - /** * Splits a wire-format buffer into an AndroidLogEntry * entry allocated by caller. Pointers will point directly into buf @@ -687,7 +717,7 @@ char *android_log_formatLogLine ( const AndroidLogEntry *entry, size_t *p_outLength) { -#if defined(HAVE_LOCALTIME_R) +#if !defined(_WIN32) struct tm tmBuf; #endif struct tm* ptm; @@ -698,6 +728,8 @@ char *android_log_formatLogLine ( char * ret = NULL; priChar = filterPriToChar(entry->priority); + size_t prefixLen = 0, suffixLen = 0; + size_t len; /* * Get the current date/time in pretty form @@ -708,7 +740,7 @@ char *android_log_formatLogLine ( * in the time stamp. Don't use forward slashes, parenthesis, * brackets, asterisks, or other special chars here. */ -#if defined(HAVE_LOCALTIME_R) +#if !defined(_WIN32) ptm = localtime_r(&(entry->tv_sec), &tmBuf); #else ptm = localtime(&(entry->tv_sec)); @@ -719,73 +751,80 @@ char *android_log_formatLogLine ( /* * Construct a buffer containing the log header and log message. */ - size_t prefixLen, suffixLen; + if (p_format->colored_output) { + prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "\x1B[38;5;%dm", + colorFromPri(entry->priority)); + prefixLen = MIN(prefixLen, sizeof(prefixBuf)); + suffixLen = snprintf(suffixBuf, sizeof(suffixBuf), "\x1B[0m"); + suffixLen = MIN(suffixLen, sizeof(suffixBuf)); + } switch (p_format->format) { case FORMAT_TAG: - prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), + len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%c/%-8s: ", priChar, entry->tag); - strcpy(suffixBuf, "\n"); suffixLen = 1; + strcpy(suffixBuf + suffixLen, "\n"); + ++suffixLen; break; case FORMAT_PROCESS: - prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), - "%c(%5d) ", priChar, entry->pid); - suffixLen = snprintf(suffixBuf, sizeof(suffixBuf), + len = snprintf(suffixBuf + suffixLen, sizeof(suffixBuf) - suffixLen, " (%s)\n", entry->tag); + suffixLen += MIN(len, sizeof(suffixBuf) - suffixLen); + len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, + "%c(%5d) ", priChar, entry->pid); break; case FORMAT_THREAD: - prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), + len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%c(%5d:%5d) ", priChar, entry->pid, entry->tid); - strcpy(suffixBuf, "\n"); - suffixLen = 1; + strcpy(suffixBuf + suffixLen, "\n"); + ++suffixLen; break; case FORMAT_RAW: - prefixBuf[0] = 0; - prefixLen = 0; - strcpy(suffixBuf, "\n"); - suffixLen = 1; + prefixBuf[prefixLen] = 0; + len = 0; + strcpy(suffixBuf + suffixLen, "\n"); + ++suffixLen; break; case FORMAT_TIME: - prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), + len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%s.%03ld %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000, priChar, entry->tag, entry->pid); - strcpy(suffixBuf, "\n"); - suffixLen = 1; + strcpy(suffixBuf + suffixLen, "\n"); + ++suffixLen; break; case FORMAT_THREADTIME: - prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), + len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000, entry->pid, entry->tid, priChar, entry->tag); - strcpy(suffixBuf, "\n"); - suffixLen = 1; + strcpy(suffixBuf + suffixLen, "\n"); + ++suffixLen; break; case FORMAT_LONG: - prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), + len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "[ %s.%03ld %5d:%5d %c/%-8s ]\n", timeBuf, entry->tv_nsec / 1000000, entry->pid, entry->tid, priChar, entry->tag); - strcpy(suffixBuf, "\n\n"); - suffixLen = 2; + strcpy(suffixBuf + suffixLen, "\n\n"); + suffixLen += 2; prefixSuffixIsHeaderFooter = 1; break; case FORMAT_BRIEF: default: - prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), + len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%c/%-8s(%5d): ", priChar, entry->tag, entry->pid); - strcpy(suffixBuf, "\n"); - suffixLen = 1; + strcpy(suffixBuf + suffixLen, "\n"); + ++suffixLen; 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; + prefixLen += MIN(len, sizeof(prefixBuf) - prefixLen); + suffixLen = MIN(suffixLen, sizeof(suffixBuf)); /* the following code is tragically unreadable */ diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk index cd1bf33..d75bbc9 100644 --- a/liblog/tests/Android.mk +++ b/liblog/tests/Android.mk @@ -39,16 +39,10 @@ benchmark_src_files := \ include $(CLEAR_VARS) LOCAL_MODULE := $(test_module_prefix)benchmarks LOCAL_MODULE_TAGS := $(test_tags) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += $(benchmark_c_flags) LOCAL_SHARED_LIBRARIES += liblog libm LOCAL_SRC_FILES := $(benchmark_src_files) -ifndef LOCAL_SDK_VERSION -LOCAL_C_INCLUDES += bionic bionic/libstdc++/include external/stlport/stlport -LOCAL_SHARED_LIBRARIES += libstlport -endif -LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) -include $(BUILD_EXECUTABLE) +include $(BUILD_NATIVE_TEST) # ----------------------------------------------------------------------------- # Unit tests. @@ -71,7 +65,7 @@ ifneq ($(wildcard $(LOCAL_PATH)/../../../../bionic/libc/bionic/libc_logging.cpp) test_src_files += \ libc_test.cpp -ifndef ($(TARGET_USES_LOGD),false) +ifneq ($(TARGET_USES_LOGD),false) test_c_flags += -DTARGET_USES_LOGD endif @@ -82,7 +76,6 @@ endif include $(CLEAR_VARS) LOCAL_MODULE := $(test_module_prefix)unit-tests LOCAL_MODULE_TAGS := $(test_tags) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += $(test_c_flags) LOCAL_SHARED_LIBRARIES := liblog LOCAL_SRC_FILES := $(test_src_files) diff --git a/liblog/tests/benchmark_main.cpp b/liblog/tests/benchmark_main.cpp index 090394c..e5ef970 100644 --- a/liblog/tests/benchmark_main.cpp +++ b/liblog/tests/benchmark_main.cpp @@ -17,6 +17,7 @@ #include <benchmark.h> #include <inttypes.h> +#include <math.h> #include <regex.h> #include <stdio.h> #include <stdlib.h> diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp index 9839729..29501be 100644 --- a/liblog/tests/libc_test.cpp +++ b/liblog/tests/libc_test.cpp @@ -39,7 +39,7 @@ TEST(libc, __libc_android_log_event_int) { pid_t pid = getpid(); ASSERT_TRUE(NULL != (logger_list = android_logger_list_open( - LOG_ID_EVENTS, O_RDONLY | O_NDELAY, 1000, pid))); + LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid))); struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); @@ -99,7 +99,7 @@ TEST(libc, __libc_fatal_no_abort) { pid_t pid = getpid(); ASSERT_TRUE(NULL != (logger_list = android_logger_list_open( - (log_id_t)LOG_ID_CRASH, O_RDONLY | O_NDELAY, 1000, pid))); + (log_id_t)LOG_ID_CRASH, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid))); char b[80]; struct timespec ts; diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp index 549d79e..b594634 100644 --- a/liblog/tests/liblog_benchmark.cpp +++ b/liblog/tests/liblog_benchmark.cpp @@ -130,7 +130,7 @@ static void BM_log_latency(int iters) { pid_t pid = getpid(); struct logger_list * logger_list = android_logger_list_open(LOG_ID_EVENTS, - O_RDONLY, 0, pid); + ANDROID_LOG_RDONLY, 0, pid); if (!logger_list) { fprintf(stderr, "Unable to open events log: %s\n", strerror(errno)); @@ -208,7 +208,7 @@ static void BM_log_delay(int iters) { pid_t pid = getpid(); struct logger_list * logger_list = android_logger_list_open(LOG_ID_EVENTS, - O_RDONLY, 0, pid); + ANDROID_LOG_RDONLY, 0, pid); if (!logger_list) { fprintf(stderr, "Unable to open events log: %s\n", strerror(errno)); @@ -266,3 +266,17 @@ static void BM_log_delay(int iters) { android_logger_list_free(logger_list); } BENCHMARK(BM_log_delay); + +/* + * Measure the time it takes for __android_log_is_loggable. + */ +static void BM_is_loggable(int iters) { + StartBenchmarkTiming(); + + for (int i = 0; i < iters; ++i) { + __android_log_is_loggable(ANDROID_LOG_WARN, "logd", ANDROID_LOG_VERBOSE); + } + + StopBenchmarkTiming(); +} +BENCHMARK(BM_is_loggable); diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp index 393e2cd..33f6481 100644 --- a/liblog/tests/liblog_test.cpp +++ b/liblog/tests/liblog_test.cpp @@ -122,7 +122,7 @@ TEST(liblog, __android_log_btwrite__android_logger_list_read) { pid_t pid = getpid(); ASSERT_TRUE(NULL != (logger_list = android_logger_list_open( - LOG_ID_EVENTS, O_RDONLY | O_NDELAY, 1000, pid))); + LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid))); log_time ts(CLOCK_MONOTONIC); @@ -223,7 +223,7 @@ TEST(liblog, android_logger_list_read__cpu) { v += pid & 0xFFFF; ASSERT_TRUE(NULL != (logger_list = android_logger_list_open( - LOG_ID_EVENTS, O_RDONLY, 1000, pid))); + LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 1000, pid))); int count = 0; @@ -443,7 +443,7 @@ TEST(liblog, max_payload) { struct logger_list *logger_list; ASSERT_TRUE(NULL != (logger_list = android_logger_list_open( - LOG_ID_SYSTEM, O_RDONLY, 100, 0))); + LOG_ID_SYSTEM, ANDROID_LOG_RDONLY, 100, 0))); bool matches = false; ssize_t max_len = 0; @@ -505,7 +505,7 @@ TEST(liblog, too_big_payload) { struct logger_list *logger_list; ASSERT_TRUE(NULL != (logger_list = android_logger_list_open( - LOG_ID_SYSTEM, O_RDONLY | O_NDELAY, 100, 0))); + LOG_ID_SYSTEM, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 100, 0))); ssize_t max_len = 0; @@ -552,12 +552,12 @@ TEST(liblog, dual_reader) { // >25 messages due to liblog.__android_log_buf_print__concurrentXX above. ASSERT_TRUE(NULL != (logger_list1 = android_logger_list_open( - LOG_ID_MAIN, O_RDONLY | O_NDELAY, 25, 0))); + LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 25, 0))); struct logger_list *logger_list2; if (NULL == (logger_list2 = android_logger_list_open( - LOG_ID_MAIN, O_RDONLY | O_NDELAY, 15, 0))) { + LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 15, 0))) { android_logger_list_close(logger_list1); ASSERT_TRUE(NULL != logger_list2); } @@ -595,7 +595,7 @@ TEST(liblog, dual_reader) { } TEST(liblog, android_logger_get_) { - struct logger_list * logger_list = android_logger_list_alloc(O_WRONLY, 0, 0); + struct logger_list * logger_list = android_logger_list_alloc(ANDROID_LOG_WRONLY, 0, 0); for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) { log_id_t id = static_cast<log_id_t>(i); diff --git a/liblog/uio.c b/liblog/uio.c index 24a6507..f77cc49 100644 --- a/liblog/uio.c +++ b/liblog/uio.c @@ -14,7 +14,7 @@ * limitations under the License. */ -#ifndef HAVE_SYS_UIO_H +#if defined(_WIN32) #include <log/uio.h> #include <unistd.h> @@ -73,4 +73,4 @@ Exit: return total; } -#endif /* !HAVE_SYS_UIO_H */ +#endif diff --git a/libmemtrack/memtrack.c b/libmemtrack/memtrack.c index 9a656df..21d9ebd 100644 --- a/libmemtrack/memtrack.c +++ b/libmemtrack/memtrack.c @@ -20,6 +20,10 @@ #include <log/log.h> +#include <errno.h> +#include <malloc.h> +#include <string.h> + #include <hardware/memtrack.h> #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk index 7906986..503bcb4 100644 --- a/libmincrypt/Android.mk +++ b/libmincrypt/Android.mk @@ -6,6 +6,8 @@ include $(CLEAR_VARS) LOCAL_MODULE := libmincrypt LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c LOCAL_CFLAGS := -Wall -Werror +# Clang's slp-vectorize phase has segmentation fault when compiling p256_ec.c. +LOCAL_CLANG_CFLAGS += -fno-slp-vectorize include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc index eab2de0..6fa4b39 100644 --- a/libnativebridge/native_bridge.cc +++ b/libnativebridge/native_bridge.cc @@ -360,7 +360,7 @@ static void SetupEnvironment(NativeBridgeCallbacks* callbacks, JNIEnv* env, cons if (env_values->os_arch != nullptr) { jclass sclass_id = env->FindClass("java/lang/System"); if (sclass_id != nullptr) { - jmethodID set_prop_id = env->GetStaticMethodID(sclass_id, "initUnchangeableSystemProperty", + jmethodID set_prop_id = env->GetStaticMethodID(sclass_id, "setUnchangeableSystemProperty", "(Ljava/lang/String;Ljava/lang/String;)V"); if (set_prop_id != nullptr) { // Init os.arch to the value reqired by the apps running with native bridge. @@ -368,7 +368,7 @@ static void SetupEnvironment(NativeBridgeCallbacks* callbacks, JNIEnv* env, cons env->NewStringUTF(env_values->os_arch)); } else { env->ExceptionClear(); - ALOGW("Could not find initUnchangeableSystemProperty method."); + ALOGW("Could not find System#setUnchangeableSystemProperty."); } } else { env->ExceptionClear(); diff --git a/libnativebridge/tests/CompleteFlow_test.cpp b/libnativebridge/tests/CompleteFlow_test.cpp index cf06d2c..b033792 100644 --- a/libnativebridge/tests/CompleteFlow_test.cpp +++ b/libnativebridge/tests/CompleteFlow_test.cpp @@ -36,6 +36,7 @@ TEST_F(NativeBridgeTest, CompleteFlow) { // Unload UnloadNativeBridge(); + ASSERT_FALSE(NativeBridgeAvailable()); ASSERT_FALSE(NativeBridgeError()); diff --git a/libnetutils/Android.mk b/libnetutils/Android.mk index 1f61511..2060df4 100644 --- a/libnetutils/Android.mk +++ b/libnetutils/Android.mk @@ -17,3 +17,10 @@ LOCAL_MODULE := libnetutils LOCAL_CFLAGS := -Werror include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := dhcptool.c +LOCAL_SHARED_LIBRARIES := libnetutils +LOCAL_MODULE := dhcptool +LOCAL_MODULE_TAGS := debug +include $(BUILD_EXECUTABLE) diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c index e1df874..70e37c6 100644 --- a/libnetutils/dhcp_utils.c +++ b/libnetutils/dhcp_utils.c @@ -72,14 +72,16 @@ static int wait_for_property(const char *name, const char *desired_value, int ma maxnaps = 1; } - while (maxnaps-- > 0) { - usleep(NAP_TIME * 1000); + while (maxnaps-- >= 0) { if (property_get(name, value, NULL)) { if (desired_value == NULL || strcmp(value, desired_value) == 0) { return 0; } } + if (maxnaps >= 0) { + usleep(NAP_TIME * 1000); + } } return -1; /* failure */ } @@ -166,14 +168,6 @@ static int fill_ip_info(const char *interface, return 0; } -static const char *ipaddr_to_string(in_addr_t addr) -{ - struct in_addr in_addr; - - in_addr.s_addr = addr; - return inet_ntoa(in_addr); -} - /* * Start the dhcp client daemon, and wait for it to finish * configuring the interface. @@ -242,7 +236,6 @@ int dhcp_do_request(const char *interface, return -1; } if (strcmp(prop_value, "ok") == 0) { - char dns_prop_name[PROPERTY_KEY_MAX]; if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns, server, lease, vendorInfo, domain, mtu) == -1) { return -1; diff --git a/libnetutils/dhcpclient.c b/libnetutils/dhcpclient.c index b58120e..240a789 100644 --- a/libnetutils/dhcpclient.c +++ b/libnetutils/dhcpclient.c @@ -150,7 +150,7 @@ static const char *dhcp_type_to_name(uint32_t type) void dump_dhcp_info(dhcp_info *info) { - char addr[20], gway[20], mask[20]; + char addr[20], gway[20]; ALOGD("--- dhcp %s (%d) ---", dhcp_type_to_name(info->type), info->type); strcpy(addr, ipaddr(info->ipaddr)); @@ -236,13 +236,13 @@ int decode_dhcp_msg(dhcp_msg *msg, int len, dhcp_info *info) #if VERBOSE -static void hex2str(char *buf, const unsigned char *array, int len) +static void hex2str(char *buf, size_t buf_size, const unsigned char *array, int len) { int i; char *cp = buf; - + char *buf_end = buf + buf_size; for (i = 0; i < len; i++) { - cp += sprintf(cp, " %02x ", array[i]); + cp += snprintf(cp, buf_end - cp, " %02x ", array[i]); } } @@ -278,7 +278,7 @@ void dump_dhcp_msg(dhcp_msg *msg, int len) ALOGD("giaddr = %s", ipaddr(msg->giaddr)); c = msg->hlen > 16 ? 16 : msg->hlen; - hex2str(buf, msg->chaddr, c); + hex2str(buf, sizeof(buf), msg->chaddr, c); ALOGD("chaddr = {%s}", buf); for (n = 0; n < 64; n++) { @@ -327,7 +327,7 @@ void dump_dhcp_msg(dhcp_msg *msg, int len) memcpy(buf, &x[2], n); buf[n] = '\0'; } else { - hex2str(buf, &x[2], optsz); + hex2str(buf, sizeof(buf), &x[2], optsz); } if (x[0] == OPT_MESSAGE_TYPE) name = dhcp_type_to_name(x[2]); @@ -353,28 +353,28 @@ static int send_message(int sock, int if_index, dhcp_msg *msg, int size) static int is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz) { if (sz < DHCP_MSG_FIXED_SIZE) { - if (verbose) ALOGD("netcfg: Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE); + if (verbose) ALOGD("Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE); return 0; } if (reply->op != OP_BOOTREPLY) { - if (verbose) ALOGD("netcfg: Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY); + if (verbose) ALOGD("Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY); return 0; } if (reply->xid != msg->xid) { - if (verbose) ALOGD("netcfg: Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid), - ntohl(msg->xid)); + if (verbose) ALOGD("Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid), + ntohl(msg->xid)); return 0; } if (reply->htype != msg->htype) { - if (verbose) ALOGD("netcfg: Wrong Htype %d != %d\n", reply->htype, msg->htype); + if (verbose) ALOGD("Wrong Htype %d != %d\n", reply->htype, msg->htype); return 0; } if (reply->hlen != msg->hlen) { - if (verbose) ALOGD("netcfg: Wrong Hlen %d != %d\n", reply->hlen, msg->hlen); + if (verbose) ALOGD("Wrong Hlen %d != %d\n", reply->hlen, msg->hlen); return 0; } if (memcmp(msg->chaddr, reply->chaddr, msg->hlen)) { - if (verbose) ALOGD("netcfg: Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr)); + if (verbose) ALOGD("Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr)); return 0; } return 1; diff --git a/libnetutils/dhcptool.c b/libnetutils/dhcptool.c new file mode 100644 index 0000000..352ac5e --- /dev/null +++ b/libnetutils/dhcptool.c @@ -0,0 +1,43 @@ +/* + * Copyright 2015, 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 <error.h> +#include <stdbool.h> +#include <stdlib.h> + +#include <netutils/dhcp.h> +#include <netutils/ifc.h> + +int main(int argc, char* argv[]) { + if (argc != 2) { + error(EXIT_FAILURE, 0, "usage: %s INTERFACE", argv[0]); + } + + char* interface = argv[1]; + if (ifc_init()) { + error(EXIT_FAILURE, errno, "dhcptool %s: ifc_init failed", interface); + } + + int rc = do_dhcp(interface); + if (rc) { + error(0, errno, "dhcptool %s: do_dhcp failed", interface); + } + + ifc_close(); + + return rc ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c index 913f51e..7d2a5fb 100644 --- a/libnetutils/ifc_utils.c +++ b/libnetutils/ifc_utils.c @@ -123,7 +123,7 @@ int ifc_init(void) { int ret; if (ifc_ctl_sock == -1) { - ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0); + ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (ifc_ctl_sock < 0) { printerr("socket() failed: %s\n", strerror(errno)); } @@ -137,7 +137,7 @@ int ifc_init(void) int ifc_init6(void) { if (ifc_ctl_sock6 == -1) { - ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM, 0); + ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (ifc_ctl_sock6 < 0) { printerr("socket() failed: %s\n", strerror(errno)); } @@ -316,7 +316,7 @@ int ifc_act_on_address(int action, const char *name, const char *address, req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len) + RTA_LENGTH(addrlen); memcpy(RTA_DATA(rta), addr, addrlen); - s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + s = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); if (send(s, &req, req.n.nlmsg_len, 0) < 0) { close(s); return -errno; @@ -421,7 +421,6 @@ int ifc_clear_addresses(const char *name) { int ifc_set_hwaddr(const char *name, const void *ptr) { - int r; struct ifreq ifr; ifc_init_ifr(name, &ifr); diff --git a/libnetutils/packet.c b/libnetutils/packet.c index 3cdefb0..cd26d05 100644 --- a/libnetutils/packet.c +++ b/libnetutils/packet.c @@ -15,6 +15,7 @@ */ #include <stdlib.h> +#include <string.h> #include <unistd.h> #include <sys/uio.h> #include <sys/socket.h> @@ -41,7 +42,7 @@ int fatal(); int open_raw_socket(const char *ifname __attribute__((unused)), uint8_t *hwaddr, int if_index) { - int s, flag; + int s; struct sockaddr_ll bindaddr; if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk index 8a427b3..f02da7f 100644 --- a/libpixelflinger/Android.mk +++ b/libpixelflinger/Android.mk @@ -34,6 +34,7 @@ PIXELFLINGER_SRC_FILES_arm := \ ifeq ($(ARCH_ARM_HAVE_NEON),true) PIXELFLINGER_SRC_FILES_arm += col32cb16blend_neon.S +PIXELFLINGER_CFLAGS_arm += -D__ARM_HAVE_NEON endif PIXELFLINGER_SRC_FILES_arm64 := \ @@ -42,11 +43,13 @@ PIXELFLINGER_SRC_FILES_arm64 := \ arch-arm64/col32cb16blend.S \ arch-arm64/t32cb16blend.S \ +ifndef ARCH_MIPS_REV6 PIXELFLINGER_SRC_FILES_mips := \ codeflinger/MIPSAssembler.cpp \ codeflinger/mips_disassem.c \ arch-mips/t32cb16blend.S \ +endif # # Shared library # @@ -57,29 +60,19 @@ LOCAL_SRC_FILES_arm := $(PIXELFLINGER_SRC_FILES_arm) LOCAL_SRC_FILES_arm64 := $(PIXELFLINGER_SRC_FILES_arm64) LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips) LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS) +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS) \ + external/safe-iop/include LOCAL_SHARED_LIBRARIES := libcutils liblog libutils -LOCAL_C_INCLUDES += external/safe-iop/include -ifneq ($(BUILD_TINY_ANDROID),true) # Really this should go away entirely or at least not depend on # libhardware, but this at least gets us built. LOCAL_SHARED_LIBRARIES += libhardware_legacy LOCAL_CFLAGS += -DWITH_LIB_HARDWARE -endif +# t32cb16blend.S does not compile with Clang. +LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as +# arch-arm64/col32cb16blend.S does not compile with Clang. +LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as include $(BUILD_SHARED_LIBRARY) -# -# Static library version -# - -include $(CLEAR_VARS) -LOCAL_MODULE:= libpixelflinger_static -LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES) -LOCAL_SRC_FILES_arm := $(PIXELFLINGER_SRC_FILES_arm) -LOCAL_SRC_FILES_arm64 := $(PIXELFLINGER_SRC_FILES_arm64) -LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips) -LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS) -include $(BUILD_STATIC_LIBRARY) - - include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp index cfd2b37..d770302 100644 --- a/libpixelflinger/codeflinger/CodeCache.cpp +++ b/libpixelflinger/codeflinger/CodeCache.cpp @@ -201,8 +201,8 @@ int CodeCache::cache( const AssemblyKeyBase& keyBase, mCacheInUse += assemblySize; mWhen++; // synchronize caches... - void* base = assembly->base(); - void* curr = (uint8_t*)base + assembly->size(); + char* base = reinterpret_cast<char*>(assembly->base()); + char* curr = reinterpret_cast<char*>(base + assembly->size()); __builtin___clear_cache(base, curr); } diff --git a/libpixelflinger/codeflinger/load_store.cpp b/libpixelflinger/codeflinger/load_store.cpp index 0a46eaa..e5a1ae0 100644 --- a/libpixelflinger/codeflinger/load_store.cpp +++ b/libpixelflinger/codeflinger/load_store.cpp @@ -20,10 +20,6 @@ #include <cutils/log.h> #include "GGLAssembler.h" -#ifdef __ARM_ARCH__ -#include <machine/cpu-features.h> -#endif - namespace android { // ---------------------------------------------------------------------------- @@ -117,20 +113,6 @@ void GGLAssembler::extract(integer_t& d, int s, int h, int l, int bits) #endif assert(h); -#if __ARM_ARCH__ >= 7 - const int mask = (1<<maskLen)-1; - if ((h == bits) && !l && (s != d.reg)) { - MOV(AL, 0, d.reg, s); // component = packed; - } else if ((h == bits) && l) { - MOV(AL, 0, d.reg, reg_imm(s, LSR, l)); // component = packed >> l; - } else if (!l && isValidImmediate(mask)) { - AND(AL, 0, d.reg, s, imm(mask)); // component = packed & mask; - } else if (!l && isValidImmediate(~mask)) { - BIC(AL, 0, d.reg, s, imm(~mask)); // component = packed & mask; - } else { - UBFX(AL, d.reg, s, l, maskLen); // component = (packed & mask) >> l; - } -#else if (h != bits) { const int mask = ((1<<maskLen)-1) << l; if (isValidImmediate(mask)) { @@ -153,7 +135,6 @@ void GGLAssembler::extract(integer_t& d, int s, int h, int l, int bits) if (s != d.reg) { MOV(AL, 0, d.reg, s); } -#endif d.s = maskLen; } diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp index 81950bf..29a3742 100644 --- a/libpixelflinger/codeflinger/texturing.cpp +++ b/libpixelflinger/codeflinger/texturing.cpp @@ -25,10 +25,6 @@ #include "GGLAssembler.h" -#ifdef __ARM_ARCH__ -#include <machine/cpu-features.h> -#endif - namespace android { // --------------------------------------------------------------------------- @@ -888,106 +884,6 @@ void GGLAssembler::filter24( load(txPtr, texel, 0); } -#if __ARM_ARCH__ >= 6 -// ARMv6 version, using UXTB16, and scheduled for Cortex-A8 pipeline -void GGLAssembler::filter32( - const fragment_parts_t& parts, - pixel_t& texel, const texture_unit_t& tmu, - int U, int V, pointer_t& txPtr, - int FRAC_BITS) -{ - const int adjust = FRAC_BITS*2 - 8; - const int round = 0; - const int prescale = 16 - adjust; - - Scratch scratches(registerFile()); - - int pixel= scratches.obtain(); - int dh = scratches.obtain(); - int u = scratches.obtain(); - int k = scratches.obtain(); - - int temp = scratches.obtain(); - int dl = scratches.obtain(); - - int offsetrt = scratches.obtain(); - int offsetlb = scratches.obtain(); - - int pixellb = offsetlb; - - // RB -> U * V - CONTEXT_LOAD(offsetrt, generated_vars.rt); - CONTEXT_LOAD(offsetlb, generated_vars.lb); - if(!round) { - MOV(AL, 0, U, reg_imm(U, LSL, prescale)); - } - ADD(AL, 0, u, offsetrt, offsetlb); - - LDR(AL, pixel, txPtr.reg, reg_scale_pre(u)); - if (round) { - SMULBB(AL, u, U, V); - RSB(AL, 0, U, U, imm(1<<FRAC_BITS)); - } else { - SMULWB(AL, u, U, V); - RSB(AL, 0, U, U, imm(1<<(FRAC_BITS+prescale))); - } - UXTB16(AL, temp, pixel, 0); - if (round) { - ADD(AL, 0, u, u, imm(1<<(adjust-1))); - MOV(AL, 0, u, reg_imm(u, LSR, adjust)); - } - LDR(AL, pixellb, txPtr.reg, reg_scale_pre(offsetlb)); - MUL(AL, 0, dh, temp, u); - UXTB16(AL, temp, pixel, 8); - MUL(AL, 0, dl, temp, u); - RSB(AL, 0, k, u, imm(0x100)); - - // LB -> (1-U) * V - if (round) { - SMULBB(AL, u, U, V); - } else { - SMULWB(AL, u, U, V); - } - UXTB16(AL, temp, pixellb, 0); - if (round) { - ADD(AL, 0, u, u, imm(1<<(adjust-1))); - MOV(AL, 0, u, reg_imm(u, LSR, adjust)); - } - MLA(AL, 0, dh, temp, u, dh); - UXTB16(AL, temp, pixellb, 8); - MLA(AL, 0, dl, temp, u, dl); - SUB(AL, 0, k, k, u); - - // LT -> (1-U)*(1-V) - RSB(AL, 0, V, V, imm(1<<FRAC_BITS)); - LDR(AL, pixel, txPtr.reg); - if (round) { - SMULBB(AL, u, U, V); - } else { - SMULWB(AL, u, U, V); - } - UXTB16(AL, temp, pixel, 0); - if (round) { - ADD(AL, 0, u, u, imm(1<<(adjust-1))); - MOV(AL, 0, u, reg_imm(u, LSR, adjust)); - } - MLA(AL, 0, dh, temp, u, dh); - UXTB16(AL, temp, pixel, 8); - MLA(AL, 0, dl, temp, u, dl); - - // RT -> U*(1-V) - LDR(AL, pixel, txPtr.reg, reg_scale_pre(offsetrt)); - SUB(AL, 0, u, k, u); - UXTB16(AL, temp, pixel, 0); - MLA(AL, 0, dh, temp, u, dh); - UXTB16(AL, temp, pixel, 8); - MLA(AL, 0, dl, temp, u, dl); - - UXTB16(AL, dh, dh, 8); - UXTB16(AL, dl, dl, 8); - ORR(AL, 0, texel.reg, dh, reg_imm(dl, LSL, 8)); -} -#else void GGLAssembler::filter32( const fragment_parts_t& /*parts*/, pixel_t& texel, const texture_unit_t& /*tmu*/, @@ -1075,7 +971,6 @@ void GGLAssembler::filter32( AND(AL, 0, dl, dl, reg_imm(mask, LSL, 8)); ORR(AL, 0, texel.reg, dh, dl); } -#endif void GGLAssembler::build_texture_environment( component_t& fragment, diff --git a/include/pixelflinger/format.h b/libpixelflinger/include/pixelflinger/format.h index 82eeca4..82eeca4 100644 --- a/include/pixelflinger/format.h +++ b/libpixelflinger/include/pixelflinger/format.h diff --git a/include/pixelflinger/pixelflinger.h b/libpixelflinger/include/pixelflinger/pixelflinger.h index 8a2b442..8a2b442 100644 --- a/include/pixelflinger/pixelflinger.h +++ b/libpixelflinger/include/pixelflinger/pixelflinger.h diff --git a/include/private/pixelflinger/ggl_context.h b/libpixelflinger/include/private/pixelflinger/ggl_context.h index d43655c..d43655c 100644 --- a/include/private/pixelflinger/ggl_context.h +++ b/libpixelflinger/include/private/pixelflinger/ggl_context.h diff --git a/include/private/pixelflinger/ggl_fixed.h b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h index d0493f3..787f620 100644 --- a/include/private/pixelflinger/ggl_fixed.h +++ b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h @@ -190,7 +190,7 @@ inline int64_t gglMulii(int32_t x, int32_t y) ); return res; } -#elif defined(__mips__) +#elif defined(__mips__) && __mips_isa_rev < 6 /*inline MIPS implementations*/ inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) CONST; diff --git a/libpixelflinger/pixelflinger.cpp b/libpixelflinger/pixelflinger.cpp index ea5bc8e..fd449b2 100644 --- a/libpixelflinger/pixelflinger.cpp +++ b/libpixelflinger/pixelflinger.cpp @@ -727,18 +727,10 @@ void ggl_enable_texture2d(context_t* c, int enable) int64_t ggl_system_time() { -#if defined(HAVE_POSIX_CLOCKS) struct timespec t; t.tv_sec = t.tv_nsec = 0; clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t); return int64_t(t.tv_sec)*1000000000LL + t.tv_nsec; -#else - // we don't support the clocks here. - struct timeval t; - t.tv_sec = t.tv_usec = 0; - gettimeofday(&t, NULL); - return int64_t(t.tv_sec)*1000000000LL + int64_t(t.tv_usec)*1000LL; -#endif } // ---------------------------------------------------------------------------- diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp index 26b9a3e..3d14531 100644 --- a/libpixelflinger/scanline.cpp +++ b/libpixelflinger/scanline.cpp @@ -39,7 +39,7 @@ #include "codeflinger/ARMAssembler.h" #elif defined(__aarch64__) #include "codeflinger/Arm64Assembler.h" -#elif defined(__mips__) && !defined(__LP64__) +#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 #include "codeflinger/MIPSAssembler.h" #endif //#include "codeflinger/ARMAssemblerOptimizer.h" @@ -59,7 +59,7 @@ # define ANDROID_CODEGEN ANDROID_CODEGEN_GENERATED #endif -#if defined(__arm__) || (defined(__mips__) && !defined(__LP64__)) || defined(__aarch64__) +#if defined(__arm__) || (defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6) || defined(__aarch64__) # define ANDROID_ARM_CODEGEN 1 #else # define ANDROID_ARM_CODEGEN 0 @@ -73,7 +73,7 @@ */ #define DEBUG_NEEDS 0 -#if defined( __mips__) && !defined(__LP64__) +#if defined( __mips__) && !defined(__LP64__) && __mips_isa_rev < 6 #define ASSEMBLY_SCRATCH_SIZE 4096 #elif defined(__aarch64__) #define ASSEMBLY_SCRATCH_SIZE 8192 @@ -134,7 +134,7 @@ extern "C" void scanline_col32cb16blend_arm(uint16_t *dst, uint32_t col, size_t #elif defined(__aarch64__) extern "C" void scanline_t32cb16blend_arm64(uint16_t*, uint32_t*, size_t); extern "C" void scanline_col32cb16blend_arm64(uint16_t *dst, uint32_t col, size_t ct); -#elif defined(__mips__) && !defined(__LP64__) +#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 extern "C" void scanline_t32cb16blend_mips(uint16_t*, uint32_t*, size_t); #endif @@ -286,7 +286,7 @@ static const needs_filter_t fill16noblend = { #if ANDROID_ARM_CODEGEN -#if defined(__mips__) +#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 static CodeCache gCodeCache(32 * 1024); #elif defined(__aarch64__) static CodeCache gCodeCache(48 * 1024); @@ -2175,7 +2175,7 @@ last_one: void scanline_t32cb16blend(context_t* c) { -#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || (defined(__mips__) && !defined(__LP64__)) || defined(__aarch64__))) +#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || (defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6) || defined(__aarch64__))) int32_t x = c->iterators.xl; size_t ct = c->iterators.xr - x; int32_t y = c->iterators.y; diff --git a/libpixelflinger/tests/arch-arm64/assembler/Android.mk b/libpixelflinger/tests/arch-arm64/assembler/Android.mk index eca36ef..448d298 100644 --- a/libpixelflinger/tests/arch-arm64/assembler/Android.mk +++ b/libpixelflinger/tests/arch-arm64/assembler/Android.mk @@ -5,12 +5,15 @@ LOCAL_SRC_FILES:= \ arm64_assembler_test.cpp\ asm_test_jacket.S +# asm_test_jacket.S does not compile with Clang. +LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as + LOCAL_SHARED_LIBRARIES := \ libcutils \ libpixelflinger LOCAL_C_INCLUDES := \ - system/core/libpixelflinger + $(LOCAL_PATH)/../../.. LOCAL_MODULE:= test-pixelflinger-arm64-assembler-test diff --git a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp index 456be58..5f58797 100644 --- a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp +++ b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp @@ -409,7 +409,7 @@ void flushcache() { const long base = long(instrMem); const long curr = base + long(instrMemSize); - __builtin___clear_cache((void*)base, (void*)curr); + __builtin___clear_cache((char*)base, (char*)curr); } void dataOpTest(dataOpTest_t test, ARMAssemblerInterface *a64asm, uint32_t Rd = 0, uint32_t Rn = 1, uint32_t Rm = 2, uint32_t Rs = 3) @@ -493,16 +493,17 @@ void dataOpTest(dataOpTest_t test, ARMAssemblerInterface *a64asm, uint32_t Rd = if(i == Rd) continue; if(regs[i] != savedRegs[i]) { - printf("Test %x failed Reg(%d) tampered Expected(0x%"PRIx64")," - "Actual(0x%"PRIx64") t\n", test.id, i, savedRegs[i], regs[i]); + printf("Test %x failed Reg(%d) tampered Expected(0x%" PRIx64 ")," + "Actual(0x%" PRIx64 ") t\n", test.id, i, savedRegs[i], + regs[i]); return; } } if(test.checkRd == 1 && (uint64_t)regs[Rd] != test.postRdValue) { - printf("Test %x failed, Expected(%"PRIx64"), Actual(%"PRIx64")\n", - test.id, test.postRdValue, regs[Rd]); + printf("Test %x failed, Expected(%" PRIx64 "), Actual(%" PRIx64 ")\n", + test.id, test.postRdValue, regs[Rd]); } else if(test.checkFlag == 1 && flags[test.postFlag] == 0) { @@ -610,7 +611,7 @@ void dataTransferTest(dataTransferTest_t test, ARMAssemblerInterface *a64asm, if(regs[i] != savedRegs[i]) { printf("Test %x failed Reg(%d) tampered" - " Expected(0x%"PRIx64"), Actual(0x%"PRIx64") t\n", + " Expected(0x%" PRIx64 "), Actual(0x%" PRIx64 ") t\n", test.id, i, savedRegs[i], regs[i]); return; } @@ -619,13 +620,13 @@ void dataTransferTest(dataTransferTest_t test, ARMAssemblerInterface *a64asm, if((uint64_t)regs[Rd] != test.postRdValue) { printf("Test %x failed, " - "Expected in Rd(0x%"PRIx64"), Actual(0x%"PRIx64")\n", + "Expected in Rd(0x%" PRIx64 "), Actual(0x%" PRIx64 ")\n", test.id, test.postRdValue, regs[Rd]); } else if((uint64_t)regs[Rn] != (uint64_t)(&dataMem[test.postRnValue])) { printf("Test %x failed, " - "Expected in Rn(0x%"PRIx64"), Actual(0x%"PRIx64")\n", + "Expected in Rn(0x%" PRIx64 "), Actual(0x%" PRIx64 ")\n", test.id, test.postRnValue, regs[Rn] - (uint64_t)dataMem); } else if(test.checkMem == true) @@ -638,7 +639,7 @@ void dataTransferTest(dataTransferTest_t test, ARMAssemblerInterface *a64asm, if(value != test.postMemValue) { printf("Test %x failed, " - "Expected in Mem(0x%"PRIx64"), Actual(0x%"PRIx64")\n", + "Expected in Mem(0x%" PRIx64 "), Actual(0x%" PRIx64 ")\n", test.id, test.postMemValue, value); } else @@ -697,8 +698,8 @@ void dataTransferLDMSTM(ARMAssemblerInterface *a64asm) if(regs[j] != j) { printf("LDM/STM Test %x failed " - "Reg%d expected(0x%x) Actual(0x%"PRIx64") \n", - patterns[i],j,j,regs[j]); + "Reg%d expected(0x%x) Actual(0x%" PRIx64 ") \n", + patterns[i], j, j, regs[j]); break; } } diff --git a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk index 3368eb0..5d69203 100644 --- a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk +++ b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk @@ -5,6 +5,8 @@ LOCAL_SRC_FILES:= \ col32cb16blend_test.c \ ../../../arch-arm64/col32cb16blend.S +LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as + LOCAL_SHARED_LIBRARIES := LOCAL_C_INCLUDES := diff --git a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk index 8f62f09..d8f7e69 100644 --- a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk +++ b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk @@ -7,9 +7,6 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := -LOCAL_C_INCLUDES := \ - system/core/libpixelflinger/codeflinger - LOCAL_MODULE:= test-pixelflinger-arm64-disassembler-test LOCAL_MODULE_TAGS := tests diff --git a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk index 8e5ec5e..2c1379b 100644 --- a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk +++ b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk @@ -5,6 +5,8 @@ LOCAL_SRC_FILES:= \ t32cb16blend_test.c \ ../../../arch-arm64/t32cb16blend.S +LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as + LOCAL_SHARED_LIBRARIES := LOCAL_C_INCLUDES := diff --git a/libpixelflinger/tests/codegen/Android.mk b/libpixelflinger/tests/codegen/Android.mk index bc07015..2f9ca2f 100644 --- a/libpixelflinger/tests/codegen/Android.mk +++ b/libpixelflinger/tests/codegen/Android.mk @@ -9,7 +9,7 @@ LOCAL_SHARED_LIBRARIES := \ libpixelflinger LOCAL_C_INCLUDES := \ - system/core/libpixelflinger + $(LOCAL_PATH)/../.. LOCAL_MODULE:= test-opengl-codegen diff --git a/libpixelflinger/tests/codegen/codegen.cpp b/libpixelflinger/tests/codegen/codegen.cpp index 46c1ccc..148b6f4 100644 --- a/libpixelflinger/tests/codegen/codegen.cpp +++ b/libpixelflinger/tests/codegen/codegen.cpp @@ -9,16 +9,18 @@ #include "codeflinger/CodeCache.h" #include "codeflinger/GGLAssembler.h" #include "codeflinger/ARMAssembler.h" +#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 #include "codeflinger/MIPSAssembler.h" +#endif #include "codeflinger/Arm64Assembler.h" -#if defined(__arm__) || defined(__mips__) || defined(__aarch64__) +#if defined(__arm__) || (defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6) || defined(__aarch64__) # define ANDROID_ARM_CODEGEN 1 #else # define ANDROID_ARM_CODEGEN 0 #endif -#if defined (__mips__) +#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 #define ASSEMBLY_SCRATCH_SIZE 4096 #elif defined(__aarch64__) #define ASSEMBLY_SCRATCH_SIZE 8192 @@ -52,7 +54,7 @@ static void ggl_test_codegen(uint32_t n, uint32_t p, uint32_t t0, uint32_t t1) GGLAssembler assembler( new ARMAssembler(a) ); #endif -#if defined(__mips__) && !defined(__LP64__) +#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 GGLAssembler assembler( new ArmToMipsAssembler(a) ); #endif diff --git a/libpixelflinger/tests/gglmul/Android.mk b/libpixelflinger/tests/gglmul/Android.mk index f479fa1..75bd39e 100644 --- a/libpixelflinger/tests/gglmul/Android.mk +++ b/libpixelflinger/tests/gglmul/Android.mk @@ -7,7 +7,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := LOCAL_C_INCLUDES := \ - system/core/libpixelflinger + $(LOCAL_PATH)/../../include LOCAL_MODULE:= test-pixelflinger-gglmul diff --git a/libprocessgroup/Android.mk b/libprocessgroup/Android.mk index 051999a..ee6ba58 100644 --- a/libprocessgroup/Android.mk +++ b/libprocessgroup/Android.mk @@ -8,7 +8,6 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH)/include LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_CFLAGS := -Wall -Werror LOCAL_REQUIRED_MODULE := processgroup_cleanup -include external/libcxx/libcxx.mk include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index 49f5903..a80965f 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -19,7 +19,9 @@ #include <assert.h> #include <dirent.h> +#include <errno.h> #include <fcntl.h> +#include <inttypes.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -100,7 +102,7 @@ static int refillBuffer(struct ctx *ctx) ctx->buf_len += ret; ctx->buf[ctx->buf_len] = 0; - SLOGV("Read %d to buffer: %s", ret, ctx->buf); + SLOGV("Read %zd to buffer: %s", ret, ctx->buf); assert(ctx->buf_len <= sizeof(ctx->buf)); @@ -251,7 +253,7 @@ int killProcessGroup(uid_t uid, int initialPid, int signal) { int processes; int sleep_us = 100; - long startTime = android::uptimeMillis(); + int64_t startTime = android::uptimeMillis(); while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) { SLOGV("killed %d processes for processgroup %d\n", processes, initialPid); @@ -265,7 +267,7 @@ int killProcessGroup(uid_t uid, int initialPid, int signal) } } - SLOGV("Killed process group uid %d pid %d in %ldms, %d procs remain", uid, initialPid, + SLOGV("Killed process group uid %d pid %d in %" PRId64 "ms, %d procs remain", uid, initialPid, android::uptimeMillis()-startTime, processes); if (processes == 0) { @@ -279,12 +281,12 @@ static int mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid) { int ret; - ret = mkdir(path, 0750); + ret = mkdir(path, mode); if (ret < 0 && errno != EEXIST) { return -errno; } - ret = chown(path, AID_SYSTEM, AID_SYSTEM); + ret = chown(path, uid, gid); if (ret < 0) { ret = -errno; rmdir(path); diff --git a/libsparse/Android.mk b/libsparse/Android.mk index 0abe33d..925b98b 100644 --- a/libsparse/Android.mk +++ b/libsparse/Android.mk @@ -16,7 +16,7 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_SRC_FILES := $(libsparse_src_files) LOCAL_MODULE := libsparse_host LOCAL_STATIC_LIBRARIES := libz -LOCAL_C_INCLUDES += $(LOCAL_PATH)/include external/zlib +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include LOCAL_CFLAGS := -Werror include $(BUILD_HOST_STATIC_LIBRARY) @@ -25,7 +25,7 @@ include $(CLEAR_VARS) LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_SRC_FILES := $(libsparse_src_files) LOCAL_MODULE := libsparse -LOCAL_C_INCLUDES += $(LOCAL_PATH)/include external/zlib +LOCAL_C_INCLUDES += $(LOCAL_PATH)/include LOCAL_SHARED_LIBRARIES := \ libz LOCAL_CFLAGS := -Werror @@ -36,7 +36,7 @@ include $(CLEAR_VARS) LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_SRC_FILES := $(libsparse_src_files) LOCAL_MODULE := libsparse_static -LOCAL_C_INCLUDES += $(LOCAL_PATH)/include external/zlib +LOCAL_C_INCLUDES += $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES := libz LOCAL_CFLAGS := -Werror include $(BUILD_STATIC_LIBRARY) diff --git a/libsparse/append2simg.c b/libsparse/append2simg.c index 65e6cc2..1cf827c 100644 --- a/libsparse/append2simg.c +++ b/libsparse/append2simg.c @@ -82,7 +82,7 @@ int main(int argc, char *argv[]) exit(-1); } - sparse_output = sparse_file_import_auto(output, true); + sparse_output = sparse_file_import_auto(output, true, true); if (!sparse_output) { fprintf(stderr, "Couldn't import output file\n"); exit(-1); diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h index 8b757d2..42d4adb 100644 --- a/libsparse/include/sparse/sparse.h +++ b/libsparse/include/sparse/sparse.h @@ -234,6 +234,7 @@ struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc); * * @fd - file descriptor to read from * @crc - verify the crc of a file in the Android sparse file format + * @verbose - whether to use verbose logging * * Reads an existing sparse or normal file into a sparse file cookie. * Attempts to determine if the file is sparse or not by looking for the sparse @@ -243,7 +244,7 @@ struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc); * * Returns a new sparse file cookie on success, NULL on error. */ -struct sparse_file *sparse_file_import_auto(int fd, bool crc); +struct sparse_file *sparse_file_import_auto(int fd, bool crc, bool verbose); /** sparse_file_resparse - rechunk an existing sparse file into smaller files * diff --git a/libsparse/sparse.c b/libsparse/sparse.c index baa30cd..311678a 100644 --- a/libsparse/sparse.c +++ b/libsparse/sparse.c @@ -101,26 +101,32 @@ unsigned int sparse_count_chunks(struct sparse_file *s) return chunks; } -static void sparse_file_write_block(struct output_file *out, +static int sparse_file_write_block(struct output_file *out, struct backed_block *bb) { + int ret = -EINVAL; + switch (backed_block_type(bb)) { case BACKED_BLOCK_DATA: - write_data_chunk(out, backed_block_len(bb), backed_block_data(bb)); + ret = write_data_chunk(out, backed_block_len(bb), backed_block_data(bb)); break; case BACKED_BLOCK_FILE: - write_file_chunk(out, backed_block_len(bb), - backed_block_filename(bb), backed_block_file_offset(bb)); + ret = write_file_chunk(out, backed_block_len(bb), + backed_block_filename(bb), + backed_block_file_offset(bb)); break; case BACKED_BLOCK_FD: - write_fd_chunk(out, backed_block_len(bb), - backed_block_fd(bb), backed_block_file_offset(bb)); + ret = write_fd_chunk(out, backed_block_len(bb), + backed_block_fd(bb), + backed_block_file_offset(bb)); break; case BACKED_BLOCK_FILL: - write_fill_chunk(out, backed_block_len(bb), - backed_block_fill_val(bb)); + ret = write_fill_chunk(out, backed_block_len(bb), + backed_block_fill_val(bb)); break; } + + return ret; } static int write_all_blocks(struct sparse_file *s, struct output_file *out) @@ -128,6 +134,7 @@ static int write_all_blocks(struct sparse_file *s, struct output_file *out) struct backed_block *bb; unsigned int last_block = 0; int64_t pad; + int ret = 0; for (bb = backed_block_iter_new(s->backed_block_list); bb; bb = backed_block_iter_next(bb)) { @@ -135,7 +142,9 @@ static int write_all_blocks(struct sparse_file *s, struct output_file *out) unsigned int blocks = backed_block_block(bb) - last_block; write_skip_chunk(out, (int64_t)blocks * s->block_size); } - sparse_file_write_block(out, bb); + ret = sparse_file_write_block(out, bb); + if (ret) + return ret; last_block = backed_block_block(bb) + DIV_ROUND_UP(backed_block_len(bb), s->block_size); } @@ -229,13 +238,15 @@ static struct backed_block *move_chunks_up_to_len(struct sparse_file *from, struct backed_block *last_bb = NULL; struct backed_block *bb; struct backed_block *start; + unsigned int last_block = 0; int64_t file_len = 0; + int ret; /* - * overhead is sparse file header, initial skip chunk, split chunk, end - * skip chunk, and crc chunk. + * overhead is sparse file header, the potential end skip + * chunk and crc chunk. */ - int overhead = sizeof(sparse_header_t) + 4 * sizeof(chunk_header_t) + + int overhead = sizeof(sparse_header_t) + 2 * sizeof(chunk_header_t) + sizeof(uint32_t); len -= overhead; @@ -248,28 +259,39 @@ static struct backed_block *move_chunks_up_to_len(struct sparse_file *from, for (bb = start; bb; bb = backed_block_iter_next(bb)) { count = 0; + if (backed_block_block(bb) > last_block) + count += sizeof(chunk_header_t); + last_block = backed_block_block(bb) + + DIV_ROUND_UP(backed_block_len(bb), to->block_size); + /* will call out_counter_write to update count */ - sparse_file_write_block(out_counter, bb); + ret = sparse_file_write_block(out_counter, bb); + if (ret) { + bb = NULL; + goto out; + } if (file_len + count > len) { /* * If the remaining available size is more than 1/8th of the * requested size, split the chunk. Results in sparse files that * are at least 7/8ths of the requested size */ + file_len += sizeof(chunk_header_t); if (!last_bb || (len - file_len > (len / 8))) { backed_block_split(from->backed_block_list, bb, len - file_len); last_bb = bb; } - goto out; + goto move; } file_len += count; last_bb = bb; } -out: +move: backed_block_list_move(from->backed_block_list, to->backed_block_list, start, last_bb); +out: output_file_close(out_counter); return bb; diff --git a/libsparse/sparse_read.c b/libsparse/sparse_read.c index 8e188e9..9b10293 100644 --- a/libsparse/sparse_read.c +++ b/libsparse/sparse_read.c @@ -472,13 +472,13 @@ struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc) return s; } -struct sparse_file *sparse_file_import_auto(int fd, bool crc) +struct sparse_file *sparse_file_import_auto(int fd, bool crc, bool verbose) { struct sparse_file *s; int64_t len; int ret; - s = sparse_file_import(fd, true, crc); + s = sparse_file_import(fd, verbose, crc); if (s) { return s; } diff --git a/libsuspend/autosuspend_autosleep.c b/libsuspend/autosuspend_autosleep.c index 5451615..0d31e74 100644 --- a/libsuspend/autosuspend_autosleep.c +++ b/libsuspend/autosuspend_autosleep.c @@ -84,7 +84,6 @@ struct autosuspend_ops autosuspend_autosleep_ops = { struct autosuspend_ops *autosuspend_autosleep_init(void) { - int ret; char buf[80]; autosleep_fd = open(SYS_POWER_AUTOSLEEP, O_WRONLY); diff --git a/libsync/sync.c b/libsync/sync.c index 4892866..d73bb11 100644 --- a/libsync/sync.c +++ b/libsync/sync.c @@ -17,6 +17,7 @@ */ #include <fcntl.h> +#include <malloc.h> #include <stdint.h> #include <string.h> diff --git a/libsync/tests/Android.mk b/libsync/tests/Android.mk index ad20e50..8137c7a 100644 --- a/libsync/tests/Android.mk +++ b/libsync/tests/Android.mk @@ -17,10 +17,8 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -include external/libcxx/libcxx.mk LOCAL_CLANG := true LOCAL_MODULE := sync-unit-tests -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers -Wno-sign-compare LOCAL_SHARED_LIBRARIES += libsync LOCAL_STATIC_LIBRARIES += libgtest_main diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk index 246f954..7bf53e3 100644 --- a/libsysutils/Android.mk +++ b/libsysutils/Android.mk @@ -1,5 +1,3 @@ -ifneq ($(BUILD_TINY_ANDROID),true) - LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) @@ -16,12 +14,12 @@ LOCAL_SRC_FILES:= \ LOCAL_MODULE:= libsysutils -LOCAL_C_INCLUDES := - LOCAL_CFLAGS := -Werror -LOCAL_SHARED_LIBRARIES := libcutils liblog +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + liblog \ + libnl include $(BUILD_SHARED_LIBRARY) -endif diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp index 9d596ef..909df86 100644 --- a/libsysutils/src/NetlinkEvent.cpp +++ b/libsysutils/src/NetlinkEvent.cpp @@ -32,13 +32,21 @@ #include <linux/if_addr.h> #include <linux/if_link.h> #include <linux/netfilter/nfnetlink.h> +#include <linux/netfilter/nfnetlink_log.h> #include <linux/netfilter_ipv4/ipt_ULOG.h> + /* From kernel's net/netfilter/xt_quota2.c */ -const int QLOG_NL_EVENT = 112; +const int LOCAL_QLOG_NL_EVENT = 112; +const int LOCAL_NFLOG_PACKET = NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET; #include <linux/netlink.h> #include <linux/rtnetlink.h> +#include <netlink/attr.h> +#include <netlink/genl/genl.h> +#include <netlink/handlers.h> +#include <netlink/msg.h> + const int NetlinkEvent::NlActionUnknown = 0; const int NetlinkEvent::NlActionAdd = 1; const int NetlinkEvent::NlActionRemove = 2; @@ -95,7 +103,8 @@ static const char *rtMessageName(int type) { NL_EVENT_RTM_NAME(RTM_NEWROUTE); NL_EVENT_RTM_NAME(RTM_DELROUTE); NL_EVENT_RTM_NAME(RTM_NEWNDUSEROPT); - NL_EVENT_RTM_NAME(QLOG_NL_EVENT); + NL_EVENT_RTM_NAME(LOCAL_QLOG_NL_EVENT); + NL_EVENT_RTM_NAME(LOCAL_NFLOG_PACKET); default: return NULL; } @@ -272,6 +281,41 @@ bool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) { } /* + * Parse a LOCAL_NFLOG_PACKET message. + */ +bool NetlinkEvent::parseNfPacketMessage(struct nlmsghdr *nh) { + int uid = -1; + int len = 0; + char* raw = NULL; + + struct nlattr *uid_attr = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_UID); + if (uid_attr) { + uid = ntohl(nla_get_u32(uid_attr)); + } + + struct nlattr *payload = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_PAYLOAD); + if (payload) { + /* First 256 bytes is plenty */ + len = nla_len(payload); + if (len > 256) len = 256; + raw = (char*) nla_data(payload); + } + + char* hex = (char*) calloc(1, 5 + (len * 2)); + strcpy(hex, "HEX="); + for (int i = 0; i < len; i++) { + hex[4 + (i * 2)] = "0123456789abcdef"[(raw[i] >> 4) & 0xf]; + hex[5 + (i * 2)] = "0123456789abcdef"[raw[i] & 0xf]; + } + + asprintf(&mParams[0], "UID=%d", uid); + mParams[1] = hex; + mSubsystem = strdup("strict"); + mAction = NlActionChange; + return true; +} + +/* * Parse a RTM_NEWROUTE or RTM_DELROUTE message. */ bool NetlinkEvent::parseRtMessage(const struct nlmsghdr *nh) { @@ -478,7 +522,7 @@ bool NetlinkEvent::parseNdUserOptMessage(const struct nlmsghdr *nh) { * TODO: consider only ever looking at the first message. */ bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { - const struct nlmsghdr *nh; + struct nlmsghdr *nh; for (nh = (struct nlmsghdr *) buffer; NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE); @@ -493,7 +537,7 @@ bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { if (parseIfInfoMessage(nh)) return true; - } else if (nh->nlmsg_type == QLOG_NL_EVENT) { + } else if (nh->nlmsg_type == LOCAL_QLOG_NL_EVENT) { if (parseUlogPacketMessage(nh)) return true; @@ -511,6 +555,10 @@ bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { if (parseNdUserOptMessage(nh)) return true; + } else if (nh->nlmsg_type == LOCAL_NFLOG_PACKET) { + if (parseNfPacketMessage(nh)) + return true; + } } @@ -588,7 +636,8 @@ bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) { } bool NetlinkEvent::decode(char *buffer, int size, int format) { - if (format == NetlinkListener::NETLINK_FORMAT_BINARY) { + if (format == NetlinkListener::NETLINK_FORMAT_BINARY + || format == NetlinkListener::NETLINK_FORMAT_BINARY_UNICAST) { return parseBinaryNetlinkMessage(buffer, size); } else { return parseAsciiNetlinkMessage(buffer, size); diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp index 81c5cc2..637aa1e 100644 --- a/libsysutils/src/NetlinkListener.cpp +++ b/libsysutils/src/NetlinkListener.cpp @@ -47,8 +47,13 @@ bool NetlinkListener::onDataAvailable(SocketClient *cli) ssize_t count; uid_t uid = -1; - count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv( - socket, mBuffer, sizeof(mBuffer), &uid)); + bool require_group = true; + if (mFormat == NETLINK_FORMAT_BINARY_UNICAST) { + require_group = false; + } + + count = TEMP_FAILURE_RETRY(uevent_kernel_recv(socket, + mBuffer, sizeof(mBuffer), require_group, &uid)); if (count < 0) { if (uid > 0) LOG_EVENT_INT(65537, uid); diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp index d3ce8f5..bb9b6a1 100644 --- a/libsysutils/src/SocketClient.cpp +++ b/libsysutils/src/SocketClient.cpp @@ -1,5 +1,6 @@ #include <alloca.h> #include <errno.h> +#include <malloc.h> #include <pthread.h> #include <signal.h> #include <string.h> @@ -220,7 +221,9 @@ int SocketClient::sendDataLockedv(struct iovec *iov, int iovcnt) { sigaction(SIGPIPE, &old_action, &new_action); - errno = e; + if (e != 0) { + errno = e; + } return ret; } diff --git a/libutils/Android.mk b/libutils/Android.mk index 035846b..63a8d70 100644 --- a/libutils/Android.mk +++ b/libutils/Android.mk @@ -14,9 +14,6 @@ LOCAL_PATH:= $(call my-dir) -# libutils is a little unique: It's built twice, once for the host -# and once for the device. - commonSources:= \ BasicHashtable.cpp \ BlobCache.cpp \ @@ -42,7 +39,7 @@ commonSources:= \ Tokenizer.cpp \ Unicode.cpp \ VectorImpl.cpp \ - misc.cpp + misc.cpp \ host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) -Werror @@ -53,13 +50,6 @@ host_commonCflags += -DMB_CUR_MAX=1 endif endif -host_commonLdlibs := - -ifeq ($(TARGET_OS),linux) -host_commonLdlibs += -lrt -ldl -endif - - # For the host # ===================================================== include $(CLEAR_VARS) @@ -67,6 +57,9 @@ LOCAL_SRC_FILES:= $(commonSources) ifeq ($(HOST_OS), linux) LOCAL_SRC_FILES += Looper.cpp endif +ifeq ($(HOST_OS),darwin) +LOCAL_CFLAGS += -Wno-unused-parameter +endif LOCAL_MODULE:= libutils LOCAL_STATIC_LIBRARIES := liblog LOCAL_CFLAGS += $(host_commonCflags) @@ -91,10 +84,6 @@ LOCAL_CFLAGS += -DALIGN_DOUBLE endif LOCAL_CFLAGS += -Werror -LOCAL_C_INCLUDES += \ - bionic/libc \ - external/zlib - LOCAL_STATIC_LIBRARIES := \ libcutils @@ -103,8 +92,6 @@ LOCAL_SHARED_LIBRARIES := \ liblog \ libdl -include external/stlport/libstlport.mk - LOCAL_MODULE:= libutils LOCAL_C_INCLUDES += external/safe-iop/include include $(BUILD_STATIC_LIBRARY) @@ -122,8 +109,6 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_CFLAGS := -Werror LOCAL_C_INCLUDES += external/safe-iop/include -include external/stlport/libstlport.mk - include $(BUILD_SHARED_LIBRARY) # Include subdirectory makefiles @@ -142,8 +127,5 @@ LOCAL_SHARED_LIBRARIES := liblog LOCAL_SRC_FILES := SharedBufferTest.cpp include $(BUILD_HOST_NATIVE_TEST) -# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework -# team really wants is to build the stuff defined by this makefile. -ifeq (,$(ONE_SHOT_MAKEFILE)) +# Build the tests in the tests/ subdirectory. include $(call first-makefiles-under,$(LOCAL_PATH)) -endif diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp index f8d6bda..91e45d8 100644 --- a/libutils/FileMap.cpp +++ b/libutils/FileMap.cpp @@ -23,7 +23,7 @@ #include <utils/FileMap.h> #include <utils/Log.h> -#if defined(HAVE_WIN32_FILEMAP) && !defined(__USE_MINGW_ANSI_STDIO) +#if defined(__MINGW32__) && !defined(__USE_MINGW_ANSI_STDIO) # define PRId32 "I32d" # define PRIx32 "I32x" # define PRId64 "I64d" @@ -33,7 +33,7 @@ #include <stdio.h> #include <stdlib.h> -#ifdef HAVE_POSIX_FILEMAP +#if !defined(__MINGW32__) #include <sys/mman.h> #endif @@ -48,7 +48,7 @@ using namespace android; // Constructor. Create an empty object. FileMap::FileMap(void) - : mRefCount(1), mFileName(NULL), mBasePtr(NULL), mBaseLength(0), + : mFileName(NULL), mBasePtr(NULL), mBaseLength(0), mDataPtr(NULL), mDataLength(0) { } @@ -56,20 +56,10 @@ FileMap::FileMap(void) // Destructor. FileMap::~FileMap(void) { - assert(mRefCount == 0); - - //printf("+++ removing FileMap %p %zu\n", mDataPtr, mDataLength); - - mRefCount = -100; // help catch double-free if (mFileName != NULL) { free(mFileName); } -#ifdef HAVE_POSIX_FILEMAP - if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) { - ALOGD("munmap(%p, %zu) failed\n", mBasePtr, mBaseLength); - } -#endif -#ifdef HAVE_WIN32_FILEMAP +#if defined(__MINGW32__) if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) { ALOGD("UnmapViewOfFile(%p) failed, error = %" PRId32 "\n", mBasePtr, GetLastError() ); @@ -77,6 +67,10 @@ FileMap::~FileMap(void) if (mFileMapping != INVALID_HANDLE_VALUE) { CloseHandle(mFileMapping); } +#else + if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) { + ALOGD("munmap(%p, %zu) failed\n", mBasePtr, mBaseLength); + } #endif } @@ -90,7 +84,7 @@ FileMap::~FileMap(void) bool FileMap::create(const char* origFileName, int fd, off64_t offset, size_t length, bool readOnly) { -#ifdef HAVE_WIN32_FILEMAP +#if defined(__MINGW32__) int adjust; off64_t adjOffset; size_t adjLength; @@ -128,35 +122,27 @@ bool FileMap::create(const char* origFileName, int fd, off64_t offset, size_t le mFileMapping = INVALID_HANDLE_VALUE; return false; } -#endif -#ifdef HAVE_POSIX_FILEMAP +#else // !defined(__MINGW32__) int prot, flags, adjust; off64_t adjOffset; size_t adjLength; void* ptr; - assert(mRefCount == 1); assert(fd >= 0); assert(offset >= 0); assert(length > 0); // init on first use if (mPageSize == -1) { -#if NOT_USING_KLIBC mPageSize = sysconf(_SC_PAGESIZE); if (mPageSize == -1) { ALOGE("could not get _SC_PAGESIZE\n"); return false; } -#else - // this holds for Linux, Darwin, Cygwin, and doesn't pain the ARM - mPageSize = 4096; -#endif } - adjust = offset % mPageSize; -try_again: + adjust = offset % mPageSize; adjOffset = offset - adjust; adjLength = length + adjust; @@ -167,19 +153,12 @@ try_again: ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset); if (ptr == MAP_FAILED) { - // Cygwin does not seem to like file mapping files from an offset. - // So if we fail, try again with offset zero - if (adjOffset > 0) { - adjust = offset; - goto try_again; - } - ALOGE("mmap(%lld,%zu) failed: %s\n", (long long)adjOffset, adjLength, strerror(errno)); return false; } mBasePtr = ptr; -#endif // HAVE_POSIX_FILEMAP +#endif // !defined(__MINGW32__) mFileName = origFileName != NULL ? strdup(origFileName) : NULL; mBaseLength = adjLength; @@ -196,9 +175,9 @@ try_again: } // Provide guidance to the system. +#if !defined(_WIN32) int FileMap::advise(MapAdvice advice) { -#if HAVE_MADVISE int cc, sysAdvice; switch (advice) { @@ -216,7 +195,11 @@ int FileMap::advise(MapAdvice advice) if (cc != 0) ALOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno)); return cc; +} + #else +int FileMap::advise(MapAdvice /* advice */) +{ return -1; -#endif // HAVE_MADVISE } +#endif diff --git a/libutils/String8.cpp b/libutils/String8.cpp index d4f5c78..ad65fdb 100644 --- a/libutils/String8.cpp +++ b/libutils/String8.cpp @@ -430,7 +430,7 @@ bool String8::removeAll(const char* other) { next = len; } - memcpy(buf + tail, buf + index + skip, next - index - skip); + memmove(buf + tail, buf + index + skip, next - index - skip); tail += next - index - skip; index = next; } diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp index dbad581..ac3dd98 100644 --- a/libutils/SystemClock.cpp +++ b/libutils/SystemClock.cpp @@ -68,7 +68,7 @@ int64_t elapsedRealtime() */ #define DEBUG_TIMESTAMP 0 -#if DEBUG_TIMESTAMP && defined(ARCH_ARM) +#if DEBUG_TIMESTAMP && defined(__arm__) static inline void checkTimeStamps(int64_t timestamp, int64_t volatile *prevTimestampPtr, int volatile *prevMethodPtr, diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp index b09d510..1e014c6 100644 --- a/libutils/Threads.cpp +++ b/libutils/Threads.cpp @@ -24,21 +24,18 @@ #include <stdlib.h> #include <unistd.h> -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) # include <pthread.h> # include <sched.h> # include <sys/resource.h> -#ifdef HAVE_ANDROID_OS -# include <private/bionic_pthread.h> -#endif -#elif defined(HAVE_WIN32_THREADS) +#else # include <windows.h> # include <stdint.h> # include <process.h> # define HAVE_CREATETHREAD // Cygwin, vs. HAVE__BEGINTHREADEX for MinGW #endif -#if defined(HAVE_PRCTL) +#if defined(__linux__) #include <sys/prctl.h> #endif @@ -62,7 +59,7 @@ using namespace android; // ---------------------------------------------------------------------------- -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) // ---------------------------------------------------------------------------- /* @@ -93,7 +90,7 @@ struct thread_data_t { } else { set_sched_policy(0, SP_FOREGROUND); } - + if (name) { androidSetThreadName(name); free(name); @@ -103,7 +100,7 @@ struct thread_data_t { }; void androidSetThreadName(const char* name) { -#if defined(HAVE_PRCTL) +#if defined(__linux__) // Mac OS doesn't have this, and we build libutil for the host too int hasAt = 0; int hasDot = 0; @@ -130,7 +127,7 @@ int androidCreateRawThreadEtc(android_thread_func_t entryFunction, size_t threadStackSize, android_thread_id_t *threadId) { - pthread_attr_t attr; + pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); @@ -149,14 +146,14 @@ int androidCreateRawThreadEtc(android_thread_func_t entryFunction, t->entryFunction = entryFunction; t->userData = userData; entryFunction = (android_thread_func_t)&thread_data_t::trampoline; - userData = t; + userData = t; } #endif if (threadStackSize) { pthread_attr_setstacksize(&attr, threadStackSize); } - + errno = 0; pthread_t thread; int result = pthread_create(&thread, &attr, @@ -191,7 +188,7 @@ android_thread_id_t androidGetThreadId() } // ---------------------------------------------------------------------------- -#elif defined(HAVE_WIN32_THREADS) +#else // !defined(_WIN32) // ---------------------------------------------------------------------------- /* @@ -271,9 +268,7 @@ android_thread_id_t androidGetThreadId() } // ---------------------------------------------------------------------------- -#else -#error "Threads not supported" -#endif +#endif // !defined(_WIN32) // ---------------------------------------------------------------------------- @@ -306,21 +301,12 @@ void androidSetCreateThreadFunc(android_create_thread_fn func) gCreateThreadFn = func; } -pid_t androidGetTid() -{ -#ifdef HAVE_GETTID - return gettid(); -#else - return getpid(); -#endif -} - #ifdef HAVE_ANDROID_OS int androidSetThreadPriority(pid_t tid, int pri) { int rc = 0; - -#if defined(HAVE_PTHREADS) + +#if !defined(_WIN32) int lasterr = 0; if (pri >= ANDROID_PRIORITY_BACKGROUND) { @@ -339,12 +325,12 @@ int androidSetThreadPriority(pid_t tid, int pri) errno = lasterr; } #endif - + return rc; } int androidGetThreadPriority(pid_t tid) { -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) return getpriority(PRIO_PROCESS, tid); #else return ANDROID_PRIORITY_NORMAL; @@ -361,9 +347,9 @@ namespace android { * =========================================================================== */ -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) // implemented as inlines in threads.h -#elif defined(HAVE_WIN32_THREADS) +#else Mutex::Mutex() { @@ -425,9 +411,7 @@ status_t Mutex::tryLock() return (dwWaitResult == WAIT_OBJECT_0) ? 0 : -1; } -#else -#error "Somebody forgot to implement threads for this platform." -#endif +#endif // !defined(_WIN32) /* @@ -436,9 +420,9 @@ status_t Mutex::tryLock() * =========================================================================== */ -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) // implemented as inlines in threads.h -#elif defined(HAVE_WIN32_THREADS) +#else /* * Windows doesn't have a condition variable solution. It's possible @@ -486,7 +470,7 @@ typedef struct WinCondition { //printf("+++ wait: incr waitersCount to %d (tid=%ld)\n", // condState->waitersCount, getThreadId()); LeaveCriticalSection(&condState->waitersCountLock); - + DWORD timeout = INFINITE; if (abstime) { nsecs_t reltime = *abstime - systemTime(); @@ -494,27 +478,27 @@ typedef struct WinCondition { reltime = 0; timeout = reltime/1000000; } - + // Atomically release the external mutex and wait on the semaphore. DWORD res = SignalObjectAndWait(hMutex, condState->sema, timeout, FALSE); - + //printf("+++ wait: awake (tid=%ld)\n", getThreadId()); - + // Reacquire lock to avoid race conditions. EnterCriticalSection(&condState->waitersCountLock); - + // No longer waiting. condState->waitersCount--; - + // Check to see if we're the last waiter after a broadcast. bool lastWaiter = (condState->wasBroadcast && condState->waitersCount == 0); - + //printf("+++ wait: lastWaiter=%d (wasBc=%d wc=%d)\n", // lastWaiter, condState->wasBroadcast, condState->waitersCount); - + LeaveCriticalSection(&condState->waitersCountLock); - + // If we're the last waiter thread during this particular broadcast // then signal broadcast() that we're all awake. It'll drop the // internal mutex. @@ -530,11 +514,11 @@ typedef struct WinCondition { // Grab the internal mutex. WaitForSingleObject(condState->internalMutex, INFINITE); } - + // Release the internal and grab the external. ReleaseMutex(condState->internalMutex); WaitForSingleObject(hMutex, INFINITE); - + return res == WAIT_OBJECT_0 ? NO_ERROR : -1; } } WinCondition; @@ -577,7 +561,7 @@ status_t Condition::wait(Mutex& mutex) { WinCondition* condState = (WinCondition*) mState; HANDLE hMutex = (HANDLE) mutex.mState; - + return ((WinCondition*)mState)->wait(condState, hMutex, NULL); } @@ -659,9 +643,7 @@ void Condition::broadcast() ReleaseMutex(condState->internalMutex); } -#else -#error "condition variables not supported on this platform" -#endif +#endif // !defined(_WIN32) // ---------------------------------------------------------------------------- @@ -704,7 +686,7 @@ status_t Thread::run(const char* name, int32_t priority, size_t stack) mStatus = NO_ERROR; mExitPending = false; mThread = thread_id_t(-1); - + // hold a strong reference on ourself mHoldSelf = this; @@ -718,7 +700,7 @@ status_t Thread::run(const char* name, int32_t priority, size_t stack) res = androidCreateRawThreadEtc(_threadLoop, this, name, priority, stack, &mThread); } - + if (res == false) { mStatus = UNKNOWN_ERROR; // something happened! mRunning = false; @@ -727,7 +709,7 @@ status_t Thread::run(const char* name, int32_t priority, size_t stack) return UNKNOWN_ERROR; } - + // Do not refer to mStatus here: The thread is already running (may, in fact // already have exited with a valid mStatus result). The NO_ERROR indication // here merely indicates successfully starting the thread and does not @@ -791,14 +773,14 @@ int Thread::_threadLoop(void* user) break; } } - + // Release our strong reference, to let a chance to the thread // to die a peaceful death. strong.clear(); // And immediately, re-acquire a strong reference for the next loop strong = weak.promote(); } while(strong != 0); - + return 0; } @@ -819,7 +801,7 @@ status_t Thread::requestExitAndWait() return WOULD_BLOCK; } - + mExitPending = true; while (mRunning == true) { @@ -864,7 +846,7 @@ pid_t Thread::getTid() const pid_t tid; if (mRunning) { pthread_t pthread = android_thread_id_t_to_pthread(mThread); - tid = __pthread_gettid(pthread); + tid = pthread_gettid_np(pthread); } else { ALOGW("Thread (this=%p): getTid() is undefined before run()", this); tid = -1; diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp index 4687d4d..fb70e15 100644 --- a/libutils/Timers.cpp +++ b/libutils/Timers.cpp @@ -18,19 +18,10 @@ // Timer functions. // #include <utils/Timers.h> -#include <utils/Log.h> -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> +#include <limits.h> #include <sys/time.h> #include <time.h> -#include <errno.h> -#include <limits.h> - -#ifdef HAVE_WIN32_THREADS -#include <windows.h> -#endif #if defined(HAVE_ANDROID_OS) nsecs_t systemTime(int clock) diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp index 7067533..610002f 100644 --- a/libutils/Tokenizer.cpp +++ b/libutils/Tokenizer.cpp @@ -43,9 +43,7 @@ Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, } Tokenizer::~Tokenizer() { - if (mFileMap) { - mFileMap->release(); - } + delete mFileMap; if (mOwnBuffer) { delete[] mBuffer; } @@ -74,7 +72,7 @@ status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) { fileMap->advise(FileMap::SEQUENTIAL); buffer = static_cast<char*>(fileMap->getDataPtr()); } else { - fileMap->release(); + delete fileMap; fileMap = NULL; // Fall back to reading into a buffer since we can't mmap files in sysfs. diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp index 378d2a7..fb876c9 100644 --- a/libutils/Unicode.cpp +++ b/libutils/Unicode.cpp @@ -24,17 +24,10 @@ # undef nhtos # undef htons -# ifdef HAVE_LITTLE_ENDIAN -# define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) ) -# define htonl(x) ntohl(x) -# define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) ) -# define htons(x) ntohs(x) -# else -# define ntohl(x) (x) -# define htonl(x) (x) -# define ntohs(x) (x) -# define htons(x) (x) -# endif +# define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) ) +# define htonl(x) ntohl(x) +# define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) ) +# define htons(x) ntohs(x) #else # include <netinet/in.h> #endif @@ -47,8 +40,9 @@ static const char32_t kByteMark = 0x00000080; // Surrogates aren't valid for UTF-32 characters, so define some // constants that will let us screen them out. static const char32_t kUnicodeSurrogateHighStart = 0x0000D800; -static const char32_t kUnicodeSurrogateHighEnd = 0x0000DBFF; -static const char32_t kUnicodeSurrogateLowStart = 0x0000DC00; +// Unused, here for completeness: +// static const char32_t kUnicodeSurrogateHighEnd = 0x0000DBFF; +// static const char32_t kUnicodeSurrogateLowStart = 0x0000DC00; static const char32_t kUnicodeSurrogateLowEnd = 0x0000DFFF; static const char32_t kUnicodeSurrogateStart = kUnicodeSurrogateHighStart; static const char32_t kUnicodeSurrogateEnd = kUnicodeSurrogateLowEnd; diff --git a/libutils/misc.cpp b/libutils/misc.cpp index 58eb499..ed1ba23 100644 --- a/libutils/misc.cpp +++ b/libutils/misc.cpp @@ -27,7 +27,7 @@ #include <errno.h> #include <stdio.h> -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) # include <pthread.h> #endif @@ -42,13 +42,13 @@ struct sysprop_change_callback_info { int priority; }; -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) static pthread_mutex_t gSyspropMutex = PTHREAD_MUTEX_INITIALIZER; static Vector<sysprop_change_callback_info>* gSyspropList = NULL; #endif void add_sysprop_change_callback(sysprop_change_callback cb, int priority) { -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) pthread_mutex_lock(&gSyspropMutex); if (gSyspropList == NULL) { gSyspropList = new Vector<sysprop_change_callback_info>(); @@ -72,7 +72,7 @@ void add_sysprop_change_callback(sysprop_change_callback cb, int priority) { } void report_sysprop_change() { -#if defined(HAVE_PTHREADS) +#if !defined(_WIN32) pthread_mutex_lock(&gSyspropMutex); Vector<sysprop_change_callback_info> listeners; if (gSyspropList != NULL) { diff --git a/libutils/tests/Android.mk b/libutils/tests/Android.mk index caedaff..7cfad89 100644 --- a/libutils/tests/Android.mk +++ b/libutils/tests/Android.mk @@ -1,9 +1,27 @@ +# +# Copyright (C) 2014 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. +# + # Build the unit tests. LOCAL_PATH := $(call my-dir) + include $(CLEAR_VARS) -# Build the unit tests. -test_src_files := \ +LOCAL_MODULE := libutils_tests + +LOCAL_SRC_FILES := \ BasicHashtable_test.cpp \ BlobCache_test.cpp \ BitSet_test.cpp \ @@ -11,24 +29,12 @@ test_src_files := \ LruCache_test.cpp \ String8_test.cpp \ Unicode_test.cpp \ - Vector_test.cpp + Vector_test.cpp \ -shared_libraries := \ +LOCAL_SHARED_LIBRARIES := \ libz \ liblog \ libcutils \ libutils \ - libstlport - -static_libraries := \ - libgtest \ - libgtest_main -$(foreach file,$(test_src_files), \ - $(eval include $(CLEAR_VARS)) \ - $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ - $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ - $(eval LOCAL_SRC_FILES := $(file)) \ - $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ - $(eval include $(BUILD_NATIVE_TEST)) \ -) +include $(BUILD_NATIVE_TEST) diff --git a/libutils/tests/BasicHashtable_test.cpp b/libutils/tests/BasicHashtable_test.cpp index a61b1e1..4b3a717 100644 --- a/libutils/tests/BasicHashtable_test.cpp +++ b/libutils/tests/BasicHashtable_test.cpp @@ -21,12 +21,12 @@ #include <gtest/gtest.h> #include <unistd.h> -namespace android { +namespace { typedef int SimpleKey; typedef int SimpleValue; -typedef key_value_pair_t<SimpleKey, SimpleValue> SimpleEntry; -typedef BasicHashtable<SimpleKey, SimpleEntry> SimpleHashtable; +typedef android::key_value_pair_t<SimpleKey, SimpleValue> SimpleEntry; +typedef android::BasicHashtable<SimpleKey, SimpleEntry> SimpleHashtable; struct ComplexKey { int k; @@ -56,10 +56,6 @@ struct ComplexKey { ssize_t ComplexKey::instanceCount = 0; -template<> inline hash_t hash_type(const ComplexKey& value) { - return hash_type(value.k); -} - struct ComplexValue { int v; @@ -80,9 +76,18 @@ struct ComplexValue { ssize_t ComplexValue::instanceCount = 0; +} // namespace + + +namespace android { + typedef key_value_pair_t<ComplexKey, ComplexValue> ComplexEntry; typedef BasicHashtable<ComplexKey, ComplexEntry> ComplexHashtable; +template<> inline hash_t hash_type(const ComplexKey& value) { + return hash_type(value.k); +} + class BasicHashtableTest : public testing::Test { protected: virtual void SetUp() { diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp index bcbea32..6534211 100644 --- a/libutils/tests/LruCache_test.cpp +++ b/libutils/tests/LruCache_test.cpp @@ -20,7 +20,7 @@ #include <cutils/log.h> #include <gtest/gtest.h> -namespace android { +namespace { typedef int SimpleKey; typedef const char* StringValue; @@ -53,10 +53,6 @@ struct ComplexKey { ssize_t ComplexKey::instanceCount = 0; -template<> inline hash_t hash_type(const ComplexKey& value) { - return hash_type(value.k); -} - struct ComplexValue { int v; @@ -77,8 +73,17 @@ struct ComplexValue { ssize_t ComplexValue::instanceCount = 0; +} // namespace + + +namespace android { + typedef LruCache<ComplexKey, ComplexValue> ComplexCache; +template<> inline android::hash_t hash_type(const ComplexKey& value) { + return hash_type(value.k); +} + class EntryRemovedCallback : public OnEntryRemoved<SimpleKey, StringValue> { public: EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(NULL) { } diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk index d23a94f..a3087ee 100644 --- a/libziparchive/Android.mk +++ b/libziparchive/Android.mk @@ -14,32 +14,23 @@ # limitations under the License. LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -source_files := \ - zip_archive.h \ - zip_archive.cc -includes := external/zlib +source_files := zip_archive.cc +include $(CLEAR_VARS) LOCAL_CPP_EXTENSION := .cc LOCAL_SRC_FILES := ${source_files} - LOCAL_STATIC_LIBRARIES := libz -LOCAL_SHARED_LIBRARIES := libutils +LOCAL_SHARED_LIBRARIES := libutils libbase LOCAL_MODULE:= libziparchive - -LOCAL_C_INCLUDES += ${includes} -LOCAL_CFLAGS := -Werror +LOCAL_CFLAGS := -Werror -Wall +LOCAL_CPPFLAGS := -Wold-style-cast include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) -LOCAL_MODULE := libziparchive LOCAL_CPP_EXTENSION := .cc LOCAL_SRC_FILES := ${source_files} -LOCAL_C_INCLUDES += ${includes} - -LOCAL_STATIC_LIBRARIES := libz libutils +LOCAL_STATIC_LIBRARIES := libz libutils libbase LOCAL_MODULE:= libziparchive-host LOCAL_CFLAGS := -Werror ifneq ($(strip $(USE_MINGW)),) @@ -49,29 +40,34 @@ LOCAL_MULTILIB := both include $(BUILD_HOST_STATIC_LIBRARY) include $(CLEAR_VARS) +LOCAL_CPP_EXTENSION := .cc +LOCAL_SRC_FILES := ${source_files} +LOCAL_STATIC_LIBRARIES := libz libutils +LOCAL_SHARED_LIBRARIES := liblog libbase +LOCAL_MODULE:= libziparchive-host +LOCAL_CFLAGS := -Werror +LOCAL_MULTILIB := both +include $(BUILD_HOST_SHARED_LIBRARY) + +# Tests. +include $(CLEAR_VARS) LOCAL_MODULE := ziparchive-tests LOCAL_CPP_EXTENSION := .cc -LOCAL_CFLAGS += \ - -DGTEST_OS_LINUX_ANDROID \ - -DGTEST_HAS_STD_STRING \ - -Werror -LOCAL_SRC_FILES := zip_archive_test.cc -LOCAL_SHARED_LIBRARIES := liblog -LOCAL_STATIC_LIBRARIES := libziparchive libz libgtest libgtest_main libutils +LOCAL_CFLAGS := -Werror +LOCAL_SRC_FILES := zip_archive_test.cc entry_name_utils_test.cc +LOCAL_SHARED_LIBRARIES := liblog libbase +LOCAL_STATIC_LIBRARIES := libziparchive libz libutils include $(BUILD_NATIVE_TEST) include $(CLEAR_VARS) LOCAL_MODULE := ziparchive-tests-host LOCAL_CPP_EXTENSION := .cc LOCAL_CFLAGS += \ - -DGTEST_OS_LINUX \ - -DGTEST_HAS_STD_STRING \ - -Werror -LOCAL_SRC_FILES := zip_archive_test.cc -LOCAL_STATIC_LIBRARIES := libziparchive-host \ - libz \ - libgtest_host \ - libgtest_main_host \ - liblog \ - libutils + -Werror \ + -Wno-unnamed-type-template-args +LOCAL_SRC_FILES := zip_archive_test.cc entry_name_utils_test.cc +LOCAL_SHARED_LIBRARIES := libziparchive-host liblog libbase +LOCAL_STATIC_LIBRARIES := \ + libz \ + libutils include $(BUILD_HOST_NATIVE_TEST) diff --git a/libziparchive/entry_name_utils-inl.h b/libziparchive/entry_name_utils-inl.h new file mode 100644 index 0000000..ddbc286 --- /dev/null +++ b/libziparchive/entry_name_utils-inl.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2014 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 LIBZIPARCHIVE_ENTRY_NAME_UTILS_INL_H_ +#define LIBZIPARCHIVE_ENTRY_NAME_UTILS_INL_H_ + +#include <stddef.h> +#include <stdint.h> + +// Check if |length| bytes at |entry_name| constitute a valid entry name. +// Entry names must be valid UTF-8 and must not contain '0'. +inline bool IsValidEntryName(const uint8_t* entry_name, const size_t length) { + for (size_t i = 0; i < length; ++i) { + const uint8_t byte = entry_name[i]; + if (byte == 0) { + return false; + } else if ((byte & 0x80) == 0) { + // Single byte sequence. + continue; + } else if ((byte & 0xc0) == 0x80 || (byte & 0xfe) == 0xfe) { + // Invalid sequence. + return false; + } else { + // 2-5 byte sequences. + for (uint8_t first = byte << 1; first & 0x80; first <<= 1) { + ++i; + + // Missing continuation byte.. + if (i == length) { + return false; + } + + // Invalid continuation byte. + const uint8_t continuation_byte = entry_name[i]; + if ((continuation_byte & 0xc0) != 0x80) { + return false; + } + } + } + } + + return true; +} + + +#endif // LIBZIPARCHIVE_ENTRY_NAME_UTILS_INL_H_ diff --git a/libziparchive/entry_name_utils_test.cc b/libziparchive/entry_name_utils_test.cc new file mode 100644 index 0000000..20715bb --- /dev/null +++ b/libziparchive/entry_name_utils_test.cc @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2014 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 "entry_name_utils-inl.h" + +#include <gtest/gtest.h> + +TEST(entry_name_utils, NullChars) { + // 'A', 'R', '\0', 'S', 'E' + const uint8_t zeroes[] = { 0x41, 0x52, 0x00, 0x53, 0x45 }; + ASSERT_FALSE(IsValidEntryName(zeroes, sizeof(zeroes))); + + const uint8_t zeroes_continuation_chars[] = { 0xc2, 0xa1, 0xc2, 0x00 }; + ASSERT_FALSE(IsValidEntryName(zeroes_continuation_chars, + sizeof(zeroes_continuation_chars))); +} + +TEST(entry_name_utils, InvalidSequence) { + // 0xfe is an invalid start byte + const uint8_t invalid[] = { 0x41, 0xfe }; + ASSERT_FALSE(IsValidEntryName(invalid, sizeof(invalid))); + + // 0x91 is an invalid start byte (it's a valid continuation byte). + const uint8_t invalid2[] = { 0x41, 0x91 }; + ASSERT_FALSE(IsValidEntryName(invalid2, sizeof(invalid2))); +} + +TEST(entry_name_utils, TruncatedContinuation) { + // Malayalam script with truncated bytes. There should be 2 bytes + // after 0xe0 + const uint8_t truncated[] = { 0xe0, 0xb4, 0x85, 0xe0, 0xb4 }; + ASSERT_FALSE(IsValidEntryName(truncated, sizeof(truncated))); + + // 0xc2 is the start of a 2 byte sequence that we've subsequently + // dropped. + const uint8_t truncated2[] = { 0xc2, 0xc2, 0xa1 }; + ASSERT_FALSE(IsValidEntryName(truncated2, sizeof(truncated2))); +} + +TEST(entry_name_utils, BadContinuation) { + // 0x41 is an invalid continuation char, since it's MSBs + // aren't "10..." (are 01). + const uint8_t bad[] = { 0xc2, 0xa1, 0xc2, 0x41 }; + ASSERT_FALSE(IsValidEntryName(bad, sizeof(bad))); + + // 0x41 is an invalid continuation char, since it's MSBs + // aren't "10..." (are 11). + const uint8_t bad2[] = { 0xc2, 0xa1, 0xc2, 0xfe }; + ASSERT_FALSE(IsValidEntryName(bad2, sizeof(bad2))); +} diff --git a/libziparchive/testdata/declaredlength.zip b/libziparchive/testdata/declaredlength.zip Binary files differnew file mode 100644 index 0000000..773380c --- /dev/null +++ b/libziparchive/testdata/declaredlength.zip diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc index 87dac0e..8582344 100644 --- a/libziparchive/zip_archive.cc +++ b/libziparchive/zip_archive.cc @@ -23,29 +23,31 @@ #include <fcntl.h> #include <inttypes.h> #include <limits.h> -#include <log/log.h> #include <stdlib.h> #include <string.h> #include <unistd.h> -#include <utils/Compat.h> -#include <utils/FileMap.h> -#include <zlib.h> -#include <JNIHelp.h> // TEMP_FAILURE_RETRY may or may not be in unistd +#include <memory> +#include <vector> +#include "base/macros.h" // TEMP_FAILURE_RETRY may or may not be in unistd +#include "base/memory.h" +#include "log/log.h" +#include "utils/Compat.h" +#include "utils/FileMap.h" +#include "zlib.h" + +#include "entry_name_utils-inl.h" #include "ziparchive/zip_archive.h" +using android::base::get_unaligned; + // This is for windows. If we don't open a file in binary mode, weird // things will happen. #ifndef O_BINARY #define O_BINARY 0 #endif -#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ - TypeName(); \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) - // The "end of central directory" (EOCD) record. Each archive // contains exactly once such record which appears at the end of // the archive. It contains archive wide information like the @@ -193,7 +195,6 @@ struct DataDescriptor { #undef DISALLOW_IMPLICIT_CONSTRUCTORS static const uint32_t kGPBDDFlagMask = 0x0008; // mask value that signifies that the entry has a DD -static const uint32_t kMaxErrorLen = 1024; // The maximum size of a central directory or a file // comment in bytes. @@ -288,10 +289,11 @@ static const char kTempMappingFileName[] = "zip: ExtractFileToFile"; struct ZipArchive { /* open Zip archive */ const int fd; + const bool close_file; /* mapped central directory area */ off64_t directory_offset; - android::FileMap* directory_map; + android::FileMap directory_map; /* number of entries in the Zip archive */ uint16_t num_entries; @@ -305,40 +307,23 @@ struct ZipArchive { uint32_t hash_table_size; ZipEntryName* hash_table; - ZipArchive(const int fd) : + ZipArchive(const int fd, bool assume_ownership) : fd(fd), + close_file(assume_ownership), directory_offset(0), - directory_map(NULL), num_entries(0), hash_table_size(0), hash_table(NULL) {} ~ZipArchive() { - if (fd >= 0) { + if (close_file && fd >= 0) { close(fd); } - if (directory_map != NULL) { - directory_map->release(); - } free(hash_table); } }; -// Returns 0 on success and negative values on failure. -static android::FileMap* MapFileSegment(const int fd, const off64_t start, - const size_t length, const bool read_only, - const char* debug_file_name) { - android::FileMap* file_map = new android::FileMap; - const bool success = file_map->create(debug_file_name, fd, start, length, read_only); - if (!success) { - file_map->release(); - return NULL; - } - - return file_map; -} - static int32_t CopyFileToFile(int fd, uint8_t* begin, const uint32_t length, uint64_t *crc_out) { static const uint32_t kBufSize = 32768; uint8_t buf[kBufSize]; @@ -385,8 +370,10 @@ static uint32_t RoundUpPower2(uint32_t val) { return val; } -static uint32_t ComputeHash(const char* str, uint16_t len) { +static uint32_t ComputeHash(const ZipEntryName& name) { uint32_t hash = 0; + uint16_t len = name.name_length; + const uint8_t* str = name.name; while (len--) { hash = hash * 31 + *str++; @@ -401,21 +388,21 @@ static uint32_t ComputeHash(const char* str, uint16_t len) { */ static int64_t EntryToIndex(const ZipEntryName* hash_table, const uint32_t hash_table_size, - const char* name, uint16_t length) { - const uint32_t hash = ComputeHash(name, length); + const ZipEntryName& name) { + const uint32_t hash = ComputeHash(name); // NOTE: (hash_table_size - 1) is guaranteed to be non-negative. uint32_t ent = hash & (hash_table_size - 1); while (hash_table[ent].name != NULL) { - if (hash_table[ent].name_length == length && - memcmp(hash_table[ent].name, name, length) == 0) { + if (hash_table[ent].name_length == name.name_length && + memcmp(hash_table[ent].name, name.name, name.name_length) == 0) { return ent; } ent = (ent + 1) & (hash_table_size - 1); } - ALOGV("Zip: Unable to find entry %.*s", length, name); + ALOGV("Zip: Unable to find entry %.*s", name.name_length, name.name); return kEntryNotFound; } @@ -423,8 +410,8 @@ static int64_t EntryToIndex(const ZipEntryName* hash_table, * Add a new entry to the hash table. */ static int32_t AddToHash(ZipEntryName *hash_table, const uint64_t hash_table_size, - const char* name, uint16_t length) { - const uint64_t hash = ComputeHash(name, length); + const ZipEntryName& name) { + const uint64_t hash = ComputeHash(name); uint32_t ent = hash & (hash_table_size - 1); /* @@ -432,17 +419,17 @@ static int32_t AddToHash(ZipEntryName *hash_table, const uint64_t hash_table_siz * Further, we guarantee that the hashtable size is not 0. */ while (hash_table[ent].name != NULL) { - if (hash_table[ent].name_length == length && - memcmp(hash_table[ent].name, name, length) == 0) { + if (hash_table[ent].name_length == name.name_length && + memcmp(hash_table[ent].name, name.name, name.name_length) == 0) { // We've found a duplicate entry. We don't accept it - ALOGW("Zip: Found duplicate entry %.*s", length, name); + ALOGW("Zip: Found duplicate entry %.*s", name.name_length, name.name); return kDuplicateEntry; } ent = (ent + 1) & (hash_table_size - 1); } - hash_table[ent].name = name; - hash_table[ent].name_length = length; + hash_table[ent].name = name.name; + hash_table[ent].name_length = name.name_length; return 0; } @@ -472,10 +459,12 @@ static int32_t MapCentralDirectory0(int fd, const char* debug_file_name, */ int i = read_amount - sizeof(EocdRecord); for (; i >= 0; i--) { - if (scan_buffer[i] == 0x50 && - ((*reinterpret_cast<uint32_t*>(&scan_buffer[i])) == EocdRecord::kSignature)) { - ALOGV("+++ Found EOCD at buf+%d", i); - break; + if (scan_buffer[i] == 0x50) { + uint32_t* sig_addr = reinterpret_cast<uint32_t*>(&scan_buffer[i]); + if (get_unaligned<uint32_t>(sig_addr) == EocdRecord::kSignature) { + ALOGV("+++ Found EOCD at buf+%d", i); + break; + } } } if (i < 0) { @@ -518,16 +507,12 @@ static int32_t MapCentralDirectory0(int fd, const char* debug_file_name, * It all looks good. Create a mapping for the CD, and set the fields * in archive. */ - android::FileMap* map = MapFileSegment(fd, - static_cast<off64_t>(eocd->cd_start_offset), - static_cast<size_t>(eocd->cd_size), - true /* read only */, debug_file_name); - if (map == NULL) { - archive->directory_map = NULL; + if (!archive->directory_map.create(debug_file_name, fd, + static_cast<off64_t>(eocd->cd_start_offset), + static_cast<size_t>(eocd->cd_size), true /* read only */) ) { return kMmapFailed; } - archive->directory_map = map; archive->num_entries = eocd->num_records; archive->directory_offset = eocd->cd_start_offset; @@ -554,7 +539,7 @@ static int32_t MapCentralDirectory(int fd, const char* debug_file_name, return kInvalidFile; } - if (file_length > (off64_t) 0xffffffff) { + if (file_length > static_cast<off64_t>(0xffffffff)) { ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length)); return kInvalidFile; } @@ -596,9 +581,9 @@ static int32_t MapCentralDirectory(int fd, const char* debug_file_name, * Returns 0 on success. */ static int32_t ParseZipArchive(ZipArchive* archive) { - int32_t result = -1; - const uint8_t* const cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr(); - const size_t cd_length = archive->directory_map->getDataLength(); + const uint8_t* const cd_ptr = + reinterpret_cast<const uint8_t*>(archive->directory_map.getDataPtr()); + const size_t cd_length = archive->directory_map.getDataLength(); const uint16_t num_entries = archive->num_entries; /* @@ -607,8 +592,8 @@ static int32_t ParseZipArchive(ZipArchive* archive) { * least one unused entry to avoid an infinite loop during creation. */ archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3); - archive->hash_table = (ZipEntryName*) calloc(archive->hash_table_size, - sizeof(ZipEntryName)); + archive->hash_table = reinterpret_cast<ZipEntryName*>(calloc(archive->hash_table_size, + sizeof(ZipEntryName))); /* * Walk through the central directory, adding entries to the hash @@ -621,53 +606,52 @@ static int32_t ParseZipArchive(ZipArchive* archive) { reinterpret_cast<const CentralDirectoryRecord*>(ptr); if (cdr->record_signature != CentralDirectoryRecord::kSignature) { ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i); - goto bail; + return -1; } if (ptr + sizeof(CentralDirectoryRecord) > cd_end) { ALOGW("Zip: ran off the end (at %" PRIu16 ")", i); - goto bail; + return -1; } const off64_t local_header_offset = cdr->local_file_header_offset; if (local_header_offset >= archive->directory_offset) { - ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16, (int64_t)local_header_offset, i); - goto bail; + ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16, + static_cast<int64_t>(local_header_offset), i); + return -1; } const uint16_t file_name_length = cdr->file_name_length; const uint16_t extra_length = cdr->extra_field_length; const uint16_t comment_length = cdr->comment_length; - const char* file_name = reinterpret_cast<const char*>(ptr + sizeof(CentralDirectoryRecord)); + const uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord); - /* check that file name doesn't contain \0 character */ - if (memchr(file_name, 0, file_name_length) != NULL) { - ALOGW("Zip: entry name can't contain \\0 character"); - goto bail; + /* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */ + if (!IsValidEntryName(file_name, file_name_length)) { + return -1; } /* add the CDE filename to the hash table */ + ZipEntryName entry_name; + entry_name.name = file_name; + entry_name.name_length = file_name_length; const int add_result = AddToHash(archive->hash_table, - archive->hash_table_size, file_name, file_name_length); - if (add_result) { + archive->hash_table_size, entry_name); + if (add_result != 0) { ALOGW("Zip: Error adding entry to hash table %d", add_result); - result = add_result; - goto bail; + return add_result; } ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length; if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) { ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16, ptr - cd_ptr, cd_length, i); - goto bail; + return -1; } } ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries); - result = 0; - -bail: - return result; + return 0; } static int32_t OpenArchiveInternal(ZipArchive* archive, @@ -685,21 +669,22 @@ static int32_t OpenArchiveInternal(ZipArchive* archive, } int32_t OpenArchiveFd(int fd, const char* debug_file_name, - ZipArchiveHandle* handle) { - ZipArchive* archive = new ZipArchive(fd); + ZipArchiveHandle* handle, bool assume_ownership) { + ZipArchive* archive = new ZipArchive(fd, assume_ownership); *handle = archive; return OpenArchiveInternal(archive, debug_file_name); } int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) { const int fd = open(fileName, O_RDONLY | O_BINARY, 0); - ZipArchive* archive = new ZipArchive(fd); + ZipArchive* archive = new ZipArchive(fd, true); *handle = archive; if (fd < 0) { ALOGW("Unable to open '%s': %s", fileName, strerror(errno)); return kIoError; } + return OpenArchiveInternal(archive, fileName); } @@ -707,7 +692,7 @@ int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) { * Close a ZipArchive, closing the file and freeing the contents. */ void CloseArchive(ZipArchiveHandle handle) { - ZipArchive* archive = (ZipArchive*) handle; + ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle); ALOGV("Closing archive %p", archive); delete archive; } @@ -739,7 +724,7 @@ static int32_t UpdateEntryFromDataDescriptor(int fd, // as a side effect of this call. static inline ssize_t ReadAtOffset(int fd, uint8_t* buf, size_t len, off64_t off) { -#ifdef HAVE_PREAD +#if !defined(_WIN32) return TEMP_FAILURE_RETRY(pread64(fd, buf, len, off)); #else // The only supported platform that doesn't support pread at the moment @@ -751,26 +736,25 @@ static inline ssize_t ReadAtOffset(int fd, uint8_t* buf, size_t len, } return TEMP_FAILURE_RETRY(read(fd, buf, len)); -#endif // HAVE_PREAD +#endif } static int32_t FindEntry(const ZipArchive* archive, const int ent, ZipEntry* data) { const uint16_t nameLen = archive->hash_table[ent].name_length; - const char* name = archive->hash_table[ent].name; // Recover the start of the central directory entry from the filename // pointer. The filename is the first entry past the fixed-size data, // so we can just subtract back from that. - const uint8_t* ptr = reinterpret_cast<const uint8_t*>(name); + const uint8_t* ptr = archive->hash_table[ent].name; ptr -= sizeof(CentralDirectoryRecord); // This is the base of our mmapped region, we have to sanity check that // the name that's in the hash table is a pointer to a location within // this mapped region. const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>( - archive->directory_map->getDataPtr()); - if (ptr < base_ptr || ptr > base_ptr + archive->directory_map->getDataLength()) { + archive->directory_map.getDataPtr()); + if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.getDataLength()) { ALOGW("Zip: Invalid entry pointer"); return kInvalidOffset; } @@ -805,7 +789,8 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent, ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf), local_header_offset); if (actual != sizeof(lfh_buf)) { - ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)local_header_offset); + ALOGW("Zip: failed reading lfh name from offset %" PRId64, + static_cast<int64_t>(local_header_offset)); return kIoError; } @@ -838,22 +823,22 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent, // name in the central directory. if (lfh->file_name_length == nameLen) { const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader); - if (name_offset + lfh->file_name_length >= cd_offset) { + if (name_offset + lfh->file_name_length > cd_offset) { ALOGW("Zip: Invalid declared length"); return kInvalidOffset; } - uint8_t* name_buf = (uint8_t*) malloc(nameLen); + uint8_t* name_buf = reinterpret_cast<uint8_t*>(malloc(nameLen)); ssize_t actual = ReadAtOffset(archive->fd, name_buf, nameLen, name_offset); if (actual != nameLen) { - ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)name_offset); + ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset)); free(name_buf); return kIoError; } - if (memcmp(name, name_buf, nameLen)) { + if (memcmp(archive->hash_table[ent].name, name_buf, nameLen)) { free(name_buf); return kInconsistentInformation; } @@ -867,20 +852,21 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent, const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader) + lfh->file_name_length + lfh->extra_field_length; if (data_offset > cd_offset) { - ALOGW("Zip: bad data offset %" PRId64 " in zip", (int64_t)data_offset); + ALOGW("Zip: bad data offset %" PRId64 " in zip", static_cast<int64_t>(data_offset)); return kInvalidOffset; } - if ((off64_t)(data_offset + data->compressed_length) > cd_offset) { + if (static_cast<off64_t>(data_offset + data->compressed_length) > cd_offset) { ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")", - (int64_t)data_offset, data->compressed_length, (int64_t)cd_offset); + static_cast<int64_t>(data_offset), data->compressed_length, static_cast<int64_t>(cd_offset)); return kInvalidOffset; } if (data->method == kCompressStored && - (off64_t)(data_offset + data->uncompressed_length) > cd_offset) { + static_cast<off64_t>(data_offset + data->uncompressed_length) > cd_offset) { ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")", - (int64_t)data_offset, data->uncompressed_length, (int64_t)cd_offset); + static_cast<int64_t>(data_offset), data->uncompressed_length, + static_cast<int64_t>(cd_offset)); return kInvalidOffset; } @@ -890,45 +876,61 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent, struct IterationHandle { uint32_t position; - const char* prefix; + // We're not using vector here because this code is used in the Windows SDK + // where the STL is not available. + const uint8_t* prefix; uint16_t prefix_len; ZipArchive* archive; + + IterationHandle() : prefix(NULL), prefix_len(0) {} + + IterationHandle(const ZipEntryName& prefix_name) + : prefix_len(prefix_name.name_length) { + uint8_t* prefix_copy = new uint8_t[prefix_len]; + memcpy(prefix_copy, prefix_name.name, prefix_len); + prefix = prefix_copy; + } + + ~IterationHandle() { + delete[] prefix; + } }; -int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, const char* prefix) { - ZipArchive* archive = (ZipArchive *) handle; +int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, + const ZipEntryName* optional_prefix) { + ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle); if (archive == NULL || archive->hash_table == NULL) { ALOGW("Zip: Invalid ZipArchiveHandle"); return kInvalidHandle; } - IterationHandle* cookie = (IterationHandle*) malloc(sizeof(IterationHandle)); + IterationHandle* cookie = + optional_prefix != NULL ? new IterationHandle(*optional_prefix) : new IterationHandle(); cookie->position = 0; - cookie->prefix = prefix; cookie->archive = archive; - if (prefix != NULL) { - cookie->prefix_len = strlen(prefix); - } *cookie_ptr = cookie ; return 0; } -int32_t FindEntry(const ZipArchiveHandle handle, const char* entryName, +void EndIteration(void* cookie) { + delete reinterpret_cast<IterationHandle*>(cookie); +} + +int32_t FindEntry(const ZipArchiveHandle handle, const ZipEntryName& entryName, ZipEntry* data) { - const ZipArchive* archive = (ZipArchive*) handle; - const int nameLen = strlen(entryName); - if (nameLen == 0 || nameLen > 65535) { - ALOGW("Zip: Invalid filename %s", entryName); + const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle); + if (entryName.name_length == 0) { + ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name); return kInvalidEntryName; } const int64_t ent = EntryToIndex(archive->hash_table, - archive->hash_table_size, entryName, nameLen); + archive->hash_table_size, entryName); if (ent < 0) { - ALOGV("Zip: Could not find entry %.*s", nameLen, entryName); + ALOGV("Zip: Could not find entry %.*s", entryName.name_length, entryName.name); return ent; } @@ -936,7 +938,7 @@ int32_t FindEntry(const ZipArchiveHandle handle, const char* entryName, } int32_t Next(void* cookie, ZipEntry* data, ZipEntryName* name) { - IterationHandle* handle = (IterationHandle *) cookie; + IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie); if (handle == NULL) { return kInvalidHandle; } @@ -953,7 +955,7 @@ int32_t Next(void* cookie, ZipEntry* data, ZipEntryName* name) { for (uint32_t i = currentOffset; i < hash_table_length; ++i) { if (hash_table[i].name != NULL && - (handle->prefix == NULL || + (handle->prefix_len == 0 || (memcmp(handle->prefix, hash_table[i].name, handle->prefix_len) == 0))) { handle->position = (i + 1); const int error = FindEntry(archive, i, data); @@ -970,13 +972,20 @@ int32_t Next(void* cookie, ZipEntry* data, ZipEntryName* name) { return kIterationEnd; } +// This method is using libz macros with old-style-casts +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wold-style-cast" +static inline int zlib_inflateInit2(z_stream* stream, int window_bits) { + return inflateInit2(stream, window_bits); +} +#pragma GCC diagnostic pop + static int32_t InflateToFile(int fd, const ZipEntry* entry, uint8_t* begin, uint32_t length, uint64_t* crc_out) { - int32_t result = -1; - const uint32_t kBufSize = 32768; - uint8_t read_buf[kBufSize]; - uint8_t write_buf[kBufSize]; + const size_t kBufSize = 32768; + std::vector<uint8_t> read_buf(kBufSize); + std::vector<uint8_t> write_buf(kBufSize); z_stream zstream; int zerr; @@ -989,7 +998,7 @@ static int32_t InflateToFile(int fd, const ZipEntry* entry, zstream.opaque = Z_NULL; zstream.next_in = NULL; zstream.avail_in = 0; - zstream.next_out = (Bytef*) write_buf; + zstream.next_out = &write_buf[0]; zstream.avail_out = kBufSize; zstream.data_type = Z_UNKNOWN; @@ -997,7 +1006,7 @@ static int32_t InflateToFile(int fd, const ZipEntry* entry, * Use the undocumented "negative window bits" feature to tell zlib * that there's no zlib header waiting for it. */ - zerr = inflateInit2(&zstream, -MAX_WBITS); + zerr = zlib_inflateInit2(&zstream, -MAX_WBITS); if (zerr != Z_OK) { if (zerr == Z_VERSION_ERROR) { ALOGE("Installed zlib is not compatible with linked version (%s)", @@ -1009,6 +1018,12 @@ static int32_t InflateToFile(int fd, const ZipEntry* entry, return kZlibError; } + auto zstream_deleter = [](z_stream* stream) { + inflateEnd(stream); /* free up any allocated structures */ + }; + + std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter); + const uint32_t uncompressed_length = entry->uncompressed_length; uint32_t compressed_length = entry->compressed_length; @@ -1017,16 +1032,15 @@ static int32_t InflateToFile(int fd, const ZipEntry* entry, /* read as much as we can */ if (zstream.avail_in == 0) { const ZD_TYPE getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length; - const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, read_buf, getSize)); + const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, &read_buf[0], getSize)); if (actual != getSize) { ALOGW("Zip: inflate read failed (" ZD " vs " ZD ")", actual, getSize); - result = kIoError; - goto z_bail; + return kIoError; } compressed_length -= getSize; - zstream.next_in = read_buf; + zstream.next_in = &read_buf[0]; zstream.avail_in = getSize; } @@ -1036,22 +1050,21 @@ static int32_t InflateToFile(int fd, const ZipEntry* entry, ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)", zerr, zstream.next_in, zstream.avail_in, zstream.next_out, zstream.avail_out); - result = kZlibError; - goto z_bail; + return kZlibError; } /* write when we're full or when we're done */ if (zstream.avail_out == 0 || (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) { - const size_t write_size = zstream.next_out - write_buf; + const size_t write_size = zstream.next_out - &write_buf[0]; // The file might have declared a bogus length. if (write_size + write_count > length) { - goto z_bail; + return -1; } - memcpy(begin + write_count, write_buf, write_size); + memcpy(begin + write_count, &write_buf[0], write_size); write_count += write_size; - zstream.next_out = write_buf; + zstream.next_out = &write_buf[0]; zstream.avail_out = kBufSize; } } while (zerr == Z_OK); @@ -1064,26 +1077,20 @@ static int32_t InflateToFile(int fd, const ZipEntry* entry, if (zstream.total_out != uncompressed_length || compressed_length != 0) { ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")", zstream.total_out, uncompressed_length); - result = kInconsistentInformation; - goto z_bail; + return kInconsistentInformation; } - result = 0; - -z_bail: - inflateEnd(&zstream); /* free up any allocated structures */ - - return result; + return 0; } int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, uint8_t* begin, uint32_t size) { - ZipArchive* archive = (ZipArchive*) handle; + ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle); const uint16_t method = entry->method; off64_t data_offset = entry->offset; if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) { - ALOGW("Zip: lseek to data at %" PRId64 " failed", (int64_t)data_offset); + ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset)); return kIoError; } @@ -1115,7 +1122,7 @@ int32_t ExtractToMemory(ZipArchiveHandle handle, int32_t ExtractEntryToFile(ZipArchiveHandle handle, ZipEntry* entry, int fd) { - const int32_t declared_length = entry->uncompressed_length; + const uint32_t declared_length = entry->uncompressed_length; const off64_t current_offset = lseek64(fd, 0, SEEK_CUR); if (current_offset == -1) { @@ -1124,10 +1131,25 @@ int32_t ExtractEntryToFile(ZipArchiveHandle handle, return kIoError; } - int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset)); + int result = 0; +#if defined(__linux__) + // Make sure we have enough space on the volume to extract the compressed + // entry. Note that the call to ftruncate below will change the file size but + // will not allocate space on disk. + if (declared_length > 0) { + result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length)); + if (result == -1) { + ALOGW("Zip: unable to allocate space for file to %" PRId64 ": %s", + static_cast<int64_t>(declared_length + current_offset), strerror(errno)); + return kIoError; + } + } +#endif // defined(__linux__) + + result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset)); if (result == -1) { ALOGW("Zip: unable to truncate file to %" PRId64 ": %s", - (int64_t)(declared_length + current_offset), strerror(errno)); + static_cast<int64_t>(declared_length + current_offset), strerror(errno)); return kIoError; } @@ -1138,16 +1160,14 @@ int32_t ExtractEntryToFile(ZipArchiveHandle handle, return 0; } - android::FileMap* map = MapFileSegment(fd, current_offset, declared_length, - false, kTempMappingFileName); - if (map == NULL) { + android::FileMap map; + if (!map.create(kTempMappingFileName, fd, current_offset, declared_length, false)) { return kMmapFailed; } const int32_t error = ExtractToMemory(handle, entry, - reinterpret_cast<uint8_t*>(map->getDataPtr()), - map->getDataLength()); - map->release(); + reinterpret_cast<uint8_t*>(map.getDataPtr()), + map.getDataLength()); return error; } @@ -1160,6 +1180,6 @@ const char* ErrorCodeString(int32_t error_code) { } int GetFileDescriptor(const ZipArchiveHandle handle) { - return ((ZipArchive*) handle)->fd; + return reinterpret_cast<ZipArchive*>(handle)->fd; } diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc index 813a87f..64faa6d 100644 --- a/libziparchive/zip_archive_test.cc +++ b/libziparchive/zip_archive_test.cc @@ -17,6 +17,7 @@ #include "ziparchive/zip_archive.h" #include <errno.h> +#include <fcntl.h> #include <getopt.h> #include <stdio.h> #include <unistd.h> @@ -40,6 +41,27 @@ static const uint8_t kBTxtContents[] = { '\n' }; +static const uint16_t kATxtNameLength = 5; +static const uint16_t kBTxtNameLength = 5; +static const uint16_t kNonexistentTxtNameLength = 15; +static const uint16_t kEmptyTxtNameLength = 9; + +static const uint8_t kATxtName[kATxtNameLength] = { + 'a', '.', 't', 'x', 't' +}; + +static const uint8_t kBTxtName[kBTxtNameLength] = { + 'b', '.', 't', 'x', 't' +}; + +static const uint8_t kNonexistentTxtName[kNonexistentTxtNameLength] = { + 'n', 'o', 'n', 'e', 'x', 'i', 's', 't', 'e', 'n', 't', '.', 't', 'x' ,'t' +}; + +static const uint8_t kEmptyTxtName[kEmptyTxtNameLength] = { + 'e', 'm', 'p', 't', 'y', '.', 't', 'x', 't' +}; + static int32_t OpenArchiveWrapper(const std::string& name, ZipArchiveHandle* handle) { const std::string abs_path = test_data_dir + "/" + name; @@ -67,6 +89,26 @@ TEST(ziparchive, OpenMissing) { ASSERT_EQ(-1, GetFileDescriptor(handle)); } +TEST(ziparchive, OpenAssumeFdOwnership) { + int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY); + ASSERT_NE(-1, fd); + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle)); + CloseArchive(handle); + ASSERT_EQ(-1, lseek(fd, 0, SEEK_SET)); + ASSERT_EQ(EBADF, errno); +} + +TEST(ziparchive, OpenDoNotAssumeFdOwnership) { + int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY); + ASSERT_NE(-1, fd); + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle, false)); + CloseArchive(handle); + ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)); + close(fd); +} + TEST(ziparchive, Iteration) { ZipArchiveHandle handle; ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle)); @@ -108,7 +150,10 @@ TEST(ziparchive, FindEntry) { ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle)); ZipEntry data; - ASSERT_EQ(0, FindEntry(handle, "a.txt", &data)); + ZipEntryName name; + name.name = kATxtName; + name.name_length = kATxtNameLength; + ASSERT_EQ(0, FindEntry(handle, name, &data)); // Known facts about a.txt, from zipinfo -v. ASSERT_EQ(63, data.offset); @@ -118,7 +163,26 @@ TEST(ziparchive, FindEntry) { ASSERT_EQ(0x950821c5, data.crc32); // An entry that doesn't exist. Should be a negative return code. - ASSERT_LT(FindEntry(handle, "nonexistent.txt", &data), 0); + ZipEntryName absent_name; + absent_name.name = kNonexistentTxtName; + absent_name.name_length = kNonexistentTxtNameLength; + ASSERT_LT(FindEntry(handle, absent_name, &data), 0); + + CloseArchive(handle); +} + +TEST(ziparchive, TestInvalidDeclaredLength) { + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle)); + + void* iteration_cookie; + ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL)); + + ZipEntryName name; + ZipEntry data; + + ASSERT_EQ(Next(iteration_cookie, &data, &name), 0); + ASSERT_EQ(Next(iteration_cookie, &data, &name), 0); CloseArchive(handle); } @@ -129,7 +193,10 @@ TEST(ziparchive, ExtractToMemory) { // An entry that's deflated. ZipEntry data; - ASSERT_EQ(0, FindEntry(handle, "a.txt", &data)); + ZipEntryName a_name; + a_name.name = kATxtName; + a_name.name_length = kATxtNameLength; + ASSERT_EQ(0, FindEntry(handle, a_name, &data)); const uint32_t a_size = data.uncompressed_length; ASSERT_EQ(a_size, sizeof(kATxtContents)); uint8_t* buffer = new uint8_t[a_size]; @@ -138,7 +205,10 @@ TEST(ziparchive, ExtractToMemory) { delete[] buffer; // An entry that's stored. - ASSERT_EQ(0, FindEntry(handle, "b.txt", &data)); + ZipEntryName b_name; + b_name.name = kBTxtName; + b_name.name_length = kBTxtNameLength; + ASSERT_EQ(0, FindEntry(handle, b_name, &data)); const uint32_t b_size = data.uncompressed_length; ASSERT_EQ(b_size, sizeof(kBTxtContents)); buffer = new uint8_t[b_size]; @@ -184,7 +254,10 @@ TEST(ziparchive, EmptyEntries) { ASSERT_EQ(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle)); ZipEntry entry; - ASSERT_EQ(0, FindEntry(handle, "empty.txt", &entry)); + ZipEntryName empty_name; + empty_name.name = kEmptyTxtName; + empty_name.name_length = kEmptyTxtNameLength; + ASSERT_EQ(0, FindEntry(handle, empty_name, &entry)); ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length); uint8_t buffer[1]; ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1)); @@ -231,7 +304,10 @@ TEST(ziparchive, ExtractToFile) { ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle)); ZipEntry entry; - ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry)); + ZipEntryName name; + name.name = kATxtName; + name.name_length = kATxtNameLength; + ASSERT_EQ(0, FindEntry(handle, name, &entry)); ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, fd)); diff --git a/libzipfile/Android.mk b/libzipfile/Android.mk deleted file mode 100644 index 12a2229..0000000 --- a/libzipfile/Android.mk +++ /dev/null @@ -1,56 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -# build host static library -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - centraldir.c \ - zipfile.c - -LOCAL_STATIC_LIBRARIES := \ - libunz - -LOCAL_MODULE:= libzipfile - -LOCAL_C_INCLUDES += external/zlib - -LOCAL_CFLAGS := -Werror - -LOCAL_MULTILIB := both - -include $(BUILD_HOST_STATIC_LIBRARY) - -# build device static library -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - centraldir.c \ - zipfile.c - -LOCAL_STATIC_LIBRARIES := \ - libunz - -LOCAL_MODULE:= libzipfile - -LOCAL_C_INCLUDES += external/zlib - -LOCAL_CFLAGS := -Werror - -include $(BUILD_STATIC_LIBRARY) - - -# build test_zipfile -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - test_zipfile.c - -LOCAL_STATIC_LIBRARIES := libzipfile libunz - -LOCAL_MODULE := test_zipfile - -LOCAL_C_INCLUDES += external/zlib - -LOCAL_CFLAGS := -Werror - -include $(BUILD_HOST_EXECUTABLE) diff --git a/libzipfile/MODULE_LICENSE_APACHE2 b/libzipfile/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29..0000000 --- a/libzipfile/MODULE_LICENSE_APACHE2 +++ /dev/null diff --git a/libzipfile/NOTICE b/libzipfile/NOTICE deleted file mode 100644 index c5b1efa..0000000 --- a/libzipfile/NOTICE +++ /dev/null @@ -1,190 +0,0 @@ - - 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/libzipfile/centraldir.c b/libzipfile/centraldir.c deleted file mode 100644 index 69cf47a..0000000 --- a/libzipfile/centraldir.c +++ /dev/null @@ -1,222 +0,0 @@ -#include "private.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <utils/Compat.h>
-
-enum {
- // finding the directory
- CD_SIGNATURE = 0x06054b50,
- EOCD_LEN = 22, // EndOfCentralDir len, excl. comment
- MAX_COMMENT_LEN = 65535,
- MAX_EOCD_SEARCH = MAX_COMMENT_LEN + EOCD_LEN,
-
- // central directory entries
- ENTRY_SIGNATURE = 0x02014b50,
- ENTRY_LEN = 46, // CentralDirEnt len, excl. var fields
-
- // local file header
- LFH_SIZE = 30,
-};
-
-unsigned int
-read_le_int(const unsigned char* buf)
-{
- return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
-}
-
-unsigned int
-read_le_short(const unsigned char* buf)
-{
- return buf[0] | (buf[1] << 8);
-}
-
-static int
-read_central_dir_values(Zipfile* file, const unsigned char* buf, int len)
-{
- if (len < EOCD_LEN) {
- // looks like ZIP file got truncated
- fprintf(stderr, " Zip EOCD: expected >= %d bytes, found %d\n",
- EOCD_LEN, len);
- return -1;
- }
-
- file->disknum = read_le_short(&buf[0x04]);
- file->diskWithCentralDir = read_le_short(&buf[0x06]);
- file->entryCount = read_le_short(&buf[0x08]);
- file->totalEntryCount = read_le_short(&buf[0x0a]);
- file->centralDirSize = read_le_int(&buf[0x0c]);
- file->centralDirOffest = read_le_int(&buf[0x10]);
- file->commentLen = read_le_short(&buf[0x14]);
-
- if (file->commentLen > 0) {
- if (EOCD_LEN + file->commentLen > len) {
- fprintf(stderr, "EOCD(%d) + comment(%d) exceeds len (%d)\n",
- EOCD_LEN, file->commentLen, len);
- return -1;
- }
- file->comment = buf + EOCD_LEN;
- }
-
- return 0;
-}
-
-static int
-read_central_directory_entry(Zipfile* file, Zipentry* entry,
- const unsigned char** buf, ssize_t* len)
-{
- const unsigned char* p;
-
- unsigned short extraFieldLength;
- unsigned short fileCommentLength;
- unsigned long localHeaderRelOffset;
- unsigned int dataOffset;
-
- p = *buf;
-
- if (*len < ENTRY_LEN) {
- fprintf(stderr, "cde entry not large enough\n");
- return -1;
- }
-
- if (read_le_int(&p[0x00]) != ENTRY_SIGNATURE) {
- fprintf(stderr, "Whoops: didn't find expected signature\n");
- return -1;
- }
-
- entry->compressionMethod = read_le_short(&p[0x0a]);
- entry->compressedSize = read_le_int(&p[0x14]);
- entry->uncompressedSize = read_le_int(&p[0x18]);
- entry->fileNameLength = read_le_short(&p[0x1c]);
- extraFieldLength = read_le_short(&p[0x1e]);
- fileCommentLength = read_le_short(&p[0x20]);
- localHeaderRelOffset = read_le_int(&p[0x2a]);
-
- p += ENTRY_LEN;
-
- // filename
- if (entry->fileNameLength != 0) {
- entry->fileName = p;
- } else {
- entry->fileName = NULL;
- }
- p += entry->fileNameLength;
-
- // extra field
- p += extraFieldLength;
-
- // comment, if any
- p += fileCommentLength;
-
- *buf = p;
-
- // the size of the extraField in the central dir is how much data there is,
- // but the one in the local file header also contains some padding.
- p = file->buf + localHeaderRelOffset;
- extraFieldLength = read_le_short(&p[0x1c]);
-
- dataOffset = localHeaderRelOffset + LFH_SIZE
- + entry->fileNameLength + extraFieldLength;
- entry->data = file->buf + dataOffset;
-#if 0
- printf("file->buf=%p entry->data=%p dataOffset=%x localHeaderRelOffset=%d "
- "entry->fileNameLength=%d extraFieldLength=%d\n",
- file->buf, entry->data, dataOffset, localHeaderRelOffset,
- entry->fileNameLength, extraFieldLength);
-#endif
- return 0;
-}
-
-/*
- * Find the central directory and read the contents.
- *
- * The fun thing about ZIP archives is that they may or may not be
- * readable from start to end. In some cases, notably for archives
- * that were written to stdout, the only length information is in the
- * central directory at the end of the file.
- *
- * Of course, the central directory can be followed by a variable-length
- * comment field, so we have to scan through it backwards. The comment
- * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
- * itself, plus apparently sometimes people throw random junk on the end
- * just for the fun of it.
- *
- * This is all a little wobbly. If the wrong value ends up in the EOCD
- * area, we're hosed. This appears to be the way that everbody handles
- * it though, so we're in pretty good company if this fails.
- */
-int
-read_central_dir(Zipfile *file)
-{
- int err;
-
- const unsigned char* buf = file->buf;
- ZD_TYPE bufsize = file->bufsize;
- const unsigned char* eocd;
- const unsigned char* p;
- const unsigned char* start;
- ssize_t len;
- int i;
-
- // too small to be a ZIP archive?
- if (bufsize < EOCD_LEN) {
- fprintf(stderr, "Length is " ZD " -- too small\n", bufsize);
- goto bail;
- }
-
- // find the end-of-central-dir magic
- if (bufsize > MAX_EOCD_SEARCH) {
- start = buf + bufsize - MAX_EOCD_SEARCH;
- } else {
- start = buf;
- }
- p = buf + bufsize - 4;
- while (p >= start) {
- if (*p == 0x50 && read_le_int(p) == CD_SIGNATURE) {
- eocd = p;
- break;
- }
- p--;
- }
- if (p < start) {
- fprintf(stderr, "EOCD not found, not Zip\n");
- goto bail;
- }
-
- // extract eocd values
- err = read_central_dir_values(file, eocd, (buf+bufsize)-eocd);
- if (err != 0) {
- goto bail;
- }
-
- if (file->disknum != 0
- || file->diskWithCentralDir != 0
- || file->entryCount != file->totalEntryCount) {
- fprintf(stderr, "Archive spanning not supported\n");
- goto bail;
- }
-
- // Loop through and read the central dir entries.
- p = buf + file->centralDirOffest;
- len = (buf+bufsize)-p;
- for (i=0; i < file->totalEntryCount; i++) {
- Zipentry* entry = malloc(sizeof(Zipentry));
- memset(entry, 0, sizeof(Zipentry));
-
- err = read_central_directory_entry(file, entry, &p, &len);
- if (err != 0) {
- fprintf(stderr, "read_central_directory_entry failed\n");
- free(entry);
- goto bail;
- }
-
- // add it to our list
- entry->next = file->entries;
- file->entries = entry;
- }
-
- return 0;
-bail:
- return -1;
-}
diff --git a/libzipfile/private.h b/libzipfile/private.h deleted file mode 100644 index 06f788d..0000000 --- a/libzipfile/private.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef PRIVATE_H
-#define PRIVATE_H
-
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-typedef struct Zipentry {
- unsigned long fileNameLength;
- const unsigned char* fileName;
- unsigned short compressionMethod;
- unsigned int uncompressedSize;
- unsigned int compressedSize;
- const unsigned char* data;
-
- struct Zipentry* next;
-} Zipentry;
-
-typedef struct Zipfile
-{
- const unsigned char *buf;
- ssize_t bufsize;
-
- // Central directory
- unsigned short disknum; //mDiskNumber;
- unsigned short diskWithCentralDir; //mDiskWithCentralDir;
- unsigned short entryCount; //mNumEntries;
- unsigned short totalEntryCount; //mTotalNumEntries;
- unsigned int centralDirSize; //mCentralDirSize;
- unsigned int centralDirOffest; // offset from first disk //mCentralDirOffset;
- unsigned short commentLen; //mCommentLen;
- const unsigned char* comment; //mComment;
-
- Zipentry* entries;
-} Zipfile;
-
-int read_central_dir(Zipfile* file);
-
-unsigned int read_le_int(const unsigned char* buf);
-unsigned int read_le_short(const unsigned char* buf);
-
-#endif // PRIVATE_H
-
diff --git a/libzipfile/test_zipfile.c b/libzipfile/test_zipfile.c deleted file mode 100644 index 1aaa913..0000000 --- a/libzipfile/test_zipfile.c +++ /dev/null @@ -1,94 +0,0 @@ -#include <zipfile/zipfile.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-void dump_zipfile(FILE* to, zipfile_t file);
-
-int
-main(int argc, char** argv)
-{
- FILE* f;
- size_t size, unsize;
- void* buf;
- void* scratch;
- zipfile_t zip;
- zipentry_t entry;
- int err;
- enum { HUH, LIST, UNZIP } what = HUH;
-
- if (strcmp(argv[2], "-l") == 0 && argc == 3) {
- what = LIST;
- }
- else if (strcmp(argv[2], "-u") == 0 && argc == 5) {
- what = UNZIP;
- }
- else {
- fprintf(stderr, "usage: test_zipfile ZIPFILE -l\n"
- " lists the files in the zipfile\n"
- " test_zipfile ZIPFILE -u FILENAME SAVETO\n"
- " saves FILENAME from the zip file into SAVETO\n");
- return 1;
- }
-
- f = fopen(argv[1], "r");
- if (f == NULL) {
- fprintf(stderr, "couldn't open %s\n", argv[1]);
- return 1;
- }
-
- fseek(f, 0, SEEK_END);
- size = ftell(f);
- rewind(f);
-
- buf = malloc(size);
- fread(buf, 1, size, f);
-
- zip = init_zipfile(buf, size);
- if (zip == NULL) {
- fprintf(stderr, "inti_zipfile failed\n");
- return 1;
- }
-
- fclose(f);
-
-
- switch (what)
- {
- case HUH:
- break;
- case LIST:
- dump_zipfile(stdout, zip);
- break;
- case UNZIP:
- entry = lookup_zipentry(zip, argv[3]);
- if (entry == NULL) {
- fprintf(stderr, "zip file '%s' does not contain file '%s'\n",
- argv[1], argv[1]);
- return 1;
- }
- f = fopen(argv[4], "w");
- if (f == NULL) {
- fprintf(stderr, "can't open file for writing '%s'\n", argv[4]);
- return 1;
- }
- unsize = get_zipentry_size(entry);
- size = unsize * 1.001;
- scratch = malloc(size);
- printf("scratch=%p\n", scratch);
- err = decompress_zipentry(entry, scratch, size);
- if (err != 0) {
- fprintf(stderr, "error decompressing file\n");
- return 1;
- }
- fwrite(scratch, unsize, 1, f);
- free(scratch);
- fclose(f);
- break;
- }
-
- free(buf);
-
- return 0;
-}
-
diff --git a/libzipfile/zipfile.c b/libzipfile/zipfile.c deleted file mode 100644 index b903fcf..0000000 --- a/libzipfile/zipfile.c +++ /dev/null @@ -1,159 +0,0 @@ -#include <zipfile/zipfile.h> - -#include "private.h" -#include <stdlib.h> -#include <string.h> -#include <zlib.h> -#define DEF_MEM_LEVEL 8 // normally in zutil.h? - -zipfile_t -init_zipfile(const void* data, size_t size) -{ - int err; - - Zipfile *file = malloc(sizeof(Zipfile)); - if (file == NULL) return NULL; - memset(file, 0, sizeof(Zipfile)); - file->buf = data; - file->bufsize = size; - - err = read_central_dir(file); - if (err != 0) goto fail; - - return file; -fail: - free(file); - return NULL; -} - -void -release_zipfile(zipfile_t f) -{ - Zipfile* file = (Zipfile*)f; - Zipentry* entry = file->entries; - while (entry) { - Zipentry* next = entry->next; - free(entry); - entry = next; - } - free(file); -} - -zipentry_t -lookup_zipentry(zipfile_t f, const char* entryName) -{ - Zipfile* file = (Zipfile*)f; - Zipentry* entry = file->entries; - while (entry) { - if (0 == memcmp(entryName, entry->fileName, entry->fileNameLength)) { - return entry; - } - entry = entry->next; - } - return NULL; -} - -size_t -get_zipentry_size(zipentry_t entry) -{ - return ((Zipentry*)entry)->uncompressedSize; -} - -char* -get_zipentry_name(zipentry_t entry) -{ - Zipentry* e = (Zipentry*)entry; - int l = e->fileNameLength; - char* s = malloc(l+1); - memcpy(s, e->fileName, l); - s[l] = '\0'; - return s; -} - -enum { - STORED = 0, - DEFLATED = 8 -}; - -static int -uninflate(unsigned char* out, int unlen, const unsigned char* in, int clen) -{ - z_stream zstream; - int err = 0; - int zerr; - - memset(&zstream, 0, sizeof(zstream)); - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - zstream.next_in = (void*)in; - zstream.avail_in = clen; - zstream.next_out = (Bytef*) out; - zstream.avail_out = unlen; - zstream.data_type = Z_UNKNOWN; - - // Use the undocumented "negative window bits" feature to tell zlib - // that there's no zlib header waiting for it. - zerr = inflateInit2(&zstream, -MAX_WBITS); - if (zerr != Z_OK) { - return -1; - } - - // uncompress the data - zerr = inflate(&zstream, Z_FINISH); - if (zerr != Z_STREAM_END) { - fprintf(stderr, "zerr=%d Z_STREAM_END=%d total_out=%lu\n", zerr, Z_STREAM_END, - zstream.total_out); - err = -1; - } - - inflateEnd(&zstream); - return err; -} - -int -decompress_zipentry(zipentry_t e, void* buf, int bufsize) -{ - Zipentry* entry = (Zipentry*)e; - switch (entry->compressionMethod) - { - case STORED: - memcpy(buf, entry->data, entry->uncompressedSize); - return 0; - case DEFLATED: - return uninflate(buf, bufsize, entry->data, entry->compressedSize); - default: - return -1; - } -} - -void -dump_zipfile(FILE* to, zipfile_t file) -{ - Zipfile* zip = (Zipfile*)file; - Zipentry* entry = zip->entries; - int i; - - fprintf(to, "entryCount=%d\n", zip->entryCount); - for (i=0; i<zip->entryCount; i++) { - fprintf(to, " file \""); - fwrite(entry->fileName, entry->fileNameLength, 1, to); - fprintf(to, "\"\n"); - entry = entry->next; - } -} - -zipentry_t -iterate_zipfile(zipfile_t file, void** cookie) -{ - Zipentry* entry = (Zipentry*)*cookie; - if (entry == NULL) { - Zipfile* zip = (Zipfile*)file; - *cookie = zip->entries; - return *cookie; - } else { - entry = entry->next; - *cookie = entry; - return entry; - } -} diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index a534a24..7bbc811 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -607,7 +607,6 @@ static int kill_one_process(struct proc *procp, int other_free, int other_file, static int find_and_kill_process(int other_free, int other_file, bool first) { int i; - int r; int min_score_adj = OOM_ADJUST_MAX + 1; int minfree = 0; int killed_size = 0; @@ -643,7 +642,6 @@ retry: } static void mp_event(uint32_t events __unused) { - int i; int ret; unsigned long long evcount; struct sysmeminfo mi; diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp index 858e56c..2b19b93 100644 --- a/logcat/logcat.cpp +++ b/logcat/logcat.cpp @@ -1,9 +1,10 @@ -// Copyright 2006-2014 The Android Open Source Project +// Copyright 2006-2015 The Android Open Source Project #include <assert.h> #include <ctype.h> #include <errno.h> #include <fcntl.h> +#include <math.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> @@ -11,6 +12,7 @@ #include <signal.h> #include <time.h> #include <unistd.h> +#include <sys/cdefs.h> #include <sys/socket.h> #include <sys/stat.h> #include <arpa/inet.h> @@ -23,7 +25,6 @@ #include <log/logprint.h> #include <log/event_tag_map.h> -#define DEFAULT_LOG_ROTATE_SIZE_KBYTES 16 #define DEFAULT_MAX_ROTATED_LOGS 4 static AndroidLogFormat * g_logformat; @@ -37,16 +38,16 @@ struct log_device_t { struct logger *logger; struct logger_list *logger_list; bool printed; - char label; log_device_t* next; - log_device_t(const char* d, bool b, char l) { + log_device_t(const char* d, bool b) { device = d; binary = b; - label = l; next = NULL; printed = false; + logger = NULL; + logger_list = NULL; } }; @@ -55,14 +56,16 @@ namespace android { /* Global Variables */ static const char * g_outputFileName = NULL; -static int g_logRotateSizeKBytes = 0; // 0 means "no log rotation" -static int g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded" +// 0 means "no log rotation" +static size_t g_logRotateSizeKBytes = 0; +// 0 means "unbounded" +static size_t g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS; static int g_outFD = -1; -static off_t g_outByteCount = 0; +static size_t g_outByteCount = 0; static int g_printBinary = 0; -static int g_devCount = 0; +static int g_devCount = 0; // >1 means multiple -static EventTagMap* g_eventTagMap = NULL; +__noreturn static void logcat_panic(bool showHelp, const char *fmt, ...) __printflike(2,3); static int openLogFile (const char *pathname) { @@ -80,18 +83,28 @@ static void rotateLogs() close(g_outFD); + // Compute the maximum number of digits needed to count up to g_maxRotatedLogs in decimal. + // eg: g_maxRotatedLogs == 30 -> log10(30) == 1.477 -> maxRotationCountDigits == 2 + int maxRotationCountDigits = + (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0; + for (int i = g_maxRotatedLogs ; i > 0 ; i--) { char *file0, *file1; - asprintf(&file1, "%s.%d", g_outputFileName, i); + asprintf(&file1, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i); if (i - 1 == 0) { asprintf(&file0, "%s", g_outputFileName); } else { - asprintf(&file0, "%s.%d", g_outputFileName, i - 1); + asprintf(&file0, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1); + } + + if (!file0 || !file1) { + perror("while rotating log files"); + break; } - err = rename (file0, file1); + err = rename(file0, file1); if (err < 0 && errno != ENOENT) { perror("while rotating log files"); @@ -101,11 +114,10 @@ static void rotateLogs() free(file0); } - g_outFD = openLogFile (g_outputFileName); + g_outFD = openLogFile(g_outputFileName); if (g_outFD < 0) { - perror ("couldn't open output file"); - exit(-1); + logcat_panic(false, "couldn't open output file"); } g_outByteCount = 0; @@ -127,8 +139,15 @@ static void processBuffer(log_device_t* dev, struct log_msg *buf) char binaryMsgBuf[1024]; if (dev->binary) { + static bool hasOpenedEventTagMap = false; + static EventTagMap *eventTagMap = NULL; + + if (!eventTagMap && !hasOpenedEventTagMap) { + eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE); + hasOpenedEventTagMap = true; + } err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry, - g_eventTagMap, + eventTagMap, binaryMsgBuf, sizeof(binaryMsgBuf)); //printf(">>> pri=%d len=%d msg='%s'\n", @@ -141,21 +160,10 @@ static void processBuffer(log_device_t* dev, struct log_msg *buf) } 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); - } - } - bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry); if (bytesWritten < 0) { - perror("output error"); - exit(-1); + logcat_panic(false, "output error"); } } @@ -172,18 +180,18 @@ error: return; } -static void maybePrintStart(log_device_t* dev) { - if (!dev->printed) { - dev->printed = true; +static void maybePrintStart(log_device_t* dev, bool printDividers) { + if (!dev->printed || printDividers) { if (g_devCount > 1 && !g_printBinary) { char buf[1024]; - snprintf(buf, sizeof(buf), "--------- beginning of %s\n", + snprintf(buf, sizeof(buf), "--------- %s %s\n", + dev->printed ? "switch to" : "beginning of", dev->device); if (write(g_outFD, buf, strlen(buf)) < 0) { - perror("output error"); - exit(-1); + logcat_panic(false, "output error"); } } + dev->printed = true; } } @@ -199,11 +207,18 @@ static void setupOutput() g_outFD = openLogFile (g_outputFileName); if (g_outFD < 0) { - perror ("couldn't open output file"); - exit(-1); + logcat_panic(false, "couldn't open output file"); } - fstat(g_outFD, &statbuf); + if (fstat(g_outFD, &statbuf) == -1) { + close(g_outFD); + logcat_panic(false, "couldn't get output file stat\n"); + } + + if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) { + close(g_outFD); + logcat_panic(false, "invalid output file stat\n"); + } g_outByteCount = statbuf.st_size; } @@ -215,12 +230,13 @@ static void show_help(const char *cmd) fprintf(stderr, "options include:\n" " -s Set default filter to silent.\n" - " Like specifying filterspec '*:s'\n" + " Like specifying filterspec '*:S'\n" " -f <filename> Log to file. Default to stdout\n" - " -r [<kbytes>] Rotate log every kbytes. (16 if unspecified). Requires -f\n" + " -r <kbytes> Rotate log every kbytes. Requires -f\n" " -n <count> Sets max number of rotated logs to <count>, default 4\n" - " -v <format> Sets the log print format, where <format> is one of:\n\n" - " brief process tag thread raw time threadtime long\n\n" + " -v <format> Sets the log print format, where <format> is:\n\n" + " brief color long process raw tag thread threadtime time\n\n" + " -D print dividers between each log buffer\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" @@ -229,6 +245,7 @@ static void show_help(const char *cmd) " -T '<time>' print most recent lines since specified time (not imply -d)\n" " count is pure numerical, time is 'MM-DD hh:mm:ss.mmm'\n" " -g get the size of the log's ring buffer and exit\n" + " -L dump logs from prior to last reboot\n" " -b <buffer> Request alternate ring buffer, 'main', 'system', 'radio',\n" " 'events', 'crash' or 'all'. Multiple -b parameters are\n" " allowed and results are interleaved. The default is\n" @@ -248,26 +265,21 @@ static void show_help(const char *cmd) fprintf(stderr,"\nfilterspecs are a series of \n" " <tag>[:priority]\n\n" "where <tag> is a log component tag (or * for all) and priority is:\n" - " V Verbose\n" - " D Debug\n" + " V Verbose (default for <tag>)\n" + " D Debug (default for '*')\n" " I Info\n" " W Warn\n" " E Error\n" " F Fatal\n" - " S Silent (supress all output)\n" - "\n'*' means '*:d' and <tag> by itself means <tag>:v\n" - "\nIf not specified on the commandline, filterspec is set from ANDROID_LOG_TAGS.\n" - "If no filterspec is found, filter defaults to '*:I'\n" - "\nIf not specified with -v, format is set from ANDROID_PRINTF_LOG\n" - "or defaults to \"brief\"\n\n"); - - - + " S Silent (suppress all output)\n" + "\n'*' by itself means '*:D' and <tag> by itself means <tag>:V.\n" + "If no '*' filterspec or -s on command line, all filter defaults to '*:V'.\n" + "eg: '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.\n" + "\nIf not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.\n" + "\nIf not specified with -v on command line, format is set from ANDROID_PRINTF_LOG\n" + "or defaults to \"threadtime\"\n\n"); } - -} /* namespace android */ - static int setLogFormat(const char * formatString) { static AndroidLogPrintFormat format; @@ -308,8 +320,46 @@ static const char *multiplier_of_size(unsigned long value) return multipliers[i]; } +/*String to unsigned int, returns -1 if it fails*/ +static bool getSizeTArg(char *ptr, size_t *val, size_t min = 0, + size_t max = SIZE_MAX) +{ + char *endp; + errno = 0; + size_t ret = (size_t) strtoll(ptr, &endp, 0); + + if (endp[0] != '\0' || errno != 0 ) { + return false; + } + + if (ret > max || ret < min) { + return false; + } + + *val = ret; + return true; +} + +static void logcat_panic(bool showHelp, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + + if (showHelp) { + show_help(getprogname()); + } + + exit(EXIT_FAILURE); +} + +} /* namespace android */ + + int main(int argc, char **argv) { + using namespace android; int err; int hasSetLogFormat = 0; int clearLog = 0; @@ -318,13 +368,13 @@ int main(int argc, char **argv) int getPruneList = 0; char *setPruneList = NULL; int printStatistics = 0; - int mode = O_RDONLY; + int mode = ANDROID_LOG_RDONLY; const char *forceFilters = NULL; log_device_t* devices = NULL; log_device_t* dev; - bool needBinary = false; + bool printDividers = false; struct logger_list *logger_list; - unsigned int tail_lines = 0; + size_t tail_lines = 0; log_time tail_time(log_time::EPOCH); signal(SIGPIPE, exit); @@ -332,14 +382,14 @@ int main(int argc, char **argv) g_logformat = android_log_format_new(); if (argc == 2 && 0 == strcmp(argv[1], "--help")) { - android::show_help(argv[0]); - exit(0); + show_help(argv[0]); + return EXIT_SUCCESS; } for (;;) { int ret; - ret = getopt(argc, argv, "cdt:T:gG:sQf:r:n:v:b:BSpP:"); + ret = getopt(argc, argv, ":cdDLt:T:gG:sQf:r:n:v:b:BSpP:"); if (ret < 0) { break; @@ -353,25 +403,28 @@ int main(int argc, char **argv) case 'c': clearLog = 1; - mode = O_WRONLY; + mode |= ANDROID_LOG_WRONLY; + break; + + case 'L': + mode |= ANDROID_LOG_PSTORE; break; case 'd': - mode = O_RDONLY | O_NDELAY; + mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK; break; case 't': - mode = O_RDONLY | O_NDELAY; + mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK; /* FALLTHRU */ case 'T': if (strspn(optarg, "0123456789") != strlen(optarg)) { char *cp = tail_time.strptime(optarg, log_time::default_format); if (!cp) { - fprintf(stderr, - "ERROR: -%c \"%s\" not in \"%s\" time format\n", - ret, optarg, log_time::default_format); - exit(1); + logcat_panic(false, + "-%c \"%s\" not in \"%s\" time format\n", + ret, optarg, log_time::default_format); } if (*cp) { char c = *cp; @@ -382,8 +435,7 @@ int main(int argc, char **argv) *cp = c; } } else { - tail_lines = atoi(optarg); - if (!tail_lines) { + if (!getSizeTArg(optarg, &tail_lines, 1)) { fprintf(stderr, "WARNING: -%c %s invalid, setting to 1\n", ret, optarg); @@ -392,18 +444,20 @@ int main(int argc, char **argv) } break; + case 'D': + printDividers = true; + break; + case 'g': getLogSize = 1; break; case 'G': { - // would use atol if not for the multiplier - char *cp = optarg; - setLogSize = 0; - while (('0' <= *cp) && (*cp <= '9')) { - setLogSize *= 10; - setLogSize += *cp - '0'; - ++cp; + char *cp; + if (strtoll(optarg, &cp, 0) > 0) { + setLogSize = strtoll(optarg, &cp, 0); + } else { + setLogSize = 0; } switch(*cp) { @@ -428,7 +482,7 @@ int main(int argc, char **argv) if (!setLogSize) { fprintf(stderr, "ERROR: -G <num><multiplier>\n"); - exit(1); + return EXIT_FAILURE; } } break; @@ -449,101 +503,76 @@ int main(int argc, char **argv) delete dev; } - dev = devices = new log_device_t("main", false, 'm'); - android::g_devCount = 1; - if (android_name_to_log_id("system") == LOG_ID_SYSTEM) { - dev->next = new log_device_t("system", false, 's'); - if (dev->next) { - dev = dev->next; - android::g_devCount++; - } - } - if (android_name_to_log_id("radio") == LOG_ID_RADIO) { - dev->next = new log_device_t("radio", false, 'r'); - if (dev->next) { - dev = dev->next; - android::g_devCount++; - } - } - if (android_name_to_log_id("events") == LOG_ID_EVENTS) { - dev->next = new log_device_t("events", true, 'e'); - if (dev->next) { - dev = dev->next; - android::g_devCount++; - needBinary = true; + devices = dev = NULL; + g_devCount = 0; + for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) { + const char *name = android_log_id_to_name((log_id_t)i); + log_id_t log_id = android_name_to_log_id(name); + + if (log_id != (log_id_t)i) { + continue; } - } - if (android_name_to_log_id("crash") == LOG_ID_CRASH) { - dev->next = new log_device_t("crash", false, 'c'); - if (dev->next) { - android::g_devCount++; + + bool binary = strcmp(name, "events") == 0; + log_device_t* d = new log_device_t(name, binary); + + if (dev) { + dev->next = d; + dev = d; + } else { + devices = dev = d; } + g_devCount++; } break; } 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(optarg, binary, optarg[0]); + dev->next = new log_device_t(optarg, binary); } else { - devices = new log_device_t(optarg, binary, optarg[0]); + devices = new log_device_t(optarg, binary); } - android::g_devCount++; + g_devCount++; } break; case 'B': - android::g_printBinary = 1; + g_printBinary = 1; break; case 'f': // redirect output to a file - - android::g_outputFileName = optarg; + g_outputFileName = optarg; break; case 'r': - if (optarg == NULL) { - android::g_logRotateSizeKBytes - = DEFAULT_LOG_ROTATE_SIZE_KBYTES; - } else { - if (!isdigit(optarg[0])) { - fprintf(stderr,"Invalid parameter to -r\n"); - android::show_help(argv[0]); - exit(-1); - } - android::g_logRotateSizeKBytes = atoi(optarg); + if (!getSizeTArg(optarg, &g_logRotateSizeKBytes, 1)) { + logcat_panic(true, "Invalid parameter %s to -r\n", optarg); } break; case 'n': - if (!isdigit(optarg[0])) { - fprintf(stderr,"Invalid parameter to -r\n"); - android::show_help(argv[0]); - exit(-1); + if (!getSizeTArg(optarg, &g_maxRotatedLogs, 1)) { + logcat_panic(true, "Invalid parameter %s to -n\n", optarg); } - - android::g_maxRotatedLogs = atoi(optarg); break; case 'v': err = setLogFormat (optarg); if (err < 0) { - fprintf(stderr,"Invalid parameter to -v\n"); - android::show_help(argv[0]); - exit(-1); + logcat_panic(true, "Invalid parameter %s to -v\n", optarg); } - hasSetLogFormat = 1; + if (strcmp("color", optarg)) { // exception for modifiers + hasSetLogFormat = 1; + } break; case 'Q': @@ -584,8 +613,9 @@ int main(int argc, char **argv) force_exit = 0; } /* if nothing found or invalid filters, exit quietly */ - if (force_exit) - exit(0); + if (force_exit) { + return EXIT_SUCCESS; + } /* redirect our output to the emulator console */ if (console) { @@ -617,55 +647,53 @@ int main(int argc, char **argv) printStatistics = 1; break; + case ':': + logcat_panic(true, "Option -%c needs an argument\n", optopt); + break; + default: - fprintf(stderr,"Unrecognized Option\n"); - android::show_help(argv[0]); - exit(-1); - break; + logcat_panic(true, "Unrecognized Option %c\n", optopt); + break; } } if (!devices) { - dev = devices = new log_device_t("main", false, 'm'); - android::g_devCount = 1; + dev = devices = new log_device_t("main", false); + g_devCount = 1; if (android_name_to_log_id("system") == LOG_ID_SYSTEM) { - dev = dev->next = new log_device_t("system", false, 's'); - android::g_devCount++; + dev = dev->next = new log_device_t("system", false); + g_devCount++; } if (android_name_to_log_id("crash") == LOG_ID_CRASH) { - dev = dev->next = new log_device_t("crash", false, 'c'); - android::g_devCount++; + dev = dev->next = new log_device_t("crash", false); + g_devCount++; } } - if (android::g_logRotateSizeKBytes != 0 - && android::g_outputFileName == NULL - ) { - fprintf(stderr,"-r requires -f as well\n"); - android::show_help(argv[0]); - exit(-1); + if (g_logRotateSizeKBytes != 0 && g_outputFileName == NULL) { + logcat_panic(true, "-r requires -f as well\n"); } - android::setupOutput(); + setupOutput(); if (hasSetLogFormat == 0) { const char* logFormat = getenv("ANDROID_PRINTF_LOG"); if (logFormat != NULL) { err = setLogFormat(logFormat); - if (err < 0) { fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", logFormat); } + } else { + setLogFormat("threadtime"); } } if (forceFilters) { err = android_log_addFilterString(g_logformat, forceFilters); if (err < 0) { - fprintf (stderr, "Invalid filter expression in -logcat option\n"); - exit(0); + logcat_panic(false, "Invalid filter expression in logcat args\n"); } } else if (argc == optind) { // Add from environment variable @@ -675,10 +703,8 @@ int main(int argc, char **argv) err = android_log_addFilterString(g_logformat, env_tags_orig); if (err < 0) { - fprintf(stderr, "Invalid filter expression in" - " ANDROID_LOG_TAGS\n"); - android::show_help(argv[0]); - exit(-1); + logcat_panic(true, + "Invalid filter expression in ANDROID_LOG_TAGS\n"); } } } else { @@ -687,9 +713,7 @@ int main(int argc, char **argv) err = android_log_addFilterString(g_logformat, argv[i]); if (err < 0) { - fprintf (stderr, "Invalid filter expression '%s'\n", argv[i]); - android::show_help(argv[0]); - exit(-1); + logcat_panic(true, "Invalid filter expression '%s'\n", argv[i]); } } } @@ -705,22 +729,20 @@ int main(int argc, char **argv) dev->logger = android_logger_open(logger_list, android_name_to_log_id(dev->device)); if (!dev->logger) { - fprintf(stderr, "Unable to open log device '%s'\n", dev->device); - exit(EXIT_FAILURE); + logcat_panic(false, "Unable to open log device '%s'\n", + dev->device); } if (clearLog) { int ret; ret = android_logger_clear(dev->logger); if (ret) { - perror("failed to clear the log"); - exit(EXIT_FAILURE); + logcat_panic(false, "failed to clear the log"); } } if (setLogSize && android_logger_set_log_size(dev->logger, setLogSize)) { - perror("failed to set the log size"); - exit(EXIT_FAILURE); + logcat_panic(false, "failed to set the log size"); } if (getLogSize) { @@ -728,14 +750,12 @@ int main(int argc, char **argv) size = android_logger_get_log_size(dev->logger); if (size < 0) { - perror("failed to get the log size"); - exit(EXIT_FAILURE); + logcat_panic(false, "failed to get the log size"); } readable = android_logger_get_log_readable_size(dev->logger); if (readable < 0) { - perror("failed to get the readable log size"); - exit(EXIT_FAILURE); + logcat_panic(false, "failed to get the readable log size"); } printf("%s: ring buffer is %ld%sb (%ld%sb consumed), " @@ -749,16 +769,18 @@ int main(int argc, char **argv) } if (setPruneList) { - size_t len = strlen(setPruneList) + 32; // margin to allow rc - char *buf = (char *) malloc(len); - - strcpy(buf, setPruneList); - int ret = android_logger_set_prune_list(logger_list, buf, len); - free(buf); - - if (ret) { - perror("failed to set the prune list"); - exit(EXIT_FAILURE); + size_t len = strlen(setPruneList); + /*extra 32 bytes are needed by android_logger_set_prune_list */ + size_t bLen = len + 32; + char *buf = NULL; + if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) { + buf[len] = '\0'; + if (android_logger_set_prune_list(logger_list, buf, bLen)) { + logcat_panic(false, "failed to set the prune list"); + } + free(buf); + } else { + logcat_panic(false, "failed to set the prune list (alloc)"); } } @@ -768,29 +790,28 @@ int main(int argc, char **argv) for(int retry = 32; (retry >= 0) && ((buf = new char [len])); - delete [] buf, --retry) { + delete [] buf, buf = NULL, --retry) { if (getPruneList) { android_logger_get_prune_list(logger_list, buf, len); } else { android_logger_get_statistics(logger_list, buf, len); } buf[len-1] = '\0'; - size_t ret = atol(buf) + 1; - if (ret < 4) { + if (atol(buf) < 3) { delete [] buf; buf = NULL; break; } - bool check = ret <= len; - len = ret; - if (check) { + size_t ret = atol(buf) + 1; + if (ret <= len) { + len = ret; break; } + len = ret; } if (!buf) { - perror("failed to read data"); - exit(EXIT_FAILURE); + logcat_panic(false, "failed to read data"); } // remove trailing FF @@ -814,34 +835,33 @@ int main(int argc, char **argv) printf("%s", cp); delete [] buf; - exit(0); + return EXIT_SUCCESS; } if (getLogSize) { - exit(0); + return EXIT_SUCCESS; } if (setLogSize || setPruneList) { - exit(0); + return EXIT_SUCCESS; } if (clearLog) { - exit(0); + return EXIT_SUCCESS; } //LOG_EVENT_INT(10, 12345); //LOG_EVENT_LONG(11, 0x1122334455667788LL); //LOG_EVENT_STRING(0, "whassup, doc?"); - if (needBinary) - android::g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE); - + dev = NULL; + log_device_t unexpected("unexpected", false); while (1) { struct log_msg log_msg; + log_device_t* d; int ret = android_logger_list_read(logger_list, &log_msg); if (ret == 0) { - fprintf(stderr, "read: Unexpected EOF!\n"); - exit(EXIT_FAILURE); + logcat_panic(false, "read: unexpected EOF!\n"); } if (ret < 0) { @@ -850,36 +870,37 @@ int main(int argc, char **argv) } if (ret == -EIO) { - fprintf(stderr, "read: Unexpected EOF!\n"); - exit(EXIT_FAILURE); + logcat_panic(false, "read: unexpected EOF!\n"); } if (ret == -EINVAL) { - fprintf(stderr, "read: unexpected length.\n"); - exit(EXIT_FAILURE); + logcat_panic(false, "read: unexpected length.\n"); } - perror("logcat read failure"); - exit(EXIT_FAILURE); + logcat_panic(false, "logcat read failure"); } - for(dev = devices; dev; dev = dev->next) { - if (android_name_to_log_id(dev->device) == log_msg.id()) { + for(d = devices; d; d = d->next) { + if (android_name_to_log_id(d->device) == log_msg.id()) { break; } } - if (!dev) { - fprintf(stderr, "read: Unexpected log ID!\n"); - exit(EXIT_FAILURE); + if (!d) { + g_devCount = 2; // set to Multiple + d = &unexpected; + d->binary = log_msg.id() == LOG_ID_EVENTS; } - android::maybePrintStart(dev); - if (android::g_printBinary) { - android::printBinary(&log_msg); + if (dev != d) { + dev = d; + maybePrintStart(dev, printDividers); + } + if (g_printBinary) { + printBinary(&log_msg); } else { - android::processBuffer(dev, &log_msg); + processBuffer(dev, &log_msg); } } android_logger_list_free(logger_list); - return 0; + return EXIT_SUCCESS; } diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk index 015a23d..a28664e 100644 --- a/logcat/tests/Android.mk +++ b/logcat/tests/Android.mk @@ -39,7 +39,6 @@ benchmark_src_files := \ include $(CLEAR_VARS) LOCAL_MODULE := $(test_module_prefix)benchmarks LOCAL_MODULE_TAGS := $(test_tags) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += $(test_c_flags) LOCAL_SRC_FILES := $(benchmark_src_files) include $(BUILD_NATIVE_TEST) @@ -56,7 +55,6 @@ test_src_files := \ include $(CLEAR_VARS) LOCAL_MODULE := $(test_module_prefix)unit-tests LOCAL_MODULE_TAGS := $(test_tags) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += $(test_c_flags) LOCAL_SHARED_LIBRARIES := liblog LOCAL_SRC_FILES := $(test_src_files) diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp index 85756d5..de2db67 100644 --- a/logcat/tests/logcat_test.cpp +++ b/logcat/tests/logcat_test.cpp @@ -243,7 +243,7 @@ TEST(logcat, End_to_End) { FILE *fp; ASSERT_TRUE(NULL != (fp = popen( - "logcat -b events -t 100 2>/dev/null", + "logcat -v brief -b events -t 100 2>/dev/null", "r"))); char buffer[5120]; @@ -275,7 +275,7 @@ TEST(logcat, get_size) { // NB: crash log only available in user space ASSERT_TRUE(NULL != (fp = popen( - "logcat -b radio -b events -b system -b main -g 2>/dev/null", + "logcat -v brief -b radio -b events -b system -b main -g 2>/dev/null", "r"))); char buffer[5120]; @@ -364,7 +364,7 @@ TEST(logcat, blocking) { ASSERT_TRUE(NULL != (fp = popen( "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&" - " logcat -b events 2>&1", + " logcat -v brief -b events 2>&1", "r"))); char buffer[5120]; @@ -433,7 +433,7 @@ TEST(logcat, blocking_tail) { ASSERT_TRUE(NULL != (fp = popen( "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&" - " logcat -b events -T 5 2>&1", + " logcat -v brief -b events -T 5 2>&1", "r"))); char buffer[5120]; @@ -503,10 +503,16 @@ TEST(logcat, logrotate) { int count = 0; while (fgets(buffer, sizeof(buffer), fp)) { - static const char match[] = "4 log.txt"; + static const char match_1[] = "4 log.txt"; + static const char match_2[] = "8 log.txt"; + static const char match_3[] = "12 log.txt"; + static const char match_4[] = "16 log.txt"; static const char total[] = "total "; - if (!strncmp(buffer, match, sizeof(match) - 1)) { + if (!strncmp(buffer, match_1, sizeof(match_1) - 1) + || !strncmp(buffer, match_2, sizeof(match_2) - 1) + || !strncmp(buffer, match_3, sizeof(match_3) - 1) + || !strncmp(buffer, match_4, sizeof(match_4) - 1)) { ++count; } else if (strncmp(buffer, total, sizeof(total) - 1)) { fprintf(stderr, "WARNING: Parse error: %s", buffer); @@ -520,6 +526,59 @@ TEST(logcat, logrotate) { EXPECT_FALSE(system(command)); } +TEST(logcat, logrotate_suffix) { + static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX"; + char tmp_out_dir[sizeof(tmp_out_dir_form)]; + ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form))); + + static const char logcat_cmd[] = "logcat -b radio -b events -b system -b main" + " -d -f %s/log.txt -n 10 -r 1"; + char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd)]; + sprintf(command, logcat_cmd, tmp_out_dir); + + int ret; + EXPECT_FALSE((ret = system(command))); + if (!ret) { + sprintf(command, "ls %s 2>/dev/null", tmp_out_dir); + + FILE *fp; + EXPECT_TRUE(NULL != (fp = popen(command, "r"))); + char buffer[5120]; + int log_file_count = 0; + + while (fgets(buffer, sizeof(buffer), fp)) { + static const char rotated_log_filename_prefix[] = "log.txt."; + static const size_t rotated_log_filename_prefix_len = + strlen(rotated_log_filename_prefix); + static const char log_filename[] = "log.txt"; + + if (!strncmp(buffer, rotated_log_filename_prefix, rotated_log_filename_prefix_len)) { + // Rotated file should have form log.txt.## + char* rotated_log_filename_suffix = buffer + rotated_log_filename_prefix_len; + char* endptr; + const long int suffix_value = strtol(rotated_log_filename_suffix, &endptr, 10); + EXPECT_EQ(rotated_log_filename_suffix + 2, endptr); + EXPECT_LE(suffix_value, 10); + EXPECT_GT(suffix_value, 0); + ++log_file_count; + continue; + } + + if (!strncmp(buffer, log_filename, strlen(log_filename))) { + ++log_file_count; + continue; + } + + fprintf(stderr, "ERROR: Unexpected file: %s", buffer); + ADD_FAILURE(); + } + pclose(fp); + EXPECT_EQ(11, log_file_count); + } + sprintf(command, "rm -rf %s", tmp_out_dir); + EXPECT_FALSE(system(command)); +} + static void caught_blocking_clear(int /*signum*/) { unsigned long long v = 0xDEADBEEFA55C0000ULL; @@ -542,7 +601,7 @@ TEST(logcat, blocking_clear) { ASSERT_TRUE(NULL != (fp = popen( "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&" " logcat -b events -c 2>&1 ;" - " logcat -b events 2>&1", + " logcat -v brief -b events 2>&1", "r"))); char buffer[5120]; diff --git a/logd/Android.mk b/logd/Android.mk index 188511f..e65e9ff 100644 --- a/logd/Android.mk +++ b/logd/Android.mk @@ -26,7 +26,17 @@ LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils -LOCAL_CFLAGS := -Werror $(shell sed -n 's/^\([0-9]*\)[ \t]*auditd[ \t].*/-DAUDITD_LOG_TAG=\1/p' $(LOCAL_PATH)/event.logtags) +# This is what we want to do: +# event_logtags = $(shell \ +# sed -n \ +# "s/^\([0-9]*\)[ \t]*$1[ \t].*/-D`echo $1 | tr a-z A-Z`_LOG_TAG=\1/p" \ +# $(LOCAL_PATH)/$2/event.logtags) +# event_flag := $(call event_logtags,auditd) +# event_flag += $(call event_logtags,logd) +# so make sure we do not regret hard-coding it as follows: +event_flag := -DAUDITD_LOG_TAG=1003 -DLOGD_LOG_TAG=1004 + +LOCAL_CFLAGS := -Werror $(event_flag) include $(BUILD_EXECUTABLE) diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp index d7088b4..bdfed3b 100644 --- a/logd/CommandListener.cpp +++ b/logd/CommandListener.cpp @@ -44,6 +44,7 @@ CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/, registerCmd(new GetStatisticsCmd(buf)); registerCmd(new SetPruneListCmd(buf)); registerCmd(new GetPruneListCmd(buf)); + registerCmd(new ReinitCmd()); } CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader, @@ -68,7 +69,11 @@ CommandListener::ClearCmd::ClearCmd(LogBuffer *buf) { } static void setname() { - prctl(PR_SET_NAME, "logd.control"); + static bool name_set; + if (!name_set) { + prctl(PR_SET_NAME, "logd.control"); + name_set = true; + } } int CommandListener::ClearCmd::runCommand(SocketClient *cli, @@ -296,6 +301,21 @@ int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli, return 0; } +CommandListener::ReinitCmd::ReinitCmd() + : LogCommand("reinit") +{ } + +int CommandListener::ReinitCmd::runCommand(SocketClient *cli, + int /*argc*/, char ** /*argv*/) { + setname(); + + reinit_signal_handler(SIGHUP); + + cli->sendMsg("success"); + + return 0; +} + int CommandListener::getLogSocket() { static const char socketName[] = "logd"; int sock = android_get_control_socket(socketName); diff --git a/logd/CommandListener.h b/logd/CommandListener.h index cd1c306..83e06b4 100644 --- a/logd/CommandListener.h +++ b/logd/CommandListener.h @@ -23,6 +23,9 @@ #include "LogReader.h" #include "LogListener.h" +// See main.cpp for implementation +void reinit_signal_handler(int /*signal*/); + class CommandListener : public FrameworkListener { LogBuffer &mBuf; @@ -60,6 +63,14 @@ private: LogBufferCmd(GetStatistics) LogBufferCmd(GetPruneList) LogBufferCmd(SetPruneList) + + class ReinitCmd : public LogCommand { + public: + ReinitCmd(); + virtual ~ReinitCmd() {} + int runCommand(SocketClient *c, int argc, char ** argv); + }; + }; #endif diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp index 3be07c0..26a1861 100644 --- a/logd/FlushCommand.cpp +++ b/logd/FlushCommand.cpp @@ -27,7 +27,7 @@ FlushCommand::FlushCommand(LogReader &reader, unsigned long tail, unsigned int logMask, pid_t pid, - log_time start) + uint64_t start) : mReader(reader) , mNonBlock(nonBlock) , mTail(tail) diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h index f34c06a..61c6858 100644 --- a/logd/FlushCommand.h +++ b/logd/FlushCommand.h @@ -31,7 +31,7 @@ class FlushCommand : public SocketClientCommand { unsigned long mTail; unsigned int mLogMask; pid_t mPid; - log_time mStart; + uint64_t mStart; public: FlushCommand(LogReader &mReader, @@ -39,7 +39,7 @@ public: unsigned long tail = -1, unsigned int logMask = -1, pid_t pid = 0, - log_time start = LogTimeEntry::EPOCH); + uint64_t start = 1); virtual void runSocketCommand(SocketClient *client); static bool hasReadLogs(SocketClient *client); diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp index ee2f32d..caae54b 100644 --- a/logd/LogAudit.cpp +++ b/logd/LogAudit.cpp @@ -15,39 +15,44 @@ */ #include <ctype.h> +#include <endian.h> #include <errno.h> #include <limits.h> #include <stdarg.h> #include <stdlib.h> -#include <sys/klog.h> #include <sys/prctl.h> #include <sys/uio.h> #include <syslog.h> +#include <private/android_filesystem_config.h> +#include <private/android_logger.h> + #include "libaudit.h" #include "LogAudit.h" -#define KMSG_PRIORITY(PRI) \ - '<', \ - '0' + (LOG_AUTH | (PRI)) / 10, \ - '0' + (LOG_AUTH | (PRI)) % 10, \ +#define KMSG_PRIORITY(PRI) \ + '<', \ + '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \ + '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, \ '>' -LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmsg) +LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg) : SocketListener(getLogSocket(), false) , logbuf(buf) , reader(reader) - , fdDmesg(-1) { + , fdDmesg(fdDmesg) + , initialized(false) { static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO), 'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':', ' ', 's', 't', 'a', 'r', 't', '\n' }; - write(fdDmsg, auditd_message, sizeof(auditd_message)); - logDmesg(); - fdDmesg = fdDmsg; + write(fdDmesg, auditd_message, sizeof(auditd_message)); } bool LogAudit::onDataAvailable(SocketClient *cli) { - prctl(PR_SET_NAME, "logd.auditd"); + if (!initialized) { + prctl(PR_SET_NAME, "logd.auditd"); + initialized = true; + } struct audit_message rep; @@ -60,7 +65,8 @@ bool LogAudit::onDataAvailable(SocketClient *cli) { return false; } - logPrint("type=%d %.*s", rep.nlh.nlmsg_type, rep.nlh.nlmsg_len, rep.data); + logPrint("type=%d %.*s", + rep.nlh.nlmsg_type, rep.nlh.nlmsg_len, rep.data); return true; } @@ -87,7 +93,7 @@ int LogAudit::logPrint(const char *fmt, ...) { } bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded "); - if (fdDmesg >= 0) { + if ((fdDmesg >= 0) && initialized) { struct iovec iov[3]; static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) }; static const char log_warning[] = { KMSG_PRIORITY(LOG_WARNING) }; @@ -105,7 +111,7 @@ int LogAudit::logPrint(const char *fmt, ...) { pid_t pid = getpid(); pid_t tid = gettid(); - uid_t uid = getuid(); + uid_t uid = AID_LOGD; log_time now; static const char audit_str[] = " audit("; @@ -136,31 +142,27 @@ int LogAudit::logPrint(const char *fmt, ...) { // log to events size_t l = strlen(str); - size_t n = l + sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t); + size_t n = l + sizeof(android_log_event_string_t); bool notify = false; - char *newstr = reinterpret_cast<char *>(malloc(n)); - if (!newstr) { + android_log_event_string_t *event = static_cast<android_log_event_string_t *>(malloc(n)); + if (!event) { rc = -ENOMEM; } else { - cp = newstr; - *cp++ = AUDITD_LOG_TAG & 0xFF; - *cp++ = (AUDITD_LOG_TAG >> 8) & 0xFF; - *cp++ = (AUDITD_LOG_TAG >> 16) & 0xFF; - *cp++ = (AUDITD_LOG_TAG >> 24) & 0xFF; - *cp++ = EVENT_TYPE_STRING; - *cp++ = l & 0xFF; - *cp++ = (l >> 8) & 0xFF; - *cp++ = (l >> 16) & 0xFF; - *cp++ = (l >> 24) & 0xFF; - memcpy(cp, str, l); - - logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid, newstr, - (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX); - free(newstr); - - notify = true; + event->header.tag = htole32(AUDITD_LOG_TAG); + event->type = EVENT_TYPE_STRING; + event->length = htole32(l); + memcpy(event->data, str, l); + + rc = logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid, + reinterpret_cast<char *>(event), + (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX); + free(event); + + if (rc >= 0) { + notify = true; + } } // log to main @@ -188,7 +190,7 @@ int LogAudit::logPrint(const char *fmt, ...) { } n = (estr - str) + strlen(ecomm) + l + 2; - newstr = reinterpret_cast<char *>(malloc(n)); + char *newstr = static_cast<char *>(malloc(n)); if (!newstr) { rc = -ENOMEM; } else { @@ -197,50 +199,44 @@ int LogAudit::logPrint(const char *fmt, ...) { strncpy(newstr + 1 + l, str, estr - str); strcpy(newstr + 1 + l + (estr - str), ecomm); - logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr, - (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX); + rc = logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr, + (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX); free(newstr); - notify = true; + if (rc >= 0) { + notify = true; + } } free(str); if (notify) { reader->notifyNewLog(); + if (rc < 0) { + rc = n; + } } return rc; } -void LogAudit::logDmesg() { - int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0); - if (len <= 0) { - return; +int LogAudit::log(char *buf) { + char *audit = strstr(buf, " audit("); + if (!audit) { + return -EXDEV; } - len++; - char buf[len]; + *audit = '\0'; - int rc = klogctl(KLOG_READ_ALL, buf, len); - - buf[len - 1] = '\0'; - - for(char *tok = buf; (rc >= 0) && ((tok = strtok(tok, "\r\n"))); tok = NULL) { - char *audit = strstr(tok, " audit("); - if (!audit) { - continue; - } - - *audit++ = '\0'; - - char *type = strstr(tok, "type="); - if (type) { - rc = logPrint("%s %s", type, audit); - } else { - rc = logPrint("%s", audit); - } + int rc; + char *type = strstr(buf, "type="); + if (type) { + rc = logPrint("%s %s", type, audit + 1); + } else { + rc = logPrint("%s", audit + 1); } + *audit = ' '; + return rc; } int LogAudit::getLogSocket() { diff --git a/logd/LogAudit.h b/logd/LogAudit.h index 111030a..f977be9 100644 --- a/logd/LogAudit.h +++ b/logd/LogAudit.h @@ -24,16 +24,17 @@ class LogAudit : public SocketListener { LogBuffer *logbuf; LogReader *reader; int fdDmesg; + bool initialized; public: LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg); + int log(char *buf); protected: virtual bool onDataAvailable(SocketClient *cli); private: static int getLogSocket(); - void logDmesg(); int logPrint(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); }; diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp index 8c1c344..1dced11 100644 --- a/logd/LogBuffer.cpp +++ b/logd/LogBuffer.cpp @@ -15,8 +15,8 @@ */ #include <ctype.h> +#include <errno.h> #include <stdio.h> -#include <stdlib.h> #include <string.h> #include <sys/user.h> #include <time.h> @@ -27,8 +27,6 @@ #include "LogBuffer.h" #include "LogReader.h" -#include "LogStatistics.h" -#include "LogWhiteBlackList.h" // Default #define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here? @@ -92,11 +90,7 @@ static unsigned long property_get_size(const char *key) { return value; } -LogBuffer::LogBuffer(LastLogTimes *times) - : dgramQlenStatistics(false) - , mTimes(*times) { - pthread_mutex_init(&mLogElementsLock, NULL); - +void LogBuffer::init() { static const char global_tuneable[] = "persist.logd.size"; // Settings App static const char global_default[] = "ro.logd.size"; // BoardConfig.mk @@ -132,11 +126,18 @@ LogBuffer::LogBuffer(LastLogTimes *times) } } -void LogBuffer::log(log_id_t log_id, log_time realtime, - uid_t uid, pid_t pid, pid_t tid, - const char *msg, unsigned short len) { +LogBuffer::LogBuffer(LastLogTimes *times) + : mTimes(*times) { + pthread_mutex_init(&mLogElementsLock, NULL); + + init(); +} + +int LogBuffer::log(log_id_t log_id, log_time realtime, + uid_t uid, pid_t pid, pid_t tid, + const char *msg, unsigned short len) { if ((log_id >= LOG_ID_MAX) || (log_id < 0)) { - return; + return -EINVAL; } LogBufferElement *elem = new LogBufferElement(log_id, realtime, uid, pid, tid, msg, len); @@ -147,25 +148,9 @@ void LogBuffer::log(log_id_t log_id, log_time realtime, // NB: if end is region locked, place element at end of list LogBufferElementCollection::iterator it = mLogElements.end(); LogBufferElementCollection::iterator last = it; - while (--it != mLogElements.begin()) { + while (last != mLogElements.begin()) { + --it; if ((*it)->getRealTime() <= realtime) { - // halves the peak performance, use with caution - if (dgramQlenStatistics) { - LogBufferElementCollection::iterator ib = it; - unsigned short buckets, num = 1; - for (unsigned short i = 0; (buckets = stats.dgramQlen(i)); ++i) { - buckets -= num; - num += buckets; - while (buckets && (--ib != mLogElements.begin())) { - --buckets; - } - if (buckets) { - break; - } - stats.recordDiff( - elem->getRealTime() - (*ib)->getRealTime(), i); - } - } break; } last = it; @@ -174,7 +159,7 @@ void LogBuffer::log(log_id_t log_id, log_time realtime, if (last == mLogElements.end()) { mLogElements.push_back(elem); } else { - log_time end = log_time::EPOCH; + uint64_t end = 1; bool end_set = false; bool end_always = false; @@ -197,7 +182,7 @@ void LogBuffer::log(log_id_t log_id, log_time realtime, } if (end_always - || (end_set && (end >= (*last)->getMonotonicTime()))) { + || (end_set && (end >= (*last)->getSequence()))) { mLogElements.push_back(elem); } else { mLogElements.insert(last,elem); @@ -206,9 +191,11 @@ void LogBuffer::log(log_id_t log_id, log_time realtime, LogTimeEntry::unlock(); } - stats.add(len, log_id, uid, pid); + stats.add(elem); maybePrune(log_id); pthread_mutex_unlock(&mLogElementsLock); + + return len; } // If we're using more than 256K of memory for log entries, prune @@ -229,6 +216,94 @@ void LogBuffer::maybePrune(log_id_t id) { } } +LogBufferElementCollection::iterator LogBuffer::erase(LogBufferElementCollection::iterator it) { + LogBufferElement *e = *it; + + it = mLogElements.erase(it); + stats.subtract(e); + delete e; + + return it; +} + +// Define a temporary mechanism to report the last LogBufferElement pointer +// for the specified uid, pid and tid. Used below to help merge-sort when +// pruning for worst UID. +class LogBufferElementKey { + const union { + struct { + uint16_t uid; + uint16_t pid; + uint16_t tid; + uint16_t padding; + } __packed; + uint64_t value; + } __packed; + +public: + LogBufferElementKey(uid_t u, pid_t p, pid_t t):uid(u),pid(p),tid(t),padding(0) { } + LogBufferElementKey(uint64_t k):value(k) { } + + uint64_t getKey() { return value; } +}; + +class LogBufferElementEntry { + const uint64_t key; + LogBufferElement *last; + +public: + LogBufferElementEntry(const uint64_t &k, LogBufferElement *e):key(k),last(e) { } + + const uint64_t&getKey() const { return key; } + + LogBufferElement *getLast() { return last; } +}; + +class LogBufferElementLast : public android::BasicHashtable<uint64_t, LogBufferElementEntry> { + +public: + bool merge(LogBufferElement *e, unsigned short dropped) { + LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid()); + android::hash_t hash = android::hash_type(key.getKey()); + ssize_t index = find(-1, hash, key.getKey()); + if (index != -1) { + LogBufferElementEntry &entry = editEntryAt(index); + LogBufferElement *l = entry.getLast(); + unsigned short d = l->getDropped(); + if ((dropped + d) > USHRT_MAX) { + removeAt(index); + } else { + l->setDropped(dropped + d); + return true; + } + } + return false; + } + + size_t add(LogBufferElement *e) { + LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid()); + android::hash_t hash = android::hash_type(key.getKey()); + return android::BasicHashtable<uint64_t, LogBufferElementEntry>:: + add(hash, LogBufferElementEntry(key.getKey(), e)); + } + + inline void clear() { + android::BasicHashtable<uint64_t, LogBufferElementEntry>::clear(); + } + + void clear(LogBufferElement *e) { + uint64_t current = e->getRealTime().nsec() - NS_PER_SEC; + ssize_t index = -1; + while((index = next(index)) >= 0) { + if (current > editEntryAt(index).getLast()->getRealTime().nsec()) { + removeAt(index); + index = -1; + } + } + } + +}; + // prune "pruneRows" of type "id" from the buffer. // // mLogElementsLock must be held when this function is called. @@ -241,7 +316,7 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { LastLogTimes::iterator t = mTimes.begin(); while(t != mTimes.end()) { LogTimeEntry *entry = (*t); - if (entry->owned_Locked() + if (entry->owned_Locked() && entry->isWatching(id) && (!oldest || (oldest->mStart > entry->mStart))) { oldest = entry; } @@ -254,7 +329,7 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { for(it = mLogElements.begin(); it != mLogElements.end();) { LogBufferElement *e = *it; - if (oldest && (oldest->mStart <= e->getMonotonicTime())) { + if (oldest && (oldest->mStart <= e->getSequence())) { break; } @@ -263,12 +338,8 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { continue; } - uid_t uid = e->getUid(); - - if (uid == caller_uid) { - it = mLogElements.erase(it); - stats.subtract(e->getMsgLen(), id, uid, e->getPid()); - delete e; + if (e->getUid() == caller_uid) { + it = erase(it); pruneRows--; if (pruneRows == 0) { break; @@ -282,31 +353,44 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { } // prune by worst offender by uid + bool hasBlacklist = mPrune.naughty(); while (pruneRows > 0) { // recalculate the worst offender on every batched pass uid_t worst = (uid_t) -1; size_t worst_sizes = 0; size_t second_worst_sizes = 0; - if ((id != LOG_ID_CRASH) && mPrune.worstUidEnabled()) { - LidStatistics &l = stats.id(id); - l.sort(); - UidStatisticsCollection::iterator iu = l.begin(); - if (iu != l.end()) { - UidStatistics *u = *iu; - worst = u->getUid(); - worst_sizes = u->sizes(); - if (++iu != l.end()) { - second_worst_sizes = (*iu)->sizes(); + if (worstUidEnabledForLogid(id) && mPrune.worstUidEnabled()) { + std::unique_ptr<const UidEntry *[]> sorted = stats.sort(2, id); + + if (sorted.get()) { + if (sorted[0] && sorted[1]) { + worst_sizes = sorted[0]->getSizes(); + // Calculate threshold as 12.5% of available storage + size_t threshold = log_buffer_size(id) / 8; + if (worst_sizes > threshold) { + worst = sorted[0]->getKey(); + second_worst_sizes = sorted[1]->getSizes(); + if (second_worst_sizes < threshold) { + second_worst_sizes = threshold; + } + } } } } + // skip if we have neither worst nor naughty filters + if ((worst == (uid_t) -1) && !hasBlacklist) { + break; + } + bool kick = false; + bool leading = true; + LogBufferElementLast last; for(it = mLogElements.begin(); it != mLogElements.end();) { LogBufferElement *e = *it; - if (oldest && (oldest->mStart <= e->getMonotonicTime())) { + if (oldest && (oldest->mStart <= e->getSequence())) { break; } @@ -315,27 +399,82 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { continue; } - uid_t uid = e->getUid(); + unsigned short dropped = e->getDropped(); - if ((uid == worst) || mPrune.naughty(e)) { // Worst or BlackListed + // remove any leading drops + if (leading && dropped) { + it = erase(it); + continue; + } + + // merge any drops + if (dropped && last.merge(e, dropped)) { it = mLogElements.erase(it); - unsigned short len = e->getMsgLen(); - stats.subtract(len, id, uid, e->getPid()); + stats.erase(e); delete e; + continue; + } + + leading = false; + + if (hasBlacklist && mPrune.naughty(e)) { + last.clear(e); + it = erase(it); + if (dropped) { + continue; + } + pruneRows--; - if (uid == worst) { + if (pruneRows == 0) { + break; + } + + if (e->getUid() == worst) { kick = true; - if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) { + if (worst_sizes < second_worst_sizes) { break; } - worst_sizes -= len; - } else if (pruneRows == 0) { - break; + worst_sizes -= e->getMsgLen(); } + continue; + } + + if (dropped) { + last.add(e); + ++it; + continue; + } + + if (e->getUid() != worst) { + last.clear(e); + ++it; + continue; + } + + pruneRows--; + if (pruneRows == 0) { + break; + } + + kick = true; + + unsigned short len = e->getMsgLen(); + stats.drop(e); + e->setDropped(1); + if (last.merge(e, 1)) { + it = mLogElements.erase(it); + stats.erase(e); + delete e; } else { + last.add(e); ++it; } + if (worst_sizes < second_worst_sizes) { + break; + } + worst_sizes -= len; } + last.clear(); if (!kick || !mPrune.worstUidEnabled()) { break; // the following loop will ask bad clients to skip/drop @@ -343,58 +482,63 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { } bool whitelist = false; + bool hasWhitelist = mPrune.nice(); it = mLogElements.begin(); while((pruneRows > 0) && (it != mLogElements.end())) { LogBufferElement *e = *it; - if (e->getLogId() == id) { - if (oldest && (oldest->mStart <= e->getMonotonicTime())) { - if (!whitelist) { - if (stats.sizes(id) > (2 * log_buffer_size(id))) { - // kick a misbehaving log reader client off the island - oldest->release_Locked(); - } else { - oldest->triggerSkip_Locked(pruneRows); - } - } + + if (e->getLogId() != id) { + it++; + continue; + } + + if (oldest && (oldest->mStart <= e->getSequence())) { + if (whitelist) { break; } - if (mPrune.nice(e)) { // WhiteListed - whitelist = true; - it++; - continue; + if (stats.sizes(id) > (2 * log_buffer_size(id))) { + // kick a misbehaving log reader client off the island + oldest->release_Locked(); + } else { + oldest->triggerSkip_Locked(id, pruneRows); } + break; + } - it = mLogElements.erase(it); - stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid()); - delete e; - pruneRows--; - } else { + if (hasWhitelist && mPrune.nice(e)) { // WhiteListed + whitelist = true; it++; + continue; } + + it = erase(it); + pruneRows--; } + // Do not save the whitelist if we are reader range limited if (whitelist && (pruneRows > 0)) { it = mLogElements.begin(); while((it != mLogElements.end()) && (pruneRows > 0)) { LogBufferElement *e = *it; - if (e->getLogId() == id) { - if (oldest && (oldest->mStart <= e->getMonotonicTime())) { - if (stats.sizes(id) > (2 * log_buffer_size(id))) { - // kick a misbehaving log reader client off the island - oldest->release_Locked(); - } else { - oldest->triggerSkip_Locked(pruneRows); - } - break; + + if (e->getLogId() != id) { + ++it; + continue; + } + + if (oldest && (oldest->mStart <= e->getSequence())) { + if (stats.sizes(id) > (2 * log_buffer_size(id))) { + // kick a misbehaving log reader client off the island + oldest->release_Locked(); + } else { + oldest->triggerSkip_Locked(id, pruneRows); } - it = mLogElements.erase(it); - stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid()); - delete e; - pruneRows--; - } else { - it++; + break; } + + it = erase(it); + pruneRows--; } } @@ -436,28 +580,51 @@ unsigned long LogBuffer::getSize(log_id_t id) { return retval; } -log_time LogBuffer::flushTo( - SocketClient *reader, const log_time start, bool privileged, - bool (*filter)(const LogBufferElement *element, void *arg), void *arg) { +uint64_t LogBuffer::flushTo( + SocketClient *reader, const uint64_t start, bool privileged, + int (*filter)(const LogBufferElement *element, void *arg), void *arg) { LogBufferElementCollection::iterator it; - log_time max = start; + uint64_t max = start; uid_t uid = reader->getUid(); pthread_mutex_lock(&mLogElementsLock); - for (it = mLogElements.begin(); it != mLogElements.end(); ++it) { + + if (start <= 1) { + // client wants to start from the beginning + it = mLogElements.begin(); + } else { + // Client wants to start from some specified time. Chances are + // we are better off starting from the end of the time sorted list. + for (it = mLogElements.end(); it != mLogElements.begin(); /* do nothing */) { + --it; + LogBufferElement *element = *it; + if (element->getSequence() <= start) { + it++; + break; + } + } + } + + for (; it != mLogElements.end(); ++it) { LogBufferElement *element = *it; if (!privileged && (element->getUid() != uid)) { continue; } - if (element->getMonotonicTime() <= start) { + if (element->getSequence() <= start) { continue; } // NB: calling out to another object with mLogElementsLock held (safe) - if (filter && !(*filter)(element, arg)) { - continue; + if (filter) { + int ret = (*filter)(element, arg); + if (ret == false) { + continue; + } + if (ret != true) { + break; + } } pthread_mutex_unlock(&mLogElementsLock); @@ -477,22 +644,9 @@ log_time LogBuffer::flushTo( } void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) { - log_time oldest(CLOCK_MONOTONIC); - pthread_mutex_lock(&mLogElementsLock); - // Find oldest element in the log(s) - LogBufferElementCollection::iterator it; - for (it = mLogElements.begin(); it != mLogElements.end(); ++it) { - LogBufferElement *element = *it; - - if ((logMask & (1 << element->getLogId()))) { - oldest = element->getMonotonicTime(); - break; - } - } - - stats.format(strp, uid, logMask, oldest); + stats.format(strp, uid, logMask); pthread_mutex_unlock(&mLogElementsLock); } diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h index 879baea..9ee243d 100644 --- a/logd/LogBuffer.h +++ b/logd/LogBuffer.h @@ -37,7 +37,6 @@ class LogBuffer { pthread_mutex_t mLogElementsLock; LogStatistics stats; - bool dgramQlenStatistics; PruneList mPrune; @@ -47,13 +46,14 @@ public: LastLogTimes &mTimes; LogBuffer(LastLogTimes *times); + void init(); - void log(log_id_t log_id, log_time realtime, - uid_t uid, pid_t pid, pid_t tid, - const char *msg, unsigned short len); - log_time flushTo(SocketClient *writer, const log_time start, + int log(log_id_t log_id, log_time realtime, + uid_t uid, pid_t pid, pid_t tid, + const char *msg, unsigned short len); + uint64_t flushTo(SocketClient *writer, const uint64_t start, bool privileged, - bool (*filter)(const LogBufferElement *element, void *arg) = NULL, + int (*filter)(const LogBufferElement *element, void *arg) = NULL, void *arg = NULL); void clear(log_id_t id, uid_t uid = AID_ROOT); @@ -63,11 +63,6 @@ public: // *strp uses malloc, use free to release. void formatStatistics(char **strp, uid_t uid, unsigned int logMask); - void enableDgramQlenStatistics() { - stats.enableDgramQlenStatistics(); - dgramQlenStatistics = true; - } - void enableStatistics() { stats.enableStatistics(); } @@ -83,7 +78,7 @@ public: private: void maybePrune(log_id_t id); void prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT); - + LogBufferElementCollection::iterator erase(LogBufferElementCollection::iterator it); }; #endif // _LOGD_LOG_BUFFER_H__ diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp index d959ceb..a173e63 100644 --- a/logd/LogBufferElement.cpp +++ b/logd/LogBufferElement.cpp @@ -14,17 +14,21 @@ * limitations under the License. */ +#include <endian.h> #include <stdio.h> #include <string.h> #include <time.h> #include <unistd.h> #include <log/logger.h> +#include <private/android_logger.h> #include "LogBufferElement.h" +#include "LogCommand.h" #include "LogReader.h" -const log_time LogBufferElement::FLUSH_ERROR((uint32_t)0, (uint32_t)0); +const uint64_t LogBufferElement::FLUSH_ERROR(0); +atomic_int_fast64_t LogBufferElement::sequence; LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, @@ -34,7 +38,7 @@ LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime, , mPid(pid) , mTid(tid) , mMsgLen(len) - , mMonotonicTime(CLOCK_MONOTONIC) + , mSequence(sequence.fetch_add(1, memory_order_relaxed)) , mRealTime(realtime) { mMsg = new char[len]; memcpy(mMsg, msg, len); @@ -44,11 +48,59 @@ LogBufferElement::~LogBufferElement() { delete [] mMsg; } -log_time LogBufferElement::flushTo(SocketClient *reader) { +// assumption: mMsg == NULL +size_t LogBufferElement::populateDroppedMessage(char *&buffer, bool privileged) { + static const char format_uid[] = "uid=%u dropped=%u"; + static const size_t unprivileged_offset = 7; + static const char tag[] = "logd"; + + size_t len; + if (privileged) { + len = snprintf(NULL, 0, format_uid, mUid, mDropped); + } else { + len = snprintf(NULL, 0, format_uid + unprivileged_offset, mDropped); + } + + size_t hdrLen; + if (mLogId == LOG_ID_EVENTS) { + hdrLen = sizeof(android_log_event_string_t); + } else { + hdrLen = 1 + sizeof(tag); + } + + buffer = static_cast<char *>(calloc(1, hdrLen + len + 1)); + if (!buffer) { + return 0; + } + + size_t retval = hdrLen + len; + if (mLogId == LOG_ID_EVENTS) { + android_log_event_string_t *e = reinterpret_cast<android_log_event_string_t *>(buffer); + + e->header.tag = htole32(LOGD_LOG_TAG); + e->type = EVENT_TYPE_STRING; + e->length = htole32(len); + } else { + ++retval; + buffer[0] = ANDROID_LOG_INFO; + strcpy(buffer + 1, tag); + } + + if (privileged) { + snprintf(buffer + hdrLen, len + 1, format_uid, mUid, mDropped); + } else { + snprintf(buffer + hdrLen, len + 1, format_uid + unprivileged_offset, mDropped); + } + + return retval; +} + +uint64_t LogBufferElement::flushTo(SocketClient *reader) { struct logger_entry_v3 entry; + memset(&entry, 0, sizeof(struct logger_entry_v3)); + entry.hdr_size = sizeof(struct logger_entry_v3); - entry.len = mMsgLen; entry.lid = mLogId; entry.pid = mPid; entry.tid = mTid; @@ -58,11 +110,26 @@ log_time LogBufferElement::flushTo(SocketClient *reader) { struct iovec iovec[2]; iovec[0].iov_base = &entry; iovec[0].iov_len = sizeof(struct logger_entry_v3); - iovec[1].iov_base = mMsg; - iovec[1].iov_len = mMsgLen; - if (reader->sendDatav(iovec, 2)) { - return FLUSH_ERROR; + + char *buffer = NULL; + + if (!mMsg) { + entry.len = populateDroppedMessage(buffer, clientHasLogCredentials(reader)); + if (!entry.len) { + return mSequence; + } + iovec[1].iov_base = buffer; + } else { + entry.len = mMsgLen; + iovec[1].iov_base = mMsg; + } + iovec[1].iov_len = entry.len; + + uint64_t retval = reader->sendDatav(iovec, 2) ? FLUSH_ERROR : mSequence; + + if (buffer) { + free(buffer); } - return mMonotonicTime; + return retval; } diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h index fdca973..7b6456d 100644 --- a/logd/LogBufferElement.h +++ b/logd/LogBufferElement.h @@ -17,20 +17,42 @@ #ifndef _LOGD_LOG_BUFFER_ELEMENT_H__ #define _LOGD_LOG_BUFFER_ELEMENT_H__ +#include <stdatomic.h> +#include <stdlib.h> #include <sys/types.h> + #include <sysutils/SocketClient.h> #include <log/log.h> #include <log/log_read.h> +namespace android { + +// Furnished in main.cpp. Caller must own and free returned value +// This function is designed for a single caller and is NOT thread-safe +char *uidToName(uid_t uid); + +} + +static inline bool worstUidEnabledForLogid(log_id_t id) { + return (id != LOG_ID_CRASH) && (id != LOG_ID_EVENTS); +} + class LogBufferElement { const log_id_t mLogId; const uid_t mUid; const pid_t mPid; const pid_t mTid; char *mMsg; - const unsigned short mMsgLen; - const log_time mMonotonicTime; + union { + const unsigned short mMsgLen; // mMSg != NULL + unsigned short mDropped; // mMsg == NULL + }; + const uint64_t mSequence; const log_time mRealTime; + static atomic_int_fast64_t sequence; + + // assumption: mMsg == NULL + size_t populateDroppedMessage(char *&buffer, bool privileged); public: LogBufferElement(log_id_t log_id, log_time realtime, @@ -42,12 +64,21 @@ public: uid_t getUid(void) const { return mUid; } pid_t getPid(void) const { return mPid; } pid_t getTid(void) const { return mTid; } - unsigned short getMsgLen() const { return mMsgLen; } - log_time getMonotonicTime(void) const { return mMonotonicTime; } + unsigned short getDropped(void) const { return mMsg ? 0 : mDropped; } + unsigned short setDropped(unsigned short value) { + if (mMsg) { + free(mMsg); + mMsg = NULL; + } + return mDropped = value; + } + unsigned short getMsgLen() const { return mMsg ? mMsgLen : 0; } + uint64_t getSequence(void) const { return mSequence; } + static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); } log_time getRealTime(void) const { return mRealTime; } - static const log_time FLUSH_ERROR; - log_time flushTo(SocketClient *writer); + static const uint64_t FLUSH_ERROR; + uint64_t flushTo(SocketClient *writer); }; #endif diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp index e4c138e..b78c0e0 100644 --- a/logd/LogCommand.cpp +++ b/logd/LogCommand.cpp @@ -17,6 +17,7 @@ #include <errno.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <private/android_filesystem_config.h> diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp index 8186cea..05ced06 100644 --- a/logd/LogListener.cpp +++ b/logd/LogListener.cpp @@ -23,6 +23,8 @@ #include <cutils/sockets.h> #include <log/logger.h> +#include <private/android_filesystem_config.h> +#include <private/android_logger.h> #include "LogListener.h" @@ -33,7 +35,11 @@ LogListener::LogListener(LogBuffer *buf, LogReader *reader) { } bool LogListener::onDataAvailable(SocketClient *cli) { - prctl(PR_SET_NAME, "logd.writer"); + static bool name_set; + if (!name_set) { + prctl(PR_SET_NAME, "logd.writer"); + name_set = true; + } char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time) + LOGGER_ENTRY_MAX_PAYLOAD]; @@ -54,7 +60,7 @@ bool LogListener::onDataAvailable(SocketClient *cli) { int socket = cli->getSocket(); ssize_t n = recvmsg(socket, &hdr, 0); - if (n <= (ssize_t)(sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time))) { + if (n <= (ssize_t)(sizeof(android_log_header_t))) { return false; } @@ -74,37 +80,29 @@ bool LogListener::onDataAvailable(SocketClient *cli) { return false; } - if (cred->uid == getuid()) { + if (cred->uid == AID_LOGD) { // ignore log messages we send to ourself. // Such log messages are often generated by libraries we depend on // which use standard Android logging. return false; } - // First log element is always log_id. - log_id_t log_id = (log_id_t) *((typeof_log_id_t *) buffer); - if (log_id < 0 || log_id >= LOG_ID_MAX) { + android_log_header_t *header = reinterpret_cast<android_log_header_t *>(buffer); + if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX) { return false; } - char *msg = ((char *)buffer) + sizeof_log_id_t; - n -= sizeof_log_id_t; - - // second element is the thread id of the caller - pid_t tid = (pid_t) *((uint16_t *) msg); - msg += sizeof(uint16_t); - n -= sizeof(uint16_t); - // third element is the realtime at point of caller - log_time realtime(msg); - msg += sizeof(log_time); - n -= sizeof(log_time); + char *msg = ((char *)buffer) + sizeof(android_log_header_t); + n -= sizeof(android_log_header_t); // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a // truncated message to the logs. - logbuf->log(log_id, realtime, cred->uid, cred->pid, tid, msg, - ((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX); - reader->notifyNewLog(); + if (logbuf->log((log_id_t)header->id, header->realtime, + cred->uid, cred->pid, header->tid, msg, + ((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX) >= 0) { + reader->notifyNewLog(); + } return true; } diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp index 26df087..745e847 100644 --- a/logd/LogReader.cpp +++ b/logd/LogReader.cpp @@ -37,7 +37,11 @@ void LogReader::notifyNewLog() { } bool LogReader::onDataAvailable(SocketClient *cli) { - prctl(PR_SET_NAME, "logd.reader"); + static bool name_set; + if (!name_set) { + prctl(PR_SET_NAME, "logd.reader"); + name_set = true; + } char buffer[255]; @@ -100,50 +104,51 @@ bool LogReader::onDataAvailable(SocketClient *cli) { nonBlock = true; } - // Convert realtime to monotonic time - if (start == log_time::EPOCH) { - start = LogTimeEntry::EPOCH; - } else { + uint64_t sequence = 1; + // Convert realtime to sequence number + if (start != log_time::EPOCH) { class LogFindStart { const pid_t mPid; const unsigned mLogMask; bool startTimeSet; log_time &start; - log_time last; + uint64_t &sequence; + uint64_t last; public: - LogFindStart(unsigned logMask, pid_t pid, log_time &start) + LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence) : mPid(pid) , mLogMask(logMask) , startTimeSet(false) , start(start) - , last(LogTimeEntry::EPOCH) + , sequence(sequence) + , last(sequence) { } - static bool callback(const LogBufferElement *element, void *obj) { + static int callback(const LogBufferElement *element, void *obj) { LogFindStart *me = reinterpret_cast<LogFindStart *>(obj); - if (!me->startTimeSet - && (!me->mPid || (me->mPid == element->getPid())) + if ((!me->mPid || (me->mPid == element->getPid())) && (me->mLogMask & (1 << element->getLogId()))) { if (me->start == element->getRealTime()) { - me->start = element->getMonotonicTime(); + me->sequence = element->getSequence(); me->startTimeSet = true; + return -1; } else { if (me->start < element->getRealTime()) { - me->start = me->last; + me->sequence = me->last; me->startTimeSet = true; + return -1; } - me->last = element->getMonotonicTime(); + me->last = element->getSequence(); } } return false; } bool found() { return startTimeSet; } - } logFindStart(logMask, pid, start); + } logFindStart(logMask, pid, start, sequence); - logbuf().flushTo(cli, LogTimeEntry::EPOCH, - FlushCommand::hasReadLogs(cli), + logbuf().flushTo(cli, sequence, FlushCommand::hasReadLogs(cli), logFindStart.callback, &logFindStart); if (!logFindStart.found()) { @@ -151,12 +156,11 @@ bool LogReader::onDataAvailable(SocketClient *cli) { doSocketDelete(cli); return false; } - log_time now(CLOCK_MONOTONIC); - start = now; + sequence = LogBufferElement::getCurrentSequence(); } } - FlushCommand command(*this, nonBlock, tail, logMask, pid, start); + FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence); command.runSocketCommand(cli); return true; } diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp index 2a45590..eadc4dd 100644 --- a/logd/LogStatistics.cpp +++ b/logd/LogStatistics.cpp @@ -14,9 +14,11 @@ * limitations under the License. */ +#include <algorithm> // std::max #include <fcntl.h> -#include <stdarg.h> -#include <time.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> #include <log/logger.h> #include <private/android_filesystem_config.h> @@ -24,80 +26,24 @@ #include "LogStatistics.h" -PidStatistics::PidStatistics(pid_t pid, char *name) - : pid(pid) - , mSizesTotal(0) - , mElementsTotal(0) - , mSizes(0) - , mElements(0) - , name(name) - , mGone(false) -{ } - -#ifdef DO_NOT_ERROR_IF_PIDSTATISTICS_USES_A_COPY_CONSTRUCTOR -PidStatistics::PidStatistics(const PidStatistics ©) - : pid(copy->pid) - , name(copy->name ? strdup(copy->name) : NULL) - , mSizesTotal(copy->mSizesTotal) - , mElementsTotal(copy->mElementsTotal) - , mSizes(copy->mSizes) - , mElements(copy->mElements) - , mGone(copy->mGone) -{ } -#endif - -PidStatistics::~PidStatistics() { - free(name); -} - -bool PidStatistics::pidGone() { - if (mGone || (pid == gone)) { - return true; - } - if (pid == 0) { - return false; - } - if (kill(pid, 0) && (errno != EPERM)) { - mGone = true; - return true; +LogStatistics::LogStatistics() + : enable(false) { + log_id_for_each(id) { + mSizes[id] = 0; + mElements[id] = 0; + mSizesTotal[id] = 0; + mElementsTotal[id] = 0; } - return false; -} - -void PidStatistics::setName(char *new_name) { - free(name); - name = new_name; -} - -void PidStatistics::add(unsigned short size) { - mSizesTotal += size; - ++mElementsTotal; - mSizes += size; - ++mElements; } -bool PidStatistics::subtract(unsigned short size) { - mSizes -= size; - --mElements; - return (mElements == 0) && pidGone(); -} - -void PidStatistics::addTotal(size_t size, size_t element) { - if (pid == gone) { - mSizesTotal += size; - mElementsTotal += element; - } -} +namespace android { -// must call free to release return value -// If only we could sniff our own logs for: -// <time> <pid> <pid> E AndroidRuntime: Process: <name>, PID: <pid> -// which debuggerd prints as a process is crashing. -char *PidStatistics::pidToName(pid_t pid) { +// caller must own and free character string +static char *pidToName(pid_t pid) { char *retval = NULL; if (pid == 0) { // special case from auditd for kernel retval = strdup("logd.auditd"); - } else if (pid != gone) { + } else { char buffer[512]; snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid); int fd = open(buffer, O_RDONLY); @@ -116,418 +62,191 @@ char *PidStatistics::pidToName(pid_t pid) { return retval; } -UidStatistics::UidStatistics(uid_t uid) - : uid(uid) - , mSizes(0) - , mElements(0) { - Pids.clear(); } -UidStatistics::~UidStatistics() { - PidStatisticsCollection::iterator it; - for (it = begin(); it != end();) { - delete (*it); - it = erase(it); - } -} +void LogStatistics::add(LogBufferElement *e) { + log_id_t log_id = e->getLogId(); + unsigned short size = e->getMsgLen(); + mSizes[log_id] += size; + ++mElements[log_id]; -void UidStatistics::add(unsigned short size, pid_t pid) { - mSizes += size; - ++mElements; - - PidStatistics *p = NULL; - PidStatisticsCollection::iterator last; - PidStatisticsCollection::iterator it; - for (last = it = begin(); it != end(); last = it, ++it) { - p = *it; - if (pid == p->getPid()) { - p->add(size); - return; - } - } - // insert if the gone entry. - bool insert_before_last = (last != it) && p && (p->getPid() == p->gone); - p = new PidStatistics(pid, pidToName(pid)); - if (insert_before_last) { - insert(last, p); + uid_t uid = e->getUid(); + unsigned short dropped = e->getDropped(); + android::hash_t hash = android::hash_type(uid); + uidTable_t &table = uidTable[log_id]; + ssize_t index = table.find(-1, hash, uid); + if (index == -1) { + UidEntry initEntry(uid); + initEntry.add(size); + initEntry.add_dropped(dropped); + table.add(hash, initEntry); } else { - push_back(p); + UidEntry &entry = table.editEntryAt(index); + entry.add(size); + entry.add_dropped(dropped); } - p->add(size); -} -void UidStatistics::subtract(unsigned short size, pid_t pid) { - mSizes -= size; - --mElements; - - PidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - PidStatistics *p = *it; - if (pid == p->getPid()) { - if (p->subtract(size)) { - size_t szsTotal = p->sizesTotal(); - size_t elsTotal = p->elementsTotal(); - delete p; - erase(it); - it = end(); - --it; - if (it == end()) { - p = new PidStatistics(p->gone); - push_back(p); - } else { - p = *it; - if (p->getPid() != p->gone) { - p = new PidStatistics(p->gone); - push_back(p); - } - } - p->addTotal(szsTotal, elsTotal); - } - return; - } - } -} - -void UidStatistics::sort() { - for (bool pass = true; pass;) { - pass = false; - PidStatisticsCollection::iterator it = begin(); - if (it != end()) { - PidStatisticsCollection::iterator lt = it; - PidStatistics *l = (*lt); - while (++it != end()) { - PidStatistics *n = (*it); - if ((n->getPid() != n->gone) && (n->sizes() > l->sizes())) { - pass = true; - erase(it); - insert(lt, n); - it = lt; - n = l; - } - lt = it; - l = n; - } - } - } -} + mSizesTotal[log_id] += size; + ++mElementsTotal[log_id]; -size_t UidStatistics::sizes(pid_t pid) { - if (pid == pid_all) { - return sizes(); + if (!enable) { + return; } - PidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - PidStatistics *p = *it; - if (pid == p->getPid()) { - return p->sizes(); + pid_t pid = e->getPid(); + hash = android::hash_type(pid); + index = pidTable.find(-1, hash, pid); + if (index == -1) { + PidEntry initEntry(pid, uid, android::pidToName(pid)); + initEntry.add(size); + initEntry.add_dropped(dropped); + pidTable.add(hash, initEntry); + } else { + PidEntry &entry = pidTable.editEntryAt(index); + if (entry.getUid() != uid) { + entry.setUid(uid); + entry.setName(android::pidToName(pid)); + } else if (!entry.getName()) { + char *name = android::pidToName(pid); + if (name) { + entry.setName(name); + } } + entry.add(size); + entry.add_dropped(dropped); } - return 0; } -size_t UidStatistics::elements(pid_t pid) { - if (pid == pid_all) { - return elements(); - } +void LogStatistics::subtract(LogBufferElement *e) { + log_id_t log_id = e->getLogId(); + unsigned short size = e->getMsgLen(); + mSizes[log_id] -= size; + --mElements[log_id]; - PidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - PidStatistics *p = *it; - if (pid == p->getPid()) { - return p->elements(); + uid_t uid = e->getUid(); + unsigned short dropped = e->getDropped(); + android::hash_t hash = android::hash_type(uid); + uidTable_t &table = uidTable[log_id]; + ssize_t index = table.find(-1, hash, uid); + if (index != -1) { + UidEntry &entry = table.editEntryAt(index); + if (entry.subtract(size) || entry.subtract_dropped(dropped)) { + table.removeAt(index); } } - return 0; -} -size_t UidStatistics::sizesTotal(pid_t pid) { - size_t sizes = 0; - PidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - PidStatistics *p = *it; - if ((pid == pid_all) || (pid == p->getPid())) { - sizes += p->sizesTotal(); - } + if (!enable) { + return; } - return sizes; -} -size_t UidStatistics::elementsTotal(pid_t pid) { - size_t elements = 0; - PidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - PidStatistics *p = *it; - if ((pid == pid_all) || (pid == p->getPid())) { - elements += p->elementsTotal(); + pid_t pid = e->getPid(); + hash = android::hash_type(pid); + index = pidTable.find(-1, hash, pid); + if (index != -1) { + PidEntry &entry = pidTable.editEntryAt(index); + if (entry.subtract(size) || entry.subtract_dropped(dropped)) { + pidTable.removeAt(index); } } - return elements; } -LidStatistics::LidStatistics() { - Uids.clear(); -} +// Atomically set an entry to drop +// entry->setDropped(1) must follow this call, caller should do this explicitly. +void LogStatistics::drop(LogBufferElement *e) { + log_id_t log_id = e->getLogId(); + unsigned short size = e->getMsgLen(); + mSizes[log_id] -= size; -LidStatistics::~LidStatistics() { - UidStatisticsCollection::iterator it; - for (it = begin(); it != end();) { - delete (*it); - it = Uids.erase(it); + uid_t uid = e->getUid(); + android::hash_t hash = android::hash_type(uid); + typeof uidTable[0] &table = uidTable[log_id]; + ssize_t index = table.find(-1, hash, uid); + if (index != -1) { + UidEntry &entry = table.editEntryAt(index); + entry.subtract(size); + entry.add_dropped(1); } -} - -void LidStatistics::add(unsigned short size, uid_t uid, pid_t pid) { - UidStatistics *u; - UidStatisticsCollection::iterator it; - UidStatisticsCollection::iterator last; - if (uid == (uid_t) -1) { // init - uid = (uid_t) AID_ROOT; + if (!enable) { + return; } - for (last = it = begin(); it != end(); last = it, ++it) { - u = *it; - if (uid == u->getUid()) { - u->add(size, pid); - if ((last != it) && ((*last)->sizesTotal() < u->sizesTotal())) { - Uids.erase(it); - Uids.insert(last, u); - } - return; - } + pid_t pid = e->getPid(); + hash = android::hash_type(pid); + index = pidTable.find(-1, hash, pid); + if (index != -1) { + PidEntry &entry = pidTable.editEntryAt(index); + entry.subtract(size); + entry.add_dropped(1); } - u = new UidStatistics(uid); - if ((last != it) && ((*last)->sizesTotal() < (size_t) size)) { - Uids.insert(last, u); - } else { - Uids.push_back(u); - } - u->add(size, pid); } -void LidStatistics::subtract(unsigned short size, uid_t uid, pid_t pid) { - if (uid == (uid_t) -1) { // init - uid = (uid_t) AID_ROOT; +// caller must own and free character string +char *LogStatistics::uidToName(uid_t uid) { + // Local hard coded favourites + if (uid == AID_LOGD) { + return strdup("auditd"); } - UidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - UidStatistics *u = *it; - if (uid == u->getUid()) { - u->subtract(size, pid); - return; - } - } -} + // Android hard coded + const struct android_id_info *info = android_ids; -void LidStatistics::sort() { - for (bool pass = true; pass;) { - pass = false; - UidStatisticsCollection::iterator it = begin(); - if (it != end()) { - UidStatisticsCollection::iterator lt = it; - UidStatistics *l = (*lt); - while (++it != end()) { - UidStatistics *n = (*it); - if (n->sizes() > l->sizes()) { - pass = true; - Uids.erase(it); - Uids.insert(lt, n); - it = lt; - n = l; - } - lt = it; - l = n; - } + for (size_t i = 0; i < android_id_count; ++i) { + if (info->aid == uid) { + return strdup(info->name); } + ++info; } -} -size_t LidStatistics::sizes(uid_t uid, pid_t pid) { - size_t sizes = 0; - UidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - UidStatistics *u = *it; - if ((uid == uid_all) || (uid == u->getUid())) { - sizes += u->sizes(pid); - } + // Parse /data/system/packages.list + char *name = android::uidToName(uid); + if (name) { + return name; } - return sizes; -} -size_t LidStatistics::elements(uid_t uid, pid_t pid) { - size_t elements = 0; - UidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - UidStatistics *u = *it; - if ((uid == uid_all) || (uid == u->getUid())) { - elements += u->elements(pid); - } - } - return elements; -} + // report uid -> pid(s) -> pidToName if unique + ssize_t index = -1; + while ((index = pidTable.next(index)) != -1) { + const PidEntry &entry = pidTable.entryAt(index); -size_t LidStatistics::sizesTotal(uid_t uid, pid_t pid) { - size_t sizes = 0; - UidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - UidStatistics *u = *it; - if ((uid == uid_all) || (uid == u->getUid())) { - sizes += u->sizesTotal(pid); - } - } - return sizes; -} + if (entry.getUid() == uid) { + const char *n = entry.getName(); -size_t LidStatistics::elementsTotal(uid_t uid, pid_t pid) { - size_t elements = 0; - UidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - UidStatistics *u = *it; - if ((uid == uid_all) || (uid == u->getUid())) { - elements += u->elementsTotal(pid); + if (n) { + if (!name) { + name = strdup(n); + } else if (strcmp(name, n)) { + free(name); + return NULL; + } + } } } - return elements; -} - -LogStatistics::LogStatistics() - : mStatistics(false) - , dgramQlenStatistics(false) - , start(CLOCK_MONOTONIC) { - log_id_for_each(i) { - mSizes[i] = 0; - mElements[i] = 0; - } - - for(unsigned short bucket = 0; dgramQlen(bucket); ++bucket) { - mMinimum[bucket].tv_sec = mMinimum[bucket].tv_sec_max; - mMinimum[bucket].tv_nsec = mMinimum[bucket].tv_nsec_max; - } -} -// Each bucket below represents a dgramQlen of log messages. By -// finding the minimum period of time from start to finish -// of each dgramQlen, we can get a performance expectation for -// the user space logger. The net result is that the period -// of time divided by the dgramQlen will give us the average time -// between log messages; at the point where the average time -// is greater than the throughput capability of the logger -// we will not longer require the benefits of the FIFO formed -// by max_dgram_qlen. We will also expect to see a very visible -// knee in the average time between log messages at this point, -// so we do not necessarily have to compare the rate against the -// measured performance (BM_log_maximum_retry) of the logger. -// -// for example (reformatted): -// -// Minimum time between log events per dgramQlen: -// 1 2 3 5 10 20 30 50 100 200 300 400 500 600 -// 5u2 12u 13u 15u 16u 27u 30u 36u 407u 3m1 3m3 3m9 3m9 5m5 -// -// demonstrates a clear knee rising at 100, so this means that for this -// case max_dgram_qlen = 100 would be more than sufficient to handle the -// worst that the system could stuff into the logger. The -// BM_log_maximum_retry performance (derated by the log collection) on the -// same system was 33.2us so we would almost be fine with max_dgram_qlen = 50. -// BM_log_maxumum_retry with statistics off is roughly 20us, so -// max_dgram_qlen = 20 would work. We will be more than willing to have -// a large engineering margin so the rule of thumb that lead us to 100 is -// fine. -// -// bucket dgramQlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300 -const unsigned short LogStatistics::mBuckets[] = { - 1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 400, 500, 600 -}; - -unsigned short LogStatistics::dgramQlen(unsigned short bucket) { - if (bucket >= sizeof(mBuckets) / sizeof(mBuckets[0])) { - return 0; - } - return mBuckets[bucket]; + // No one + return name; } -unsigned long long LogStatistics::minimum(unsigned short bucket) { - if (mMinimum[bucket].tv_sec == mMinimum[bucket].tv_sec_max) { - return 0; - } - return mMinimum[bucket].nsec(); -} +static void format_line(android::String8 &output, + android::String8 &name, android::String8 &size, android::String8 &pruned) { + static const size_t pruned_len = 6; + static const size_t total_len = 70 + pruned_len; -void LogStatistics::recordDiff(log_time diff, unsigned short bucket) { - if ((diff.tv_sec || diff.tv_nsec) && (mMinimum[bucket] > diff)) { - mMinimum[bucket] = diff; - } -} + ssize_t drop_len = std::max(pruned.length() + 1, pruned_len); + ssize_t size_len = std::max(size.length() + 1, + total_len - name.length() - drop_len - 1); -void LogStatistics::add(unsigned short size, - log_id_t log_id, uid_t uid, pid_t pid) { - mSizes[log_id] += size; - ++mElements[log_id]; - if (!mStatistics) { - return; - } - id(log_id).add(size, uid, pid); -} - -void LogStatistics::subtract(unsigned short size, - log_id_t log_id, uid_t uid, pid_t pid) { - mSizes[log_id] -= size; - --mElements[log_id]; - if (!mStatistics) { - return; - } - id(log_id).subtract(size, uid, pid); -} - -size_t LogStatistics::sizes(log_id_t log_id, uid_t uid, pid_t pid) { - if (log_id != log_id_all) { - return id(log_id).sizes(uid, pid); - } - size_t sizes = 0; - log_id_for_each(i) { - sizes += id(i).sizes(uid, pid); - } - return sizes; -} - -size_t LogStatistics::elements(log_id_t log_id, uid_t uid, pid_t pid) { - if (log_id != log_id_all) { - return id(log_id).elements(uid, pid); - } - size_t elements = 0; - log_id_for_each(i) { - elements += id(i).elements(uid, pid); - } - return elements; -} - -size_t LogStatistics::sizesTotal(log_id_t log_id, uid_t uid, pid_t pid) { - if (log_id != log_id_all) { - return id(log_id).sizesTotal(uid, pid); - } - size_t sizes = 0; - log_id_for_each(i) { - sizes += id(i).sizesTotal(uid, pid); - } - return sizes; -} - -size_t LogStatistics::elementsTotal(log_id_t log_id, uid_t uid, pid_t pid) { - if (log_id != log_id_all) { - return id(log_id).elementsTotal(uid, pid); - } - size_t elements = 0; - log_id_for_each(i) { - elements += id(i).elementsTotal(uid, pid); + if (pruned.length()) { + output.appendFormat("%s%*s%*s\n", name.string(), + (int)size_len, size.string(), + (int)drop_len, pruned.string()); + } else { + output.appendFormat("%s%*s\n", name.string(), + (int)size_len, size.string()); } - return elements; } -void LogStatistics::format(char **buf, - uid_t uid, unsigned int logMask, log_time oldest) { - static const unsigned short spaces_current = 13; +void LogStatistics::format(char **buf, uid_t uid, unsigned int logMask) { static const unsigned short spaces_total = 19; if (*buf) { @@ -535,411 +254,254 @@ void LogStatistics::format(char **buf, *buf = NULL; } - android::String8 string(" span -> size/num"); + // Report on total logging, current and for all time + + android::String8 output("size/num"); size_t oldLength; - short spaces = 2; + short spaces = 1; - log_id_for_each(i) { - if (!(logMask & (1 << i))) { + log_id_for_each(id) { + if (!(logMask & (1 << id))) { continue; } - oldLength = string.length(); + oldLength = output.length(); if (spaces < 0) { spaces = 0; } - string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i)); - spaces += spaces_total + oldLength - string.length(); + output.appendFormat("%*s%s", spaces, "", android_log_id_to_name(id)); + spaces += spaces_total + oldLength - output.length(); + } - LidStatistics &l = id(i); - l.sort(); + spaces = 4; + output.appendFormat("\nTotal"); - UidStatisticsCollection::iterator iu; - for (iu = l.begin(); iu != l.end(); ++iu) { - (*iu)->sort(); + log_id_for_each(id) { + if (!(logMask & (1 << id))) { + continue; } - } - - spaces = 1; - log_time t(CLOCK_MONOTONIC); - unsigned long long d; - if (mStatistics) { - d = t.nsec() - start.nsec(); - string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu", - d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60, - (d / NS_PER_SEC) % 60, d % NS_PER_SEC); - - log_id_for_each(i) { - if (!(logMask & (1 << i))) { - continue; - } - oldLength = string.length(); - if (spaces < 0) { - spaces = 0; - } - string.appendFormat("%*s%zu/%zu", spaces, "", - sizesTotal(i), elementsTotal(i)); - spaces += spaces_total + oldLength - string.length(); + oldLength = output.length(); + if (spaces < 0) { + spaces = 0; } - spaces = 1; + output.appendFormat("%*s%zu/%zu", spaces, "", + sizesTotal(id), elementsTotal(id)); + spaces += spaces_total + oldLength - output.length(); } - d = t.nsec() - oldest.nsec(); - string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu", - d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60, - (d / NS_PER_SEC) % 60, d % NS_PER_SEC); + spaces = 6; + output.appendFormat("\nNow"); - log_id_for_each(i) { - if (!(logMask & (1 << i))) { + log_id_for_each(id) { + if (!(logMask & (1 << id))) { continue; } - size_t els = elements(i); + size_t els = elements(id); if (els) { - oldLength = string.length(); + oldLength = output.length(); if (spaces < 0) { spaces = 0; } - string.appendFormat("%*s%zu/%zu", spaces, "", sizes(i), els); - spaces -= string.length() - oldLength; + output.appendFormat("%*s%zu/%zu", spaces, "", sizes(id), els); + spaces -= output.length() - oldLength; } spaces += spaces_total; } - // Construct list of worst spammers by Pid - static const unsigned char num_spammers = 10; - bool header = false; + // Report on Chattiest - log_id_for_each(i) { - if (!(logMask & (1 << i))) { + // Chattiest by application (UID) + static const size_t maximum_sorted_entries = 32; + log_id_for_each(id) { + if (!(logMask & (1 << id))) { continue; } - PidStatisticsCollection pids; - pids.clear(); - - LidStatistics &l = id(i); - UidStatisticsCollection::iterator iu; - for (iu = l.begin(); iu != l.end(); ++iu) { - UidStatistics &u = *(*iu); - PidStatisticsCollection::iterator ip; - for (ip = u.begin(); ip != u.end(); ++ip) { - PidStatistics *p = (*ip); - if (p->getPid() == p->gone) { - break; - } + bool headerPrinted = false; + std::unique_ptr<const UidEntry *[]> sorted = sort(maximum_sorted_entries, id); + ssize_t index = -1; + while ((index = uidTable_t::next(index, sorted, maximum_sorted_entries)) >= 0) { + const UidEntry *entry = sorted[index]; + uid_t u = entry->getKey(); + if ((uid != AID_ROOT) && (u != uid)) { + continue; + } - size_t mySizes = p->sizes(); - - PidStatisticsCollection::iterator q; - unsigned char num = 0; - for (q = pids.begin(); q != pids.end(); ++q) { - if (mySizes > (*q)->sizes()) { - pids.insert(q, p); - break; - } - // do we need to traverse deeper in the list? - if (++num > num_spammers) { - break; - } + if (!headerPrinted) { + output.appendFormat("\n\n"); + android::String8 name(""); + if (uid == AID_ROOT) { + name.appendFormat( + "Chattiest UIDs in %s log buffer:", + android_log_id_to_name(id)); + } else { + name.appendFormat( + "Logging for your UID in %s log buffer:", + android_log_id_to_name(id)); } - if (q == pids.end()) { - pids.push_back(p); + android::String8 size("Size"); + android::String8 pruned("Pruned"); + if (!worstUidEnabledForLogid(id)) { + pruned.setTo(""); } - } - } - - size_t threshold = sizes(i); - if (threshold < 65536) { - threshold = 65536; - } - threshold /= 100; - - PidStatisticsCollection::iterator pt = pids.begin(); - - for(int line = 0; - (pt != pids.end()) && (line < num_spammers); - ++line, pt = pids.erase(pt)) { - PidStatistics *p = *pt; + format_line(output, name, size, pruned); - size_t sizes = p->sizes(); - if (sizes < threshold) { - break; - } - - char *name = p->getName(); - pid_t pid = p->getPid(); - if (!name || !*name) { - name = pidToName(pid); - if (name) { - if (*name) { - p->setName(name); - } else { - free(name); - name = NULL; - } + name.setTo("UID PACKAGE"); + size.setTo("BYTES"); + pruned.setTo("LINES"); + if (!worstUidEnabledForLogid(id)) { + pruned.setTo(""); } - } + format_line(output, name, size, pruned); - if (!header) { - string.appendFormat("\n\nChattiest clients:\n" - "log id %-*s PID[?] name", - spaces_total, "size/total"); - header = true; + headerPrinted = true; } - size_t sizesTotal = p->sizesTotal(); - - android::String8 sz(""); - sz.appendFormat((sizes != sizesTotal) ? "%zu/%zu" : "%zu", - sizes, sizesTotal); - - android::String8 pd(""); - pd.appendFormat("%u%c", pid, p->pidGone() ? '?' : ' '); - - string.appendFormat("\n%-7s%-*s %-7s%s", - line ? "" : android_log_id_to_name(i), - spaces_total, sz.string(), pd.string(), - name ? name : ""); - } + android::String8 name(""); + name.appendFormat("%u", u); + char *n = uidToName(u); + if (n) { + name.appendFormat("%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", n); + free(n); + } - pids.clear(); - } + android::String8 size(""); + size.appendFormat("%zu", entry->getSizes()); - if (dgramQlenStatistics) { - const unsigned short spaces_time = 6; - const unsigned long long max_seconds = 100000; - spaces = 0; - string.append("\n\nMinimum time between log events per max_dgram_qlen:\n"); - for(unsigned short i = 0; dgramQlen(i); ++i) { - oldLength = string.length(); - if (spaces < 0) { - spaces = 0; + android::String8 pruned(""); + size_t dropped = entry->getDropped(); + if (dropped) { + pruned.appendFormat("%zu", dropped); } - string.appendFormat("%*s%u", spaces, "", dgramQlen(i)); - spaces += spaces_time + oldLength - string.length(); - } - string.append("\n"); - spaces = 0; - unsigned short n; - for(unsigned short i = 0; (n = dgramQlen(i)); ++i) { - unsigned long long duration = minimum(i); - if (duration) { - duration /= n; - if (duration >= (NS_PER_SEC * max_seconds)) { - duration = NS_PER_SEC * (max_seconds - 1); - } - oldLength = string.length(); - if (spaces < 0) { - spaces = 0; - } - string.appendFormat("%*s", spaces, ""); - if (duration >= (NS_PER_SEC * 10)) { - string.appendFormat("%llu", - (duration + (NS_PER_SEC / 2)) - / NS_PER_SEC); - } else if (duration >= (NS_PER_SEC / (1000 / 10))) { - string.appendFormat("%llum", - (duration + (NS_PER_SEC / 2 / 1000)) - / (NS_PER_SEC / 1000)); - } else if (duration >= (NS_PER_SEC / (1000000 / 10))) { - string.appendFormat("%lluu", - (duration + (NS_PER_SEC / 2 / 1000000)) - / (NS_PER_SEC / 1000000)); - } else { - string.appendFormat("%llun", duration); - } - spaces -= string.length() - oldLength; - } - spaces += spaces_time; - } - } - log_id_for_each(i) { - if (!(logMask & (1 << i))) { - continue; + format_line(output, name, size, pruned); } + } - header = false; - bool first = true; - - UidStatisticsCollection::iterator ut; - for(ut = id(i).begin(); ut != id(i).end(); ++ut) { - UidStatistics *up = *ut; - if ((uid != AID_ROOT) && (uid != up->getUid())) { - continue; - } - - PidStatisticsCollection::iterator pt = up->begin(); - if (pt == up->end()) { + if (enable) { + bool headerPrinted = false; + std::unique_ptr<const PidEntry *[]> sorted = pidTable.sort(maximum_sorted_entries); + ssize_t index = -1; + while ((index = pidTable.next(index, sorted, maximum_sorted_entries)) >= 0) { + const PidEntry *entry = sorted[index]; + uid_t u = entry->getUid(); + if ((uid != AID_ROOT) && (u != uid)) { continue; } - android::String8 intermediate; - - if (!header) { - // header below tuned to match spaces_total and spaces_current - spaces = 0; - intermediate = string.format("%s: UID/PID Total size/num", - android_log_id_to_name(i)); - string.appendFormat("\n\n%-31sNow " - "UID/PID[?] Total Now", - intermediate.string()); - intermediate.clear(); - header = true; - } + if (!headerPrinted) { + output.appendFormat("\n\n"); + android::String8 name(""); + if (uid == AID_ROOT) { + name.appendFormat("Chattiest PIDs:"); + } else { + name.appendFormat("Logging for this PID:"); + } + android::String8 size("Size"); + android::String8 pruned("Pruned"); + format_line(output, name, size, pruned); - bool oneline = ++pt == up->end(); - --pt; + name.setTo(" PID/UID COMMAND LINE"); + size.setTo("BYTES"); + pruned.setTo("LINES"); + format_line(output, name, size, pruned); - if (!oneline) { - first = true; - } else if (!first && (spaces > 0)) { - string.appendFormat("%*s", spaces, ""); + headerPrinted = true; } - spaces = 0; - uid_t u = up->getUid(); - PidStatistics *pp = *pt; - pid_t p = pp->getPid(); - - intermediate = string.format(oneline - ? ((p == PidStatistics::gone) - ? "%d/?" - : "%d/%d%c") - : "%d", - u, p, pp->pidGone() ? '?' : '\0'); - string.appendFormat(first ? "\n%-12s" : "%-12s", - intermediate.string()); - intermediate.clear(); - - size_t elsTotal = up->elementsTotal(); - oldLength = string.length(); - string.appendFormat("%zu/%zu", up->sizesTotal(), elsTotal); - spaces += spaces_total + oldLength - string.length(); - - size_t els = up->elements(); - if (els == elsTotal) { - if (spaces < 0) { - spaces = 0; - } - string.appendFormat("%*s=", spaces, ""); - spaces = -1; - } else if (els) { - oldLength = string.length(); - if (spaces < 0) { - spaces = 0; + android::String8 name(""); + name.appendFormat("%5u/%u", entry->getKey(), u); + const char *n = entry->getName(); + if (n) { + name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", n); + } else { + char *un = uidToName(u); + if (un) { + name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", un); + free(un); } - string.appendFormat("%*s%zu/%zu", spaces, "", up->sizes(), els); - spaces -= string.length() - oldLength; } - spaces += spaces_current; - first = !first; + android::String8 size(""); + size.appendFormat("%zu", entry->getSizes()); - if (oneline) { - continue; + android::String8 pruned(""); + size_t dropped = entry->getDropped(); + if (dropped) { + pruned.appendFormat("%zu", dropped); } - size_t gone_szs = 0; - size_t gone_els = 0; - - for(; pt != up->end(); ++pt) { - pp = *pt; - p = pp->getPid(); - - // If a PID no longer has any current logs, and is not - // active anymore, skip & report totals for gone. - elsTotal = pp->elementsTotal(); - size_t szsTotal = pp->sizesTotal(); - if (p == pp->gone) { - gone_szs += szsTotal; - gone_els += elsTotal; - continue; - } - els = pp->elements(); - bool gone = pp->pidGone(); - if (gone && (els == 0)) { - // ToDo: garbage collection: move this statistical bucket - // from its current UID/PID to UID/? (races and - // wrap around are our achilles heel). Below is - // merely lipservice to catch PIDs that were still - // around when the stats were pruned to zero. - gone_szs += szsTotal; - gone_els += elsTotal; - continue; - } + format_line(output, name, size, pruned); + } + } - if (!first && (spaces > 0)) { - string.appendFormat("%*s", spaces, ""); - } - spaces = 0; + *buf = strdup(output.string()); +} - intermediate = string.format(gone ? "%d/%d?" : "%d/%d", u, p); - string.appendFormat(first ? "\n%-12s" : "%-12s", - intermediate.string()); - intermediate.clear(); - - oldLength = string.length(); - string.appendFormat("%zu/%zu", szsTotal, elsTotal); - spaces += spaces_total + oldLength - string.length(); - - if (els == elsTotal) { - if (spaces < 0) { - spaces = 0; - } - string.appendFormat("%*s=", spaces, ""); - spaces = -1; - } else if (els) { - oldLength = string.length(); - if (spaces < 0) { - spaces = 0; - } - string.appendFormat("%*s%zu/%zu", spaces, "", - pp->sizes(), els); - spaces -= string.length() - oldLength; - } - spaces += spaces_current; +namespace android { - first = !first; +uid_t pidToUid(pid_t pid) { + char buffer[512]; + snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid); + FILE *fp = fopen(buffer, "r"); + if (fp) { + while (fgets(buffer, sizeof(buffer), fp)) { + int uid; + if (sscanf(buffer, "Uid: %d", &uid) == 1) { + fclose(fp); + return uid; } + } + fclose(fp); + } + return AID_LOGD; // associate this with the logger +} - if (gone_els) { - if (!first && (spaces > 0)) { - string.appendFormat("%*s", spaces, ""); - } - - intermediate = string.format("%d/?", u); - string.appendFormat(first ? "\n%-12s" : "%-12s", - intermediate.string()); - intermediate.clear(); - - spaces = spaces_total + spaces_current; - - oldLength = string.length(); - string.appendFormat("%zu/%zu", gone_szs, gone_els); - spaces -= string.length() - oldLength; +} - first = !first; +uid_t LogStatistics::pidToUid(pid_t pid) { + uid_t uid; + android::hash_t hash = android::hash_type(pid); + ssize_t index = pidTable.find(-1, hash, pid); + if (index == -1) { + uid = android::pidToUid(pid); + PidEntry initEntry(pid, uid, android::pidToName(pid)); + pidTable.add(hash, initEntry); + } else { + PidEntry &entry = pidTable.editEntryAt(index); + if (!entry.getName()) { + char *name = android::pidToName(pid); + if (name) { + entry.setName(name); } } + uid = entry.getUid(); } - - *buf = strdup(string.string()); + return uid; } -uid_t LogStatistics::pidToUid(pid_t pid) { - log_id_for_each(i) { - LidStatistics &l = id(i); - UidStatisticsCollection::iterator iu; - for (iu = l.begin(); iu != l.end(); ++iu) { - UidStatistics &u = *(*iu); - PidStatisticsCollection::iterator ip; - for (ip = u.begin(); ip != u.end(); ++ip) { - if ((*ip)->getPid() == pid) { - return u.getUid(); - } +// caller must free character string +char *LogStatistics::pidToName(pid_t pid) { + char *name; + + android::hash_t hash = android::hash_type(pid); + ssize_t index = pidTable.find(-1, hash, pid); + if (index == -1) { + name = android::pidToName(pid); + PidEntry initEntry(pid, android::pidToUid(pid), name ? strdup(name) : NULL); + pidTable.add(hash, initEntry); + } else { + PidEntry &entry = pidTable.editEntryAt(index); + const char *n = entry.getName(); + if (n) { + name = strdup(n); + } else { + name = android::pidToName(pid); + if (name) { + entry.setName(strdup(name)); } } } - return getuid(); // associate this with the logger + + return name; } diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h index f6c4329..f3110d7 100644 --- a/logd/LogStatistics.h +++ b/logd/LogStatistics.h @@ -17,183 +17,153 @@ #ifndef _LOGD_LOG_STATISTICS_H__ #define _LOGD_LOG_STATISTICS_H__ +#include <memory> +#include <stdlib.h> #include <sys/types.h> #include <log/log.h> -#include <log/log_read.h> -#include <utils/List.h> +#include <utils/BasicHashtable.h> + +#include "LogBufferElement.h" #define log_id_for_each(i) \ for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1)) -class PidStatistics { - const pid_t pid; - - // Total - size_t mSizesTotal; - size_t mElementsTotal; - // Current - size_t mSizes; - size_t mElements; - - char *name; - bool mGone; - +template <typename TKey, typename TEntry> +class LogHashtable : public android::BasicHashtable<TKey, TEntry> { public: - static const pid_t gone = (pid_t) -1; - - PidStatistics(pid_t pid, char *name = NULL); - PidStatistics(const PidStatistics ©); - ~PidStatistics(); - - pid_t getPid() const { return pid; } - bool pidGone(); - char *getName() const { return name; } - void setName(char *name); - - void add(unsigned short size); - bool subtract(unsigned short size); // returns true if stats and PID gone - void addTotal(size_t size, size_t element); - - size_t sizes() const { return mSizes; } - size_t elements() const { return mElements; } - - size_t sizesTotal() const { return mSizesTotal; } - size_t elementsTotal() const { return mElementsTotal; } - - // helper - static char *pidToName(pid_t pid); + std::unique_ptr<const TEntry *[]> sort(size_t n) { + if (!n) { + std::unique_ptr<const TEntry *[]> sorted(NULL); + return sorted; + } + + const TEntry **retval = new const TEntry* [n]; + memset(retval, 0, sizeof(*retval) * n); + + ssize_t index = -1; + while ((index = android::BasicHashtable<TKey, TEntry>::next(index)) >= 0) { + const TEntry &entry = android::BasicHashtable<TKey, TEntry>::entryAt(index); + size_t s = entry.getSizes(); + ssize_t i = n - 1; + while ((!retval[i] || (s > retval[i]->getSizes())) && (--i >= 0)) + ; + if (++i < (ssize_t)n) { + size_t b = n - i - 1; + if (b) { + memmove(&retval[i+1], &retval[i], b * sizeof(retval[0])); + } + retval[i] = &entry; + } + } + std::unique_ptr<const TEntry *[]> sorted(retval); + return sorted; + } + + // Iteration handler for the sort method output + static ssize_t next(ssize_t index, std::unique_ptr<const TEntry *[]> &sorted, size_t n) { + ++index; + if (!sorted.get() || (index < 0) || (n <= (size_t)index) || !sorted[index] + || (sorted[index]->getSizes() <= (sorted[0]->getSizes() / 100))) { + return -1; + } + return index; + } + + ssize_t next(ssize_t index) { + return android::BasicHashtable<TKey, TEntry>::next(index); + } }; -typedef android::List<PidStatistics *> PidStatisticsCollection; - -class UidStatistics { +struct UidEntry { const uid_t uid; + size_t size; + size_t dropped; - PidStatisticsCollection Pids; - - void insert(PidStatisticsCollection::iterator i, PidStatistics *p) - { Pids.insert(i, p); } - void push_back(PidStatistics *p) { Pids.push_back(p); } - - size_t mSizes; - size_t mElements; - -public: - UidStatistics(uid_t uid); - ~UidStatistics(); - - PidStatisticsCollection::iterator begin() { return Pids.begin(); } - PidStatisticsCollection::iterator end() { return Pids.end(); } - PidStatisticsCollection::iterator erase(PidStatisticsCollection::iterator i) - { return Pids.erase(i); } - - uid_t getUid() { return uid; } + UidEntry(uid_t uid):uid(uid),size(0),dropped(0) { } - void add(unsigned short size, pid_t pid); - void subtract(unsigned short size, pid_t pid); - void sort(); + inline const uid_t&getKey() const { return uid; } + size_t getSizes() const { return size; } + size_t getDropped() const { return dropped; } - static const pid_t pid_all = (pid_t) -1; - - // fast track current value - size_t sizes() const { return mSizes; }; - size_t elements() const { return mElements; }; - - // statistical track - size_t sizes(pid_t pid); - size_t elements(pid_t pid); - - size_t sizesTotal(pid_t pid = pid_all); - size_t elementsTotal(pid_t pid = pid_all); - - // helper - static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); } + inline void add(size_t s) { size += s; } + inline void add_dropped(size_t d) { dropped += d; } + inline bool subtract(size_t s) { size -= s; return !dropped && !size; } + inline bool subtract_dropped(size_t d) { dropped -= d; return !dropped && !size; } }; -typedef android::List<UidStatistics *> UidStatisticsCollection; - -class LidStatistics { - UidStatisticsCollection Uids; - -public: - LidStatistics(); - ~LidStatistics(); - - UidStatisticsCollection::iterator begin() { return Uids.begin(); } - UidStatisticsCollection::iterator end() { return Uids.end(); } - - void add(unsigned short size, uid_t uid, pid_t pid); - void subtract(unsigned short size, uid_t uid, pid_t pid); - void sort(); - - static const pid_t pid_all = (pid_t) -1; - static const uid_t uid_all = (uid_t) -1; - - size_t sizes(uid_t uid = uid_all, pid_t pid = pid_all); - size_t elements(uid_t uid = uid_all, pid_t pid = pid_all); - - size_t sizesTotal(uid_t uid = uid_all, pid_t pid = pid_all); - size_t elementsTotal(uid_t uid = uid_all, pid_t pid = pid_all); +struct PidEntry { + const pid_t pid; + uid_t uid; + char *name; + size_t size; + size_t dropped; + + PidEntry(pid_t p, uid_t u, char *n):pid(p),uid(u),name(n),size(0),dropped(0) { } + PidEntry(const PidEntry &c): + pid(c.pid), + uid(c.uid), + name(c.name ? strdup(c.name) : NULL), + size(c.size), + dropped(c.dropped) { } + ~PidEntry() { free(name); } + + const pid_t&getKey() const { return pid; } + const uid_t&getUid() const { return uid; } + uid_t&setUid(uid_t u) { return uid = u; } + const char*getName() const { return name; } + char *setName(char *n) { free(name); return name = n; } + size_t getSizes() const { return size; } + size_t getDropped() const { return dropped; } + inline void add(size_t s) { size += s; } + inline void add_dropped(size_t d) { dropped += d; } + inline bool subtract(size_t s) { size -= s; return !dropped && !size; } + inline bool subtract_dropped(size_t d) { dropped -= d; return !dropped && !size; } }; // Log Statistics class LogStatistics { - LidStatistics LogIds[LOG_ID_MAX]; - size_t mSizes[LOG_ID_MAX]; size_t mElements[LOG_ID_MAX]; + size_t mSizesTotal[LOG_ID_MAX]; + size_t mElementsTotal[LOG_ID_MAX]; + bool enable; - bool mStatistics; - bool dgramQlenStatistics; + // uid to size list + typedef LogHashtable<uid_t, UidEntry> uidTable_t; + uidTable_t uidTable[LOG_ID_MAX]; - static const unsigned short mBuckets[14]; - log_time mMinimum[sizeof(mBuckets) / sizeof(mBuckets[0])]; + // pid to uid list + typedef LogHashtable<pid_t, PidEntry> pidTable_t; + pidTable_t pidTable; public: - const log_time start; - LogStatistics(); - LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; } + void enableStatistics() { enable = true; } - void enableDgramQlenStatistics() { dgramQlenStatistics = true; } - void enableStatistics() { mStatistics = true; } - static unsigned short dgramQlen(unsigned short bucket); - unsigned long long minimum(unsigned short bucket); - void recordDiff(log_time diff, unsigned short bucket); + void add(LogBufferElement *entry); + void subtract(LogBufferElement *entry); + // entry->setDropped(1) must follow this call + void drop(LogBufferElement *entry); + // Correct for merging two entries referencing dropped content + void erase(LogBufferElement *e) { --mElements[e->getLogId()]; } - void add(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid); - void subtract(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid); - void sort(); + std::unique_ptr<const UidEntry *[]> sort(size_t n, log_id i) { return uidTable[i].sort(n); } // fast track current value by id only size_t sizes(log_id_t id) const { return mSizes[id]; } size_t elements(log_id_t id) const { return mElements[id]; } - - // statistical track - static const log_id_t log_id_all = (log_id_t) -1; - static const uid_t uid_all = (uid_t) -1; - static const pid_t pid_all = (pid_t) -1; - - size_t sizes(log_id_t id, uid_t uid, pid_t pid = pid_all); - size_t elements(log_id_t id, uid_t uid, pid_t pid = pid_all); - size_t sizes() { return sizes(log_id_all, uid_all); } - size_t elements() { return elements(log_id_all, uid_all); } - - size_t sizesTotal(log_id_t id = log_id_all, - uid_t uid = uid_all, - pid_t pid = pid_all); - size_t elementsTotal(log_id_t id = log_id_all, - uid_t uid = uid_all, - pid_t pid = pid_all); + size_t sizesTotal(log_id_t id) const { return mSizesTotal[id]; } + size_t elementsTotal(log_id_t id) const { return mElementsTotal[id]; } // *strp = malloc, balance with free - void format(char **strp, uid_t uid, unsigned int logMask, log_time oldest); + void format(char **strp, uid_t uid, unsigned int logMask); // helper - static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); } + char *pidToName(pid_t pid); uid_t pidToUid(pid_t pid); + char *uidToName(uid_t uid); }; #endif // _LOGD_LOG_STATISTICS_H__ diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp index ea4e8c8..1b60b7e 100644 --- a/logd/LogTimes.cpp +++ b/logd/LogTimes.cpp @@ -23,12 +23,10 @@ pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER; -const struct timespec LogTimeEntry::EPOCH = { 0, 1 }; - LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client, bool nonBlock, unsigned long tail, unsigned int logMask, pid_t pid, - log_time start) + uint64_t start) : mRefCount(1) , mRelease(false) , mError(false) @@ -36,16 +34,16 @@ LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client, , mReader(reader) , mLogMask(logMask) , mPid(pid) - , skipAhead(0) , mCount(0) , mTail(tail) , mIndex(0) , mClient(client) , mStart(start) , mNonBlock(nonBlock) - , mEnd(CLOCK_MONOTONIC) + , mEnd(LogBufferElement::getCurrentSequence()) { pthread_cond_init(&threadTriggeredCondition, NULL); + cleanSkip_Locked(); } void LogTimeEntry::startReader_Locked(void) { @@ -129,7 +127,7 @@ void *LogTimeEntry::threadStart(void *obj) { lock(); while (me->threadRunning && !me->isError_Locked()) { - log_time start = me->mStart; + uint64_t start = me->mStart; unlock(); @@ -148,6 +146,8 @@ void *LogTimeEntry::threadStart(void *obj) { break; } + me->cleanSkip_Locked(); + pthread_cond_wait(&me->threadTriggeredCondition, ×Lock); } @@ -159,17 +159,17 @@ void *LogTimeEntry::threadStart(void *obj) { } // A first pass to count the number of elements -bool LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) { +int LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) { LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); LogTimeEntry::lock(); if (me->mCount == 0) { - me->mStart = element->getMonotonicTime(); + me->mStart = element->getSequence(); } if ((!me->mPid || (me->mPid == element->getPid())) - && (me->mLogMask & (1 << element->getLogId()))) { + && (me->isWatching(element->getLogId()))) { ++me->mCount; } @@ -179,24 +179,24 @@ bool LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) { } // A second pass to send the selected elements -bool LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) { +int LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) { LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); LogTimeEntry::lock(); - if (me->skipAhead) { - me->skipAhead--; + me->mStart = element->getSequence(); + + if (me->skipAhead[element->getLogId()]) { + me->skipAhead[element->getLogId()]--; goto skip; } - me->mStart = element->getMonotonicTime(); - // Truncate to close race between first and second pass if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) { - goto skip; + goto stop; } - if ((me->mLogMask & (1 << element->getLogId())) == 0) { + if (!me->isWatching(element->getLogId())) { goto skip; } @@ -205,7 +205,7 @@ bool LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) } if (me->isError_Locked()) { - goto skip; + goto stop; } if (!me->mTail) { @@ -223,7 +223,7 @@ bool LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) } ok: - if (!me->skipAhead) { + if (!me->skipAhead[element->getLogId()]) { LogTimeEntry::unlock(); return true; } @@ -232,4 +232,14 @@ ok: skip: LogTimeEntry::unlock(); return false; + +stop: + LogTimeEntry::unlock(); + return -1; +} + +void LogTimeEntry::cleanSkip_Locked(void) { + for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1)) { + skipAhead[i] = 0; + } } diff --git a/logd/LogTimes.h b/logd/LogTimes.h index 0bfa7a2..ae2f92b 100644 --- a/logd/LogTimes.h +++ b/logd/LogTimes.h @@ -22,6 +22,7 @@ #include <sys/types.h> #include <sysutils/SocketClient.h> #include <utils/List.h> +#include <log/log.h> class LogReader; @@ -38,7 +39,7 @@ class LogTimeEntry { static void threadStop(void *me); const unsigned int mLogMask; const pid_t mPid; - unsigned int skipAhead; + unsigned int skipAhead[LOG_ID_MAX]; unsigned long mCount; unsigned long mTail; unsigned long mIndex; @@ -46,13 +47,12 @@ class LogTimeEntry { public: LogTimeEntry(LogReader &reader, SocketClient *client, bool nonBlock, unsigned long tail, unsigned int logMask, pid_t pid, - log_time start); + uint64_t start); SocketClient *mClient; - static const struct timespec EPOCH; - log_time mStart; + uint64_t mStart; const bool mNonBlock; - const log_time mEnd; // only relevant if mNonBlock + const uint64_t mEnd; // only relevant if mNonBlock // Protect List manipulations static void lock(void) { pthread_mutex_lock(×Lock); } @@ -67,7 +67,8 @@ public: pthread_cond_signal(&threadTriggeredCondition); } - void triggerSkip_Locked(unsigned int skip) { skipAhead = skip; } + void triggerSkip_Locked(log_id_t id, unsigned int skip) { skipAhead[id] = skip; } + void cleanSkip_Locked(void); // Called after LogTimeEntry removed from list, lock implicitly held void release_Locked(void) { @@ -99,10 +100,10 @@ public: // No one else is holding a reference to this delete this; } - + bool isWatching(log_id_t id) { return (mLogMask & (1<<id)) != 0; } // flushTo filter callbacks - static bool FilterFirstPass(const LogBufferElement *element, void *me); - static bool FilterSecondPass(const LogBufferElement *element, void *me); + static int FilterFirstPass(const LogBufferElement *element, void *me); + static int FilterSecondPass(const LogBufferElement *element, void *me); }; typedef android::List<LogTimeEntry *> LastLogTimes; diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp index e87b604..bee940d 100644 --- a/logd/LogWhiteBlackList.cpp +++ b/logd/LogWhiteBlackList.cpp @@ -39,15 +39,20 @@ int Prune::cmp(uid_t uid, pid_t pid) const { void Prune::format(char **strp) { if (mUid != uid_all) { - asprintf(strp, (mPid != pid_all) ? "%u/%u" : "%u", mUid, mPid); - } else { - // NB: mPid == pid_all can not happen if mUid == uid_all - asprintf(strp, (mPid != pid_all) ? "/%u" : "/", mPid); + if (mPid != pid_all) { + asprintf(strp, "%u/%u", mUid, mPid); + } else { + asprintf(strp, "%u", mUid); + } + } else if (mPid != pid_all) { + asprintf(strp, "/%u", mPid); + } else { // NB: mPid == pid_all can not happen if mUid == uid_all + asprintf(strp, "/"); } } PruneList::PruneList() - : mWorstUidEnabled(false) { + : mWorstUidEnabled(true) { mNaughty.clear(); mNice.clear(); } @@ -65,7 +70,7 @@ PruneList::~PruneList() { } int PruneList::init(char *str) { - mWorstUidEnabled = false; + mWorstUidEnabled = true; PruneCollection::iterator it; for (it = mNice.begin(); it != mNice.end();) { delete (*it); diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h index 769d651..5f60801 100644 --- a/logd/LogWhiteBlackList.h +++ b/logd/LogWhiteBlackList.h @@ -61,7 +61,9 @@ public: int init(char *str); bool naughty(LogBufferElement *element); + bool naughty(void) { return !mNaughty.empty(); } bool nice(LogBufferElement *element); + bool nice(void) { return !mNice.empty(); } bool worstUidEnabled() const { return mWorstUidEnabled; } // *strp is malloc'd, use free to release diff --git a/logd/README.property b/logd/README.property index b7fcece..60542b2 100644 --- a/logd/README.property +++ b/logd/README.property @@ -7,12 +7,6 @@ logd.auditd.dmesg bool true selinux audit messages duplicated and logd.statistics bool depends Enable logcat -S statistics. ro.config.low_ram bool false if true, logd.statistics default false ro.build.type string if user, logd.statistics default false -logd.statistics.dgram_qlen bool false Record dgram_qlen statistics. This - represents a performance impact and - is used to determine the platform's - minimum domain socket network FIFO - size (see source for details) based - on typical load (logcat -S to view) persist.logd.size number 256K default size of the buffer for all log ids at initial startup, at runtime use: logcat -b all -G <value> diff --git a/logd/event.logtags b/logd/event.logtags index a63f034..db8c19b 100644 --- a/logd/event.logtags +++ b/logd/event.logtags @@ -34,3 +34,4 @@ # TODO: generate ".java" and ".h" files with integer constants from this file. 1003 auditd (avc|3) +1004 logd (dropped|3) diff --git a/logd/libaudit.c b/logd/libaudit.c index d00d579..cf76305 100644 --- a/logd/libaudit.c +++ b/logd/libaudit.c @@ -177,7 +177,7 @@ int audit_setup(int fd, uint32_t pid) */ status.pid = pid; status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT; - status.rate_limit = 20; // audit entries per second + status.rate_limit = 5; // audit entries per second /* Let the kernel know this pid will be registering for audit events */ rc = audit_send(fd, AUDIT_SET, &status, sizeof(status)); diff --git a/logd/main.cpp b/logd/main.cpp index 54da7e3..eb29596 100644 --- a/logd/main.cpp +++ b/logd/main.cpp @@ -17,24 +17,37 @@ #include <dirent.h> #include <errno.h> #include <fcntl.h> +#include <poll.h> #include <sched.h> +#include <semaphore.h> +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/capability.h> +#include <sys/klog.h> #include <sys/prctl.h> #include <sys/stat.h> #include <sys/types.h> +#include <syslog.h> #include <unistd.h> #include <cutils/properties.h> +#include <cutils/sched_policy.h> +#include <cutils/sockets.h> +#include <private/android_filesystem_config.h> -#include "private/android_filesystem_config.h" #include "CommandListener.h" #include "LogBuffer.h" #include "LogListener.h" #include "LogAudit.h" +#define KMSG_PRIORITY(PRI) \ + '<', \ + '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \ + '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) % 10, \ + '>' + // // The service is designed to be run by init, it does not respond well // to starting up manually. When starting up manually the sockets will @@ -68,6 +81,10 @@ static int drop_privs() { struct sched_param param; memset(¶m, 0, sizeof(param)); + if (set_sched_policy(0, SP_BACKGROUND) < 0) { + return -1; + } + if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 0) { return -1; } @@ -121,17 +138,161 @@ static bool property_get_bool(const char *key, bool def) { return def; } -// Foreground waits for exit of the three main persistent threads that -// are started here. The three threads are created to manage UNIX -// domain client sockets for writing, reading and controlling the user -// space logger. Additional transitory per-client threads are created -// for each reader once they register. -int main() { - bool auditd = property_get_bool("logd.auditd", true); +// Remove the static, and use this variable +// globally for debugging if necessary. eg: +// write(fdDmesg, "I am here\n", 10); +static int fdDmesg = -1; + +static sem_t uidName; +static uid_t uid; +static char *name; + +static sem_t reinit; +static bool reinit_running = false; +static LogBuffer *logBuf = NULL; + +static void *reinit_thread_start(void * /*obj*/) { + prctl(PR_SET_NAME, "logd.daemon"); + set_sched_policy(0, SP_BACKGROUND); + + setgid(AID_SYSTEM); + setuid(AID_SYSTEM); + + while (reinit_running && !sem_wait(&reinit) && reinit_running) { + + // uidToName Privileged Worker + if (uid) { + name = NULL; + + FILE *fp = fopen("/data/system/packages.list", "r"); + if (fp) { + // This simple parser is sensitive to format changes in + // frameworks/base/services/core/java/com/android/server/pm/Settings.java + // A dependency note has been added to that file to correct + // this parser. + + char *buffer = NULL; + size_t len; + while (getline(&buffer, &len, fp) > 0) { + char *userId = strchr(buffer, ' '); + if (!userId) { + continue; + } + *userId = '\0'; + unsigned long value = strtoul(userId + 1, NULL, 10); + if (value != uid) { + continue; + } + name = strdup(buffer); + break; + } + free(buffer); + fclose(fp); + } + uid = 0; + sem_post(&uidName); + continue; + } - int fdDmesg = -1; - if (auditd && property_get_bool("logd.auditd.dmesg", true)) { - fdDmesg = open("/dev/kmsg", O_WRONLY); + if (fdDmesg >= 0) { + static const char reinit_message[] = { KMSG_PRIORITY(LOG_INFO), + 'l', 'o', 'g', 'd', '.', 'd', 'a', 'e', 'm', 'o', 'n', ':', + ' ', 'r', 'e', 'i', 'n', 'i', 't', '\n' }; + write(fdDmesg, reinit_message, sizeof(reinit_message)); + } + + // Anything that reads persist.<property> + if (logBuf) { + logBuf->init(); + } + } + + return NULL; +} + +char *android::uidToName(uid_t u) { + if (!u || !reinit_running) { + return NULL; + } + + // Not multi-thread safe, we know there is only one caller + uid = u; + + name = NULL; + sem_post(&reinit); + sem_wait(&uidName); + return name; +} + +// Serves as a global method to trigger reinitialization +// and as a function that can be provided to signal(). +void reinit_signal_handler(int /*signal*/) { + sem_post(&reinit); +} + +// Foreground waits for exit of the main persistent threads +// that are started here. The threads are created to manage +// UNIX domain client sockets for writing, reading and +// controlling the user space logger, and for any additional +// logging plugins like auditd and restart control. Additional +// transitory per-client threads are created for each reader. +int main(int argc, char *argv[]) { + fdDmesg = open("/dev/kmsg", O_WRONLY); + + // issue reinit command. KISS argument parsing. + if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) { + int sock = TEMP_FAILURE_RETRY( + socket_local_client("logd", + ANDROID_SOCKET_NAMESPACE_RESERVED, + SOCK_STREAM)); + if (sock < 0) { + return -errno; + } + static const char reinit[] = "reinit"; + ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinit, sizeof(reinit))); + if (ret < 0) { + return -errno; + } + struct pollfd p; + memset(&p, 0, sizeof(p)); + p.fd = sock; + p.events = POLLIN; + ret = TEMP_FAILURE_RETRY(poll(&p, 1, 100)); + if (ret < 0) { + return -errno; + } + if ((ret == 0) || !(p.revents & POLLIN)) { + return -ETIME; + } + static const char success[] = "success"; + char buffer[sizeof(success) - 1]; + memset(buffer, 0, sizeof(buffer)); + ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer))); + if (ret < 0) { + return -errno; + } + return strncmp(buffer, success, sizeof(success) - 1) != 0; + } + + // Reinit Thread + sem_init(&reinit, 0, 0); + sem_init(&uidName, 0, 0); + pthread_attr_t attr; + if (!pthread_attr_init(&attr)) { + struct sched_param param; + + memset(¶m, 0, sizeof(param)); + pthread_attr_setschedparam(&attr, ¶m); + pthread_attr_setschedpolicy(&attr, SCHED_BATCH); + if (!pthread_attr_setdetachstate(&attr, + PTHREAD_CREATE_DETACHED)) { + pthread_t thread; + reinit_running = true; + if (pthread_create(&thread, &attr, reinit_thread_start, NULL)) { + reinit_running = false; + } + } + pthread_attr_destroy(&attr); } if (drop_privs() != 0) { @@ -147,11 +308,10 @@ int main() { // LogBuffer is the object which is responsible for holding all // log entries. - LogBuffer *logBuf = new LogBuffer(times); + logBuf = new LogBuffer(times); + + signal(SIGHUP, reinit_signal_handler); - if (property_get_bool("logd.statistics.dgram_qlen", false)) { - logBuf->enableDgramQlenStatistics(); - } { char property[PROPERTY_VALUE_MAX]; property_get("ro.build.type", property, ""); @@ -192,16 +352,36 @@ int main() { // initiated log messages. New log entries are added to LogBuffer // and LogReader is notified to send updates to connected clients. + bool auditd = property_get_bool("logd.auditd", true); + if (auditd) { + bool dmesg = property_get_bool("logd.auditd.dmesg", true); + // failure is an option ... messages are in dmesg (required by standard) - LogAudit *al = new LogAudit(logBuf, reader, fdDmesg); + LogAudit *al = new LogAudit(logBuf, reader, dmesg ? fdDmesg : -1); + + int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0); + if (len > 0) { + len++; + char buf[len]; + + int rc = klogctl(KLOG_READ_ALL, buf, len); + + if (rc >= 0) { + buf[len - 1] = '\0'; + + for (char *ptr, *tok = buf; (tok = strtok_r(tok, "\r\n", &ptr)); tok = NULL) { + al->log(tok); + } + } + } + if (al->startListener()) { delete al; - close(fdDmesg); } } - pause(); + TEMP_FAILURE_RETRY(pause()); + exit(0); } - diff --git a/logd/tests/Android.mk b/logd/tests/Android.mk index f851288..85ca4ac 100644 --- a/logd/tests/Android.mk +++ b/logd/tests/Android.mk @@ -46,7 +46,6 @@ test_src_files := \ include $(CLEAR_VARS) LOCAL_MODULE := $(test_module_prefix)unit-tests LOCAL_MODULE_TAGS := $(test_tags) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += $(test_c_flags) LOCAL_SHARED_LIBRARIES := libcutils LOCAL_SRC_FILES := $(test_src_files) diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp index 4bea4be..46bd9c0 100644 --- a/logd/tests/logd_test.cpp +++ b/logd/tests/logd_test.cpp @@ -192,164 +192,6 @@ TEST(logd, statistics) { EXPECT_TRUE(NULL != events_logs); #endif - // Parse timing stats - - cp = strstr(cp, "Minimum time between log events per dgram_qlen:"); - - if (cp) { - while (*cp && (*cp != '\n')) { - ++cp; - } - if (*cp == '\n') { - ++cp; - } - - char *list_of_spans = cp; - EXPECT_NE('\0', *list_of_spans); - - unsigned short number_of_buckets = 0; - unsigned short *dgram_qlen = NULL; - unsigned short bucket = 0; - while (*cp && (*cp != '\n')) { - bucket = 0; - while (isdigit(*cp)) { - bucket = bucket * 10 + *cp - '0'; - ++cp; - } - while (*cp == ' ') { - ++cp; - } - if (!bucket) { - break; - } - unsigned short *new_dgram_qlen = new unsigned short[number_of_buckets + 1]; - EXPECT_TRUE(new_dgram_qlen != NULL); - if (dgram_qlen) { - memcpy(new_dgram_qlen, dgram_qlen, sizeof(*dgram_qlen) * number_of_buckets); - delete [] dgram_qlen; - } - - dgram_qlen = new_dgram_qlen; - dgram_qlen[number_of_buckets++] = bucket; - } - - char *end_of_spans = cp; - EXPECT_NE('\0', *end_of_spans); - - EXPECT_LT(5, number_of_buckets); - - unsigned long long *times = new unsigned long long [number_of_buckets]; - ASSERT_TRUE(times != NULL); - - memset(times, 0, sizeof(*times) * number_of_buckets); - - while (*cp == '\n') { - ++cp; - } - - unsigned short number_of_values = 0; - unsigned long long value; - while (*cp && (*cp != '\n')) { - EXPECT_GE(number_of_buckets, number_of_values); - - value = 0; - while (isdigit(*cp)) { - value = value * 10ULL + *cp - '0'; - ++cp; - } - - switch(*cp) { - case ' ': - case '\n': - value *= 1000ULL; - /* FALLTHRU */ - case 'm': - value *= 1000ULL; - /* FALLTHRU */ - case 'u': - value *= 1000ULL; - /* FALLTHRU */ - case 'n': - default: - break; - } - while (*++cp == ' '); - - if (!value) { - break; - } - - times[number_of_values] = value; - ++number_of_values; - } - -#ifdef TARGET_USES_LOGD - EXPECT_EQ(number_of_values, number_of_buckets); -#endif - - FILE *fp; - ASSERT_TRUE(NULL != (fp = fopen("/proc/sys/net/unix/max_dgram_qlen", "r"))); - - unsigned max_dgram_qlen = 0; - fscanf(fp, "%u", &max_dgram_qlen); - - fclose(fp); - - // Find launch point - unsigned short launch = 0; - unsigned long long total = 0; - do { - total += times[launch]; - } while (((++launch < number_of_buckets) - && ((total / launch) >= (times[launch] / 8ULL))) - || (launch == 1)); // too soon - - bool failure = number_of_buckets <= launch; - if (!failure) { - unsigned short l = launch; - if (l >= number_of_buckets) { - l = number_of_buckets - 1; - } - failure = max_dgram_qlen < dgram_qlen[l]; - } - - // We can get failure if at any time liblog_benchmarks has been run - // because designed to overload /proc/sys/net/unix/max_dgram_qlen even - // at excessive values like 20000. It does so to measure the raw processing - // performance of logd. - if (failure) { - cp = find_benchmark_spam(cp); - } - - if (cp) { - // Fake a failure, but without the failure code - if (number_of_buckets <= launch) { - printf ("Expected: number_of_buckets > launch, actual: %u vs %u\n", - number_of_buckets, launch); - } - if (launch >= number_of_buckets) { - launch = number_of_buckets - 1; - } - if (max_dgram_qlen < dgram_qlen[launch]) { - printf ("Expected: max_dgram_qlen >= dgram_qlen[%d]," - " actual: %u vs %u\n", - launch, max_dgram_qlen, dgram_qlen[launch]); - } - } else -#ifndef TARGET_USES_LOGD - if (total) -#endif - { - EXPECT_GT(number_of_buckets, launch); - if (launch >= number_of_buckets) { - launch = number_of_buckets - 1; - } - EXPECT_GE(max_dgram_qlen, dgram_qlen[launch]); - } - - delete [] dgram_qlen; - delete [] times; - } delete [] buf; } @@ -417,7 +259,11 @@ static void dump_log_msg(const char *prefix, if (((p - cp) > 3) && !*p && ((unsigned int)(p - cp) < len)) { fprintf(stderr, "\""); while (*cp) { - fprintf(stderr, (*cp != '\n') ? "%c" : "\\n", *cp); + if (*cp != '\n') { + fprintf(stderr, "%c", *cp); + } else { + fprintf(stderr, "\\n"); + } ++cp; --len; } diff --git a/netcfg/Android.mk b/netcfg/Android.mk deleted file mode 100644 index fc01a54..0000000 --- a/netcfg/Android.mk +++ /dev/null @@ -1,17 +0,0 @@ -ifneq ($(BUILD_TINY_ANDROID),true) -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES:= netcfg.c -LOCAL_MODULE:= netcfg - -#LOCAL_FORCE_STATIC_EXECUTABLE := true -#LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN) -#LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED) -#LOCAL_STATIC_LIBRARIES := libcutils libc - -LOCAL_SHARED_LIBRARIES := libc libnetutils -LOCAL_CFLAGS := -Werror - -include $(BUILD_EXECUTABLE) -endif diff --git a/netcfg/MODULE_LICENSE_APACHE2 b/netcfg/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29..0000000 --- a/netcfg/MODULE_LICENSE_APACHE2 +++ /dev/null diff --git a/netcfg/NOTICE b/netcfg/NOTICE deleted file mode 100644 index c5b1efa..0000000 --- a/netcfg/NOTICE +++ /dev/null @@ -1,190 +0,0 @@ - - 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/netcfg/netcfg.c b/netcfg/netcfg.c deleted file mode 100644 index 4e83ba4..0000000 --- a/netcfg/netcfg.c +++ /dev/null @@ -1,182 +0,0 @@ -/* -** Copyright 2006, 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 <dirent.h> -#include <netinet/ether.h> -#include <netinet/if_ether.h> -#include <netutils/dhcp.h> -#include <netutils/ifc.h> -#include <stdio.h> -#include <stdlib.h> - -void die(const char *reason) -{ - perror(reason); - exit(1); -} - -const char *ipaddr(in_addr_t addr) -{ - struct in_addr in_addr; - - in_addr.s_addr = addr; - return inet_ntoa(in_addr); -} - -void usage(void) -{ - fprintf(stderr,"usage: netcfg [<interface> {dhcp|up|down}]\n"); - exit(1); -} - -int dump_interface(const char *name) -{ - unsigned addr, flags; - unsigned char hwbuf[ETH_ALEN]; - int prefixLength; - - if(ifc_get_info(name, &addr, &prefixLength, &flags)) { - return 0; - } - - printf("%-8s %s ", name, flags & 1 ? "UP " : "DOWN"); - printf("%40s", ipaddr(addr)); - printf("/%-4d", prefixLength); - printf("0x%08x ", flags); - if (!ifc_get_hwaddr(name, hwbuf)) { - int i; - for(i=0; i < (ETH_ALEN-1); i++) - printf("%02x:", hwbuf[i]); - printf("%02x\n", hwbuf[i]); - } else { - printf("\n"); - } - return 0; -} - -int dump_interfaces(void) -{ - DIR *d; - struct dirent *de; - - d = opendir("/sys/class/net"); - if(d == 0) return -1; - - while((de = readdir(d))) { - if(de->d_name[0] == '.') continue; - dump_interface(de->d_name); - } - closedir(d); - return 0; -} - -int set_hwaddr(const char *name, const char *asc) { - struct ether_addr *addr = ether_aton(asc); - if (!addr) { - printf("Failed to parse '%s'\n", asc); - return -1; - } - return ifc_set_hwaddr(name, addr->ether_addr_octet); -} - -struct -{ - const char *name; - int nargs; - void *func; -} CMDS[] = { - { "dhcp", 1, do_dhcp }, - { "up", 1, ifc_up }, - { "down", 1, ifc_down }, - { "deldefault", 1, ifc_remove_default_route }, - { "hwaddr", 2, set_hwaddr }, - { 0, 0, 0 }, -}; - -static int call_func(void *_func, unsigned nargs, char **args) -{ - switch(nargs){ - case 1: { - int (*func)(char *a0) = _func; - return func(args[0]); - } - case 2: { - int (*func)(char *a0, char *a1) = _func; - return func(args[0], args[1]); - } - case 3: { - int (*func)(char *a0, char *a1, char *a2) = _func; - return func(args[0], args[1], args[2]); - } - default: - return -1; - } -} - -int main(int argc, char **argv) -{ - char *iname; - int n; - - if(ifc_init()) { - die("Cannot perform requested operation"); - } - - if(argc == 1) { - int result = dump_interfaces(); - ifc_close(); - return result; - } - - if(argc < 3) usage(); - - iname = argv[1]; - if(strlen(iname) > 16) usage(); - - argc -= 2; - argv += 2; - while(argc > 0) { - for(n = 0; CMDS[n].name; n++){ - if(!strcmp(argv[0], CMDS[n].name)) { - char *cmdname = argv[0]; - int nargs = CMDS[n].nargs; - - argv[0] = iname; - if(argc < nargs) { - fprintf(stderr, "not enough arguments for '%s'\n", cmdname); - ifc_close(); - exit(1); - } - if(call_func(CMDS[n].func, nargs, argv)) { - fprintf(stderr, "action '%s' failed (%s)\n", cmdname, strerror(errno)); - ifc_close(); - exit(1); - } - argc -= nargs; - argv += nargs; - goto done; - } - } - fprintf(stderr,"no such action '%s'\n", argv[0]); - usage(); - done: - ; - } - ifc_close(); - - return 0; -} diff --git a/rootdir/etc/hosts b/rootdir/etc/hosts index 99848f6..649151c 100644 --- a/rootdir/etc/hosts +++ b/rootdir/etc/hosts @@ -1 +1,2 @@ -127.0.0.1 localhost +127.0.0.1 localhost +::1 ip6-localhost diff --git a/rootdir/etc/init.testmenu b/rootdir/etc/init.testmenu deleted file mode 100755 index 7ae16d5..0000000 --- a/rootdir/etc/init.testmenu +++ /dev/null @@ -1,322 +0,0 @@ -#!/system/bin/sh - -atdev=/dev/omap_csmi_tty0 -pppdev=/dev/omap_csmi_tty1 - -n1=`cat /data/phoneentry1 2>/dev/null` -n2=`cat /data/phoneentry2 2>/dev/null` -n3=`cat /data/phoneentry3 2>/dev/null` -n1=${n1:-"*#06#"} -n2=${n2:-"*#06#"} -n3=${n3:-"*#06#"} -phoneoutputpid= -eventoutputpid= -notifypid= -notifytoggle=false -pppdpid= -powerdidletime=120 - -# map phone specific keys -setkey -k 0xe4 -v 0x23 # map # -setkey -k 0xe3 -v 0x2a # map * -setkey -k 231 -v 513 # map send to newline -#setkey -k 0x67 -v 0x20b # map up to scroll back -#setkey -k 0x6c -v 0x20a # map down to scroll forward -setkey -k 0x73 -v 0x20b # map volume up to scroll back -setkey -k 0x72 -v 0x20a # map volume down to scroll forward -setkey -k 0x60 -v 0x211 # map PoC to next console - -# tuttle keys -setkey -k 0x38 -v 0x703 # map leftalt to alt -setkey -k 0x9b -v 0x703 # map mail to alt -setkey -t 8 -k 0x9b -v 0x703 # map alt-mail to alt -setkey -t 8 -k 0x10 -v 0x21 # map alt-q to ! -setkey -t 8 -k 0x11 -v 0x31 # map alt-w to 1 -setkey -t 8 -k 0x12 -v 0x32 # map alt-e to 2 -setkey -t 8 -k 0x13 -v 0x33 # map alt-r to 3 -setkey -t 8 -k 0x14 -v 0x2b # map alt-t to + -setkey -t 8 -k 0x15 -v 0x28 # map alt-y to ( -setkey -t 8 -k 0x16 -v 0x29 # map alt-u to ) -setkey -t 8 -k 0x17 -v 0x2d # map alt-i to - -setkey -t 8 -k 0x18 -v 0x5f # map alt-o to _ -setkey -t 8 -k 0x19 -v 0x22 # map alt-p to " -setkey -t 8 -k 0x1e -v 0x23 # map alt-a to # -setkey -t 8 -k 0x1f -v 0x34 # map alt-s to 4 -setkey -t 8 -k 0x20 -v 0x35 # map alt-d to 5 -setkey -t 8 -k 0x21 -v 0x36 # map alt-f to 6 -setkey -t 8 -k 0x22 -v 0x2f # map alt-g to / -setkey -t 8 -k 0x23 -v 0x3f # map alt-h to ? -setkey -t 8 -k 0x24 -v 0xa3 # map alt-j to pound -setkey -t 8 -k 0x25 -v 0x24 # map alt-k to $ -setkey -t 8 -k 0x2c -v 0x2a # map alt-z to * -setkey -t 8 -k 0x2d -v 0x37 # map alt-x to 7 -setkey -t 8 -k 0x2e -v 0x38 # map alt-c to 8 -setkey -t 8 -k 0x2f -v 0x39 # map alt-v to 9 -setkey -t 8 -k 0x30 -v 0x7c # map alt-b to | -setkey -t 8 -k 0x31 -v 0x40 # map alt-n to @ -setkey -t 8 -k 0x32 -v 0x3d # map alt-m to = -setkey -t 8 -k 0x33 -v 0x3b # map alt-, to ; -setkey -t 8 -k 0x34 -v 0x3a # map alt-. to : -setkey -t 8 -k 0x0f -v 0x30 # map alt-tab to 0 -setkey -t 8 -k 0x67 -v 0x20b # map alt-up to scroll back -setkey -t 8 -k 0x6c -v 0x20a # map alt-down to scroll forward - -while true -do - echo - echo "------------------------------" - echo " 1: init commands" - echo " 2: call commands" - echo " 3: misc phone" - echo " 4: phone debug output" - echo " 5: test data connection" - echo " 6: start runtime" - echo " 7: start runtime w/output" - echo " 8: stop runtime" - echo " 9: misc" - echo -n ": " - while true - do - c=`readtty -t 50 -f -a 1234567890#` - case "$c" in - "" ) ;; - * ) break; - esac - done - echo Got key -$c- - case $c in - "1" ) - while true; do - echo - echo "------------------------------" - echo " 1: Print phone output" - echo " 2: ATQ0V1E1+CMEE=2;+CREG=0" - echo " 3: AT+CFUN=1" - echo " 4: AT+COPS=0" - echo " 5: AT+CREG?" - echo " 6: Stop phone output" - echo " 0: back" - echo -n ": " - c=`readtty -f -a 1234560#` - echo Got key -$c- - case "$c" in - "1" ) kill $phoneoutputpid; cat $atdev & phoneoutputpid=$! ;; - "2" ) echo -e "ATQ0V1E1+CMEE=2;+CREG=0\r" >$atdev;; - "3" ) echo -e "AT+CFUN=1\r" >$atdev;; - "4" ) echo -e "AT+COPS=0\r" >$atdev;; - "5" ) echo -e "AT+CREG?\r" >$atdev;; - "6" ) kill $phoneoutputpid; phoneoutputpid= ;; - "0" ) break;; - esac - done - ;; - "2" ) - while true; do - echo - echo "------------------------------" - echo " 1: Dial: ATD $n1;" - echo " 2: Dial: ATD $n2;" - echo " 3: Dial: ATD $n3;" - echo " 4: Set number for 1" - echo " 5: Set number for 2" - echo " 6: Set number for 3" - echo " 7: Dial: ATD ...;" - echo " 8: Hang up: ATH" - echo " 9: Answer: ATA" - echo " 0: back" - echo -n ": " - c=`readtty -f -a 1234567890#` - echo Got key -$c- - case "$c" in - "1" ) echo "Dialing $n1"; echo -e "ATD $n1;\r" >$atdev;; - "2" ) echo "Dialing $n2"; echo -e "ATD $n2;\r" >$atdev;; - "3" ) echo "Dialing $n3"; echo -e "ATD $n3;\r" >$atdev;; - "4" ) echo -n "Number: "; read n1; echo $n1 >/data/phoneentry1;; - "5" ) echo -n "Number: "; read n2; echo $n2 >/data/phoneentry2;; - "6" ) echo -n "Number: "; read n3; echo $n3 >/data/phoneentry3;; - "7" ) echo -n "Number: "; read n; echo "Dialing $n"; echo -e "ATD $n;\r" >$atdev;; - "8" ) echo -e "ATH\r" >$atdev;; - "9" ) echo -e "ATA\r" >$atdev;; - "0" ) break;; - esac - done - ;; - "3" ) - while true; do - echo - echo "------------------------------" - echo " 1: Save FFS data" - echo " 2: Load user FFS data" - echo " 3: Load system FFS data" - echo " 4: Reset FFS data" - echo " 5: Set uplink gain" - echo " 6: Set echo" - echo " 7: cat /dev/omap_csmi_battery_t" - echo " 8: cat /dev/omap_csmi_htc" - echo " 0: back" - echo -n ": " - c=`readtty -f -a 123456780#` - echo Got key -$c- - case "$c" in - "1" ) cat /dev/omap_csmi_ffs >/data/ffsdata;; - "2" ) cat /data/ffsdata >/dev/omap_csmi_ffs;; - "3" ) cat /system/ffsdata >/dev/omap_csmi_ffs;; - "4" ) echo - >/dev/omap_csmi_ffs;; - "5" ) - echo -n "Gain: "; read g; - echo gu$g >/tmp/gain; - cat /tmp/gain 2>/dev/null >/dev/omap_csmi_audio_tes - ;; - "6" ) - echo -n "Echo param (hex): "; read e; - echo "e0x$e" >/tmp/echo; - cat /tmp/echo 2>/dev/null >/dev/omap_csmi_audio_tes - ;; - "7" ) cat /dev/omap_csmi_battery_t;; - "8" ) cat /dev/omap_csmi_htc;; - "0" ) break;; - esac - done - ;; - "4" ) - while true; do - echo - echo "------------------------------" - echo " 1: Toggle debug I/O" - echo " 2: Toggle debug Flow" - echo " 3: Toggle debug Interrupt" - echo " 4: Toggle debug Info" - echo " 5: Toggle GSM run state" - echo " 6: Clear GSM data area" - echo " 0: back" - echo -n ": " - c=`readtty -f -a 1234560#` - echo Got key -$c- - case "$c" in - "1" ) echo -n "i" >/sys/devices/system/omap_csmi/debug;; - "2" ) echo -n "f" >/sys/devices/system/omap_csmi/debug;; - "3" ) echo -n "I" >/sys/devices/system/omap_csmi/debug;; - "4" ) echo -n "F" >/sys/devices/system/omap_csmi/debug;; - "5" ) echo -n "s" >/sys/devices/system/omap_csmi/debug;; - "6" ) echo -n "c" >/sys/devices/system/omap_csmi/debug;; - "0" ) break;; - esac - done - ;; - "5" ) - while true; do - echo - echo "------------------------------" - echo " 1: Start pppd - userspace" - echo " 2: Start pppd - kernel" - echo " 3: Start pppd - kernel <at1" - echo " 4: Configure ppp data to at2" - echo " 5: Test with HTTP GET" - echo " 6: Kill pppd" - echo " 0: back" - echo -n ": " - c=`readtty -f -a 1234560#` - echo Got key -$c- - case "$c" in - "1" ) kill $pppdpid; pppd notty < $pppdev > $pppdev & pppdpid=$!;; - "2" ) kill $pppdpid; pppd nodetach $pppdev & pppdpid=$!;; - "3" ) kill &pppdpid; pppd nodetach $pppdev connect "sh -c \"chat -v -f /etc/ppp/connect-data <$atdev >$atdev\"" & pppdpid=$!;; - "4" ) echo -e 'AT%DATA=2,"UART",1,,"SER","UART",0\r' >$atdev;; - "5" ) test-data-connection;; - "6" ) kill $pppdpid; pppdpid=;; - "0" ) break;; - esac - done - ;; - "6" ) - echo - echo ------------------------ - echo Starting android runtime - echo ------------------------ - start - ;; - "7" ) - echo - echo ------------------------ - echo Starting android runtime - echo ------------------------ - if exists /data/singleproc - then - single_process="-s" - else - single_process="" - fi - start runtime $single_process - ;; - "8" ) - stop - ;; - "9" ) - while true; do - echo - echo "------------------------------" - echo " 1: Print events" - echo " 2: Stop event output" - if $notifytoggle - then - echo " 3: stop notify" - else - echo " 3: notify /sys/android_power" - fi - echo " 4: start powerd" - echo " 5: start powerd verbose" - echo " 6: stop powerd" - echo " 7: set powerd idletime ($powerdidletime)" - echo " 8: start multitap shell" - if exists /data/singleproc - then - echo " 9: enable multiprocess" - else - echo " 9: disable multiprocess" - fi - echo " c: start shell" - echo " 0: back" - echo -n ": " - c=`readtty -f -a 1234567890c#` - echo Got key -$c- - case "$c" in - "1" ) kill $eventoutputpid; getevent & eventoutputpid=$! ;; - "2" ) kill $eventoutputpid; eventoutputpid= ;; - "3" ) - if $notifytoggle - then - kill $notifypid - notifypid= - notifytoggle=false - else - kill $notifypid - notify -m 0x00000002 -c 0 -p -v 0 -w 30 /sys/android_power & - notifypid=$! - notifytoggle=true - fi - ;; - "4" ) start powerd -i $powerdidletime ;; - "5" ) start powerd -i $powerdidletime -v ;; - "6" ) stop powerd ;; - "7" ) echo -n "Idle time (seconds): "; read powerdidletime ;; - "8" ) - readtty -f -p -t 10 -e "[ ~" | sh -i - ;; - "9" ) - if exists /data/singleproc - then - echo "Enabling multiprocess environment." - rm /data/singleproc - else - echo "Disabling multiprocess environment." - echo >/data/singleproc "true" - fi - ;; - "c" ) sh -i <>/dev/tty0 1>&0 2>&1 ;; - "0" ) break;; - esac - done - ;; - esac -done - diff --git a/rootdir/etc/mountd.conf b/rootdir/etc/mountd.conf deleted file mode 100644 index 094a2c7..0000000 --- a/rootdir/etc/mountd.conf +++ /dev/null @@ -1,19 +0,0 @@ -## mountd configuration file - -## add a mount entry for each mount point to be managed by mountd -mount { - ## root block device with partition map or raw FAT file system - block_device /dev/block/mmcblk0 - - ## mount point for block device - mount_point /sdcard - - ## true if this mount point can be shared via USB mass storage - enable_ums true - - ## path to the UMS driver file for specifying the block device path - ## use this for the mass_storage function driver - driver_store_path /sys/devices/platform/usb_mass_storage/lun0/file - ## use this for android_usb composite gadget driver - ##driver_store_path /sys/devices/platform/msm_hsusb/gadget/lun0/file -} diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in index 30bef46..0064790 100644 --- a/rootdir/init.environ.rc.in +++ b/rootdir/init.environ.rc.in @@ -1,6 +1,5 @@ # set up the global environment on init - export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin export ANDROID_BOOTLOGO 1 export ANDROID_ROOT /system export ANDROID_ASSETS /system/app diff --git a/rootdir/init.rc b/rootdir/init.rc index cbcb842..c00c590 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -14,13 +14,6 @@ on early-init # Set init and its forked children's oom_adj. write /proc/1/oom_score_adj -1000 - # Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls. - write /sys/fs/selinux/checkreqprot 0 - - # Set the security context for the init process. - # This should occur before anything else (e.g. ueventd) is started. - setcon u:r:init:s0 - # Set the security context of /adb_keys if present. restorecon /adb_keys @@ -32,14 +25,11 @@ on early-init on init sysclktz 0 - loglevel 3 - - # Backward compatibility + # Backward compatibility. symlink /system/etc /etc symlink /sys/kernel/debug /d - # Right now vendor lives on the same filesystem as system, - # but someday that may change. + # Link /vendor to /system/vendor for devices without a vendor partition. symlink /system/vendor /vendor # Create cgroup mount point for cpu accounting @@ -150,6 +140,11 @@ on init mount pstore pstore /sys/fs/pstore chown system log /sys/fs/pstore/console-ramoops chmod 0440 /sys/fs/pstore/console-ramoops + chown system log /sys/fs/pstore/pmsg-ramoops-0 + chmod 0440 /sys/fs/pstore/pmsg-ramoops-0 + + # enable armv8_deprecated instruction hooks + write /proc/sys/abi/swp 1 # Healthd can trigger a full boot from charger mode by signaling this # property when the power button is held. @@ -160,6 +155,8 @@ on property:sys.boot_from_charger_mode=1 # Load properties from /system/ + /factory after fs mount. on load_all_props_action load_all_props + start logd + start logd-reinit # Indicate to fw loaders that the relevant mounts are up. on firmware_mounts_complete @@ -185,6 +182,7 @@ on late-init on post-fs + start logd # once everything is setup, no need to modify / mount rootfs rootfs / ro remount # mount shared so changes propagate into child namespaces @@ -222,37 +220,29 @@ on post-fs mkdir /cache/lost+found 0770 root root on post-fs-data + installkey /data + # We chown/chmod /data again so because mount is run as root + defaults chown system system /data chmod 0771 /data # We restorecon /data in case the userdata partition has been reset. restorecon /data + # Start bootcharting as soon as possible after the data partition is + # mounted to collect more data. + mkdir /data/bootchart 0755 shell shell + bootchart_init + # Avoid predictable entropy pool. Carry over entropy from previous boot. copy /data/system/entropy.dat /dev/urandom - # Create dump dir and collect dumps. - # Do this before we mount cache so eventually we can use cache for - # storing dumps on platforms which do not have a dedicated dump partition. - mkdir /data/dontpanic 0750 root log - - # Collect apanic data, free resources and re-arm trigger - copy /proc/apanic_console /data/dontpanic/apanic_console - chown root log /data/dontpanic/apanic_console - chmod 0640 /data/dontpanic/apanic_console - - copy /proc/apanic_threads /data/dontpanic/apanic_threads - chown root log /data/dontpanic/apanic_threads - chmod 0640 /data/dontpanic/apanic_threads - - write /proc/apanic_console 1 - # create basic filesystem structure mkdir /data/misc 01771 system misc mkdir /data/misc/adb 02750 system shell mkdir /data/misc/bluedroid 0770 bluetooth net_bt_stack mkdir /data/misc/bluetooth 0770 system system mkdir /data/misc/keystore 0700 keystore keystore + mkdir /data/misc/gatekeeper 0700 system system mkdir /data/misc/keychain 0771 system system mkdir /data/misc/net 0750 root shell mkdir /data/misc/radio 0770 system radio @@ -281,6 +271,7 @@ on post-fs-data mkdir /data/app-lib 0771 system system mkdir /data/app 0771 system system mkdir /data/property 0700 root root + mkdir /data/tombstones 0771 system system # create dalvik-cache, so as to enforce our permissions mkdir /data/dalvik-cache 0771 root root @@ -310,12 +301,24 @@ on post-fs-data # Separate location for storing security policy files on data mkdir /data/security 0711 system system + # Create all remaining /data root dirs so that they are made through init + # and get proper encryption policy installed + mkdir /data/backup 0700 system system + mkdir /data/media 0770 media_rw media_rw + mkdir /data/ss 0700 system system + mkdir /data/system 0775 system system + mkdir /data/system/heapdump 0700 system system + mkdir /data/user 0711 system system + # Reload policy from /data/security if present. setprop selinux.reload_policy 1 # Set SELinux security contexts on upgrade or policy update. restorecon_recursive /data + # Check any timezone data in /data is newer than the copy in /system, delete if not. + exec u:r:tzdatacheck:s0 system system -- /system/bin/tzdatacheck /system/usr/share/zoneinfo /data/misc/zoneinfo + # If there is no fs-post-data action in the init.<device>.rc file, you # must uncomment this line, otherwise encrypted filesystems # won't work. @@ -436,6 +439,8 @@ on property:vold.decrypt=trigger_reset_main on property:vold.decrypt=trigger_load_persist_props load_persist_props + start logd + start logd-reinit on property:vold.decrypt=trigger_post_fs_data trigger post-fs-data @@ -444,6 +449,7 @@ on property:vold.decrypt=trigger_restart_min_framework class_start main on property:vold.decrypt=trigger_restart_framework + installkey /data class_start main class_start late_start @@ -477,7 +483,10 @@ service logd /system/bin/logd socket logd stream 0666 logd logd socket logdr seqpacket 0666 logd logd socket logdw dgram 0222 logd logd - seclabel u:r:logd:s0 + +service logd-reinit /system/bin/logd --reinit + oneshot + disabled service healthd /sbin/healthd class core @@ -591,7 +600,6 @@ service installd /system/bin/installd service flash_recovery /system/bin/install-recovery.sh class main - seclabel u:r:install_recovery:s0 oneshot service racoon /system/bin/racoon diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc index 474f630..9cf9ed9 100644 --- a/rootdir/ueventd.rc +++ b/rootdir/ueventd.rc @@ -16,6 +16,7 @@ subsystem adf # Anyone can read the logs, but if they're not in the "logs" # group, then they'll only see log entries for their UID. /dev/log/* 0666 root log +/dev/pmsg0 0222 root log # the msm hw3d client device node is world writable/readable. /dev/msm_hw3dc 0666 root root diff --git a/run-as/package.c b/run-as/package.c index 4f8f3a7..9e1f5bb 100644 --- a/run-as/package.c +++ b/run-as/package.c @@ -16,9 +16,11 @@ */ #include <errno.h> #include <fcntl.h> -#include <unistd.h> -#include <sys/stat.h> +#include <string.h> #include <sys/mman.h> +#include <sys/stat.h> +#include <unistd.h> + #include <private/android_filesystem_config.h> #include "package.h" diff --git a/run-as/run-as.c b/run-as/run-as.c index cc05e63..368b8f1 100644 --- a/run-as/run-as.c +++ b/run-as/run-as.c @@ -15,22 +15,25 @@ ** limitations under the License. */ -#define PROGNAME "run-as" -#define LOG_TAG PROGNAME +#define PROGNAME "run-as" +#define LOG_TAG PROGNAME +#include <dirent.h> +#include <errno.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/types.h> +#include <sys/capability.h> +#include <sys/cdefs.h> #include <sys/stat.h> -#include <dirent.h> -#include <errno.h> -#include <unistd.h> +#include <sys/types.h> #include <time.h> -#include <stdarg.h> +#include <unistd.h> -#include <selinux/android.h> #include <private/android_filesystem_config.h> +#include <selinux/android.h> + #include "package.h" /* @@ -83,37 +86,37 @@ * - 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 +__noreturn static void panic(const char* format, ...) { va_list args; + int e = errno; fprintf(stderr, "%s: ", PROGNAME); va_start(args, format); vfprintf(stderr, format, args); va_end(args); - exit(1); + exit(e ? -e : 1); } +static void +usage(void) +{ + panic("Usage:\n " PROGNAME " <package-name> <command> [<args>]\n"); +} int main(int argc, char **argv) { const char* pkgname; int myuid, uid, gid; PackageInfo info; + struct __user_cap_header_struct capheader; + struct __user_cap_data_struct capdata[2]; /* check arguments */ - if (argc < 2) + if (argc < 2) { usage(); + } /* check userid of caller - must be 'shell' or 'root' */ myuid = getuid(); @@ -121,29 +124,37 @@ int main(int argc, char **argv) panic("only 'shell' or 'root' users can run this program\n"); } - /* retrieve package information from system */ + memset(&capheader, 0, sizeof(capheader)); + memset(&capdata, 0, sizeof(capdata)); + capheader.version = _LINUX_CAPABILITY_VERSION_3; + capdata[CAP_TO_INDEX(CAP_SETUID)].effective |= CAP_TO_MASK(CAP_SETUID); + capdata[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID); + capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID); + capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID); + + if (capset(&capheader, &capdata[0]) < 0) { + panic("Could not set capabilities: %s\n", strerror(errno)); + } + + /* retrieve package information from system (does setegid) */ 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; } /* Ensure that we change all real/effective/saved IDs at the @@ -152,38 +163,30 @@ int main(int argc, char **argv) uid = gid = info.uid; if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) { panic("Permission denied\n"); - return 1; + } + + /* Required if caller has uid and gid all non-zero */ + memset(&capdata, 0, sizeof(capdata)); + if (capset(&capheader, &capdata[0]) < 0) { + panic("Could not clear all capabilities: %s\n", strerror(errno)); } if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) { - panic("Could not set SELinux security context: %s\n", strerror(errno)); - return 1; + panic("Could not set SELinux security context: %s\n", strerror(errno)); } /* cd into the data directory */ - { - 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; - } + if (TEMP_FAILURE_RETRY(chdir(info.dataDir)) < 0) { + panic("Could not cd to package's data directory: %s\n", strerror(errno)); } /* 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; - } + if ((argc >= 3) && (execvp(argv[2], argv+2) < 0)) { + panic("exec failed for %s: %s\n", argv[2], strerror(errno)); } /* Default exec shell. */ execlp("/system/bin/sh", "sh", NULL); - panic("exec failed\n"); - return 1; + panic("exec failed: %s\n", strerror(errno)); } diff --git a/sdcard/Android.mk b/sdcard/Android.mk index 63b0f41..cb3a8fb 100644 --- a/sdcard/Android.mk +++ b/sdcard/Android.mk @@ -6,6 +6,6 @@ LOCAL_SRC_FILES := sdcard.c LOCAL_MODULE := sdcard LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror -LOCAL_SHARED_LIBRARIES := libc libcutils +LOCAL_SHARED_LIBRARIES := libcutils include $(BUILD_EXECUTABLE) diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index 9cfb040..893c0dc 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -29,6 +29,7 @@ #include <string.h> #include <sys/inotify.h> #include <sys/mount.h> +#include <sys/param.h> #include <sys/resource.h> #include <sys/stat.h> #include <sys/statfs.h> @@ -198,6 +199,8 @@ struct node { * position. Used to support things like OBB. */ char* graft_path; size_t graft_pathlen; + + bool deleted; }; static int str_hash(void *key) { @@ -414,12 +417,12 @@ static void attr_from_stat(struct fuse_attr *attr, const struct stat *s, const s attr->ino = node->ino; attr->size = s->st_size; attr->blocks = s->st_blocks; - attr->atime = s->st_atime; - attr->mtime = s->st_mtime; - attr->ctime = s->st_ctime; - attr->atimensec = s->st_atime_nsec; - attr->mtimensec = s->st_mtime_nsec; - attr->ctimensec = s->st_ctime_nsec; + attr->atime = s->st_atim.tv_sec; + attr->mtime = s->st_mtim.tv_sec; + attr->ctime = s->st_ctim.tv_sec; + attr->atimensec = s->st_atim.tv_nsec; + attr->mtimensec = s->st_mtim.tv_nsec; + attr->ctimensec = s->st_ctim.tv_nsec; attr->mode = s->st_mode; attr->nlink = s->st_nlink; @@ -630,6 +633,8 @@ struct node *create_node_locked(struct fuse* fuse, node->ino = fuse->inode_ctr++; node->gen = fuse->next_generation++; + node->deleted = false; + derive_permissions_locked(fuse, parent, node); acquire_node_locked(node); add_node_to_parent_locked(node, parent); @@ -703,7 +708,7 @@ static struct node *lookup_child_by_name_locked(struct node *node, const char *n * must be considered distinct even if they refer to the same * underlying file as otherwise operations such as "mv x x" * will not work because the source and target nodes are the same. */ - if (!strcmp(name, node->name)) { + if (!strcmp(name, node->name) && !node->deleted) { return node; } } @@ -936,7 +941,9 @@ static int handle_setattr(struct fuse* fuse, struct fuse_handler* handler, if (!node) { return -ENOENT; } - if (!check_caller_access_to_node(fuse, hdr, node, W_OK, has_rw)) { + + if (!(req->valid & FATTR_FH) && + !check_caller_access_to_node(fuse, hdr, node, W_OK, has_rw)) { return -EACCES; } @@ -1067,6 +1074,7 @@ static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler, { bool has_rw; struct node* parent_node; + struct node* child_node; char parent_path[PATH_MAX]; char child_path[PATH_MAX]; @@ -1088,6 +1096,12 @@ static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler, if (unlink(child_path) < 0) { return -errno; } + pthread_mutex_lock(&fuse->lock); + child_node = lookup_child_by_name_locked(parent_node, name); + if (child_node) { + child_node->deleted = true; + } + pthread_mutex_unlock(&fuse->lock); return 0; } @@ -1095,6 +1109,7 @@ static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler, const struct fuse_in_header* hdr, const char* name) { bool has_rw; + struct node* child_node; struct node* parent_node; char parent_path[PATH_MAX]; char child_path[PATH_MAX]; @@ -1117,6 +1132,12 @@ static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler, if (rmdir(child_path) < 0) { return -errno; } + pthread_mutex_lock(&fuse->lock); + child_node = lookup_child_by_name_locked(parent_node, name); + if (child_node) { + child_node->deleted = true; + } + pthread_mutex_unlock(&fuse->lock); return 0; } @@ -1301,6 +1322,7 @@ static int handle_write(struct fuse* fuse, struct fuse_handler* handler, return -errno; } out.size = res; + out.padding = 0; fuse_reply(fuse, hdr->unique, &out, sizeof(out)); return NO_STATUS; } @@ -1460,17 +1482,42 @@ static int handle_init(struct fuse* fuse, struct fuse_handler* handler, const struct fuse_in_header* hdr, const struct fuse_init_in* req) { struct fuse_init_out out; + size_t fuse_struct_size; TRACE("[%d] INIT ver=%d.%d maxread=%d flags=%x\n", handler->token, req->major, req->minor, req->max_readahead, req->flags); + + /* Kernel 2.6.16 is the first stable kernel with struct fuse_init_out + * defined (fuse version 7.6). The structure is the same from 7.6 through + * 7.22. Beginning with 7.23, the structure increased in size and added + * new parameters. + */ + if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) { + ERROR("Fuse kernel version mismatch: Kernel version %d.%d, Expected at least %d.6", + req->major, req->minor, FUSE_KERNEL_VERSION); + return -1; + } + + out.minor = MIN(req->minor, FUSE_KERNEL_MINOR_VERSION); + fuse_struct_size = sizeof(out); +#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE) + /* FUSE_KERNEL_VERSION >= 23. */ + + /* If the kernel only works on minor revs older than or equal to 22, + * then use the older structure size since this code only uses the 7.22 + * version of the structure. */ + if (req->minor <= 22) { + fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE; + } +#endif + out.major = FUSE_KERNEL_VERSION; - out.minor = FUSE_KERNEL_MINOR_VERSION; out.max_readahead = req->max_readahead; out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES; out.max_background = 32; out.congestion_threshold = 32; out.max_write = MAX_WRITE; - fuse_reply(fuse, hdr->unique, &out, sizeof(out)); + fuse_reply(fuse, hdr->unique, &out, fuse_struct_size); return NO_STATUS; } @@ -1828,7 +1875,7 @@ static int run(const char* source_path, const char* dest_path, uid_t uid, struct fuse fuse; /* cleanup from previous instance, if necessary */ - umount2(dest_path, 2); + umount2(dest_path, MNT_DETACH); fd = open("/dev/fuse", O_RDWR); if (fd < 0){ @@ -1840,7 +1887,8 @@ static int run(const char* source_path, const char* dest_path, uid_t uid, "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d", fd, uid, gid); - res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC, opts); + res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC | + MS_NOATIME, opts); if (res < 0) { ERROR("cannot mount fuse filesystem: %s\n", strerror(errno)); goto error; diff --git a/toolbox/Android.mk b/toolbox/Android.mk index 84714cf..ad99a39 100644 --- a/toolbox/Android.mk +++ b/toolbox/Android.mk @@ -9,230 +9,75 @@ common_cflags := \ include $(CLEAR_VARS) -LOCAL_SRC_FILES := upstream-netbsd/bin/cat/cat.c -LOCAL_CFLAGS += $(common_cflags) -Dmain=cat_main -LOCAL_MODULE := libtoolbox_cat -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := upstream-netbsd/sbin/chown/chown.c -LOCAL_CFLAGS += $(common_cflags) -Dmain=chown_main -LOCAL_MODULE := libtoolbox_chown -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := \ - upstream-netbsd/bin/cp/cp.c \ - upstream-netbsd/bin/cp/utils.c -LOCAL_CFLAGS += $(common_cflags) -Dmain=cp_main -LOCAL_MODULE := libtoolbox_cp -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) LOCAL_SRC_FILES := \ upstream-netbsd/bin/dd/args.c \ upstream-netbsd/bin/dd/conv.c \ upstream-netbsd/bin/dd/dd.c \ upstream-netbsd/bin/dd/dd_hostops.c \ upstream-netbsd/bin/dd/misc.c \ - upstream-netbsd/bin/dd/position.c + upstream-netbsd/bin/dd/position.c \ + upstream-netbsd/lib/libc/gen/getbsize.c \ + upstream-netbsd/lib/libc/gen/humanize_number.c \ + upstream-netbsd/lib/libc/stdlib/strsuftoll.c \ + upstream-netbsd/lib/libc/string/swab.c \ + upstream-netbsd/lib/libutil/raise_default_signal.c LOCAL_CFLAGS += $(common_cflags) -Dmain=dd_main -DNO_CONV LOCAL_MODULE := libtoolbox_dd -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_SRC_FILES := upstream-netbsd/usr.bin/du/du.c LOCAL_CFLAGS += $(common_cflags) -Dmain=du_main LOCAL_MODULE := libtoolbox_du -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := \ - upstream-netbsd/usr.bin/grep/fastgrep.c \ - upstream-netbsd/usr.bin/grep/file.c \ - upstream-netbsd/usr.bin/grep/grep.c \ - upstream-netbsd/usr.bin/grep/queue.c \ - upstream-netbsd/usr.bin/grep/util.c -LOCAL_CFLAGS += $(common_cflags) -Dmain=grep_main -LOCAL_MODULE := libtoolbox_grep -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := upstream-netbsd/bin/kill/kill.c -LOCAL_CFLAGS += $(common_cflags) -Dmain=kill_main -LOCAL_MODULE := libtoolbox_kill -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := upstream-netbsd/bin/ln/ln.c -LOCAL_CFLAGS += $(common_cflags) -Dmain=ln_main -LOCAL_MODULE := libtoolbox_ln -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := upstream-netbsd/bin/mv/mv.c -LOCAL_CFLAGS += $(common_cflags) -Dmain=mv_main -D__SVR4 -LOCAL_MODULE := libtoolbox_mv -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := upstream-netbsd/usr.bin/printenv/printenv.c -LOCAL_CFLAGS += $(common_cflags) -Dmain=printenv_main -LOCAL_MODULE := libtoolbox_printenv -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := upstream-netbsd/bin/rm/rm.c -LOCAL_CFLAGS += $(common_cflags) -Dmain=rm_main -LOCAL_MODULE := libtoolbox_rm -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := upstream-netbsd/bin/rmdir/rmdir.c -LOCAL_CFLAGS += $(common_cflags) -Dmain=rmdir_main -LOCAL_MODULE := libtoolbox_rmdir -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := upstream-netbsd/bin/sleep/sleep.c -LOCAL_CFLAGS += $(common_cflags) -Dmain=sleep_main -LOCAL_MODULE := libtoolbox_sleep -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := upstream-netbsd/bin/sync/sync.c -LOCAL_CFLAGS += $(common_cflags) -Dmain=sync_main -LOCAL_MODULE := libtoolbox_sync -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) BSD_TOOLS := \ - cat \ - chown \ - cp \ dd \ du \ - grep \ - kill \ - ln \ - mv \ - printenv \ - rm \ - rmdir \ - sleep \ - sync \ OUR_TOOLS := \ - chcon \ - chmod \ - clear \ - cmp \ - date \ df \ - dmesg \ - getenforce \ getevent \ - getprop \ - getsebool \ - hd \ - id \ - ifconfig \ iftop \ - insmod \ ioctl \ ionice \ - load_policy \ log \ ls \ - lsmod \ lsof \ - md5 \ - mkdir \ - mknod \ - mkswap \ mount \ nandread \ - netstat \ newfs_msdos \ - nohup \ - notify \ ps \ - readlink \ - renice \ - restorecon \ prlimit \ - rmmod \ - route \ - runcon \ - schedtop \ + renice \ sendevent \ - setenforce \ - setprop \ - setsebool \ - smd \ start \ stop \ - swapoff \ - swapon \ top \ - touch \ - umount \ uptime \ - vmstat \ watchprops \ - wipe \ - -ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) -OUR_TOOLS += r -endif ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS) LOCAL_SRC_FILES := \ - upstream-netbsd/lib/libc/gen/getbsize.c \ - upstream-netbsd/lib/libc/gen/humanize_number.c \ - upstream-netbsd/lib/libc/stdlib/strsuftoll.c \ - upstream-netbsd/lib/libc/string/swab.c \ - upstream-netbsd/lib/libutil/raise_default_signal.c \ - dynarray.c \ - pwcache.c \ - $(patsubst %,%.c,$(OUR_TOOLS)) \ toolbox.c \ + $(patsubst %,%.c,$(OUR_TOOLS)) \ LOCAL_CFLAGS += $(common_cflags) -LOCAL_C_INCLUDES += external/openssl/include - LOCAL_SHARED_LIBRARIES := \ - libcrypto \ libcutils \ libselinux \ -# libusbhost is only used by lsusb, and that isn't usually included in toolbox. -# The linker strips out all the unused library code in the normal case. -LOCAL_STATIC_LIBRARIES := \ - libusbhost \ - LOCAL_WHOLE_STATIC_LIBRARIES := $(patsubst %,libtoolbox_%,$(BSD_TOOLS)) LOCAL_MODULE := toolbox -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk + +# Install the symlinks. +LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,$(ALL_TOOLS),ln -sf toolbox $(TARGET_OUT)/bin/$(t);) # Including this will define $(intermediates). # @@ -247,19 +92,33 @@ $(TOOLS_H): $(LOCAL_PATH)/Android.mk $(TOOLS_H): $(transform-generated-source) -# Make #!/system/bin/toolbox launchers for each tool. -# -SYMLINKS := $(addprefix $(TARGET_OUT)/bin/,$(ALL_TOOLS)) -$(SYMLINKS): TOOLBOX_BINARY := $(LOCAL_MODULE) -$(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk - @echo "Symlink: $@ -> $(TOOLBOX_BINARY)" - @mkdir -p $(dir $@) - @rm -rf $@ - $(hide) ln -sf $(TOOLBOX_BINARY) $@ +$(LOCAL_PATH)/getevent.c: $(intermediates)/input.h-labels.h + +INPUT_H_LABELS_H := $(intermediates)/input.h-labels.h +$(INPUT_H_LABELS_H): PRIVATE_LOCAL_PATH := $(LOCAL_PATH) +$(INPUT_H_LABELS_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_LOCAL_PATH)/generate-input.h-labels.py > $@ +$(INPUT_H_LABELS_H): $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/generate-input.h-labels.py +$(INPUT_H_LABELS_H): + $(transform-generated-source) + +# We only want 'r' on userdebug and eng builds. +include $(CLEAR_VARS) +LOCAL_SRC_FILES := r.c +LOCAL_CFLAGS += $(common_cflags) +LOCAL_MODULE := r +LOCAL_MODULE_TAGS := debug +include $(BUILD_EXECUTABLE) -ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS) -# We need this so that the installed files could be picked up based on the -# local module name -ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \ - $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(SYMLINKS) +# We build BSD grep separately, so it can provide egrep and fgrep too. +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + upstream-netbsd/usr.bin/grep/fastgrep.c \ + upstream-netbsd/usr.bin/grep/file.c \ + upstream-netbsd/usr.bin/grep/grep.c \ + upstream-netbsd/usr.bin/grep/queue.c \ + upstream-netbsd/usr.bin/grep/util.c +LOCAL_CFLAGS += $(common_cflags) +LOCAL_MODULE := grep +LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,egrep fgrep,ln -sf grep $(TARGET_OUT)/bin/$(t);) +include $(BUILD_EXECUTABLE) diff --git a/toolbox/alarm.c b/toolbox/alarm.c deleted file mode 100644 index 9bd58aa..0000000 --- a/toolbox/alarm.c +++ /dev/null @@ -1,190 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> -#include <string.h> -#include <errno.h> -#include <time.h> -#include <asm/ioctl.h> -//#include <linux/rtc.h> -#include <linux/android_alarm.h> - -int alarm_main(int argc, char *argv[]) -{ - int c; - int res; - struct tm tm; - time_t t; - struct timespec ts; -// struct rtc_time rtc_time; - char strbuf[26]; - int afd; - int nfd; -// struct timeval timeout = { 0, 0 }; - int wait = 0; - fd_set rfds; - const char wake_lock_id[] = "alarm_test"; - int waitalarmmask = 0; - - int useutc = 0; - android_alarm_type_t alarmtype_low = ANDROID_ALARM_RTC_WAKEUP; - android_alarm_type_t alarmtype_high = ANDROID_ALARM_RTC_WAKEUP; - android_alarm_type_t alarmtype = 0; - - do { - //c = getopt(argc, argv, "uw:"); - c = getopt(argc, argv, "uwat:"); - if (c == EOF) - break; - switch (c) { - case 'u': - useutc = 1; - break; - case 't': - alarmtype_low = alarmtype_high = strtol(optarg, NULL, 0); - break; - case 'a': - alarmtype_low = ANDROID_ALARM_RTC_WAKEUP; - alarmtype_high = ANDROID_ALARM_TYPE_COUNT - 1; - break; - case 'w': - //timeout.tv_sec = strtol(optarg, NULL, 0); - wait = 1; - break; - case '?': - fprintf(stderr, "%s: invalid option -%c\n", - argv[0], optopt); - exit(1); - } - } while (1); - if(optind + 2 < argc) { - fprintf(stderr,"%s [-uwa] [-t type] [seconds]\n", argv[0]); - return 1; - } - - afd = open("/dev/alarm", O_RDWR); - if(afd < 0) { - fprintf(stderr, "Unable to open rtc: %s\n", strerror(errno)); - return 1; - } - - if(optind == argc) { - for(alarmtype = alarmtype_low; alarmtype <= alarmtype_high; alarmtype++) { - waitalarmmask |= 1U << alarmtype; - } -#if 0 - res = ioctl(fd, RTC_ALM_READ, &tm); - if(res < 0) { - fprintf(stderr, "Unable to read alarm: %s\n", strerror(errno)); - return 1; - } -#endif -#if 0 - t = timegm(&tm); - if(useutc) - gmtime_r(&t, &tm); - else - localtime_r(&t, &tm); -#endif -#if 0 - asctime_r(&tm, strbuf); - printf("%s", strbuf); -#endif - } - else if(optind + 1 == argc) { -#if 0 - res = ioctl(fd, RTC_RD_TIME, &tm); - if(res < 0) { - fprintf(stderr, "Unable to set alarm: %s\n", strerror(errno)); - return 1; - } - asctime_r(&tm, strbuf); - printf("Now: %s", strbuf); - time(&tv.tv_sec); -#endif -#if 0 - time(&ts.tv_sec); - ts.tv_nsec = 0; - - //strptime(argv[optind], NULL, &tm); - //tv.tv_sec = mktime(&tm); - //tv.tv_usec = 0; -#endif - for(alarmtype = alarmtype_low; alarmtype <= alarmtype_high; alarmtype++) { - waitalarmmask |= 1U << alarmtype; - res = ioctl(afd, ANDROID_ALARM_GET_TIME(alarmtype), &ts); - if(res < 0) { - fprintf(stderr, "Unable to get current time: %s\n", strerror(errno)); - return 1; - } - ts.tv_sec += strtol(argv[optind], NULL, 0); - //strtotimeval(argv[optind], &tv); - gmtime_r(&ts.tv_sec, &tm); - printf("time %s -> %ld.%09ld\n", argv[optind], ts.tv_sec, ts.tv_nsec); - asctime_r(&tm, strbuf); - printf("Requested %s", strbuf); - - res = ioctl(afd, ANDROID_ALARM_SET(alarmtype), &ts); - if(res < 0) { - fprintf(stderr, "Unable to set alarm: %s\n", strerror(errno)); - return 1; - } - } -#if 0 - res = ioctl(fd, RTC_ALM_SET, &tm); - if(res < 0) { - fprintf(stderr, "Unable to set alarm: %s\n", strerror(errno)); - return 1; - } - res = ioctl(fd, RTC_AIE_ON); - if(res < 0) { - fprintf(stderr, "Unable to enable alarm: %s\n", strerror(errno)); - return 1; - } -#endif - } - else { - fprintf(stderr,"%s [-u] [date]\n", argv[0]); - return 1; - } - - if(wait) { - while(waitalarmmask) { - printf("wait for alarm %x\n", waitalarmmask); - res = ioctl(afd, ANDROID_ALARM_WAIT); - if(res < 0) { - fprintf(stderr, "alarm wait failed\n"); - } - printf("got alarm %x\n", res); - waitalarmmask &= ~res; - nfd = open("/sys/android_power/acquire_full_wake_lock", O_RDWR); - write(nfd, wake_lock_id, sizeof(wake_lock_id) - 1); - close(nfd); - //sleep(5); - nfd = open("/sys/android_power/release_wake_lock", O_RDWR); - write(nfd, wake_lock_id, sizeof(wake_lock_id) - 1); - close(nfd); - } - printf("done\n"); - } -#if 0 - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - res = select(fd + 1, &rfds, NULL, NULL, &timeout); - if(res < 0) { - fprintf(stderr, "select failed: %s\n", strerror(errno)); - return 1; - } - if(res > 0) { - int event; - read(fd, &event, sizeof(event)); - fprintf(stderr, "got %x\n", event); - } - else { - fprintf(stderr, "timeout waiting for alarm\n"); - } -#endif - - close(afd); - - return 0; -} diff --git a/toolbox/bsd-compatibility.h b/toolbox/bsd-compatibility.h index 9c6c34a..434d370 100644 --- a/toolbox/bsd-compatibility.h +++ b/toolbox/bsd-compatibility.h @@ -50,16 +50,8 @@ #define S_ISWHT(x) false -// TODO: should this be in bionic? (glibc does this, even though it's not quite right.) -#define O_RSYNC O_SYNC - __BEGIN_DECLS -/* From NetBSD <grp.h> and <pwd.h>. */ -char* group_from_gid(gid_t gid, int noname); -int uid_from_user(const char* name, uid_t* uid); -char* user_from_uid(uid_t uid, int noname); - /* From NetBSD <stdlib.h>. */ #define HN_DECIMAL 0x01 #define HN_NOSPACE 0x02 diff --git a/toolbox/chcon.c b/toolbox/chcon.c deleted file mode 100644 index d594b9b..0000000 --- a/toolbox/chcon.c +++ /dev/null @@ -1,25 +0,0 @@ -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <selinux/selinux.h> - -int chcon_main(int argc, char **argv) -{ - int rc, i; - - if (argc < 3) { - fprintf(stderr, "usage: %s context path...\n", argv[0]); - exit(1); - } - - for (i = 2; i < argc; i++) { - rc = setfilecon(argv[i], argv[1]); - if (rc < 0) { - fprintf(stderr, "%s: Could not label %s with %s: %s\n", - argv[0], argv[i], argv[1], strerror(errno)); - exit(2); - } - } - exit(0); -} diff --git a/toolbox/chmod.c b/toolbox/chmod.c deleted file mode 100644 index 2a524e9..0000000 --- a/toolbox/chmod.c +++ /dev/null @@ -1,101 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <dirent.h> -#include <errno.h> -#include <sys/limits.h> -#include <sys/stat.h> - -#include <unistd.h> -#include <time.h> - -void recurse_chmod(char* path, int mode) -{ - struct dirent *dp; - DIR *dir = opendir(path); - if (dir == NULL) { - // not a directory, carry on - return; - } - char *subpath = malloc(sizeof(char)*PATH_MAX); - int pathlen = strlen(path); - - while ((dp = readdir(dir)) != NULL) { - if (strcmp(dp->d_name, ".") == 0 || - strcmp(dp->d_name, "..") == 0) continue; - - if (strlen(dp->d_name) + pathlen + 2/*NUL and slash*/ > PATH_MAX) { - fprintf(stderr, "Invalid path specified: too long\n"); - exit(1); - } - - strcpy(subpath, path); - strcat(subpath, "/"); - strcat(subpath, dp->d_name); - - if (chmod(subpath, mode) < 0) { - fprintf(stderr, "Unable to chmod %s: %s\n", subpath, strerror(errno)); - exit(1); - } - - recurse_chmod(subpath, mode); - } - free(subpath); - closedir(dir); -} - -static int usage() -{ - fprintf(stderr, "Usage: chmod [OPTION] <MODE> <FILE>\n"); - fprintf(stderr, " -R, --recursive change files and directories recursively\n"); - fprintf(stderr, " --help display this help and exit\n"); - - return 10; -} - -int chmod_main(int argc, char **argv) -{ - int i; - - if (argc < 3 || strcmp(argv[1], "--help") == 0) { - return usage(); - } - - int recursive = (strcmp(argv[1], "-R") == 0 || - strcmp(argv[1], "--recursive") == 0) ? 1 : 0; - - if (recursive && argc < 4) { - return usage(); - } - - if (recursive) { - argc--; - argv++; - } - - int mode = 0; - const char* s = argv[1]; - while (*s) { - if (*s >= '0' && *s <= '7') { - mode = (mode<<3) | (*s-'0'); - } - else { - fprintf(stderr, "Bad mode\n"); - return 10; - } - s++; - } - - for (i = 2; i < argc; i++) { - if (chmod(argv[i], mode) < 0) { - fprintf(stderr, "Unable to chmod %s: %s\n", argv[i], strerror(errno)); - return 10; - } - if (recursive) { - recurse_chmod(argv[i], mode); - } - } - return 0; -} - diff --git a/toolbox/clear.c b/toolbox/clear.c deleted file mode 100644 index df46ad2..0000000 --- a/toolbox/clear.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2012, The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <stdio.h> - -int clear_main(int argc, char **argv) { - /* This prints the clear screen and move cursor to top-left corner control - * characters for VT100 terminals. This means it will not work on - * non-VT100 compliant terminals, namely Windows' cmd.exe, but should - * work on anything unix-y. */ - fputs("\x1b[2J\x1b[H", stdout); - return 0; -} diff --git a/toolbox/cmp.c b/toolbox/cmp.c deleted file mode 100644 index 80635ad..0000000 --- a/toolbox/cmp.c +++ /dev/null @@ -1,91 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdint.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <errno.h> - -int cmp_main(int argc, char *argv[]) -{ - int c; - int fd1, fd2; - char buf1[4096], buf2[4096]; - int res, res1, res2; - int rv = 0; - int i; - int filepos = 0; - - int show_byte = 0; - int show_all = 0; - int limit = 0; - - do { - c = getopt(argc, argv, "bln:"); - if (c == EOF) - break; - switch (c) { - case 'b': - show_byte = 1; - break; - case 'l': - show_all = 1; - break; - case 'n': - limit = atoi(optarg); - break; - case '?': - fprintf(stderr, "%s: invalid option -%c\n", - argv[0], optopt); - exit(1); - } - } while (1); - - if (optind + 2 != argc) { - fprintf(stderr, "Usage: %s [-b] [-l] [-n count] file1 file2\n", argv[0]); - exit(1); - } - - fd1 = open(argv[optind], O_RDONLY); - if(fd1 < 0) { - fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno)); - return 1; - } - - fd2 = open(argv[optind+1], O_RDONLY); - if(fd2 < 0) { - fprintf(stderr, "could not open %s, %s\n", argv[optind+1], strerror(errno)); - return 1; - } - - while(1) { - res1 = read(fd1, &buf1, sizeof(buf1)); - res2 = read(fd2, &buf2, sizeof(buf2)); - res = res1 < res2 ? res1 : res2; - if(res1 == 0 && res2 == 0) { - return rv; - } - for(i = 0; i < res; i++) { - if(buf1[i] != buf2[i]) { - printf("%s %s differ byte %d", argv[optind], argv[optind+1], filepos + i); - if(show_byte) - printf(" 0x%02x 0x%02x", buf1[i], buf2[i]); - printf("\n"); - if(!show_all) - return 1; - rv = 1; - } - if(limit) { - limit--; - if(limit == 0) - return rv; - } - } - if(res1 != res2 || res < 0) { - printf("%s on %s\n", res < 0 ? "Read error" : "EOF", res1 < res2 ? argv[optind] : argv[optind+1]); - return 1; - } - filepos += res; - } -} diff --git a/toolbox/date.c b/toolbox/date.c deleted file mode 100644 index 70ce1d5..0000000 --- a/toolbox/date.c +++ /dev/null @@ -1,227 +0,0 @@ -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> - -#include <linux/android_alarm.h> -#include <linux/rtc.h> -#include <sys/ioctl.h> - -static int settime_alarm(struct timespec *ts) { - int fd, ret; - - fd = open("/dev/alarm", O_RDWR); - if (fd < 0) - return fd; - - ret = ioctl(fd, ANDROID_ALARM_SET_RTC, ts); - close(fd); - return ret; -} - -static int settime_alarm_tm(struct tm *tm) { - time_t t; - struct timespec ts; - - t = mktime(tm); - ts.tv_sec = t; - ts.tv_nsec = 0; - return settime_alarm(&ts); -} - -static int settime_alarm_timeval(struct timeval *tv) { - struct timespec ts; - - ts.tv_sec = tv->tv_sec; - ts.tv_nsec = tv->tv_usec * 1000; - return settime_alarm(&ts); -} - -static int settime_rtc_tm(struct tm *tm) { - int fd, ret; - struct timeval tv; - struct rtc_time rtc; - - fd = open("/dev/rtc0", O_RDWR); - if (fd < 0) - return fd; - - tv.tv_sec = mktime(tm); - tv.tv_usec = 0; - - ret = settimeofday(&tv, NULL); - if (ret < 0) - goto done; - - memset(&rtc, 0, sizeof(rtc)); - rtc.tm_sec = tm->tm_sec; - rtc.tm_min = tm->tm_min; - rtc.tm_hour = tm->tm_hour; - rtc.tm_mday = tm->tm_mday; - rtc.tm_mon = tm->tm_mon; - rtc.tm_year = tm->tm_year; - rtc.tm_wday = tm->tm_wday; - rtc.tm_yday = tm->tm_yday; - rtc.tm_isdst = tm->tm_isdst; - - ret = ioctl(fd, RTC_SET_TIME, rtc); -done: - close(fd); - return ret; -} - -static int settime_rtc_timeval(struct timeval *tv) { - struct tm tm, *err; - time_t t = tv->tv_sec; - - err = gmtime_r(&t, &tm); - if (!err) - return -1; - - return settime_rtc_tm(&tm); -} - -static void settime(char *s) { - struct tm tm; - int day = atoi(s); - int hour; - - while (*s && *s != '.') - s++; - - if (*s) - s++; - - hour = atoi(s); - - tm.tm_year = day / 10000 - 1900; - tm.tm_mon = (day % 10000) / 100 - 1; - tm.tm_mday = (day % 100); - tm.tm_hour = hour / 10000; - tm.tm_min = (hour % 10000) / 100; - tm.tm_sec = (hour % 100); - tm.tm_isdst = -1; - - if (settime_alarm_tm(&tm) < 0) - settime_rtc_tm(&tm); -} - -static char *parse_time(const char *str, struct timeval *ts) { - char *s; - long fs = 0; /* fractional seconds */ - - ts->tv_sec = strtoumax(str, &s, 10); - - if (*s == '.') { - s++; - int count = 0; - - /* read up to 6 digits (microseconds) */ - while (*s && isdigit(*s)) { - if (++count < 7) { - fs = fs*10 + (*s - '0'); - } - s++; - } - - for (; count < 6; count++) { - fs *= 10; - } - } - - ts->tv_usec = fs; - return s; -} - -int date_main(int argc, char *argv[]) -{ - int c; - int res; - struct tm tm; - time_t t; - struct timeval tv; - char strbuf[260]; - - int useutc = 0; - - tzset(); - - do { - c = getopt(argc, argv, "us:"); - if (c == EOF) - break; - switch (c) { - case 'u': - useutc = 1; - break; - case 's': - settime(optarg); - break; - case '?': - fprintf(stderr, "%s: invalid option -%c\n", - argv[0], optopt); - exit(1); - } - } while (1); - if(optind + 2 < argc) { - fprintf(stderr,"%s [-u] [date]\n", argv[0]); - return 1; - } - - int hasfmt = argc == optind + 1 && argv[optind][0] == '+'; - if(optind == argc || hasfmt) { - time(&t); - if (useutc) { - gmtime_r(&t, &tm); - strftime(strbuf, sizeof(strbuf), - (hasfmt ? argv[optind] + 1 : "%a %b %e %H:%M:%S GMT %Y"), - &tm); - } else { - localtime_r(&t, &tm); - strftime(strbuf, sizeof(strbuf), - (hasfmt ? argv[optind] + 1 : "%a %b %e %H:%M:%S %Z %Y"), - &tm); - } - printf("%s\n", strbuf); - } - else if(optind + 1 == argc) { -#if 0 - struct tm *tmptr; - tmptr = getdate(argv[optind]); - if(tmptr == NULL) { - fprintf(stderr,"getdate_r failed\n"); - return 1; - } - tm = *tmptr; -#if 0 - if(getdate_r(argv[optind], &tm) < 0) { - fprintf(stderr,"getdate_r failed %s\n", strerror(errno)); - return 1; - } -#endif -#endif - //strptime(argv[optind], NULL, &tm); - //tv.tv_sec = mktime(&tm); - //tv.tv_usec = 0; - parse_time(argv[optind], &tv); - printf("time %s -> %lu.%lu\n", argv[optind], tv.tv_sec, tv.tv_usec); - res = settime_alarm_timeval(&tv); - if (res < 0) - res = settime_rtc_timeval(&tv); - if(res < 0) { - fprintf(stderr,"settimeofday failed %s\n", strerror(errno)); - return 1; - } - } - else { - fprintf(stderr,"%s [-s 20070325.123456] [-u] [date]\n", argv[0]); - return 1; - } - - return 0; -} diff --git a/toolbox/dmesg.c b/toolbox/dmesg.c deleted file mode 100644 index 9c73b00..0000000 --- a/toolbox/dmesg.c +++ /dev/null @@ -1,58 +0,0 @@ -#include <stdlib.h> -#include <unistd.h> -#include <stdio.h> -#include <errno.h> -#include <sys/klog.h> -#include <string.h> - -#define FALLBACK_KLOG_BUF_SHIFT 17 /* CONFIG_LOG_BUF_SHIFT from our kernel */ -#define FALLBACK_KLOG_BUF_LEN (1 << FALLBACK_KLOG_BUF_SHIFT) - -int dmesg_main(int argc, char **argv) -{ - char *buffer; - char *p; - ssize_t ret; - int n, op, klog_buf_len; - - klog_buf_len = klogctl(KLOG_SIZE_BUFFER, 0, 0); - - if (klog_buf_len <= 0) { - klog_buf_len = FALLBACK_KLOG_BUF_LEN; - } - - buffer = (char *)malloc(klog_buf_len + 1); - - if (!buffer) { - perror("malloc"); - return EXIT_FAILURE; - } - - p = buffer; - - if((argc == 2) && (!strcmp(argv[1],"-c"))) { - op = KLOG_READ_CLEAR; - } else { - op = KLOG_READ_ALL; - } - - n = klogctl(op, buffer, klog_buf_len); - if (n < 0) { - perror("klogctl"); - return EXIT_FAILURE; - } - buffer[n] = '\0'; - - while((ret = write(STDOUT_FILENO, p, n))) { - if (ret == -1) { - if (errno == EINTR) - continue; - perror("write"); - return EXIT_FAILURE; - } - p += ret; - n -= ret; - } - - return 0; -} diff --git a/toolbox/dynarray.c b/toolbox/dynarray.c deleted file mode 100644 index e9b7b03..0000000 --- a/toolbox/dynarray.c +++ /dev/null @@ -1,103 +0,0 @@ -#include "dynarray.h" -#include <stdlib.h> -#include <limits.h> - -void -dynarray_init( dynarray_t *a ) -{ - a->count = a->capacity = 0; - a->items = NULL; -} - - -static void -dynarray_reserve_more( dynarray_t *a, int count ) -{ - int old_cap = a->capacity; - int new_cap = old_cap; - const int max_cap = INT_MAX/sizeof(void*); - void** new_items; - int new_count = a->count + count; - - if (count <= 0) - return; - - if (count > max_cap - a->count) - abort(); - - new_count = a->count + count; - - while (new_cap < new_count) { - old_cap = new_cap; - new_cap += (new_cap >> 2) + 4; - if (new_cap < old_cap || new_cap > max_cap) { - new_cap = max_cap; - } - } - new_items = realloc(a->items, new_cap*sizeof(void*)); - if (new_items == NULL) - abort(); - - a->items = new_items; - a->capacity = new_cap; -} - -void -dynarray_append( dynarray_t *a, void* item ) -{ - if (a->count >= a->capacity) - dynarray_reserve_more(a, 1); - - a->items[a->count++] = item; -} - -void -dynarray_done( dynarray_t *a ) -{ - free(a->items); - a->items = NULL; - a->count = a->capacity = 0; -} - -// string arrays - -void strlist_init( strlist_t *list ) -{ - dynarray_init(list); -} - -void strlist_append_b( strlist_t *list, const void* str, size_t slen ) -{ - char *copy = malloc(slen+1); - memcpy(copy, str, slen); - copy[slen] = '\0'; - dynarray_append(list, copy); -} - -void strlist_append_dup( strlist_t *list, const char *str) -{ - strlist_append_b(list, str, strlen(str)); -} - -void strlist_done( strlist_t *list ) -{ - STRLIST_FOREACH(list, string, free(string)); - dynarray_done(list); -} - -static int strlist_compare_strings(const void* a, const void* b) -{ - const char *sa = *(const char **)a; - const char *sb = *(const char **)b; - return strcmp(sa, sb); -} - -void strlist_sort( strlist_t *list ) -{ - if (list->count > 0) { - qsort(list->items, - (size_t)list->count, - sizeof(void*), - strlist_compare_strings); - } -} diff --git a/toolbox/dynarray.h b/toolbox/dynarray.h deleted file mode 100644 index f73fb3b..0000000 --- a/toolbox/dynarray.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef DYNARRAY_H -#define DYNARRAY_H - -#include <stddef.h> - -/* simple dynamic array of pointers */ -typedef struct { - int count; - int capacity; - void** items; -} dynarray_t; - -#define DYNARRAY_INITIALIZER { 0, 0, NULL } - -void dynarray_init( dynarray_t *a ); -void dynarray_done( dynarray_t *a ); - -void dynarray_append( dynarray_t *a, void* item ); - -/* Used to iterate over a dynarray_t - * _array :: pointer to the array - * _item_type :: type of objects pointed to by the array - * _item :: name of a local variable defined within the loop - * with type '_item_type' - * _stmnt :: C statement that will be executed in each iteration. - * - * You case use 'break' and 'continue' within _stmnt - * - * This macro is only intended for simple uses. I.e. do not add or - * remove items from the array during iteration. - */ -#define DYNARRAY_FOREACH_TYPE(_array,_item_type,_item,_stmnt) \ - do { \ - int _nn_##__LINE__ = 0; \ - for (;_nn_##__LINE__ < (_array)->count; ++ _nn_##__LINE__) { \ - _item_type _item = (_item_type)(_array)->items[_nn_##__LINE__]; \ - _stmnt; \ - } \ - } while (0) - -#define DYNARRAY_FOREACH(_array,_item,_stmnt) \ - DYNARRAY_FOREACH_TYPE(_array,void *,_item,_stmnt) - -/* Simple dynamic string arrays - * - * NOTE: A strlist_t owns the strings it references. - */ -typedef dynarray_t strlist_t; - -#define STRLIST_INITIALIZER DYNARRAY_INITIALIZER - -/* Used to iterate over a strlist_t - * _list :: pointer to strlist_t object - * _string :: name of local variable name defined within the loop with - * type 'char*' - * _stmnt :: C statement executed in each iteration - * - * This macro is only intended for simple uses. Do not add or remove items - * to/from the list during iteration. - */ -#define STRLIST_FOREACH(_list,_string,_stmnt) \ - DYNARRAY_FOREACH_TYPE(_list,char *,_string,_stmnt) - -void strlist_init( strlist_t *list ); - -/* note: strlist_done will free all the strings owned by the list */ -void strlist_done( strlist_t *list ); - -/* append a new string made of the first 'slen' characters from 'str' - * followed by a trailing zero. - */ -void strlist_append_b( strlist_t *list, const void* str, size_t slen ); - -/* append the copy of a given input string to a strlist_t */ -void strlist_append_dup( strlist_t *list, const char *str); - -/* sort the strings in a given list (using strcmp) */ -void strlist_sort( strlist_t *list ); - -#endif /* DYNARRAY_H */
\ No newline at end of file diff --git a/toolbox/exists.c b/toolbox/exists.c deleted file mode 100644 index e348668..0000000 --- a/toolbox/exists.c +++ /dev/null @@ -1,16 +0,0 @@ -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> - -int exists_main(int argc, char *argv[]) -{ - struct stat s; - - if(argc < 2) return 1; - - if(stat(argv[1], &s)) { - return 1; - } else { - return 0; - } -} diff --git a/toolbox/generate-input.h-labels.py b/toolbox/generate-input.h-labels.py new file mode 100755 index 0000000..ebb9588 --- /dev/null +++ b/toolbox/generate-input.h-labels.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +# +# Copyright (C) 2015 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. +# +# pylint: disable=bad-indentation,bad-continuation + +import os +import re + +input_prop_list = [] +ev_list = [] +syn_list = [] +key_list = [] +rel_list = [] +abs_list = [] +sw_list = [] +msc_list = [] +led_list = [] +rep_list = [] +snd_list = [] +mt_tool_list = [] +ff_status_list = [] +ff_list = [] + +r = re.compile(r'#define\s+(\S+)\s+((?:0x)?\d+)') + +with open('bionic/libc/kernel/uapi/linux/input.h', 'r') as f: + for line in f: + m = r.match(line) + if m: + name = m.group(1) + if name.startswith("INPUT_PROP_"): + input_prop_list.append(name) + elif name.startswith("EV_"): + ev_list.append(name) + elif name.startswith("SYN_"): + syn_list.append(name) + elif name.startswith("KEY_") or name.startswith("BTN_"): + key_list.append(name) + elif name.startswith("REL_"): + rel_list.append(name) + elif name.startswith("ABS_"): + abs_list.append(name) + elif name.startswith("SW_"): + sw_list.append(name) + elif name.startswith("MSC_"): + msc_list.append(name) + elif name.startswith("LED_"): + led_list.append(name) + elif name.startswith("REP_"): + rep_list.append(name) + elif name.startswith("SND_"): + snd_list.append(name) + elif name.startswith("MT_TOOL_"): + mt_tool_list.append(name) + elif name.startswith("FF_STATUS_"): + ff_status_list.append(name) + elif name.startswith("FF_"): + ff_list.append(name) + +def Dump(struct_name, values): + print 'static struct label %s[] = {' % (struct_name) + for value in values: + print ' LABEL(%s),' % (value) + print ' LABEL_END,' + print '};' + +Dump("input_prop_labels", input_prop_list) +Dump("ev_labels", ev_list) +Dump("syn_labels", syn_list) +Dump("key_labels", key_list) +Dump("rel_labels", rel_list) +Dump("abs_labels", abs_list) +Dump("sw_labels", sw_list) +Dump("msc_labels", msc_list) +Dump("led_labels", led_list) +Dump("rep_labels", rep_list) +Dump("snd_labels", snd_list) +Dump("mt_tool_labels", mt_tool_list) +Dump("ff_status_labels", ff_status_list) +Dump("ff_labels", ff_list) diff --git a/toolbox/getenforce.c b/toolbox/getenforce.c deleted file mode 100644 index 9e7589a..0000000 --- a/toolbox/getenforce.c +++ /dev/null @@ -1,30 +0,0 @@ -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <selinux/selinux.h> - -int getenforce_main(int argc, char **argv) -{ - int rc; - - rc = is_selinux_enabled(); - if (rc <= 0) { - printf("Disabled\n"); - return 0; - } - - rc = security_getenforce(); - if (rc < 0) { - fprintf(stderr, "Could not get enforcing status: %s\n", - strerror(errno)); - return 2; - } - - if (rc) - printf("Enforcing\n"); - else - printf("Permissive\n"); - - return 0; -} diff --git a/toolbox/getevent.c b/toolbox/getevent.c index da83ec3..30053af 100644 --- a/toolbox/getevent.c +++ b/toolbox/getevent.c @@ -10,8 +10,27 @@ #include <sys/poll.h> #include <linux/input.h> #include <errno.h> +#include <unistd.h> -#include "getevent.h" +struct label { + const char *name; + int value; +}; + +#define LABEL(constant) { #constant, constant } +#define LABEL_END { NULL, -1 } + +static struct label key_value_labels[] = { + { "UP", 0 }, + { "DOWN", 1 }, + { "REPEAT", 2 }, + LABEL_END, +}; + +#include "input.h-labels.h" + +#undef LABEL +#undef LABEL_END static struct pollfd *ufds; static char **device_names; diff --git a/toolbox/getevent.h b/toolbox/getevent.h deleted file mode 100644 index 0482d04..0000000 --- a/toolbox/getevent.h +++ /dev/null @@ -1,727 +0,0 @@ -#include <linux/input.h> - -struct label { - const char *name; - int value; -}; - -#define LABEL(constant) { #constant, constant } -#define LABEL_END { NULL, -1 } - -static struct label input_prop_labels[] = { - LABEL(INPUT_PROP_POINTER), - LABEL(INPUT_PROP_DIRECT), - LABEL(INPUT_PROP_BUTTONPAD), - LABEL(INPUT_PROP_SEMI_MT), - LABEL_END, -}; - -static struct label ev_labels[] = { - LABEL(EV_SYN), - LABEL(EV_KEY), - LABEL(EV_REL), - LABEL(EV_ABS), - LABEL(EV_MSC), - LABEL(EV_SW), - LABEL(EV_LED), - LABEL(EV_SND), - LABEL(EV_REP), - LABEL(EV_FF), - LABEL(EV_PWR), - LABEL(EV_FF_STATUS), - LABEL_END, -}; - -static struct label syn_labels[] = { - LABEL(SYN_REPORT), - LABEL(SYN_CONFIG), - LABEL(SYN_MT_REPORT), - LABEL(SYN_DROPPED), - LABEL_END, -}; - -static struct label key_labels[] = { - LABEL(KEY_RESERVED), - LABEL(KEY_ESC), - LABEL(KEY_1), - LABEL(KEY_2), - LABEL(KEY_3), - LABEL(KEY_4), - LABEL(KEY_5), - LABEL(KEY_6), - LABEL(KEY_7), - LABEL(KEY_8), - LABEL(KEY_9), - LABEL(KEY_0), - LABEL(KEY_MINUS), - LABEL(KEY_EQUAL), - LABEL(KEY_BACKSPACE), - LABEL(KEY_TAB), - LABEL(KEY_Q), - LABEL(KEY_W), - LABEL(KEY_E), - LABEL(KEY_R), - LABEL(KEY_T), - LABEL(KEY_Y), - LABEL(KEY_U), - LABEL(KEY_I), - LABEL(KEY_O), - LABEL(KEY_P), - LABEL(KEY_LEFTBRACE), - LABEL(KEY_RIGHTBRACE), - LABEL(KEY_ENTER), - LABEL(KEY_LEFTCTRL), - LABEL(KEY_A), - LABEL(KEY_S), - LABEL(KEY_D), - LABEL(KEY_F), - LABEL(KEY_G), - LABEL(KEY_H), - LABEL(KEY_J), - LABEL(KEY_K), - LABEL(KEY_L), - LABEL(KEY_SEMICOLON), - LABEL(KEY_APOSTROPHE), - LABEL(KEY_GRAVE), - LABEL(KEY_LEFTSHIFT), - LABEL(KEY_BACKSLASH), - LABEL(KEY_Z), - LABEL(KEY_X), - LABEL(KEY_C), - LABEL(KEY_V), - LABEL(KEY_B), - LABEL(KEY_N), - LABEL(KEY_M), - LABEL(KEY_COMMA), - LABEL(KEY_DOT), - LABEL(KEY_SLASH), - LABEL(KEY_RIGHTSHIFT), - LABEL(KEY_KPASTERISK), - LABEL(KEY_LEFTALT), - LABEL(KEY_SPACE), - LABEL(KEY_CAPSLOCK), - LABEL(KEY_F1), - LABEL(KEY_F2), - LABEL(KEY_F3), - LABEL(KEY_F4), - LABEL(KEY_F5), - LABEL(KEY_F6), - LABEL(KEY_F7), - LABEL(KEY_F8), - LABEL(KEY_F9), - LABEL(KEY_F10), - LABEL(KEY_NUMLOCK), - LABEL(KEY_SCROLLLOCK), - LABEL(KEY_KP7), - LABEL(KEY_KP8), - LABEL(KEY_KP9), - LABEL(KEY_KPMINUS), - LABEL(KEY_KP4), - LABEL(KEY_KP5), - LABEL(KEY_KP6), - LABEL(KEY_KPPLUS), - LABEL(KEY_KP1), - LABEL(KEY_KP2), - LABEL(KEY_KP3), - LABEL(KEY_KP0), - LABEL(KEY_KPDOT), - LABEL(KEY_ZENKAKUHANKAKU), - LABEL(KEY_102ND), - LABEL(KEY_F11), - LABEL(KEY_F12), - LABEL(KEY_RO), - LABEL(KEY_KATAKANA), - LABEL(KEY_HIRAGANA), - LABEL(KEY_HENKAN), - LABEL(KEY_KATAKANAHIRAGANA), - LABEL(KEY_MUHENKAN), - LABEL(KEY_KPJPCOMMA), - LABEL(KEY_KPENTER), - LABEL(KEY_RIGHTCTRL), - LABEL(KEY_KPSLASH), - LABEL(KEY_SYSRQ), - LABEL(KEY_RIGHTALT), - LABEL(KEY_LINEFEED), - LABEL(KEY_HOME), - LABEL(KEY_UP), - LABEL(KEY_PAGEUP), - LABEL(KEY_LEFT), - LABEL(KEY_RIGHT), - LABEL(KEY_END), - LABEL(KEY_DOWN), - LABEL(KEY_PAGEDOWN), - LABEL(KEY_INSERT), - LABEL(KEY_DELETE), - LABEL(KEY_MACRO), - LABEL(KEY_MUTE), - LABEL(KEY_VOLUMEDOWN), - LABEL(KEY_VOLUMEUP), - LABEL(KEY_POWER), - LABEL(KEY_KPEQUAL), - LABEL(KEY_KPPLUSMINUS), - LABEL(KEY_PAUSE), - LABEL(KEY_SCALE), - LABEL(KEY_KPCOMMA), - LABEL(KEY_HANGEUL), - LABEL(KEY_HANGUEL), - LABEL(KEY_HANJA), - LABEL(KEY_YEN), - LABEL(KEY_LEFTMETA), - LABEL(KEY_RIGHTMETA), - LABEL(KEY_COMPOSE), - LABEL(KEY_STOP), - LABEL(KEY_AGAIN), - LABEL(KEY_PROPS), - LABEL(KEY_UNDO), - LABEL(KEY_FRONT), - LABEL(KEY_COPY), - LABEL(KEY_OPEN), - LABEL(KEY_PASTE), - LABEL(KEY_FIND), - LABEL(KEY_CUT), - LABEL(KEY_HELP), - LABEL(KEY_MENU), - LABEL(KEY_CALC), - LABEL(KEY_SETUP), - LABEL(KEY_SLEEP), - LABEL(KEY_WAKEUP), - LABEL(KEY_FILE), - LABEL(KEY_SENDFILE), - LABEL(KEY_DELETEFILE), - LABEL(KEY_XFER), - LABEL(KEY_PROG1), - LABEL(KEY_PROG2), - LABEL(KEY_WWW), - LABEL(KEY_MSDOS), - LABEL(KEY_COFFEE), - LABEL(KEY_SCREENLOCK), - LABEL(KEY_DIRECTION), - LABEL(KEY_CYCLEWINDOWS), - LABEL(KEY_MAIL), - LABEL(KEY_BOOKMARKS), - LABEL(KEY_COMPUTER), - LABEL(KEY_BACK), - LABEL(KEY_FORWARD), - LABEL(KEY_CLOSECD), - LABEL(KEY_EJECTCD), - LABEL(KEY_EJECTCLOSECD), - LABEL(KEY_NEXTSONG), - LABEL(KEY_PLAYPAUSE), - LABEL(KEY_PREVIOUSSONG), - LABEL(KEY_STOPCD), - LABEL(KEY_RECORD), - LABEL(KEY_REWIND), - LABEL(KEY_PHONE), - LABEL(KEY_ISO), - LABEL(KEY_CONFIG), - LABEL(KEY_HOMEPAGE), - LABEL(KEY_REFRESH), - LABEL(KEY_EXIT), - LABEL(KEY_MOVE), - LABEL(KEY_EDIT), - LABEL(KEY_SCROLLUP), - LABEL(KEY_SCROLLDOWN), - LABEL(KEY_KPLEFTPAREN), - LABEL(KEY_KPRIGHTPAREN), - LABEL(KEY_NEW), - LABEL(KEY_REDO), - LABEL(KEY_F13), - LABEL(KEY_F14), - LABEL(KEY_F15), - LABEL(KEY_F16), - LABEL(KEY_F17), - LABEL(KEY_F18), - LABEL(KEY_F19), - LABEL(KEY_F20), - LABEL(KEY_F21), - LABEL(KEY_F22), - LABEL(KEY_F23), - LABEL(KEY_F24), - LABEL(KEY_PLAYCD), - LABEL(KEY_PAUSECD), - LABEL(KEY_PROG3), - LABEL(KEY_PROG4), - LABEL(KEY_DASHBOARD), - LABEL(KEY_SUSPEND), - LABEL(KEY_CLOSE), - LABEL(KEY_PLAY), - LABEL(KEY_FASTFORWARD), - LABEL(KEY_BASSBOOST), - LABEL(KEY_PRINT), - LABEL(KEY_HP), - LABEL(KEY_CAMERA), - LABEL(KEY_SOUND), - LABEL(KEY_QUESTION), - LABEL(KEY_EMAIL), - LABEL(KEY_CHAT), - LABEL(KEY_SEARCH), - LABEL(KEY_CONNECT), - LABEL(KEY_FINANCE), - LABEL(KEY_SPORT), - LABEL(KEY_SHOP), - LABEL(KEY_ALTERASE), - LABEL(KEY_CANCEL), - LABEL(KEY_BRIGHTNESSDOWN), - LABEL(KEY_BRIGHTNESSUP), - LABEL(KEY_MEDIA), - LABEL(KEY_SWITCHVIDEOMODE), - LABEL(KEY_KBDILLUMTOGGLE), - LABEL(KEY_KBDILLUMDOWN), - LABEL(KEY_KBDILLUMUP), - LABEL(KEY_SEND), - LABEL(KEY_REPLY), - LABEL(KEY_FORWARDMAIL), - LABEL(KEY_SAVE), - LABEL(KEY_DOCUMENTS), - LABEL(KEY_BATTERY), - LABEL(KEY_BLUETOOTH), - LABEL(KEY_WLAN), - LABEL(KEY_UWB), - LABEL(KEY_UNKNOWN), - LABEL(KEY_VIDEO_NEXT), - LABEL(KEY_VIDEO_PREV), - LABEL(KEY_BRIGHTNESS_CYCLE), - LABEL(KEY_BRIGHTNESS_ZERO), - LABEL(KEY_DISPLAY_OFF), - LABEL(KEY_WIMAX), - LABEL(KEY_RFKILL), - LABEL(BTN_0), - LABEL(BTN_1), - LABEL(BTN_2), - LABEL(BTN_3), - LABEL(BTN_4), - LABEL(BTN_5), - LABEL(BTN_6), - LABEL(BTN_7), - LABEL(BTN_8), - LABEL(BTN_9), - LABEL(BTN_LEFT), - LABEL(BTN_RIGHT), - LABEL(BTN_MIDDLE), - LABEL(BTN_SIDE), - LABEL(BTN_EXTRA), - LABEL(BTN_FORWARD), - LABEL(BTN_BACK), - LABEL(BTN_TASK), - LABEL(BTN_JOYSTICK), - LABEL(BTN_TRIGGER), - LABEL(BTN_THUMB), - LABEL(BTN_THUMB2), - LABEL(BTN_TOP), - LABEL(BTN_TOP2), - LABEL(BTN_PINKIE), - LABEL(BTN_BASE), - LABEL(BTN_BASE2), - LABEL(BTN_BASE3), - LABEL(BTN_BASE4), - LABEL(BTN_BASE5), - LABEL(BTN_BASE6), - LABEL(BTN_DEAD), - LABEL(BTN_A), - LABEL(BTN_B), - LABEL(BTN_C), - LABEL(BTN_X), - LABEL(BTN_Y), - LABEL(BTN_Z), - LABEL(BTN_TL), - LABEL(BTN_TR), - LABEL(BTN_TL2), - LABEL(BTN_TR2), - LABEL(BTN_SELECT), - LABEL(BTN_START), - LABEL(BTN_MODE), - LABEL(BTN_THUMBL), - LABEL(BTN_THUMBR), - LABEL(BTN_TOOL_PEN), - LABEL(BTN_TOOL_RUBBER), - LABEL(BTN_TOOL_BRUSH), - LABEL(BTN_TOOL_PENCIL), - LABEL(BTN_TOOL_AIRBRUSH), - LABEL(BTN_TOOL_FINGER), - LABEL(BTN_TOOL_MOUSE), - LABEL(BTN_TOOL_LENS), - LABEL(BTN_TOUCH), - LABEL(BTN_STYLUS), - LABEL(BTN_STYLUS2), - LABEL(BTN_TOOL_DOUBLETAP), - LABEL(BTN_TOOL_TRIPLETAP), - LABEL(BTN_TOOL_QUADTAP), - LABEL(BTN_GEAR_DOWN), - LABEL(BTN_GEAR_UP), - LABEL(KEY_OK), - LABEL(KEY_SELECT), - LABEL(KEY_GOTO), - LABEL(KEY_CLEAR), - LABEL(KEY_POWER2), - LABEL(KEY_OPTION), - LABEL(KEY_INFO), - LABEL(KEY_TIME), - LABEL(KEY_VENDOR), - LABEL(KEY_ARCHIVE), - LABEL(KEY_PROGRAM), - LABEL(KEY_CHANNEL), - LABEL(KEY_FAVORITES), - LABEL(KEY_EPG), - LABEL(KEY_PVR), - LABEL(KEY_MHP), - LABEL(KEY_LANGUAGE), - LABEL(KEY_TITLE), - LABEL(KEY_SUBTITLE), - LABEL(KEY_ANGLE), - LABEL(KEY_ZOOM), - LABEL(KEY_MODE), - LABEL(KEY_KEYBOARD), - LABEL(KEY_SCREEN), - LABEL(KEY_PC), - LABEL(KEY_TV), - LABEL(KEY_TV2), - LABEL(KEY_VCR), - LABEL(KEY_VCR2), - LABEL(KEY_SAT), - LABEL(KEY_SAT2), - LABEL(KEY_CD), - LABEL(KEY_TAPE), - LABEL(KEY_RADIO), - LABEL(KEY_TUNER), - LABEL(KEY_PLAYER), - LABEL(KEY_TEXT), - LABEL(KEY_DVD), - LABEL(KEY_AUX), - LABEL(KEY_MP3), - LABEL(KEY_AUDIO), - LABEL(KEY_VIDEO), - LABEL(KEY_DIRECTORY), - LABEL(KEY_LIST), - LABEL(KEY_MEMO), - LABEL(KEY_CALENDAR), - LABEL(KEY_RED), - LABEL(KEY_GREEN), - LABEL(KEY_YELLOW), - LABEL(KEY_BLUE), - LABEL(KEY_CHANNELUP), - LABEL(KEY_CHANNELDOWN), - LABEL(KEY_FIRST), - LABEL(KEY_LAST), - LABEL(KEY_AB), - LABEL(KEY_NEXT), - LABEL(KEY_RESTART), - LABEL(KEY_SLOW), - LABEL(KEY_SHUFFLE), - LABEL(KEY_BREAK), - LABEL(KEY_PREVIOUS), - LABEL(KEY_DIGITS), - LABEL(KEY_TEEN), - LABEL(KEY_TWEN), - LABEL(KEY_VIDEOPHONE), - LABEL(KEY_GAMES), - LABEL(KEY_ZOOMIN), - LABEL(KEY_ZOOMOUT), - LABEL(KEY_ZOOMRESET), - LABEL(KEY_WORDPROCESSOR), - LABEL(KEY_EDITOR), - LABEL(KEY_SPREADSHEET), - LABEL(KEY_GRAPHICSEDITOR), - LABEL(KEY_PRESENTATION), - LABEL(KEY_DATABASE), - LABEL(KEY_NEWS), - LABEL(KEY_VOICEMAIL), - LABEL(KEY_ADDRESSBOOK), - LABEL(KEY_MESSENGER), - LABEL(KEY_DISPLAYTOGGLE), - LABEL(KEY_SPELLCHECK), - LABEL(KEY_LOGOFF), - LABEL(KEY_DOLLAR), - LABEL(KEY_EURO), - LABEL(KEY_FRAMEBACK), - LABEL(KEY_FRAMEFORWARD), - LABEL(KEY_CONTEXT_MENU), - LABEL(KEY_MEDIA_REPEAT), - LABEL(KEY_10CHANNELSUP), - LABEL(KEY_10CHANNELSDOWN), - LABEL(KEY_IMAGES), - LABEL(KEY_DEL_EOL), - LABEL(KEY_DEL_EOS), - LABEL(KEY_INS_LINE), - LABEL(KEY_DEL_LINE), - LABEL(KEY_FN), - LABEL(KEY_FN_ESC), - LABEL(KEY_FN_F1), - LABEL(KEY_FN_F2), - LABEL(KEY_FN_F3), - LABEL(KEY_FN_F4), - LABEL(KEY_FN_F5), - LABEL(KEY_FN_F6), - LABEL(KEY_FN_F7), - LABEL(KEY_FN_F8), - LABEL(KEY_FN_F9), - LABEL(KEY_FN_F10), - LABEL(KEY_FN_F11), - LABEL(KEY_FN_F12), - LABEL(KEY_FN_1), - LABEL(KEY_FN_2), - LABEL(KEY_FN_D), - LABEL(KEY_FN_E), - LABEL(KEY_FN_F), - LABEL(KEY_FN_S), - LABEL(KEY_FN_B), - LABEL(KEY_BRL_DOT1), - LABEL(KEY_BRL_DOT2), - LABEL(KEY_BRL_DOT3), - LABEL(KEY_BRL_DOT4), - LABEL(KEY_BRL_DOT5), - LABEL(KEY_BRL_DOT6), - LABEL(KEY_BRL_DOT7), - LABEL(KEY_BRL_DOT8), - LABEL(KEY_BRL_DOT9), - LABEL(KEY_BRL_DOT10), - LABEL(KEY_NUMERIC_0), - LABEL(KEY_NUMERIC_1), - LABEL(KEY_NUMERIC_2), - LABEL(KEY_NUMERIC_3), - LABEL(KEY_NUMERIC_4), - LABEL(KEY_NUMERIC_5), - LABEL(KEY_NUMERIC_6), - LABEL(KEY_NUMERIC_7), - LABEL(KEY_NUMERIC_8), - LABEL(KEY_NUMERIC_9), - LABEL(KEY_NUMERIC_STAR), - LABEL(KEY_NUMERIC_POUND), - LABEL(KEY_CAMERA_FOCUS), - LABEL(KEY_WPS_BUTTON), - LABEL(KEY_TOUCHPAD_TOGGLE), - LABEL(KEY_TOUCHPAD_ON), - LABEL(KEY_TOUCHPAD_OFF), - LABEL(KEY_CAMERA_ZOOMIN), - LABEL(KEY_CAMERA_ZOOMOUT), - LABEL(KEY_CAMERA_UP), - LABEL(KEY_CAMERA_DOWN), - LABEL(KEY_CAMERA_LEFT), - LABEL(KEY_CAMERA_RIGHT), - LABEL(BTN_TRIGGER_HAPPY1), - LABEL(BTN_TRIGGER_HAPPY2), - LABEL(BTN_TRIGGER_HAPPY3), - LABEL(BTN_TRIGGER_HAPPY4), - LABEL(BTN_TRIGGER_HAPPY5), - LABEL(BTN_TRIGGER_HAPPY6), - LABEL(BTN_TRIGGER_HAPPY7), - LABEL(BTN_TRIGGER_HAPPY8), - LABEL(BTN_TRIGGER_HAPPY9), - LABEL(BTN_TRIGGER_HAPPY10), - LABEL(BTN_TRIGGER_HAPPY11), - LABEL(BTN_TRIGGER_HAPPY12), - LABEL(BTN_TRIGGER_HAPPY13), - LABEL(BTN_TRIGGER_HAPPY14), - LABEL(BTN_TRIGGER_HAPPY15), - LABEL(BTN_TRIGGER_HAPPY16), - LABEL(BTN_TRIGGER_HAPPY17), - LABEL(BTN_TRIGGER_HAPPY18), - LABEL(BTN_TRIGGER_HAPPY19), - LABEL(BTN_TRIGGER_HAPPY20), - LABEL(BTN_TRIGGER_HAPPY21), - LABEL(BTN_TRIGGER_HAPPY22), - LABEL(BTN_TRIGGER_HAPPY23), - LABEL(BTN_TRIGGER_HAPPY24), - LABEL(BTN_TRIGGER_HAPPY25), - LABEL(BTN_TRIGGER_HAPPY26), - LABEL(BTN_TRIGGER_HAPPY27), - LABEL(BTN_TRIGGER_HAPPY28), - LABEL(BTN_TRIGGER_HAPPY29), - LABEL(BTN_TRIGGER_HAPPY30), - LABEL(BTN_TRIGGER_HAPPY31), - LABEL(BTN_TRIGGER_HAPPY32), - LABEL(BTN_TRIGGER_HAPPY33), - LABEL(BTN_TRIGGER_HAPPY34), - LABEL(BTN_TRIGGER_HAPPY35), - LABEL(BTN_TRIGGER_HAPPY36), - LABEL(BTN_TRIGGER_HAPPY37), - LABEL(BTN_TRIGGER_HAPPY38), - LABEL(BTN_TRIGGER_HAPPY39), - LABEL(BTN_TRIGGER_HAPPY40), - LABEL_END, -}; - -static struct label rel_labels[] = { - LABEL(REL_X), - LABEL(REL_Y), - LABEL(REL_Z), - LABEL(REL_RX), - LABEL(REL_RY), - LABEL(REL_RZ), - LABEL(REL_HWHEEL), - LABEL(REL_DIAL), - LABEL(REL_WHEEL), - LABEL(REL_MISC), - LABEL_END, -}; - -static struct label abs_labels[] = { - LABEL(ABS_X), - LABEL(ABS_Y), - LABEL(ABS_Z), - LABEL(ABS_RX), - LABEL(ABS_RY), - LABEL(ABS_RZ), - LABEL(ABS_THROTTLE), - LABEL(ABS_RUDDER), - LABEL(ABS_WHEEL), - LABEL(ABS_GAS), - LABEL(ABS_BRAKE), - LABEL(ABS_HAT0X), - LABEL(ABS_HAT0Y), - LABEL(ABS_HAT1X), - LABEL(ABS_HAT1Y), - LABEL(ABS_HAT2X), - LABEL(ABS_HAT2Y), - LABEL(ABS_HAT3X), - LABEL(ABS_HAT3Y), - LABEL(ABS_PRESSURE), - LABEL(ABS_DISTANCE), - LABEL(ABS_TILT_X), - LABEL(ABS_TILT_Y), - LABEL(ABS_TOOL_WIDTH), - LABEL(ABS_VOLUME), - LABEL(ABS_MISC), - LABEL(ABS_MT_SLOT), - LABEL(ABS_MT_TOUCH_MAJOR), - LABEL(ABS_MT_TOUCH_MINOR), - LABEL(ABS_MT_WIDTH_MAJOR), - LABEL(ABS_MT_WIDTH_MINOR), - LABEL(ABS_MT_ORIENTATION), - LABEL(ABS_MT_POSITION_X), - LABEL(ABS_MT_POSITION_Y), - LABEL(ABS_MT_TOOL_TYPE), - LABEL(ABS_MT_BLOB_ID), - LABEL(ABS_MT_TRACKING_ID), - LABEL(ABS_MT_PRESSURE), - LABEL(ABS_MT_DISTANCE), - LABEL_END, -}; - -static struct label sw_labels[] = { - LABEL(SW_LID), - LABEL(SW_TABLET_MODE), - LABEL(SW_HEADPHONE_INSERT), - LABEL(SW_RFKILL_ALL), - LABEL(SW_RADIO), - LABEL(SW_MICROPHONE_INSERT), - LABEL(SW_DOCK), - LABEL(SW_LINEOUT_INSERT), - LABEL(SW_JACK_PHYSICAL_INSERT), - LABEL(SW_VIDEOOUT_INSERT), - LABEL(SW_CAMERA_LENS_COVER), - LABEL(SW_KEYPAD_SLIDE), - LABEL(SW_FRONT_PROXIMITY), - LABEL(SW_ROTATE_LOCK), - LABEL_END, -}; - -static struct label msc_labels[] = { - LABEL(MSC_SERIAL), - LABEL(MSC_PULSELED), - LABEL(MSC_GESTURE), - LABEL(MSC_RAW), - LABEL(MSC_SCAN), - LABEL_END, -}; - -static struct label led_labels[] = { - LABEL(LED_NUML), - LABEL(LED_CAPSL), - LABEL(LED_SCROLLL), - LABEL(LED_COMPOSE), - LABEL(LED_KANA), - LABEL(LED_SLEEP), - LABEL(LED_SUSPEND), - LABEL(LED_MUTE), - LABEL(LED_MISC), - LABEL(LED_MAIL), - LABEL(LED_CHARGING), - LABEL_END, -}; - -static struct label rep_labels[] = { - LABEL(REP_DELAY), - LABEL(REP_PERIOD), - LABEL_END, -}; - -static struct label snd_labels[] = { - LABEL(SND_CLICK), - LABEL(SND_BELL), - LABEL(SND_TONE), - LABEL_END, -}; - -#if 0 -static struct label id_labels[] = { - LABEL(ID_BUS), - LABEL(ID_VENDOR), - LABEL(ID_PRODUCT), - LABEL(ID_VERSION), - LABEL_END, -}; - -static struct label bus_labels[] = { - LABEL(BUS_PCI), - LABEL(BUS_ISAPNP), - LABEL(BUS_USB), - LABEL(BUS_HIL), - LABEL(BUS_BLUETOOTH), - LABEL(BUS_VIRTUAL), - LABEL(BUS_ISA), - LABEL(BUS_I8042), - LABEL(BUS_XTKBD), - LABEL(BUS_RS232), - LABEL(BUS_GAMEPORT), - LABEL(BUS_PARPORT), - LABEL(BUS_AMIGA), - LABEL(BUS_ADB), - LABEL(BUS_I2C), - LABEL(BUS_HOST), - LABEL(BUS_GSC), - LABEL(BUS_ATARI), - LABEL(BUS_SPI), - LABEL_END, -}; -#endif - -static struct label mt_tool_labels[] = { - LABEL(MT_TOOL_FINGER), - LABEL(MT_TOOL_PEN), - LABEL(MT_TOOL_MAX), - LABEL_END, -}; - -static struct label ff_status_labels[] = { - LABEL(FF_STATUS_STOPPED), - LABEL(FF_STATUS_PLAYING), - LABEL(FF_STATUS_MAX), - LABEL_END, -}; - -static struct label ff_labels[] = { - LABEL(FF_RUMBLE), - LABEL(FF_PERIODIC), - LABEL(FF_CONSTANT), - LABEL(FF_SPRING), - LABEL(FF_FRICTION), - LABEL(FF_DAMPER), - LABEL(FF_INERTIA), - LABEL(FF_RAMP), - LABEL(FF_SQUARE), - LABEL(FF_TRIANGLE), - LABEL(FF_SINE), - LABEL(FF_SAW_UP), - LABEL(FF_SAW_DOWN), - LABEL(FF_CUSTOM), - LABEL(FF_GAIN), - LABEL(FF_AUTOCENTER), - LABEL_END, -}; - -static struct label key_value_labels[] = { - { "UP", 0 }, - { "DOWN", 1 }, - { "REPEAT", 2 }, - LABEL_END, -}; diff --git a/toolbox/getprop.c b/toolbox/getprop.c deleted file mode 100644 index dcc0ea0..0000000 --- a/toolbox/getprop.c +++ /dev/null @@ -1,50 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> - -#include <cutils/properties.h> - -#include "dynarray.h" - -static void record_prop(const char* key, const char* name, void* opaque) -{ - strlist_t* list = opaque; - char temp[PROP_VALUE_MAX + PROP_NAME_MAX + 16]; - snprintf(temp, sizeof temp, "[%s]: [%s]", key, name); - strlist_append_dup(list, temp); -} - -static void list_properties(void) -{ - strlist_t list[1] = { STRLIST_INITIALIZER }; - - /* Record properties in the string list */ - (void)property_list(record_prop, list); - - /* Sort everything */ - strlist_sort(list); - - /* print everything */ - STRLIST_FOREACH(list, str, printf("%s\n", str)); - - /* voila */ - strlist_done(list); -} - -int getprop_main(int argc, char *argv[]) -{ - if (argc == 1) { - list_properties(); - } else { - char value[PROPERTY_VALUE_MAX]; - char *default_value; - if(argc > 2) { - default_value = argv[2]; - } else { - default_value = ""; - } - - property_get(argv[1], value, default_value); - printf("%s\n", value); - } - return 0; -} diff --git a/toolbox/getsebool.c b/toolbox/getsebool.c deleted file mode 100644 index aab5200..0000000 --- a/toolbox/getsebool.c +++ /dev/null @@ -1,104 +0,0 @@ -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <getopt.h> -#include <errno.h> -#include <string.h> -#include <selinux/selinux.h> - -static void usage(const char *progname) -{ - fprintf(stderr, "usage: %s -a or %s boolean...\n", progname, progname); - exit(1); -} - -int getsebool_main(int argc, char **argv) -{ - int i, get_all = 0, rc = 0, active, pending, len = 0, opt; - char **names; - - while ((opt = getopt(argc, argv, "a")) > 0) { - switch (opt) { - case 'a': - if (argc > 2) - usage(argv[0]); - if (is_selinux_enabled() <= 0) { - fprintf(stderr, "%s: SELinux is disabled\n", - argv[0]); - return 1; - } - errno = 0; - rc = security_get_boolean_names(&names, &len); - if (rc) { - fprintf(stderr, - "%s: Unable to get boolean names: %s\n", - argv[0], strerror(errno)); - return 1; - } - if (!len) { - printf("No booleans\n"); - return 0; - } - get_all = 1; - break; - default: - usage(argv[0]); - } - } - - if (is_selinux_enabled() <= 0) { - fprintf(stderr, "%s: SELinux is disabled\n", argv[0]); - return 1; - } - if (!len) { - if (argc < 2) - usage(argv[0]); - len = argc - 1; - names = malloc(sizeof(char *) * len); - if (!names) { - fprintf(stderr, "%s: out of memory\n", argv[0]); - return 2; - } - for (i = 0; i < len; i++) { - names[i] = strdup(argv[i + 1]); - if (!names[i]) { - fprintf(stderr, "%s: out of memory\n", - argv[0]); - return 2; - } - } - } - - for (i = 0; i < len; i++) { - active = security_get_boolean_active(names[i]); - if (active < 0) { - if (get_all && errno == EACCES) - continue; - fprintf(stderr, "Error getting active value for %s\n", - names[i]); - rc = -1; - goto out; - } - pending = security_get_boolean_pending(names[i]); - if (pending < 0) { - fprintf(stderr, "Error getting pending value for %s\n", - names[i]); - rc = -1; - goto out; - } - if (pending != active) { - printf("%s --> %s pending: %s\n", names[i], - (active ? "on" : "off"), - (pending ? "on" : "off")); - } else { - printf("%s --> %s\n", names[i], - (active ? "on" : "off")); - } - } - -out: - for (i = 0; i < len; i++) - free(names[i]); - free(names); - return rc; -} diff --git a/toolbox/hd.c b/toolbox/hd.c deleted file mode 100644 index 7c9998e..0000000 --- a/toolbox/hd.c +++ /dev/null @@ -1,97 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdint.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <errno.h> - -int hd_main(int argc, char *argv[]) -{ - int c; - int fd; - unsigned char buf[4096]; - int res; - int read_len; - int i; - int filepos = 0; - int sum; - int lsum; - - int base = -1; - int count = 0; - int repeat = 0; - - do { - c = getopt(argc, argv, "b:c:r:"); - if (c == EOF) - break; - switch (c) { - case 'b': - base = strtol(optarg, NULL, 0); - break; - case 'c': - count = strtol(optarg, NULL, 0); - break; - case 'r': - repeat = strtol(optarg, NULL, 0); - break; - case '?': - fprintf(stderr, "%s: invalid option -%c\n", - argv[0], optopt); - exit(1); - } - } while (1); - - if (optind + 1 != argc) { - fprintf(stderr, "Usage: %s [-b base] [-c count] [-r delay] file\n", argv[0]); - exit(1); - } - - fd = open(argv[optind], O_RDONLY); - if(fd < 0) { - fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno)); - return 1; - } - - do { - if(base >= 0) { - lseek(fd, base, SEEK_SET); - filepos = base; - } - sum = 0; - lsum = 0; - while(1) { - read_len = sizeof(buf); - if(count > 0 && base + count - filepos < read_len) - read_len = base + count - filepos; - res = read(fd, &buf, read_len); - if(res == 0) - break; - for(i = 0; i < res; i++) { - if((i & 15) == 0) { - printf("%08x: ", filepos + i); - } - lsum += buf[i]; - sum += buf[i]; - printf("%02x ", buf[i]); - if(((i & 15) == 15) || (i == res - 1)) { - printf("s %x\n", lsum); - lsum = 0; - } - } - if(res < 0) { - printf("Read error on %s, offset %d len %d, %s\n", argv[optind], filepos, read_len, strerror(errno)); - return 1; - } - filepos += res; - if(filepos == base + count) - break; - } - printf("sum %x\n", sum); - if(repeat) - sleep(repeat); - } while(repeat); - return 0; -} diff --git a/toolbox/id.c b/toolbox/id.c deleted file mode 100644 index 8ec79c1..0000000 --- a/toolbox/id.c +++ /dev/null @@ -1,57 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/types.h> -#include <pwd.h> -#include <grp.h> -#include <selinux/selinux.h> - -static void print_uid(uid_t uid) -{ - struct passwd *pw = getpwuid(uid); - - if (pw) { - printf("%d(%s)", uid, pw->pw_name); - } else { - printf("%d",uid); - } -} - -static void print_gid(gid_t gid) -{ - struct group *gr = getgrgid(gid); - if (gr) { - printf("%d(%s)", gid, gr->gr_name); - } else { - printf("%d",gid); - } -} - -int id_main(int argc, char **argv) -{ - gid_t list[64]; - int n, max; - char *secctx; - - max = getgroups(64, list); - if (max < 0) max = 0; - - printf("uid="); - print_uid(getuid()); - printf(" gid="); - print_gid(getgid()); - if (max) { - printf(" groups="); - print_gid(list[0]); - for(n = 1; n < max; n++) { - printf(","); - print_gid(list[n]); - } - } - if (getcon(&secctx) == 0) { - printf(" context=%s", secctx); - free(secctx); - } - printf("\n"); - return 0; -} diff --git a/toolbox/ifconfig.c b/toolbox/ifconfig.c deleted file mode 100644 index b953176..0000000 --- a/toolbox/ifconfig.c +++ /dev/null @@ -1,157 +0,0 @@ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include <errno.h> -#include <string.h> -#include <ctype.h> - -#include <sys/socket.h> -#include <netinet/in.h> -#include <linux/if.h> -#include <linux/sockios.h> -#include <arpa/inet.h> - -static void die(const char *s) -{ - fprintf(stderr,"error: %s (%s)\n", s, strerror(errno)); - exit(-1); -} - -static void setflags(int s, struct ifreq *ifr, int set, int clr) -{ - if(ioctl(s, SIOCGIFFLAGS, ifr) < 0) die("SIOCGIFFLAGS"); - ifr->ifr_flags = (ifr->ifr_flags & (~clr)) | set; - if(ioctl(s, SIOCSIFFLAGS, ifr) < 0) die("SIOCSIFFLAGS"); -} - -static inline void init_sockaddr_in(struct sockaddr_in *sin, const char *addr) -{ - sin->sin_family = AF_INET; - sin->sin_port = 0; - sin->sin_addr.s_addr = inet_addr(addr); -} - -static void setmtu(int s, struct ifreq *ifr, const char *mtu) -{ - int m = atoi(mtu); - ifr->ifr_mtu = m; - if(ioctl(s, SIOCSIFMTU, ifr) < 0) die("SIOCSIFMTU"); -} -static void setdstaddr(int s, struct ifreq *ifr, const char *addr) -{ - init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_dstaddr, addr); - if(ioctl(s, SIOCSIFDSTADDR, ifr) < 0) die("SIOCSIFDSTADDR"); -} - -static void setnetmask(int s, struct ifreq *ifr, const char *addr) -{ - init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_netmask, addr); - if(ioctl(s, SIOCSIFNETMASK, ifr) < 0) die("SIOCSIFNETMASK"); -} - -static void setaddr(int s, struct ifreq *ifr, const char *addr) -{ - init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_addr, addr); - if(ioctl(s, SIOCSIFADDR, ifr) < 0) die("SIOCSIFADDR"); -} - -int ifconfig_main(int argc, char *argv[]) -{ - struct ifreq ifr; - int s; - unsigned int flags; - char astring[20]; - char mstring[20]; - char *updown, *brdcst, *loopbk, *ppp, *running, *multi; - - argc--; - argv++; - - if(argc == 0) return 0; - - memset(&ifr, 0, sizeof(struct ifreq)); - strncpy(ifr.ifr_name, argv[0], IFNAMSIZ); - ifr.ifr_name[IFNAMSIZ-1] = 0; - argc--, argv++; - - if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - die("cannot open control socket\n"); - } - - if (argc == 0) { - if (ioctl(s, SIOCGIFADDR, &ifr) < 0) { - perror(ifr.ifr_name); - return -1; - } else - strlcpy(astring, - inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr), - sizeof(astring)); - - if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0) { - perror(ifr.ifr_name); - return -1; - } else - strlcpy(mstring, - inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr), - sizeof(mstring)); - - if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) { - perror(ifr.ifr_name); - return -1; - } else - flags = ifr.ifr_flags; - - printf("%s: ip %s mask %s flags [", ifr.ifr_name, - astring, - mstring - ); - - updown = (flags & IFF_UP) ? "up" : "down"; - brdcst = (flags & IFF_BROADCAST) ? " broadcast" : ""; - loopbk = (flags & IFF_LOOPBACK) ? " loopback" : ""; - ppp = (flags & IFF_POINTOPOINT) ? " point-to-point" : ""; - running = (flags & IFF_RUNNING) ? " running" : ""; - multi = (flags & IFF_MULTICAST) ? " multicast" : ""; - printf("%s%s%s%s%s%s]\n", updown, brdcst, loopbk, ppp, running, multi); - return 0; - } - - while(argc > 0) { - if (!strcmp(argv[0], "up")) { - setflags(s, &ifr, IFF_UP, 0); - } else if (!strcmp(argv[0], "mtu")) { - argc--, argv++; - if (!argc) { - errno = EINVAL; - die("expecting a value for parameter \"mtu\""); - } - setmtu(s, &ifr, argv[0]); - } else if (!strcmp(argv[0], "-pointopoint")) { - setflags(s, &ifr, IFF_POINTOPOINT, 1); - } else if (!strcmp(argv[0], "pointopoint")) { - argc--, argv++; - if (!argc) { - errno = EINVAL; - die("expecting an IP address for parameter \"pointtopoint\""); - } - setdstaddr(s, &ifr, argv[0]); - setflags(s, &ifr, IFF_POINTOPOINT, 0); - } else if (!strcmp(argv[0], "down")) { - setflags(s, &ifr, 0, IFF_UP); - } else if (!strcmp(argv[0], "netmask")) { - argc--, argv++; - if (!argc) { - errno = EINVAL; - die("expecting an IP address for parameter \"netmask\""); - } - setnetmask(s, &ifr, argv[0]); - } else if (isdigit(argv[0][0])) { - setaddr(s, &ifr, argv[0]); - setflags(s, &ifr, IFF_UP, 0); - } - argc--, argv++; - } - return 0; -} diff --git a/toolbox/insmod.c b/toolbox/insmod.c deleted file mode 100644 index d252433..0000000 --- a/toolbox/insmod.c +++ /dev/null @@ -1,97 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <unistd.h> -#include <malloc.h> -#include <errno.h> -#include <sys/param.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> - -extern int init_module(void *, unsigned long, const char *); - -static void *read_file(const 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; -} - -int insmod_main(int argc, char **argv) -{ - void *file; - ssize_t size = 0; - char opts[1024]; - int ret; - - /* make sure we've got an argument */ - if (argc < 2) { - fprintf(stderr, "usage: insmod <module.o>\n"); - return -1; - } - - /* read the file into memory */ - file = read_file(argv[1], &size); - if (!file) { - fprintf(stderr, "insmod: can't open '%s'\n", argv[1]); - return -1; - } - - opts[0] = '\0'; - if (argc > 2) { - int i, len; - char *end = opts + sizeof(opts) - 1; - char *ptr = opts; - - for (i = 2; (i < argc) && (ptr < end); i++) { - len = MIN(strlen(argv[i]), (size_t)(end - ptr)); - memcpy(ptr, argv[i], len); - ptr += len; - *ptr++ = ' '; - } - *(ptr - 1) = '\0'; - } - - /* pass it to the kernel */ - ret = init_module(file, size, opts); - if (ret != 0) { - fprintf(stderr, - "insmod: init_module '%s' failed (%s)\n", - argv[1], strerror(errno)); - } - - /* free the file buffer */ - free(file); - - return ret; -} - diff --git a/toolbox/ioctl.c b/toolbox/ioctl.c index fd90812..093e467 100644 --- a/toolbox/ioctl.c +++ b/toolbox/ioctl.c @@ -1,35 +1,81 @@ -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> +/* + * Copyright (c) 2008, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + */ + +#include <errno.h> +#include <error.h> #include <fcntl.h> #include <getopt.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> #include <string.h> -#include <linux/kd.h> -#include <linux/vt.h> -#include <errno.h> -#include <pthread.h> #include <sys/ioctl.h> +#include <unistd.h> -int ioctl_main(int argc, char *argv[]) -{ - int c; - int fd; - int res; +static void usage() { + fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n" + " -l <length> Length of io buffer\n" + " -a <argsize> Size of each argument (1-8)\n" + " -r Open device in read only mode\n" + " -d Direct argument (no iobuffer)\n" + " -h Print help\n", getprogname()); + exit(1); +} + +static int xstrtoi(const char* s, const char* what) { + char* endp; + errno = 0; + long result = strtol(s, &endp, 0); + if (errno != 0 || *endp != '\0') { + error(1, errno, "couldn't parse %s '%s'", what, s); + } + if (result > INT_MAX || result < INT_MIN) { + error(1, errno, "%s '%s' out of range", what, s); + } + return result; +} +int ioctl_main(int argc, char* argv[]) { int read_only = 0; int length = -1; int arg_size = 4; int direct_arg = 0; - uint32_t ioctl_nr; + void *ioctl_args = NULL; uint8_t *ioctl_argp; uint8_t *ioctl_argp_save = NULL; int rem; - do { - c = getopt(argc, argv, "rdl:a:h"); - if (c == EOF) - break; + int c; + while ((c = getopt(argc, argv, "rdl:a:h")) != -1) { switch (c) { case 'r': read_only = 1; @@ -38,43 +84,44 @@ int ioctl_main(int argc, char *argv[]) direct_arg = 1; break; case 'l': - length = strtol(optarg, NULL, 0); + length = xstrtoi(optarg, "length"); break; case 'a': - arg_size = strtol(optarg, NULL, 0); + arg_size = xstrtoi(optarg, "argument size"); break; case 'h': - fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n" - " -l <lenght> Length of io buffer\n" - " -a <argsize> Size of each argument (1-8)\n" - " -r Open device in read only mode\n" - " -d Direct argument (no iobuffer)\n" - " -h Print help\n", argv[0]); - return -1; - case '?': - fprintf(stderr, "%s: invalid option -%c\n", - argv[0], optopt); - exit(1); + usage(); + break; + default: + error(1, 0, "invalid option -%c", optopt); } - } while (1); + } - if(optind + 2 > argc) { - fprintf(stderr, "%s: too few arguments\n", argv[0]); - exit(1); + if (optind + 2 > argc) { + usage(); } - if (!strcmp(argv[optind], "-")) { + const char* device = argv[optind]; + int fd; + if (strcmp(device, "-") == 0) { fd = STDIN_FILENO; } else { - fd = open(argv[optind], read_only ? O_RDONLY : (O_RDWR | O_SYNC)); - if (fd < 0) { - fprintf(stderr, "cannot open %s\n", argv[optind]); - return 1; + fd = open(device, read_only ? O_RDONLY : (O_RDWR | O_SYNC)); + if (fd == -1) { + error(1, errno, "cannot open %s", argv[optind]); } } optind++; - - ioctl_nr = strtol(argv[optind], NULL, 0); + + // IOCTL(2) wants second parameter as a signed int. + // Let's let the user specify either negative numbers or large positive + // numbers, for the case where ioctl number is larger than INT_MAX. + errno = 0; + char* endp; + int ioctl_nr = UINT_MAX & strtoll(argv[optind], &endp, 0); + if (errno != 0 || *endp != '\0') { + error(1, errno, "couldn't parse ioctl number '%s'", argv[optind]); + } optind++; if(direct_arg) { @@ -90,11 +137,10 @@ int ioctl_main(int argc, char *argv[]) ioctl_argp_save = ioctl_argp = ioctl_args; rem = length; - while(optind < argc) { + while (optind < argc) { uint64_t tmp = strtoull(argv[optind], NULL, 0); - if(rem < arg_size) { - fprintf(stderr, "%s: too many arguments\n", argv[0]); - exit(1); + if (rem < arg_size) { + error(1, 0, "too many arguments"); } memcpy(ioctl_argp, &tmp, arg_size); ioctl_argp += arg_size; @@ -107,8 +153,9 @@ int ioctl_main(int argc, char *argv[]) while(rem--) { printf(" 0x%02x", *ioctl_argp_save++); } - printf("\n"); + printf(" to %s\n", device); + int res; if(direct_arg) res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args); else if(length) @@ -117,10 +164,10 @@ int ioctl_main(int argc, char *argv[]) res = ioctl(fd, ioctl_nr, 0); if (res < 0) { free(ioctl_args); - fprintf(stderr, "ioctl 0x%x failed, %d\n", ioctl_nr, res); - return 1; + error(1, errno, "ioctl 0x%x failed (returned %d)", ioctl_nr, res); } - if(length) { + + if (length) { printf("return buf:"); ioctl_argp = ioctl_args; rem = length; @@ -130,5 +177,6 @@ int ioctl_main(int argc, char *argv[]) printf("\n"); } free(ioctl_args); + close(fd); return 0; } diff --git a/toolbox/ionice.c b/toolbox/ionice.c index 4a182f2..7abc261 100644 --- a/toolbox/ionice.c +++ b/toolbox/ionice.c @@ -1,5 +1,6 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> #include <errno.h> diff --git a/toolbox/load_policy.c b/toolbox/load_policy.c deleted file mode 100644 index 90d48c4..0000000 --- a/toolbox/load_policy.c +++ /dev/null @@ -1,49 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <errno.h> -#include <selinux/selinux.h> - -int load_policy_main(int argc, char **argv) -{ - int fd, rc; - struct stat sb; - void *map; - const char *path; - - if (argc != 2) { - fprintf(stderr, "usage: %s policy-file\n", argv[0]); - exit(1); - } - - path = argv[1]; - fd = open(path, O_RDONLY); - if (fd < 0) { - fprintf(stderr, "Could not open %s: %s\n", path, strerror(errno)); - exit(2); - } - - if (fstat(fd, &sb) < 0) { - fprintf(stderr, "Could not stat %s: %s\n", path, strerror(errno)); - exit(3); - } - - map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (map == MAP_FAILED) { - fprintf(stderr, "Could not mmap %s: %s\n", path, strerror(errno)); - exit(4); - } - - rc = security_load_policy(map, sb.st_size); - if (rc < 0) { - fprintf(stderr, "Could not load %s: %s\n", path, strerror(errno)); - exit(5); - } - munmap(map, sb.st_size); - close(fd); - exit(0); -} diff --git a/toolbox/ls.c b/toolbox/ls.c index 963fcb5..9a89dd4 100644 --- a/toolbox/ls.c +++ b/toolbox/ls.c @@ -1,23 +1,119 @@ +#include <dirent.h> +#include <errno.h> +#include <grp.h> +#include <limits.h> +#include <pwd.h> +#include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> #include <sys/types.h> -#include <dirent.h> -#include <errno.h> +#include <time.h> +#include <unistd.h> #include <selinux/selinux.h> -#include <sys/stat.h> -#include <unistd.h> -#include <time.h> +// simple dynamic array of strings. +typedef struct { + int count; + int capacity; + void** items; +} strlist_t; + +#define STRLIST_INITIALIZER { 0, 0, NULL } + +/* Used to iterate over a strlist_t + * _list :: pointer to strlist_t object + * _item :: name of local variable name defined within the loop with + * type 'char*' + * _stmnt :: C statement executed in each iteration + * + * This macro is only intended for simple uses. Do not add or remove items + * to/from the list during iteration. + */ +#define STRLIST_FOREACH(_list,_item,_stmnt) \ + do { \ + int _nn_##__LINE__ = 0; \ + for (;_nn_##__LINE__ < (_list)->count; ++ _nn_##__LINE__) { \ + char* _item = (char*)(_list)->items[_nn_##__LINE__]; \ + _stmnt; \ + } \ + } while (0) + +static void dynarray_reserve_more( strlist_t *a, int count ) { + int old_cap = a->capacity; + int new_cap = old_cap; + const int max_cap = INT_MAX/sizeof(void*); + void** new_items; + int new_count = a->count + count; + + if (count <= 0) + return; + + if (count > max_cap - a->count) + abort(); + + new_count = a->count + count; + + while (new_cap < new_count) { + old_cap = new_cap; + new_cap += (new_cap >> 2) + 4; + if (new_cap < old_cap || new_cap > max_cap) { + new_cap = max_cap; + } + } + new_items = realloc(a->items, new_cap*sizeof(void*)); + if (new_items == NULL) + abort(); -#include <pwd.h> -#include <grp.h> + a->items = new_items; + a->capacity = new_cap; +} -#include <linux/kdev_t.h> -#include <limits.h> +void strlist_init( strlist_t *list ) { + list->count = list->capacity = 0; + list->items = NULL; +} + +// append a new string made of the first 'slen' characters from 'str' +// followed by a trailing zero. +void strlist_append_b( strlist_t *list, const void* str, size_t slen ) { + char *copy = malloc(slen+1); + memcpy(copy, str, slen); + copy[slen] = '\0'; + if (list->count >= list->capacity) + dynarray_reserve_more(list, 1); + list->items[list->count++] = copy; +} + +// append the copy of a given input string to a strlist_t. +void strlist_append_dup( strlist_t *list, const char *str) { + strlist_append_b(list, str, strlen(str)); +} + +// note: strlist_done will free all the strings owned by the list. +void strlist_done( strlist_t *list ) { + STRLIST_FOREACH(list, string, free(string)); + free(list->items); + list->items = NULL; + list->count = list->capacity = 0; +} + +static int strlist_compare_strings(const void* a, const void* b) { + const char *sa = *(const char **)a; + const char *sb = *(const char **)b; + return strcmp(sa, sb); +} + +/* sort the strings in a given list (using strcmp) */ +void strlist_sort( strlist_t *list ) { + if (list->count > 0) { + qsort(list->items, (size_t)list->count, sizeof(void*), strlist_compare_strings); + } +} -#include "dynarray.h" // bits for flags argument #define LIST_LONG (1 << 0) @@ -200,7 +296,7 @@ static int listfile_long(const char *path, struct stat *s, int flags) case S_IFCHR: printf("%s %-8s %-8s %3d, %3d %s %s\n", mode, user, group, - (int) MAJOR(s->st_rdev), (int) MINOR(s->st_rdev), + major(s->st_rdev), minor(s->st_rdev), date, name); break; case S_IFREG: diff --git a/toolbox/lsmod.c b/toolbox/lsmod.c deleted file mode 100644 index 8b55ee6..0000000 --- a/toolbox/lsmod.c +++ /dev/null @@ -1,10 +0,0 @@ -#include <stdio.h> - -extern int cat_main(int argc, char **argv); - -int lsmod_main(int argc, char **argv) -{ - char *cat_argv[] = { "cat", "/proc/modules", NULL }; - return cat_main(2, cat_argv); -} - diff --git a/toolbox/lsof.c b/toolbox/lsof.c index bee981d..982f5aa 100644 --- a/toolbox/lsof.c +++ b/toolbox/lsof.c @@ -35,6 +35,7 @@ #include <libgen.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> #include <pwd.h> diff --git a/toolbox/lsusb.c b/toolbox/lsusb.c deleted file mode 100644 index 236e74b..0000000 --- a/toolbox/lsusb.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 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 <endian.h> -#include <errno.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> - -#include <usbhost/usbhost.h> - -static int verbose = 0; -static char str_buff[4096]; - -static const char *get_str(struct usb_device *dev, int id) -{ - char *str = usb_device_get_string(dev, id); - - if (id && str) { - strlcpy(str_buff, str, sizeof(str_buff)); - free(str); - } else { - snprintf(str_buff, sizeof(str_buff), "%02x", id); - } - - return str_buff; -} - - -static void lsusb_parse_device_descriptor(struct usb_device *dev, - struct usb_device_descriptor *desc) -{ - printf(" Device Descriptor\n"); - printf("\tbcdUSB: %04x\n", letoh16(desc->bcdUSB)); - printf("\tbDeviceClass: %02x\n", desc->bDeviceClass); - printf("\tbDeviceSubClass: %02x\n", desc->bDeviceSubClass); - printf("\tbDeviceProtocol: %02x\n", desc->bDeviceProtocol); - printf("\tbMaxPacketSize0: %02x\n", desc->bMaxPacketSize0); - printf("\tidVendor: %04x\n", letoh16(desc->idVendor)); - printf("\tidProduct: %04x\n", letoh16(desc->idProduct)); - printf("\tbcdDevice: %04x\n", letoh16(desc->bcdDevice)); - printf("\tiManufacturer: %s\n", get_str(dev, desc->iManufacturer)); - printf("\tiProduct: %s\n", get_str(dev, desc->iProduct)); - printf("\tiSerialNumber: %s\n", get_str(dev,desc->iSerialNumber)); - printf("\tbNumConfiguration: %02x\n", desc->bNumConfigurations); - printf("\n"); -} - -static void lsusb_parse_config_descriptor(struct usb_device *dev, - struct usb_config_descriptor *desc) -{ - printf(" Config Descriptor\n"); - printf("\twTotalLength: %04x\n", letoh16(desc->wTotalLength)); - printf("\tbNumInterfaces: %02x\n", desc->bNumInterfaces); - printf("\tbConfigurationValue: %02x\n", desc->bConfigurationValue); - printf("\tiConfiguration: %s\n", get_str(dev, desc->iConfiguration)); - printf("\tbmAttributes: %02x\n", desc->bmAttributes); - printf("\tbMaxPower: %d mA\n", desc->bMaxPower * 2); - printf("\n"); -} - -static void lsusb_parse_interface_descriptor(struct usb_device *dev, - struct usb_interface_descriptor *desc) -{ - printf(" Interface Descriptor\n"); - printf("\tbInterfaceNumber: %02x\n", desc->bInterfaceNumber); - printf("\tbAlternateSetting: %02x\n", desc->bAlternateSetting); - printf("\tbNumEndpoints: %02x\n", desc->bNumEndpoints); - printf("\tbInterfaceClass: %02x\n", desc->bInterfaceClass); - printf("\tbInterfaceSubClass: %02x\n", desc->bInterfaceSubClass); - printf("\tbInterfaceProtocol: %02x\n", desc->bInterfaceProtocol); - printf("\tiInterface: %s\n", get_str(dev, desc->iInterface)); - printf("\n"); -} - -static void lsusb_parse_endpoint_descriptor(struct usb_device *dev, - struct usb_endpoint_descriptor *desc) -{ - printf(" Endpoint Descriptor\n"); - printf("\tbEndpointAddress: %02x\n", desc->bEndpointAddress); - printf("\tbmAttributes: %02x\n", desc->bmAttributes); - printf("\twMaxPacketSize: %02x\n", letoh16(desc->wMaxPacketSize)); - printf("\tbInterval: %02x\n", desc->bInterval); - printf("\tbRefresh: %02x\n", desc->bRefresh); - printf("\tbSynchAddress: %02x\n", desc->bSynchAddress); - printf("\n"); -} - -static void lsusb_dump_descriptor(struct usb_device *dev, - struct usb_descriptor_header *desc) -{ - int i; - printf(" Descriptor type %02x\n", desc->bDescriptorType); - - for (i = 0; i < desc->bLength; i++ ) { - if ((i % 16) == 0) - printf("\t%02x:", i); - printf(" %02x", ((uint8_t *)desc)[i]); - if ((i % 16) == 15) - printf("\n"); - } - - if ((i % 16) != 0) - printf("\n"); - printf("\n"); -} - -static void lsusb_parse_descriptor(struct usb_device *dev, - struct usb_descriptor_header *desc) -{ - switch (desc->bDescriptorType) { - case USB_DT_DEVICE: - lsusb_parse_device_descriptor(dev, (struct usb_device_descriptor *) desc); - break; - - case USB_DT_CONFIG: - lsusb_parse_config_descriptor(dev, (struct usb_config_descriptor *) desc); - break; - - case USB_DT_INTERFACE: - lsusb_parse_interface_descriptor(dev, (struct usb_interface_descriptor *) desc); - break; - - case USB_DT_ENDPOINT: - lsusb_parse_endpoint_descriptor(dev, (struct usb_endpoint_descriptor *) desc); - break; - - default: - lsusb_dump_descriptor(dev, desc); - - break; - } -} - -static int lsusb_device_added(const char *dev_name, void *client_data) -{ - struct usb_device *dev = usb_device_open(dev_name); - - if (!dev) { - fprintf(stderr, "can't open device %s: %s\n", dev_name, strerror(errno)); - return 0; - } - - if (verbose) { - struct usb_descriptor_iter iter; - struct usb_descriptor_header *desc; - - printf("%s:\n", dev_name); - - usb_descriptor_iter_init(dev, &iter); - - while ((desc = usb_descriptor_iter_next(&iter)) != NULL) - lsusb_parse_descriptor(dev, desc); - - } else { - uint16_t vid, pid; - char *mfg_name, *product_name, *serial; - - vid = usb_device_get_vendor_id(dev); - pid = usb_device_get_product_id(dev); - mfg_name = usb_device_get_manufacturer_name(dev); - product_name = usb_device_get_product_name(dev); - serial = usb_device_get_serial(dev); - - printf("%s: %04x:%04x %s %s %s\n", dev_name, vid, pid, - mfg_name, product_name, serial); - - free(mfg_name); - free(product_name); - free(serial); - } - - usb_device_close(dev); - - return 0; -} - -static int lsusb_device_removed(const char *dev_name, void *client_data) -{ - return 0; -} - - -static int lsusb_discovery_done(void *client_data) -{ - return 1; -} - - - -int lsusb_main(int argc, char **argv) -{ - struct usb_host_context *ctx; - - if (argc == 2 && !strcmp(argv[1], "-v")) - verbose = 1; - - ctx = usb_host_init(); - if (!ctx) { - perror("usb_host_init:"); - return 1; - } - - usb_host_run(ctx, - lsusb_device_added, - lsusb_device_removed, - lsusb_discovery_done, - NULL); - - usb_host_cleanup(ctx); - - return 0; -} - diff --git a/toolbox/md5.c b/toolbox/md5.c deleted file mode 100644 index 5de4d9e..0000000 --- a/toolbox/md5.c +++ /dev/null @@ -1,71 +0,0 @@ -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <unistd.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <openssl/md5.h> - -static int usage() -{ - fprintf(stderr,"md5 file ...\n"); - return -1; -} - -static int do_md5(const char *path) -{ - unsigned int i; - int fd; - MD5_CTX md5_ctx; - unsigned char md5[MD5_DIGEST_LENGTH]; - - fd = open(path, O_RDONLY); - if (fd < 0) { - fprintf(stderr,"could not open %s, %s\n", path, strerror(errno)); - return -1; - } - - MD5_Init(&md5_ctx); - - while (1) { - char buf[4096]; - ssize_t rlen; - rlen = read(fd, buf, sizeof(buf)); - if (rlen == 0) - break; - else if (rlen < 0) { - (void)close(fd); - fprintf(stderr,"could not read %s, %s\n", path, strerror(errno)); - return -1; - } - MD5_Update(&md5_ctx, buf, rlen); - } - if (close(fd)) { - fprintf(stderr,"could not close %s, %s\n", path, strerror(errno)); - return -1; - } - - MD5_Final(md5, &md5_ctx); - - for (i = 0; i < (int)sizeof(md5); i++) - printf("%02x", md5[i]); - printf(" %s\n", path); - - return 0; -} - -int md5_main(int argc, char *argv[]) -{ - int i, ret = 0; - - if (argc < 2) - return usage(); - - /* loop over the file args */ - for (i = 1; i < argc; i++) { - if (do_md5(argv[i])) - ret = 1; - } - - return ret; -} diff --git a/toolbox/mkdir.c b/toolbox/mkdir.c deleted file mode 100644 index 398d350..0000000 --- a/toolbox/mkdir.c +++ /dev/null @@ -1,77 +0,0 @@ -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <sys/limits.h> -#include <sys/stat.h> - -static int usage() -{ - fprintf(stderr,"mkdir [OPTION] <target>\n"); - fprintf(stderr," --help display usage and exit\n"); - fprintf(stderr," -p, --parents create parent directories as needed\n"); - return -1; -} - -int mkdir_main(int argc, char *argv[]) -{ - int ret; - if(argc < 2 || strcmp(argv[1], "--help") == 0) { - return usage(); - } - - int recursive = (strcmp(argv[1], "-p") == 0 || - strcmp(argv[1], "--parents") == 0) ? 1 : 0; - - if(recursive && argc < 3) { - // -p specified without a path - return usage(); - } - - if(recursive) { - argc--; - argv++; - } - - char currpath[PATH_MAX], *pathpiece; - struct stat st; - - while(argc > 1) { - argc--; - argv++; - if(recursive) { - // reset path - strcpy(currpath, ""); - // create the pieces of the path along the way - pathpiece = strtok(argv[0], "/"); - if(argv[0][0] == '/') { - // prepend / if needed - strcat(currpath, "/"); - } - while(pathpiece != NULL) { - if(strlen(currpath) + strlen(pathpiece) + 2/*NUL and slash*/ > PATH_MAX) { - fprintf(stderr, "Invalid path specified: too long\n"); - return 1; - } - strcat(currpath, pathpiece); - strcat(currpath, "/"); - if(stat(currpath, &st) != 0) { - ret = mkdir(currpath, 0777); - if(ret < 0) { - fprintf(stderr, "mkdir failed for %s, %s\n", currpath, strerror(errno)); - return ret; - } - } - pathpiece = strtok(NULL, "/"); - } - } else { - ret = mkdir(argv[0], 0777); - if(ret < 0) { - fprintf(stderr, "mkdir failed for %s, %s\n", argv[0], strerror(errno)); - return ret; - } - } - } - - return 0; -} diff --git a/toolbox/mknod.c b/toolbox/mknod.c deleted file mode 100644 index 0fedece..0000000 --- a/toolbox/mknod.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2014, The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/stat.h> - -static int print_usage() { - fprintf(stderr, "mknod <path> [b|c|u|p] <major> <minor>\n"); - return EXIT_FAILURE; -} - -int mknod_main(int argc, char **argv) { - char *path = NULL; - int major = 0; - int minor = 0; - int args = 0; - mode_t mode = 0660; - - /* Check correct argument count is 3 or 5 */ - if (argc != 3 && argc != 5) { - fprintf(stderr, "Incorrect argument count\n"); - return print_usage(); - } - - path = argv[1]; - - const char node_type = *argv[2]; - switch (node_type) { - case 'b': - mode |= S_IFBLK; - args = 5; - break; - case 'c': - case 'u': - mode |= S_IFCHR; - args = 5; - break; - case 'p': - mode |= S_IFIFO; - args = 3; - break; - default: - fprintf(stderr, "Invalid node type '%c'\n", node_type); - return print_usage(); - } - - if (argc != args) { - if (args == 5) { - fprintf(stderr, "Node type '%c' requires <major> and <minor>\n", node_type); - } else { - fprintf(stderr, "Node type '%c' does not require <major> and <minor>\n", node_type); - } - return print_usage(); - } - - if (args == 5) { - major = atoi(argv[3]); - minor = atoi(argv[4]); - } - - if (mknod(path, mode, makedev(major, minor))) { - perror("Unable to create node"); - return EXIT_FAILURE; - } - return 0; -} diff --git a/toolbox/mkswap.c b/toolbox/mkswap.c deleted file mode 100644 index 0904152..0000000 --- a/toolbox/mkswap.c +++ /dev/null @@ -1,93 +0,0 @@ -#include <stdio.h> -#include <unistd.h> -#include <sys/swap.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -/* XXX This needs to be obtained from kernel headers. See b/9336527 */ -struct linux_swap_header { - char bootbits[1024]; /* Space for disklabel etc. */ - uint32_t version; - uint32_t last_page; - uint32_t nr_badpages; - unsigned char sws_uuid[16]; - unsigned char sws_volume[16]; - uint32_t padding[117]; - uint32_t badpages[1]; -}; - -#define MAGIC_SWAP_HEADER "SWAPSPACE2" -#define MAGIC_SWAP_HEADER_LEN 10 -#define MIN_PAGES 10 - -int mkswap_main(int argc, char **argv) -{ - int err = 0; - int fd; - ssize_t len; - off_t swap_size; - int pagesize; - struct linux_swap_header sw_hdr; - - if (argc != 2) { - fprintf(stderr, "Usage: %s <filename>\n", argv[0]); - return -EINVAL; - } - - fd = open(argv[1], O_WRONLY); - if (fd < 0) { - err = errno; - fprintf(stderr, "Cannot open %s\n", argv[1]); - return err; - } - - pagesize = getpagesize(); - /* Determine the length of the swap file */ - swap_size = lseek(fd, 0, SEEK_END); - if (swap_size < MIN_PAGES * pagesize) { - fprintf(stderr, "Swap file needs to be at least %dkB\n", - (MIN_PAGES * pagesize) >> 10); - err = -ENOSPC; - goto err; - } - if (lseek(fd, 0, SEEK_SET)) { - err = errno; - fprintf(stderr, "Can't seek to the beginning of the file\n"); - goto err; - } - - memset(&sw_hdr, 0, sizeof(sw_hdr)); - sw_hdr.version = 1; - sw_hdr.last_page = (swap_size / pagesize) - 1; - - len = write(fd, &sw_hdr, sizeof(sw_hdr)); - if (len != sizeof(sw_hdr)) { - err = errno; - fprintf(stderr, "Failed to write swap header into %s\n", argv[1]); - goto err; - } - - /* Write the magic header */ - if (lseek(fd, pagesize - MAGIC_SWAP_HEADER_LEN, SEEK_SET) < 0) { - err = errno; - fprintf(stderr, "Failed to seek into %s\n", argv[1]); - goto err; - } - - len = write(fd, MAGIC_SWAP_HEADER, MAGIC_SWAP_HEADER_LEN); - if (len != MAGIC_SWAP_HEADER_LEN) { - err = errno; - fprintf(stderr, "Failed to write magic swap header into %s\n", argv[1]); - goto err; - } - - if (fsync(fd) < 0) { - err = errno; - fprintf(stderr, "Failed to sync %s\n", argv[1]); - goto err; - } -err: - close(fd); - return err; -} diff --git a/toolbox/netstat.c b/toolbox/netstat.c deleted file mode 100644 index 05dc640..0000000 --- a/toolbox/netstat.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2008, The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <arpa/inet.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/socket.h> -#include <sys/types.h> - -typedef union iaddr iaddr; -typedef union iaddr6 iaddr6; - -union iaddr { - unsigned u; - unsigned char b[4]; -}; - -union iaddr6 { - struct { - unsigned a; - unsigned b; - unsigned c; - unsigned d; - } u; - unsigned char b[16]; -}; - -static const char *state2str(unsigned state) -{ - switch(state){ - case 0x1: return "ESTABLISHED"; - case 0x2: return "SYN_SENT"; - case 0x3: return "SYN_RECV"; - case 0x4: return "FIN_WAIT1"; - case 0x5: return "FIN_WAIT2"; - case 0x6: return "TIME_WAIT"; - case 0x7: return "CLOSE"; - case 0x8: return "CLOSE_WAIT"; - case 0x9: return "LAST_ACK"; - case 0xA: return "LISTEN"; - case 0xB: return "CLOSING"; - default: return "UNKNOWN"; - } -} - -/* addr + : + port + \0 */ -#define ADDR_LEN INET6_ADDRSTRLEN + 1 + 5 + 1 - -static void addr2str(int af, const void *addr, unsigned port, char *buf) -{ - if (inet_ntop(af, addr, buf, ADDR_LEN) == NULL) { - *buf = '\0'; - return; - } - size_t len = strlen(buf); - if (port) { - snprintf(buf+len, ADDR_LEN-len, ":%d", port); - } else { - strncat(buf+len, ":*", ADDR_LEN-len-1); - } -} - -static void ipv4(const char *filename, const char *label) { - FILE *fp = fopen(filename, "r"); - if (fp == NULL) { - return; - } - char buf[BUFSIZ]; - fgets(buf, BUFSIZ, fp); - while (fgets(buf, BUFSIZ, fp)){ - char lip[ADDR_LEN]; - char rip[ADDR_LEN]; - iaddr laddr, raddr; - unsigned lport, rport, state, txq, rxq, num; - int n = sscanf(buf, " %d: %x:%x %x:%x %x %x:%x", - &num, &laddr.u, &lport, &raddr.u, &rport, - &state, &txq, &rxq); - if (n == 8) { - addr2str(AF_INET, &laddr, lport, lip); - addr2str(AF_INET, &raddr, rport, rip); - - printf("%4s %6d %6d %-22s %-22s %s\n", - label, rxq, txq, lip, rip, - state2str(state)); - } - } - fclose(fp); -} - -static void ipv6(const char *filename, const char *label) { - FILE *fp = fopen(filename, "r"); - if (fp == NULL) { - return; - } - char buf[BUFSIZ]; - fgets(buf, BUFSIZ, fp); - while (fgets(buf, BUFSIZ, fp)){ - char lip[ADDR_LEN]; - char rip[ADDR_LEN]; - iaddr6 laddr6, raddr6; - unsigned lport, rport, state, txq, rxq, num; - int n = sscanf(buf, " %d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %x:%x", - &num, &laddr6.u.a, &laddr6.u.b, &laddr6.u.c, &laddr6.u.d, &lport, - &raddr6.u.a, &raddr6.u.b, &raddr6.u.c, &raddr6.u.d, &rport, - &state, &txq, &rxq); - if (n == 14) { - addr2str(AF_INET6, &laddr6, lport, lip); - addr2str(AF_INET6, &raddr6, rport, rip); - - printf("%4s %6d %6d %-22s %-22s %s\n", - label, rxq, txq, lip, rip, - state2str(state)); - } - } - fclose(fp); -} - -int netstat_main(int argc, char *argv[]) -{ - printf("Proto Recv-Q Send-Q Local Address Foreign Address State\n"); - ipv4("/proc/net/tcp", "tcp"); - ipv4("/proc/net/udp", "udp"); - ipv6("/proc/net/tcp6", "tcp6"); - ipv6("/proc/net/udp6", "udp6"); - return 0; -} diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c index 01517fd..5b98a01 100644 --- a/toolbox/newfs_msdos.c +++ b/toolbox/newfs_msdos.c @@ -798,6 +798,7 @@ static void getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag,struct bpb *bpb) { struct hd_geometry geom; + u_long block_size; if (ioctl(fd, BLKSSZGET, &bpb->bps)) { fprintf(stderr, "Error getting bytes / sector (%s)\n", strerror(errno)); @@ -806,11 +807,18 @@ static void getdiskinfo(int fd, const char *fname, const char *dtype, ckgeom(fname, bpb->bps, "bytes/sector"); - if (ioctl(fd, BLKGETSIZE, &bpb->bsec)) { + if (ioctl(fd, BLKGETSIZE, &block_size)) { fprintf(stderr, "Error getting blocksize (%s)\n", strerror(errno)); exit(1); } + if (block_size > UINT32_MAX) { + fprintf(stderr, "Error blocksize too large: %lu\n", block_size); + exit(1); + } + + bpb->bsec = (u_int)block_size; + if (ioctl(fd, HDIO_GETGEO, &geom)) { fprintf(stderr, "Error getting gemoetry (%s) - trying sane values\n", strerror(errno)); geom.heads = 64; diff --git a/toolbox/nohup.c b/toolbox/nohup.c deleted file mode 100644 index 363999d..0000000 --- a/toolbox/nohup.c +++ /dev/null @@ -1,26 +0,0 @@ -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -int nohup_main(int argc, char *argv[]) -{ - if (argc < 2) { - fprintf(stderr, "Usage: %s [-n] program args...\n", argv[0]); - return EXIT_FAILURE; - } - signal(SIGHUP, SIG_IGN); - argv++; - if (strcmp(argv[0], "-n") == 0) { - argv++; - signal(SIGINT, SIG_IGN); - signal(SIGSTOP, SIG_IGN); - signal(SIGTTIN, SIG_IGN); - signal(SIGTTOU, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - signal(SIGTERM, SIG_IGN); - } - execvp(argv[0], argv); - perror(argv[0]); - return EXIT_FAILURE; -} diff --git a/toolbox/notify.c b/toolbox/notify.c deleted file mode 100644 index c983ed5..0000000 --- a/toolbox/notify.c +++ /dev/null @@ -1,145 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdint.h> -#include <fcntl.h> -#include <unistd.h> -#include <sys/ioctl.h> -#include <sys/inotify.h> -#include <errno.h> - -int notify_main(int argc, char *argv[]) -{ - int c; - int nfd, ffd; - int res; - char event_buf[512]; - struct inotify_event *event; - int event_mask = IN_ALL_EVENTS; - int event_count = 1; - int print_files = 0; - int verbose = 2; - int width = 80; - char **file_names; - int file_count; - int id_offset = 0; - int i; - char *buf; - - do { - c = getopt(argc, argv, "m:c:pv:w:"); - if (c == EOF) - break; - switch (c) { - case 'm': - event_mask = strtol(optarg, NULL, 0); - break; - case 'c': - event_count = atoi(optarg); - break; - case 'p': - print_files = 1; - break; - case 'v': - verbose = atoi(optarg); - break; - case 'w': - width = atoi(optarg); - break; - case '?': - fprintf(stderr, "%s: invalid option -%c\n", - argv[0], optopt); - exit(1); - } - } while (1); - - if (argc <= optind) { - fprintf(stderr, "Usage: %s [-m eventmask] [-c count] [-p] [-v verbosity] path [path ...]\n", argv[0]); - return 1; - } - - nfd = inotify_init(); - if(nfd < 0) { - fprintf(stderr, "inotify_init failed, %s\n", strerror(errno)); - return 1; - } - file_names = argv + optind; - file_count = argc - optind; - for(i = 0; i < file_count; i++) { - res = inotify_add_watch(nfd, file_names[i], event_mask); - if(res < 0) { - fprintf(stderr, "inotify_add_watch failed for %s, %s\n", file_names[i], strerror(errno)); - return 1; - } - if(i == 0) - id_offset = -res; - if(res + id_offset != i) { - fprintf(stderr, "%s got unexpected id %d instead of %d\n", file_names[i], res, i); - return 1; - } - } - - buf = malloc(width + 2); - - while(1) { - int event_pos = 0; - res = read(nfd, event_buf, sizeof(event_buf)); - if(res < (int)sizeof(*event)) { - if(errno == EINTR) - continue; - fprintf(stderr, "could not get event, %s\n", strerror(errno)); - return 1; - } - //printf("got %d bytes of event information\n", res); - while(res >= (int)sizeof(*event)) { - int event_size; - event = (struct inotify_event *)(event_buf + event_pos); - if(verbose >= 2) - printf("%s: %08x %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->cookie, event->len ? event->name : ""); - else if(verbose >= 2) - printf("%s: %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->len ? event->name : ""); - else if(verbose >= 1) - printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : ""); - if(print_files && (event->mask & IN_MODIFY)) { - char filename[512]; - ssize_t read_len; - char *display_name; - int buflen; - strcpy(filename, file_names[event->wd + id_offset]); - if(event->len) { - strcat(filename, "/"); - strcat(filename, event->name); - } - ffd = open(filename, O_RDONLY); - display_name = (verbose >= 2 || event->len == 0) ? filename : event->name; - buflen = width - strlen(display_name); - read_len = read(ffd, buf, buflen); - if(read_len > 0) { - if(read_len < buflen && buf[read_len-1] != '\n') { - buf[read_len] = '\n'; - read_len++; - } - if(read_len == buflen) { - buf[--read_len] = '\0'; - buf[--read_len] = '\n'; - buf[--read_len] = '.'; - buf[--read_len] = '.'; - buf[--read_len] = '.'; - } - else { - buf[read_len] = '\0'; - } - printf("%s: %s", display_name, buf); - } - close(ffd); - } - if(event_count && --event_count == 0) - return 0; - event_size = sizeof(*event) + event->len; - res -= event_size; - event_pos += event_size; - } - } - - return 0; -} diff --git a/toolbox/ps.c b/toolbox/ps.c index 5458f6b..cf3f05a 100644 --- a/toolbox/ps.c +++ b/toolbox/ps.c @@ -1,15 +1,14 @@ -#include <stdio.h> -#include <stdlib.h> #include <ctype.h> +#include <dirent.h> #include <fcntl.h> - +#include <inttypes.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> #include <string.h> - #include <sys/stat.h> #include <sys/types.h> -#include <dirent.h> - -#include <pwd.h> +#include <unistd.h> #include <cutils/sched_policy.h> @@ -31,7 +30,14 @@ static char *nexttok(char **strp) #define SHOW_NUMERIC_UID 32 #define SHOW_ABI 64 +#if __LP64__ +#define PC_WIDTH 10 /* Realistically, the top bits will be 0, so don't waste space. */ +#else +#define PC_WIDTH (2*sizeof(uintptr_t)) +#endif + static int display_flags = 0; +static int ppid_filter = 0; static void print_exe_abi(int pid); @@ -45,7 +51,8 @@ static int ps_line(int pid, int tid, char *namefilter) int fd, r; char *ptr, *name, *state; int ppid; - unsigned wchan, rss, vss, eip; + unsigned rss, vss; + uintptr_t eip; unsigned utime, stime; int prio, nice, rtprio, sched, psr; struct passwd *pw; @@ -125,7 +132,7 @@ static int ps_line(int pid, int tid, char *namefilter) nexttok(&ptr); // blocked nexttok(&ptr); // sigignore nexttok(&ptr); // sigcatch - wchan = strtoul(nexttok(&ptr), 0, 10); // wchan + nexttok(&ptr); // wchan nexttok(&ptr); // nswap nexttok(&ptr); // cnswap nexttok(&ptr); // exit signal @@ -147,7 +154,11 @@ static int ps_line(int pid, int tid, char *namefilter) strcpy(user,pw->pw_name); } - if(!namefilter || !strncmp(name, namefilter, strlen(namefilter))) { + if(ppid_filter != 0 && ppid != ppid_filter) { + return 0; + } + + if(!namefilter || !strncmp(cmdline[0] ? cmdline : name, namefilter, strlen(namefilter))) { if (display_flags & SHOW_MACLABEL) { fd = open(macline, O_RDONLY); strcpy(macline, "-"); @@ -173,7 +184,16 @@ static int ps_line(int pid, int tid, char *namefilter) else printf(" %.2s ", get_sched_policy_name(p)); } - printf(" %08x %08x %s ", wchan, eip, state); + char path[PATH_MAX]; + snprintf(path, sizeof(path), "/proc/%d/wchan", pid); + char wchan[10]; + int fd = open(path, O_RDONLY); + ssize_t wchan_len = read(fd, wchan, sizeof(wchan)); + if (wchan_len == -1) { + wchan[wchan_len = 0] = '\0'; + } + close(fd); + printf(" %10.*s %0*" PRIxPTR " %s ", (int) wchan_len, wchan, (int) PC_WIDTH, eip, state); if (display_flags & SHOW_ABI) { print_exe_abi(pid); } @@ -268,6 +288,10 @@ int ps_main(int argc, char **argv) display_flags |= SHOW_CPU; } else if(!strcmp(argv[1],"--abi")) { display_flags |= SHOW_ABI; + } else if(!strcmp(argv[1],"--ppid")) { + ppid_filter = atoi(argv[2]); + argc--; + argv++; } else if(isdigit(argv[1][0])){ pidfilter = atoi(argv[1]); } else { @@ -278,12 +302,13 @@ int ps_main(int argc, char **argv) } if (display_flags & SHOW_MACLABEL) { - printf("LABEL USER PID PPID NAME\n"); + printf("LABEL USER PID PPID NAME\n"); } else { - printf("USER PID PPID VSIZE RSS %s%s %s WCHAN PC %sNAME\n", + printf("USER PID PPID VSIZE RSS %s%s %sWCHAN %*s %sNAME\n", (display_flags&SHOW_CPU)?"CPU ":"", (display_flags&SHOW_PRIO)?"PRIO NICE RTPRI SCHED ":"", (display_flags&SHOW_POLICY)?"PCY " : "", + (int) PC_WIDTH, "PC", (display_flags&SHOW_ABI)?"ABI " : ""); } while((de = readdir(d)) != 0){ diff --git a/toolbox/pwcache.c b/toolbox/pwcache.c deleted file mode 100644 index 9d81981..0000000 --- a/toolbox/pwcache.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2014, The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <grp.h> -#include <pwd.h> -#include <stdio.h> -#include <sys/types.h> - -int uid_from_user(const char* name, uid_t* uid) { - struct passwd* pw = getpwnam(name); - if (pw == NULL) { - return -1; - } - *uid = pw->pw_uid; - return 0; -} - -char* group_from_gid(gid_t gid, int noname) { - struct group* g = getgrgid(gid); - if (g == NULL) { - static char buf[32]; - snprintf(buf, sizeof(buf), "%lu", (long) gid); - return noname ? NULL : buf; - } - return g->gr_name; -} - -char* user_from_uid(uid_t uid, int noname) { - struct passwd* pw = getpwuid(uid); - if (pw == NULL) { - static char buf[32]; - snprintf(buf, sizeof(buf), "%lu", (long) uid); - return noname ? NULL : buf; - } - return pw->pw_name; -} diff --git a/toolbox/r.c b/toolbox/r.c index 3b80db7..b96cdb2 100644 --- a/toolbox/r.c +++ b/toolbox/r.c @@ -5,6 +5,7 @@ #include <stdlib.h> #include <string.h> #include <sys/mman.h> +#include <unistd.h> #if __LP64__ #define strtoptr strtoull @@ -18,7 +19,7 @@ static int usage() return -1; } -int r_main(int argc, char *argv[]) +int main(int argc, char *argv[]) { if(argc < 2) return usage(); diff --git a/toolbox/readlink.c b/toolbox/readlink.c deleted file mode 100644 index d114e20..0000000 --- a/toolbox/readlink.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2013, The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -static int skip_newline, quiet_errors, canonicalize; - -static void usage(char* name) { - fprintf(stderr, "Usage: %s [OPTION]... FILE\n", name); -} - -int readlink_main(int argc, char* argv[]) { - int c; - while ((c = getopt(argc, argv, "nfqs")) != -1) { - switch (c) { - case 'n': - skip_newline = 1; - break; - case 'f': - canonicalize = 1; - break; - case 'q': - case 's': - quiet_errors = 1; - break; - case '?': - default: - usage(argv[0]); - return EXIT_FAILURE; - } - } - int index = optind; - if (argc - index != 1) { - usage(argv[0]); - return EXIT_FAILURE; - } - - char name[PATH_MAX+1]; - if (canonicalize) { - if(!realpath(argv[optind], name)) { - if (!quiet_errors) { - perror("readlink"); - } - return EXIT_FAILURE; - } - } else { - ssize_t len = readlink(argv[1], name, PATH_MAX); - - if (len < 0) { - if (!quiet_errors) { - perror("readlink"); - } - return EXIT_FAILURE; - } - name[len] = '\0'; - } - - fputs(name, stdout); - if (!skip_newline) { - fputs("\n", stdout); - } - - return EXIT_SUCCESS; -} diff --git a/toolbox/readtty.c b/toolbox/readtty.c deleted file mode 100644 index 2b27548..0000000 --- a/toolbox/readtty.c +++ /dev/null @@ -1,183 +0,0 @@ -#include <ctype.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/mman.h> -#include <fcntl.h> -#include <string.h> -#include <termios.h> -#include <unistd.h> - -struct { - char key; - char *chars; -} map[] = { - { '1', "_ -1?!,.:;\"'<=>()_" }, - { '2', "Cabc2ABC" }, - { '3', "Fdef3DEF" }, - { '4', "Ighi4GHI" }, - { '5', "Ljkl5JKL" }, - { '6', "Omno6MNO" }, - { '7', "Spqrs7PQRS" }, - { '8', "Vtuv8TUV" }, - { '9', "Zwxyz9WXYZ" }, - { '0', "*+&0@/#*" }, -}; - -char next_char(char key, char current) -{ - int i; - char *next; - for(i = 0; i < sizeof(map) / sizeof(map[0]); i++) { - if(key == map[i].key) { - next = strchr(map[i].chars, current); - if(next && next[1]) - return next[1]; - return map[i].chars[1]; - } - } - return key; -} - -char prev_char(char key, char current) -{ - int i; - char *next; - for(i = 0; i < sizeof(map) / sizeof(map[0]); i++) { - if(key == map[i].key) { - next = strchr(map[i].chars+1, current); - if(next && next[-1]) - return next[-1]; - return map[i].chars[1]; - } - } - return key; -} - -int readtty_main(int argc, char *argv[]) -{ - int c; - //int flags; - char buf[1]; - int res; - struct termios ttyarg; - struct termios savedttyarg; - int nonblock = 0; - int timeout = 0; - int flush = 0; - int phone = 0; - char *accept = NULL; - char *rejectstring = NULL; - char last_char_in = 0; - char current_char = 0; - char *exit_string = NULL; - int exit_match = 0; - - do { - c = getopt(argc, argv, "nt:fa:r:pe:"); - if (c == EOF) - break; - switch (c) { - case 't': - timeout = atoi(optarg); - break; - case 'n': - nonblock = 1; - break; - case 'f': - flush = 1; - break; - case 'a': - accept = optarg; - break; - case 'r': - rejectstring = optarg; - break; - case 'p': - phone = 1; - break; - case 'e': - exit_string = optarg; - break; - case '?': - fprintf(stderr, "%s: invalid option -%c\n", - argv[0], optopt); - exit(1); - } - } while (1); - - if(flush) - tcflush(STDIN_FILENO, TCIFLUSH); - ioctl(STDIN_FILENO, TCGETS , &savedttyarg) ; /* set changed tty arguments */ - ttyarg = savedttyarg; - ttyarg.c_cc[VMIN] = (timeout > 0 || nonblock) ? 0 : 1; /* minimum of 0 chars */ - ttyarg.c_cc[VTIME] = timeout; /* wait max 15/10 sec */ - ttyarg.c_iflag = BRKINT | ICRNL; - ttyarg.c_lflag &= ~(ECHO | ICANON); - ioctl(STDIN_FILENO, TCSETS , &ttyarg); - - while (1) { - res = read(STDIN_FILENO, buf, 1); - if(res <= 0) { - if(phone) { - if(current_char) { - write(STDERR_FILENO, ¤t_char, 1); - write(STDOUT_FILENO, ¤t_char, 1); - if(exit_string && current_char == exit_string[exit_match]) { - exit_match++; - if(exit_string[exit_match] == '\0') - break; - } - else - exit_match = 0; - current_char = 0; - } - continue; - } - break; - } - if(accept && strchr(accept, buf[0]) == NULL) { - if(rejectstring) { - write(STDOUT_FILENO, rejectstring, strlen(rejectstring)); - break; - } - if(flush) - tcflush(STDIN_FILENO, TCIFLUSH); - continue; - } - if(phone) { - //if(!isprint(buf[0])) { - // fprintf(stderr, "got unprintable character 0x%x\n", buf[0]); - //} - if(buf[0] == '\0') { - if(current_char) { - current_char = prev_char(last_char_in, current_char); - write(STDERR_FILENO, ¤t_char, 1); - write(STDERR_FILENO, "\b", 1); - } - continue; - } - if(current_char && buf[0] != last_char_in) { - write(STDERR_FILENO, ¤t_char, 1); - write(STDOUT_FILENO, ¤t_char, 1); - if(exit_string && current_char == exit_string[exit_match]) { - exit_match++; - if(exit_string[exit_match] == '\0') - break; - } - else - exit_match = 0; - current_char = 0; - } - last_char_in = buf[0]; - current_char = next_char(last_char_in, current_char); - write(STDERR_FILENO, ¤t_char, 1); - write(STDERR_FILENO, "\b", 1); - continue; - } - write(STDOUT_FILENO, buf, 1); - break; - } - ioctl(STDIN_FILENO, TCSETS , &savedttyarg) ; /* set changed tty arguments */ - - return 0; -} diff --git a/toolbox/renice.c b/toolbox/renice.c index 9dfeb51..99a06f4 100644 --- a/toolbox/renice.c +++ b/toolbox/renice.c @@ -32,6 +32,7 @@ #include <stdio.h> #include <unistd.h> #include <stdlib.h> +#include <string.h> #include <sys/time.h> #include <sys/resource.h> #include <sched.h> diff --git a/toolbox/restorecon.c b/toolbox/restorecon.c deleted file mode 100644 index 3568625..0000000 --- a/toolbox/restorecon.c +++ /dev/null @@ -1,62 +0,0 @@ -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <selinux/selinux.h> -#include <selinux/android.h> - -static const char *progname; - -static void usage(void) -{ - fprintf(stderr, "usage: %s [-DFnrRv] pathname...\n", progname); - exit(1); -} - -int restorecon_main(int argc, char **argv) -{ - int ch, i, rc; - unsigned int flags = 0; - - progname = argv[0]; - - do { - ch = getopt(argc, argv, "DFnrRv"); - if (ch == EOF) - break; - switch (ch) { - case 'D': - flags |= SELINUX_ANDROID_RESTORECON_DATADATA; - break; - case 'F': - flags |= SELINUX_ANDROID_RESTORECON_FORCE; - break; - case 'n': - flags |= SELINUX_ANDROID_RESTORECON_NOCHANGE; - break; - case 'r': - case 'R': - flags |= SELINUX_ANDROID_RESTORECON_RECURSE; - break; - case 'v': - flags |= SELINUX_ANDROID_RESTORECON_VERBOSE; - break; - default: - usage(); - } - } while (1); - - argc -= optind; - argv += optind; - if (!argc) - usage(); - - for (i = 0; i < argc; i++) { - rc = selinux_android_restorecon(argv[i], flags); - if (rc < 0) - fprintf(stderr, "Could not restorecon %s: %s\n", argv[i], - strerror(errno)); - } - - return 0; -} diff --git a/toolbox/rmmod.c b/toolbox/rmmod.c deleted file mode 100644 index c7e0d6a..0000000 --- a/toolbox/rmmod.c +++ /dev/null @@ -1,53 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <unistd.h> -#include <malloc.h> -#include <errno.h> -#include <asm/unistd.h> - -extern int delete_module(const char *, unsigned int); - -int rmmod_main(int argc, char **argv) -{ - int ret, i; - char *modname, *dot; - - /* make sure we've got an argument */ - if (argc < 2) { - fprintf(stderr, "usage: rmmod <module>\n"); - return -1; - } - - /* if given /foo/bar/blah.ko, make a weak attempt - * to convert to "blah", just for convenience - */ - modname = strrchr(argv[1], '/'); - if (!modname) - modname = argv[1]; - else modname++; - - dot = strchr(argv[1], '.'); - if (dot) - *dot = '\0'; - - /* Replace "-" with "_". This would keep rmmod - * compatible with module-init-tools version of - * rmmod - */ - for (i = 0; modname[i] != '\0'; i++) { - if (modname[i] == '-') - modname[i] = '_'; - } - - /* pass it to the kernel */ - ret = delete_module(modname, O_NONBLOCK | O_EXCL); - if (ret != 0) { - fprintf(stderr, "rmmod: delete_module '%s' failed (errno %d)\n", - modname, errno); - return -1; - } - - return 0; -} - diff --git a/toolbox/rotatefb.c b/toolbox/rotatefb.c deleted file mode 100644 index 2ff4127..0000000 --- a/toolbox/rotatefb.c +++ /dev/null @@ -1,71 +0,0 @@ -#include <ctype.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/mman.h> -#include <fcntl.h> -#include <string.h> -#include <termios.h> -#include <unistd.h> -#include <errno.h> -#include <linux/fb.h> - - -int rotatefb_main(int argc, char *argv[]) -{ - int c; - char *fbdev = "/dev/graphics/fb0"; - int rotation = 0; - int fd; - int res; - struct fb_var_screeninfo fbinfo; - - do { - c = getopt(argc, argv, "d:"); - if (c == EOF) - break; - switch (c) { - case 'd': - fbdev = optarg; - break; - case '?': - fprintf(stderr, "%s: invalid option -%c\n", - argv[0], optopt); - exit(1); - } - } while (1); - - if(optind + 1 != argc) { - fprintf(stderr, "%s: specify rotation\n", argv[0]); - exit(1); - } - rotation = atoi(argv[optind]); - - fd = open(fbdev, O_RDWR); - if(fd < 0) { - fprintf(stderr, "cannot open %s\n", fbdev); - return 1; - } - - res = ioctl(fd, FBIOGET_VSCREENINFO, &fbinfo); - if(res < 0) { - fprintf(stderr, "failed to get fbinfo: %s\n", strerror(errno)); - return 1; - } - if((fbinfo.rotate ^ rotation) & 1) { - unsigned int xres = fbinfo.yres; - fbinfo.yres = fbinfo.xres; - fbinfo.xres = xres; - fbinfo.xres_virtual = fbinfo.xres; - fbinfo.yres_virtual = fbinfo.yres * 2; - if(fbinfo.yoffset == xres) - fbinfo.yoffset = fbinfo.yres; - } - fbinfo.rotate = rotation; - res = ioctl(fd, FBIOPUT_VSCREENINFO, &fbinfo); - if(res < 0) { - fprintf(stderr, "failed to set fbinfo: %s\n", strerror(errno)); - return 1; - } - - return 0; -} diff --git a/toolbox/route.c b/toolbox/route.c deleted file mode 100644 index 3e10014..0000000 --- a/toolbox/route.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2009, The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <linux/route.h> - -static inline int set_address(const char *address, struct sockaddr *sa) { - return inet_aton(address, &((struct sockaddr_in *)sa)->sin_addr); -} - -/* current support the following routing entries */ -/* route add default dev wlan0 */ -/* route add default gw 192.168.1.1 dev wlan0 */ -/* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */ - -int route_main(int argc, char *argv[]) -{ - struct rtentry rt = { - .rt_dst = {.sa_family = AF_INET}, - .rt_genmask = {.sa_family = AF_INET}, - .rt_gateway = {.sa_family = AF_INET}, - }; - - errno = EINVAL; - if (argc > 2 && !strcmp(argv[1], "add")) { - if (!strcmp(argv[2], "default")) { - /* route add default dev wlan0 */ - if (argc > 4 && !strcmp(argv[3], "dev")) { - rt.rt_flags = RTF_UP; - rt.rt_dev = argv[4]; - errno = 0; - goto apply; - } - - /* route add default gw 192.168.1.1 dev wlan0 */ - if (argc > 6 && !strcmp(argv[3], "gw") && !strcmp(argv[5], "dev")) { - rt.rt_flags = RTF_UP | RTF_GATEWAY; - rt.rt_dev = argv[6]; - if (set_address(argv[4], &rt.rt_gateway)) { - errno = 0; - } - goto apply; - } - } - - /* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */ - if (argc > 7 && !strcmp(argv[2], "-net") && - !strcmp(argv[4], "netmask")) { - if (!strcmp(argv[6], "gw")) { - rt.rt_flags = RTF_UP | RTF_GATEWAY; - if (set_address(argv[3], &rt.rt_dst) && - set_address(argv[5], &rt.rt_genmask) && - set_address(argv[7], &rt.rt_gateway)) { - errno = 0; - } - goto apply; - } else if (!strcmp(argv[6], "dev")) { - rt.rt_flags = RTF_UP; - rt.rt_dev = argv[7]; - if (set_address(argv[3], &rt.rt_dst) && - set_address(argv[5], &rt.rt_genmask)) { - errno = 0; - } - goto apply; - } - } - } - -apply: - if (!errno) { - int s = socket(AF_INET, SOCK_DGRAM, 0); - if (s != -1 && (ioctl(s, SIOCADDRT, &rt) != -1 || errno == EEXIST)) { - return 0; - } - } - puts(strerror(errno)); - return errno; -} diff --git a/toolbox/runcon.c b/toolbox/runcon.c deleted file mode 100644 index 4a57bf3..0000000 --- a/toolbox/runcon.c +++ /dev/null @@ -1,28 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <selinux/selinux.h> - -int runcon_main(int argc, char **argv) -{ - int rc; - - if (argc < 3) { - fprintf(stderr, "usage: %s context program args...\n", argv[0]); - exit(1); - } - - rc = setexeccon(argv[1]); - if (rc < 0) { - fprintf(stderr, "Could not set context to %s: %s\n", argv[1], strerror(errno)); - exit(2); - } - - argv += 2; - argc -= 2; - execvp(argv[0], argv); - fprintf(stderr, "Could not exec %s: %s\n", argv[0], strerror(errno)); - exit(3); -} diff --git a/toolbox/schedtop.c b/toolbox/schedtop.c deleted file mode 100644 index 2fccd2e..0000000 --- a/toolbox/schedtop.c +++ /dev/null @@ -1,330 +0,0 @@ -#include <ctype.h> -#include <dirent.h> -#include <fcntl.h> -#include <pwd.h> -#include <signal.h> -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -struct thread_info { - int pid; - int tid; - char name[64]; - unsigned long long exec_time; - unsigned long long delay_time; - unsigned long long run_count; -}; - -struct thread_table { - size_t allocated; - size_t active; - struct thread_info *data; -}; - -enum { - FLAG_BATCH = 1U << 0, - FLAG_HIDE_IDLE = 1U << 1, - FLAG_SHOW_THREADS = 1U << 2, - FLAG_USE_ALTERNATE_SCREEN = 1U << 3, -}; - -static int time_dp = 9; -static int time_div = 1; -#define NS_TO_S_D(ns) \ - (uint32_t)((ns) / 1000000000), time_dp, ((uint32_t)((ns) % 1000000000) / time_div) - -struct thread_table processes; -struct thread_table last_processes; -struct thread_table threads; -struct thread_table last_threads; - -static void grow_table(struct thread_table *table) -{ - size_t size = table->allocated; - struct thread_info *new_table; - if (size < 128) - size = 128; - else - size *= 2; - - new_table = realloc(table->data, size * sizeof(*table->data)); - if (new_table == NULL) { - fprintf(stderr, "out of memory\n"); - exit(1); - } - table->data = new_table; - table->allocated = size; -} - -static struct thread_info *get_item(struct thread_table *table) -{ - if (table->active >= table->allocated) - grow_table(table); - return table->data + table->active; -} - -static void commit_item(struct thread_table *table) -{ - table->active++; -} - -static int read_line(char *line, size_t line_size) -{ - int fd; - int len; - fd = open(line, O_RDONLY); - if(fd == 0) - return -1; - len = read(fd, line, line_size - 1); - close(fd); - if (len <= 0) - return -1; - line[len] = '\0'; - return 0; -} - -static void add_thread(int pid, int tid, struct thread_info *proc_info) -{ - char line[1024]; - char *name, *name_end; - size_t name_len; - struct thread_info *info; - if(tid == 0) - info = get_item(&processes); - else - info = get_item(&threads); - info->pid = pid; - info->tid = tid; - - if(tid) - sprintf(line, "/proc/%d/task/%d/schedstat", pid, tid); - else - sprintf(line, "/proc/%d/schedstat", pid); - if (read_line(line, sizeof(line))) - return; - if(sscanf(line, "%llu %llu %llu", - &info->exec_time, &info->delay_time, &info->run_count) != 3) - return; - if (proc_info) { - proc_info->exec_time += info->exec_time; - proc_info->delay_time += info->delay_time; - proc_info->run_count += info->run_count; - } - - name = NULL; - if (!tid) { - sprintf(line, "/proc/%d/cmdline", pid); - if (read_line(line, sizeof(line)) == 0 && line[0]) { - name = line; - name_len = strlen(name); - } - } - if (!name) { - if (tid) - sprintf(line, "/proc/%d/task/%d/stat", pid, tid); - else - sprintf(line, "/proc/%d/stat", pid); - if (read_line(line, sizeof(line))) - return; - name = strchr(line, '('); - if (name == NULL) - return; - name_end = strchr(name, ')'); - if (name_end == NULL) - return; - name++; - name_len = name_end - name; - } - if (name_len >= sizeof(info->name)) - name_len = sizeof(info->name) - 1; - memcpy(info->name, name, name_len); - info->name[name_len] = '\0'; - if(tid == 0) - commit_item(&processes); - else - commit_item(&threads); -} - -static void add_threads(int pid, struct thread_info *proc_info) -{ - char path[1024]; - DIR *d; - struct dirent *de; - sprintf(path, "/proc/%d/task", pid); - d = opendir(path); - if(d == 0) return; - while((de = readdir(d)) != 0){ - if(isdigit(de->d_name[0])){ - int tid = atoi(de->d_name); - add_thread(pid, tid, proc_info); - } - } - closedir(d); -} - -static void print_threads(int pid, uint32_t flags) -{ - size_t i, j; - for (i = 0; i < last_threads.active; i++) { - int epid = last_threads.data[i].pid; - int tid = last_threads.data[i].tid; - if (epid != pid) - continue; - for (j = 0; j < threads.active; j++) - if (tid == threads.data[j].tid) - break; - if (j == threads.active) - printf(" %5u died\n", tid); - else if (!(flags & FLAG_HIDE_IDLE) || threads.data[j].run_count - last_threads.data[i].run_count) - printf(" %5u %2u.%0*u %2u.%0*u %5llu %5u.%0*u %5u.%0*u %7llu %s\n", tid, - NS_TO_S_D(threads.data[j].exec_time - last_threads.data[i].exec_time), - NS_TO_S_D(threads.data[j].delay_time - last_threads.data[i].delay_time), - threads.data[j].run_count - last_threads.data[i].run_count, - NS_TO_S_D(threads.data[j].exec_time), NS_TO_S_D(threads.data[j].delay_time), - threads.data[j].run_count, threads.data[j].name); - } -} - -static void update_table(DIR *d, uint32_t flags) -{ - size_t i, j; - struct dirent *de; - - rewinddir(d); - while((de = readdir(d)) != 0){ - if(isdigit(de->d_name[0])){ - int pid = atoi(de->d_name); - struct thread_info *proc_info; - add_thread(pid, 0, NULL); - proc_info = &processes.data[processes.active - 1]; - proc_info->exec_time = 0; - proc_info->delay_time = 0; - proc_info->run_count = 0; - add_threads(pid, proc_info); - } - } - if (!(flags & FLAG_BATCH)) - printf("\e[H\e[0J"); - printf("Processes: %zu, Threads %zu\n", processes.active, threads.active); - switch (time_dp) { - case 3: - printf(" TID --- SINCE LAST ---- ---------- TOTAL ----------\n"); - printf(" PID EXEC_T DELAY SCHED EXEC_TIME DELAY_TIM SCHED NAME\n"); - break; - case 6: - printf(" TID ------ SINCE LAST ------- ------------ TOTAL -----------\n"); - printf(" PID EXEC_TIME DELAY_TIM SCHED EXEC_TIME DELAY_TIME SCHED NAME\n"); - break; - default: - printf(" TID -------- SINCE LAST -------- ------------- TOTAL -------------\n"); - printf(" PID EXEC_TIME DELAY_TIME SCHED EXEC_TIME DELAY_TIME SCHED NAME\n"); - break; - } - for (i = 0; i < last_processes.active; i++) { - int pid = last_processes.data[i].pid; - for (j = 0; j < processes.active; j++) - if (pid == processes.data[j].pid) - break; - if (j == processes.active) - printf("%5u died\n", pid); - else if (!(flags & FLAG_HIDE_IDLE) || processes.data[j].run_count - last_processes.data[i].run_count) { - printf("%5u %2u.%0*u %2u.%0*u %5llu %5u.%0*u %5u.%0*u %7llu %s\n", pid, - NS_TO_S_D(processes.data[j].exec_time - last_processes.data[i].exec_time), - NS_TO_S_D(processes.data[j].delay_time - last_processes.data[i].delay_time), - processes.data[j].run_count - last_processes.data[i].run_count, - NS_TO_S_D(processes.data[j].exec_time), NS_TO_S_D(processes.data[j].delay_time), - processes.data[j].run_count, processes.data[j].name); - if (flags & FLAG_SHOW_THREADS) - print_threads(pid, flags); - } - } - - { - struct thread_table tmp; - tmp = last_processes; - last_processes = processes; - processes = tmp; - processes.active = 0; - tmp = last_threads; - last_threads = threads; - threads = tmp; - threads.active = 0; - } -} - -void -sig_abort(int signum) -{ - printf("\e[?47l"); - exit(0); -} - - -int schedtop_main(int argc, char **argv) -{ - int c; - DIR *d; - uint32_t flags = 0; - int delay = 3000000; - float delay_f; - - while(1) { - c = getopt(argc, argv, "d:ibtamun"); - if (c == EOF) - break; - switch (c) { - case 'd': - delay_f = atof(optarg); - delay = delay_f * 1000000; - break; - case 'b': - flags |= FLAG_BATCH; - break; - case 'i': - flags |= FLAG_HIDE_IDLE; - break; - case 't': - flags |= FLAG_SHOW_THREADS; - break; - case 'a': - flags |= FLAG_USE_ALTERNATE_SCREEN; - break; - case 'm': - time_dp = 3; - time_div = 1000000; - break; - case 'u': - time_dp = 6; - time_div = 1000; - break; - case 'n': - time_dp = 9; - time_div = 1; - break; - } - } - - d = opendir("/proc"); - if(d == 0) return -1; - - if (!(flags & FLAG_BATCH)) { - if(flags & FLAG_USE_ALTERNATE_SCREEN) { - signal(SIGINT, sig_abort); - signal(SIGPIPE, sig_abort); - signal(SIGTERM, sig_abort); - printf("\e7\e[?47h"); - } - printf("\e[2J"); - } - while (1) { - update_table(d, flags); - usleep(delay); - } - closedir(d); - return 0; -} diff --git a/toolbox/sendevent.c b/toolbox/sendevent.c index 9b813f6..4d0ca17 100644 --- a/toolbox/sendevent.c +++ b/toolbox/sendevent.c @@ -1,49 +1,12 @@ +#include <errno.h> +#include <fcntl.h> +#include <linux/input.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <stdint.h> -#include <fcntl.h> #include <sys/ioctl.h> -//#include <linux/input.h> // this does not compile -#include <errno.h> - - -// from <linux/input.h> - -struct input_event { - struct timeval time; - __u16 type; - __u16 code; - __s32 value; -}; - -#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ -#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ -#define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */ -#define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */ - -#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ -#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ -#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */ - -#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */ -#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */ -#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */ -#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */ - -#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */ -#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */ -#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */ - -#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */ -#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */ -#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */ - -#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ - -// end <linux/input.h> - - +#include <unistd.h> int sendevent_main(int argc, char *argv[]) { diff --git a/toolbox/setenforce.c b/toolbox/setenforce.c deleted file mode 100644 index 444073d..0000000 --- a/toolbox/setenforce.c +++ /dev/null @@ -1,44 +0,0 @@ -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <string.h> -#include <strings.h> -#include <errno.h> -#include <selinux/selinux.h> - -static void usage(const char *progname) -{ - fprintf(stderr, "usage: %s [ Enforcing | Permissive | 1 | 0 ]\n", - progname); - exit(1); -} - -int setenforce_main(int argc, char **argv) -{ - int rc = 0; - if (argc != 2) { - usage(argv[0]); - } - - if (is_selinux_enabled() <= 0) { - fprintf(stderr, "%s: SELinux is disabled\n", argv[0]); - return 1; - } - if (strlen(argv[1]) == 1 && (argv[1][0] == '0' || argv[1][0] == '1')) { - rc = security_setenforce(atoi(argv[1])); - } else { - if (strcasecmp(argv[1], "enforcing") == 0) { - rc = security_setenforce(1); - } else if (strcasecmp(argv[1], "permissive") == 0) { - rc = security_setenforce(0); - } else - usage(argv[0]); - } - if (rc < 0) { - fprintf(stderr, "%s: Could not set enforcing status: %s\n", - argv[0], strerror(errno)); - return 2; - } - return 0; -} diff --git a/toolbox/setkey.c b/toolbox/setkey.c deleted file mode 100644 index 1ff2774..0000000 --- a/toolbox/setkey.c +++ /dev/null @@ -1,89 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> -#include <string.h> -#include <linux/kd.h> -#include <linux/vt.h> -#include <errno.h> - -static void setkey_usage(char *argv[]) -{ - fprintf(stderr, "%s [-t <table>] [-k <index>] [-v value] [-r] [-h]\n" - " -t <table> Select table\n" - " -k <index> Select key\n" - " -v <value> Set entry\n" - " -r Read current entry\n" - " -h Print help\n", argv[0]); -} - -#define TTYDEV "/dev/tty0" - -int setkey_main(int argc, char *argv[]) -{ - int fd; - struct kbentry kbe; - int did_something = 0; - - kbe.kb_table = 0; - kbe.kb_index = -1; - kbe.kb_value = 0; - - fd = open(TTYDEV, O_RDWR | O_SYNC); - if (fd < 0) { - fprintf(stderr, "open %s: %s\n", TTYDEV, strerror(errno)); - return 1; - } - - do { - int c, ret; - - c = getopt(argc, argv, "t:k:v:hr"); - if (c == EOF) - break; - - switch (c) { - case 't': - kbe.kb_table = strtol(optarg, NULL, 0); - break; - case 'k': - kbe.kb_index = strtol(optarg, NULL, 0); - break; - case 'v': - kbe.kb_value = strtol(optarg, NULL, 0); - ret = ioctl(fd, KDSKBENT, &kbe); - if (ret < 0) { - fprintf(stderr, "KDSKBENT %d %d %d failed: %s\n", - kbe.kb_table, kbe.kb_index, kbe.kb_value, - strerror(errno)); - return 1; - } - did_something = 1; - break; - case 'r': - ret = ioctl(fd, KDGKBENT, &kbe); - if (ret < 0) { - fprintf(stderr, "KDGKBENT %d %d failed: %s\n", - kbe.kb_table, kbe.kb_index, strerror(errno)); - return 1; - } - printf("0x%x 0x%x 0x%x\n", - kbe.kb_table, kbe.kb_index, kbe.kb_value); - did_something = 1; - break; - case 'h': - setkey_usage(argv); - return 1; - case '?': - fprintf(stderr, "%s: invalid option -%c\n", - argv[0], optopt); - return 1; - } - } while (1); - - if(optind != argc || !did_something) { - setkey_usage(argv); - return 1; - } - - return 0; -} diff --git a/toolbox/setprop.c b/toolbox/setprop.c deleted file mode 100644 index 63ad2b4..0000000 --- a/toolbox/setprop.c +++ /dev/null @@ -1,18 +0,0 @@ -#include <stdio.h> - -#include <cutils/properties.h> - -int setprop_main(int argc, char *argv[]) -{ - if(argc != 3) { - fprintf(stderr,"usage: setprop <key> <value>\n"); - return 1; - } - - if(property_set(argv[1], argv[2])){ - fprintf(stderr,"could not set property\n"); - return 1; - } - - return 0; -} diff --git a/toolbox/setsebool.c b/toolbox/setsebool.c deleted file mode 100644 index f79a612..0000000 --- a/toolbox/setsebool.c +++ /dev/null @@ -1,46 +0,0 @@ -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <selinux/selinux.h> -#include <errno.h> - -static int do_setsebool(int nargs, char **args) { - const char *name = args[1]; - const char *value = args[2]; - SELboolean b; - - if (is_selinux_enabled() <= 0) - return 0; - - b.name = name; - if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on")) - b.value = 1; - else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off")) - b.value = 0; - else { - fprintf(stderr, "setsebool: invalid value %s\n", value); - return -1; - } - - if (security_set_boolean_list(1, &b, 0) < 0) - { - fprintf(stderr, "setsebool: could not set %s to %s: %s", name, value, strerror(errno)); - return -1; - } - - return 0; -} - -int setsebool_main(int argc, char **argv) -{ - if (argc != 3) { - fprintf(stderr, "Usage: %s name value\n", argv[0]); - exit(1); - } - - return do_setsebool(argc, argv); -} diff --git a/toolbox/smd.c b/toolbox/smd.c deleted file mode 100644 index 91e495c..0000000 --- a/toolbox/smd.c +++ /dev/null @@ -1,41 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <fcntl.h> -#include <errno.h> - -int smd_main(int argc, char **argv) -{ - int fd, len, r, port = 0; - char devname[32]; - argc--; - argv++; - - if((argc > 0) && (argv[0][0] == '-')) { - port = atoi(argv[0] + 1); - argc--; - argv++; - } - - sprintf(devname,"/dev/smd%d",port); - fd = open(devname, O_WRONLY); - if(fd < 0) { - fprintf(stderr,"failed to open smd0 - %s\n", - strerror(errno)); - return -1; - } - while(argc > 0) { - len = strlen(argv[0]); - r = write(fd, argv[0], len); - if(r != len) { - fprintf(stderr,"failed to write smd0 (%d) %s\n", - r, strerror(errno)); - return -1; - } - argc--; - argv++; - write(fd, argc ? " " : "\r", 1); - } - close(fd); - return 0; -} diff --git a/toolbox/swapoff.c b/toolbox/swapoff.c deleted file mode 100644 index d8f6a00..0000000 --- a/toolbox/swapoff.c +++ /dev/null @@ -1,20 +0,0 @@ -#include <stdio.h> -#include <unistd.h> -#include <sys/swap.h> - -int swapoff_main(int argc, char **argv) -{ - int err = 0; - - if (argc != 2) { - fprintf(stderr, "Usage: %s <filename>\n", argv[0]); - return -EINVAL; - } - - err = swapoff(argv[1]); - if (err) { - fprintf(stderr, "swapoff failed for %s\n", argv[1]); - } - - return err; -} diff --git a/toolbox/swapon.c b/toolbox/swapon.c deleted file mode 100644 index 150701a..0000000 --- a/toolbox/swapon.c +++ /dev/null @@ -1,66 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <getopt.h> -#include <sys/swap.h> - -static void usage(char *name) -{ - fprintf(stderr, "Usage: %s [-p prio] <filename>\n" - " prio must be between 0 and %d\n", name, SWAP_FLAG_PRIO_MASK); -} - -static int parse_prio(char *prio_str) -{ - unsigned long p = strtoul(prio_str, NULL, 10); - - return (p > SWAP_FLAG_PRIO_MASK)? -1 : (int)p; -} - -int swapon_main(int argc, char **argv) -{ - int err = 0; - int flags = 0; - int prio; - - opterr = 0; - do { - int c = getopt(argc, argv, "hp:"); - if (c == -1) - break; - - switch (c) { - case 'p': - if (optarg != NULL) - prio = parse_prio(optarg); - else - prio = -1; - - if (prio < 0) { - usage(argv[0]); - return -EINVAL; - } - flags |= SWAP_FLAG_PREFER; - flags |= (prio << SWAP_FLAG_PRIO_SHIFT) & SWAP_FLAG_PRIO_MASK; - break; - case 'h': - usage(argv[0]); - return 0; - case '?': - fprintf(stderr, "unknown option: %c\n", optopt); - return -EINVAL; - } - } while (1); - - if (optind != argc - 1) { - usage(argv[0]); - return -EINVAL; - } - - err = swapon(argv[argc - 1], flags); - if (err) { - fprintf(stderr, "swapon failed for %s\n", argv[argc - 1]); - } - - return err; -} diff --git a/toolbox/syren.c b/toolbox/syren.c deleted file mode 100644 index 47c2460..0000000 --- a/toolbox/syren.c +++ /dev/null @@ -1,158 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <malloc.h> - -/* ioctl crap */ -#define SYREN_RD 101 -#define SYREN_WR 102 -#define SYREN_OLD_RD 108 -#define SYREN_OLD_WR 109 - -struct syren_io_args { - unsigned long page; - unsigned long addr; - unsigned long value; -}; - -typedef struct { - u_char page; - u_char addr; - const char *name; -} syren_reg; - -static syren_reg registers[] = { - { 0, 0x04, "TOGBR1" }, - { 0, 0x05, "TOGBR2" }, - { 0, 0x06, "VBDCTRL" }, - { 1, 0x07, "VBUCTRL" }, - { 1, 0x08, "VBCTRL" }, - { 1, 0x09, "PWDNRG" }, - { 1, 0x0a, "VBPOP" }, - { 1, 0x0b, "VBCTRL2" }, - { 1, 0x0f, "VAUDCTRL" }, - { 1, 0x10, "VAUSCTRL" }, - { 1, 0x11, "VAUOCTRL" }, - { 1, 0x12, "VAUDPLL" }, - { 1, 0x17, "VRPCSIMR" }, - { 0, 0, 0 } -}; - -static syren_reg *find_reg(const char *name) -{ - int i; - - for (i = 0; registers[i].name != 0; i++) { - if (!strcasecmp(registers[i].name, name)) - return ®isters[i]; - } - - return NULL; -} - -static int usage(void) -{ - fprintf(stderr, "usage: syren [r/w] [REGNAME | page:addr] (value)\n"); - return 1; -} - -int -syren_main(int argc, char **argv) -{ - int cmd = -1; - syren_reg *r; - struct syren_io_args sio; - char name[32]; - int fd; - - if (argc < 3) { - return usage(); - } - - switch(argv[1][0]) { - case 'r': - cmd = SYREN_RD; - break; - case 'w': - cmd = SYREN_WR; - break; - case 'R': - cmd = SYREN_OLD_RD; - break; - case 'W': - cmd = SYREN_OLD_WR; - break; - default: - return usage(); - } - - if (cmd == SYREN_WR || cmd == SYREN_OLD_WR) { - if (argc < 4) - return usage(); - sio.value = strtoul(argv[3], 0, 0); - } - - fd = open("/dev/eac", O_RDONLY); - if (fd < 0) { - fprintf(stderr, "can't open /dev/eac\n"); - return 1; - } - - if (strcasecmp(argv[2], "all") == 0) { - int i; - if (cmd != SYREN_RD && cmd != SYREN_OLD_RD) { - fprintf(stderr, "can only read all registers\n"); - return 1; - } - - for (i = 0; registers[i].name; i++) { - sio.page = registers[i].page; - sio.addr = registers[i].addr; - if (ioctl(fd, cmd, &sio) < 0) { - fprintf(stderr, "%s: error\n", registers[i].name); - } else { - fprintf(stderr, "%s: %04x\n", registers[i].name, sio.value); - } - } - - close(fd); - return 0; - } - - r = find_reg(argv[2]); - if (r == NULL) { - if(strlen(argv[2]) >= sizeof(name)){ - fprintf(stderr, "REGNAME too long\n"); - return 0; - } - strlcpy(name, argv[2], sizeof(name)); - char *addr_str = strchr(argv[2], ':'); - if (addr_str == NULL) - return usage(); - *addr_str++ = 0; - sio.page = strtoul(argv[2], 0, 0); - sio.addr = strtoul(addr_str, 0, 0); - } else { - strlcpy(name, r->name, sizeof(name)); - sio.page = r->page; - sio.addr = r->addr; - } - - if (ioctl(fd, cmd, &sio) < 0) { - fprintf(stderr, "ioctl(%d) failed\n", cmd); - return 1; - } - - if (cmd == SYREN_RD || cmd == SYREN_OLD_RD) { - printf("%s: %04x\n", name, sio.value); - } else { - printf("wrote %04x to %s\n", sio.value, name); - } - - close(fd); - - return 0; -} - diff --git a/toolbox/toolbox.c b/toolbox/toolbox.c index 0eac390..915da44 100644 --- a/toolbox/toolbox.c +++ b/toolbox/toolbox.c @@ -1,6 +1,8 @@ +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> int main(int, char **); @@ -31,11 +33,24 @@ static struct { 0, 0 }, }; +static void SIGPIPE_handler(int signal) { + // Those desktop Linux tools that catch SIGPIPE seem to agree that it's + // a successful way to exit, not a failure. (Which makes sense --- we were + // told to stop by a reader, rather than failing to continue ourselves.) + _exit(0); +} + int main(int argc, char **argv) { int i; char *name = argv[0]; + // Let's assume that none of this code handles broken pipes. At least ls, + // ps, and top were broken (though I'd previously added this fix locally + // to top). We exit rather than use SIG_IGN because tools like top will + // just keep on writing to nowhere forever if we don't stop them. + signal(SIGPIPE, SIGPIPE_handler); + if((argc > 1) && (argv[1][0] == '@')) { name = argv[1] + 1; argc--; diff --git a/toolbox/top.c b/toolbox/top.c index b1a275c..1e99d4c 100644 --- a/toolbox/top.c +++ b/toolbox/top.c @@ -109,15 +109,9 @@ static int proc_thr_cmp(const void *a, const void *b); static int numcmp(long long a, long long b); static void usage(char *cmd); -static void exit_top(int signal) { - exit(EXIT_FAILURE); -} - int top_main(int argc, char *argv[]) { num_used_procs = num_free_procs = 0; - signal(SIGPIPE, exit_top); - max_procs = 0; delay = 3; iterations = -1; diff --git a/toolbox/touch.c b/toolbox/touch.c deleted file mode 100644 index 52ddf2a..0000000 --- a/toolbox/touch.c +++ /dev/null @@ -1,114 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <stdlib.h> -#include <fcntl.h> -#include <time.h> - -static void usage(void) -{ - fprintf(stderr, "touch: usage: touch [-alm] [-t YYYYMMDD[.hhmmss]] <file>\n"); - exit(1); -} - -static time_t parse_time(char *s) -{ - struct tm tm; - int day = atoi(s); - int hour = 0; - - while (*s && *s != '.') { - s++; - } - - if (*s) { - s++; - hour = atoi(s); - } - - tm.tm_year = day / 10000 - 1900; - tm.tm_mon = (day % 10000) / 100 - 1; - tm.tm_mday = day % 100; - tm.tm_hour = hour / 10000; - tm.tm_min = (hour % 10000) / 100; - tm.tm_sec = hour % 100; - tm.tm_isdst = -1; - - return mktime(&tm); -} - -int touch_main(int argc, char *argv[]) -{ - int i, fd, aflag = 0, mflag = 0, debug = 0, flags = 0; - struct timespec specified_time, times[2]; - char *file = 0; - - specified_time.tv_nsec = UTIME_NOW; - - for (i = 1; i < argc; i++) { - if (argv[i][0] == '-') { - /* an option */ - const char *arg = argv[i]+1; - while (arg[0]) { - switch (arg[0]) { - case 'a': aflag = 1; break; - case 'm': mflag = 1; break; - case 't': - if ((i+1) >= argc) - usage(); - specified_time.tv_sec = parse_time(argv[++i]); - if (specified_time.tv_sec == -1) { - fprintf(stderr, "touch: invalid timestamp specified\n"); - exit(1); - } - specified_time.tv_nsec = 0; - break; - case 'l': flags |= AT_SYMLINK_NOFOLLOW; break; - case 'd': debug = 1; break; - default: - usage(); - } - arg++; - } - } else { - /* not an option, and only accept one filename */ - if (i+1 != argc) - usage(); - file = argv[i]; - } - } - - if (! file) { - fprintf(stderr, "touch: no file specified\n"); - exit(1); - } - - if (access(file, F_OK)) - if ((fd=creat(file, 0666)) != -1) - close(fd); - - if ((mflag == 0) && (aflag == 0)) - aflag = mflag = 1; - - if (aflag) - times[0] = specified_time; - else - times[0].tv_nsec = UTIME_OMIT; - - if (mflag) - times[1] = specified_time; - else - times[1].tv_nsec = UTIME_OMIT; - - if (debug) { - fprintf(stderr, "file = %s\n", file); - fprintf(stderr, "times[0].tv_sec = %ld, times[0].tv_nsec = %ld\n", times[0].tv_sec, times[0].tv_nsec); - fprintf(stderr, "times[1].tv_sec = %ld, times[1].tv_nsec = %ld\n", times[1].tv_sec, times[1].tv_nsec); - fprintf(stderr, "flags = 0x%8.8x\n", flags); - } - - return utimensat(AT_FDCWD, file, times, flags); -} - diff --git a/toolbox/umount.c b/toolbox/umount.c deleted file mode 100644 index 3e17396..0000000 --- a/toolbox/umount.c +++ /dev/null @@ -1,90 +0,0 @@ - -#include <sys/mount.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <linux/loop.h> -#include <errno.h> - -#define LOOPDEV_MAXLEN 64 -#define LOOP_MAJOR 7 - -static int is_loop(char *dev) -{ - struct stat st; - int ret = 0; - - if (stat(dev, &st) == 0) { - if (S_ISBLK(st.st_mode) && (major(st.st_rdev) == LOOP_MAJOR)) { - ret = 1; - } - } - - return ret; -} - -static int is_loop_mount(const char* path, char *loopdev) -{ - FILE* f; - int count; - char device[256]; - char mount_path[256]; - char rest[256]; - int result = 0; - - f = fopen("/proc/mounts", "r"); - if (!f) { - fprintf(stdout, "could not open /proc/mounts: %s\n", strerror(errno)); - return -1; - } - - do { - count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest); - if (count == 3) { - if (is_loop(device) && strcmp(path, mount_path) == 0) { - strlcpy(loopdev, device, LOOPDEV_MAXLEN); - result = 1; - break; - } - } - } while (count == 3); - - fclose(f); - return result; -} - -int umount_main(int argc, char *argv[]) -{ - int loop, loop_fd; - char loopdev[LOOPDEV_MAXLEN]; - - if(argc != 2) { - fprintf(stderr,"umount <path>\n"); - return 1; - } - - loop = is_loop_mount(argv[1], loopdev); - if (umount(argv[1])) { - fprintf(stderr, "failed: %s\n", strerror(errno)); - return 1; - } - - if (loop) { - // free the loop device - loop_fd = open(loopdev, O_RDONLY); - if (loop_fd < 0) { - fprintf(stderr, "open loop device failed: %s\n", strerror(errno)); - return 1; - } - if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) { - fprintf(stderr, "ioctl LOOP_CLR_FD failed: %s\n", strerror(errno)); - return 1; - } - - close(loop_fd); - } - - return 0; -} diff --git a/toolbox/upstream-netbsd/bin/cat/cat.c b/toolbox/upstream-netbsd/bin/cat/cat.c deleted file mode 100644 index cca8cf5..0000000 --- a/toolbox/upstream-netbsd/bin/cat/cat.c +++ /dev/null @@ -1,329 +0,0 @@ -/* $NetBSD: cat.c,v 1.54 2013/12/08 08:32:13 spz Exp $ */ - -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kevin Fall. - * - * 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. - * 3. 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. - */ - -#if HAVE_NBTOOL_CONFIG_H -#include "nbtool_config.h" -#endif - -#include <sys/cdefs.h> -#if !defined(lint) -__COPYRIGHT( -"@(#) Copyright (c) 1989, 1993\ - The Regents of the University of California. All rights reserved."); -#if 0 -static char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95"; -#else -__RCSID("$NetBSD: cat.c,v 1.54 2013/12/08 08:32:13 spz Exp $"); -#endif -#endif /* not lint */ - -#include <sys/param.h> -#include <sys/stat.h> - -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <locale.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -static int bflag, eflag, fflag, lflag, nflag, sflag, tflag, vflag; -static size_t bsize; -static int rval; -static const char *filename; - -void cook_args(char *argv[]); -void cook_buf(FILE *); -void raw_args(char *argv[]); -void raw_cat(int); - -int -main(int argc, char *argv[]) -{ - int ch; - struct flock stdout_lock; - - setprogname(argv[0]); - (void)setlocale(LC_ALL, ""); - - while ((ch = getopt(argc, argv, "B:beflnstuv")) != -1) - switch (ch) { - case 'B': - bsize = (size_t)strtol(optarg, NULL, 0); - break; - case 'b': - bflag = nflag = 1; /* -b implies -n */ - break; - case 'e': - eflag = vflag = 1; /* -e implies -v */ - break; - case 'f': - fflag = 1; - break; - case 'l': - lflag = 1; - break; - case 'n': - nflag = 1; - break; - case 's': - sflag = 1; - break; - case 't': - tflag = vflag = 1; /* -t implies -v */ - break; - case 'u': - setbuf(stdout, NULL); - break; - case 'v': - vflag = 1; - break; - default: - case '?': - (void)fprintf(stderr, - "Usage: %s [-beflnstuv] [-B bsize] [-] " - "[file ...]\n", getprogname()); - return EXIT_FAILURE; - } - argv += optind; - - if (lflag) { - stdout_lock.l_len = 0; - stdout_lock.l_start = 0; - stdout_lock.l_type = F_WRLCK; - stdout_lock.l_whence = SEEK_SET; - if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1) - err(EXIT_FAILURE, "stdout"); - } - - if (bflag || eflag || nflag || sflag || tflag || vflag) - cook_args(argv); - else - raw_args(argv); - if (fclose(stdout)) - err(EXIT_FAILURE, "stdout"); - return rval; -} - -void -cook_args(char **argv) -{ - FILE *fp; - - fp = stdin; - filename = "stdin"; - do { - if (*argv) { - if (!strcmp(*argv, "-")) - fp = stdin; - else if ((fp = fopen(*argv, - fflag ? "rf" : "r")) == NULL) { - warn("%s", *argv); - rval = EXIT_FAILURE; - ++argv; - continue; - } - filename = *argv++; - } - cook_buf(fp); - if (fp != stdin) - (void)fclose(fp); - else - clearerr(fp); - } while (*argv); -} - -void -cook_buf(FILE *fp) -{ - int ch, gobble, line, prev; - - line = gobble = 0; - for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { - if (prev == '\n') { - if (ch == '\n') { - if (sflag) { - if (!gobble && nflag && !bflag) - (void)fprintf(stdout, - "%6d\t\n", ++line); - else if (!gobble && putchar(ch) == EOF) - break; - gobble = 1; - continue; - } - if (nflag) { - if (!bflag) { - (void)fprintf(stdout, - "%6d\t", ++line); - if (ferror(stdout)) - break; - } else if (eflag) { - (void)fprintf(stdout, - "%6s\t", ""); - if (ferror(stdout)) - break; - } - } - } else if (nflag) { - (void)fprintf(stdout, "%6d\t", ++line); - if (ferror(stdout)) - break; - } - } - gobble = 0; - if (ch == '\n') { - if (eflag) - if (putchar('$') == EOF) - break; - } else if (ch == '\t') { - if (tflag) { - if (putchar('^') == EOF || putchar('I') == EOF) - break; - continue; - } - } else if (vflag) { - if (!isascii(ch)) { - if (putchar('M') == EOF || putchar('-') == EOF) - break; - ch = toascii(ch); - } - if (iscntrl(ch)) { - if (putchar('^') == EOF || - putchar(ch == '\177' ? '?' : - ch | 0100) == EOF) - break; - continue; - } - } - if (putchar(ch) == EOF) - break; - } - if (ferror(fp)) { - warn("%s", filename); - rval = EXIT_FAILURE; - clearerr(fp); - } - if (ferror(stdout)) - err(EXIT_FAILURE, "stdout"); -} - -void -raw_args(char **argv) -{ - int fd; - - fd = fileno(stdin); - filename = "stdin"; - do { - if (*argv) { - if (!strcmp(*argv, "-")) { - fd = fileno(stdin); - if (fd < 0) - goto skip; - } else if (fflag) { - struct stat st; - fd = open(*argv, O_RDONLY|O_NONBLOCK, 0); - if (fd < 0) - goto skip; - - if (fstat(fd, &st) == -1) { - close(fd); - goto skip; - } - if (!S_ISREG(st.st_mode)) { - close(fd); - warnx("%s: not a regular file", *argv); - goto skipnomsg; - } - } - else if ((fd = open(*argv, O_RDONLY, 0)) < 0) { -skip: - warn("%s", *argv); -skipnomsg: - rval = EXIT_FAILURE; - ++argv; - continue; - } - filename = *argv++; - } else if (fd < 0) { - err(EXIT_FAILURE, "stdin"); - } - raw_cat(fd); - if (fd != fileno(stdin)) - (void)close(fd); - } while (*argv); -} - -void -raw_cat(int rfd) -{ - static char *buf; - static char fb_buf[BUFSIZ]; - - ssize_t nr, nw, off; - int wfd; - - wfd = fileno(stdout); - if (wfd < 0) - err(EXIT_FAILURE, "stdout"); - if (buf == NULL) { - struct stat sbuf; - - if (bsize == 0) { - if (fstat(wfd, &sbuf) == 0 && sbuf.st_blksize > 0 && - (size_t)sbuf.st_blksize > sizeof(fb_buf)) - bsize = sbuf.st_blksize; - } - if (bsize > sizeof(fb_buf)) { - buf = malloc(bsize); - if (buf == NULL) - warnx("malloc, using %zu buffer", bsize); - } - if (buf == NULL) { - bsize = sizeof(fb_buf); - buf = fb_buf; - } - } - while ((nr = read(rfd, buf, bsize)) > 0) - for (off = 0; nr; nr -= nw, off += nw) - if ((nw = write(wfd, buf + off, (size_t)nr)) < 0) - err(EXIT_FAILURE, "stdout"); - if (nr < 0) { - warn("%s", filename); - rval = EXIT_FAILURE; - } -} diff --git a/toolbox/upstream-netbsd/bin/cp/cp.c b/toolbox/upstream-netbsd/bin/cp/cp.c deleted file mode 100644 index 4bbe1b7..0000000 --- a/toolbox/upstream-netbsd/bin/cp/cp.c +++ /dev/null @@ -1,548 +0,0 @@ -/* $NetBSD: cp.c,v 1.58 2012/01/04 15:58:37 christos Exp $ */ - -/* - * Copyright (c) 1988, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * David Hitz of Auspex Systems Inc. - * - * 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. - * 3. 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. - */ - -#include <sys/cdefs.h> -#ifndef lint -__COPYRIGHT( -"@(#) Copyright (c) 1988, 1993, 1994\ - The Regents of the University of California. All rights reserved."); -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)cp.c 8.5 (Berkeley) 4/29/95"; -#else -__RCSID("$NetBSD: cp.c,v 1.58 2012/01/04 15:58:37 christos Exp $"); -#endif -#endif /* not lint */ - -/* - * Cp copies source files to target files. - * - * The global PATH_T structure "to" always contains the path to the - * current target file. Since fts(3) does not change directories, - * this path can be either absolute or dot-relative. - * - * The basic algorithm is to initialize "to" and use fts(3) to traverse - * the file hierarchy rooted in the argument list. A trivial case is the - * case of 'cp file1 file2'. The more interesting case is the case of - * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the - * path (relative to the root of the traversal) is appended to dir (stored - * in "to") to form the final target path. - */ - -#include <sys/param.h> -#include <sys/stat.h> - -#include <assert.h> -#include <err.h> -#include <errno.h> -#include <fts.h> -#include <locale.h> -#include <signal.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -#include "extern.h" - -#define STRIP_TRAILING_SLASH(p) { \ - while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \ - *--(p).p_end = '\0'; \ -} - -static char empty[] = ""; -PATH_T to = { .p_end = to.p_path, .target_end = empty }; - -uid_t myuid; -int Hflag, Lflag, Rflag, Pflag, fflag, iflag, lflag, pflag, rflag, vflag, Nflag; -mode_t myumask; -sig_atomic_t pinfo; - -enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; - -static int copy(char *[], enum op, int); - -static void -progress(int sig __unused) -{ - - pinfo++; -} - -int -main(int argc, char *argv[]) -{ - struct stat to_stat, tmp_stat; - enum op type; - int ch, fts_options, r, have_trailing_slash; - char *target, **src; - - setprogname(argv[0]); - (void)setlocale(LC_ALL, ""); - - Hflag = Lflag = Pflag = Rflag = 0; - while ((ch = getopt(argc, argv, "HLNPRfailprv")) != -1) - switch (ch) { - case 'H': - Hflag = 1; - Lflag = Pflag = 0; - break; - case 'L': - Lflag = 1; - Hflag = Pflag = 0; - break; - case 'N': - Nflag = 1; - break; - case 'P': - Pflag = 1; - Hflag = Lflag = 0; - break; - case 'R': - Rflag = 1; - break; - case 'a': - Pflag = 1; - pflag = 1; - Rflag = 1; - Hflag = Lflag = 0; - break; - case 'f': - fflag = 1; - iflag = 0; - break; - case 'i': - iflag = isatty(fileno(stdin)); - fflag = 0; - break; - case 'l': - lflag = 1; - break; - case 'p': - pflag = 1; - break; - case 'r': - rflag = 1; - break; - case 'v': - vflag = 1; - break; - case '?': - default: - usage(); - /* NOTREACHED */ - } - argc -= optind; - argv += optind; - - if (argc < 2) - usage(); - - fts_options = FTS_NOCHDIR | FTS_PHYSICAL; - if (rflag) { - if (Rflag) { - errx(EXIT_FAILURE, - "the -R and -r options may not be specified together."); - /* NOTREACHED */ - } - if (Hflag || Lflag || Pflag) { - errx(EXIT_FAILURE, - "the -H, -L, and -P options may not be specified with the -r option."); - /* NOTREACHED */ - } - fts_options &= ~FTS_PHYSICAL; - fts_options |= FTS_LOGICAL; - } - - if (Rflag) { - if (Hflag) - fts_options |= FTS_COMFOLLOW; - if (Lflag) { - fts_options &= ~FTS_PHYSICAL; - fts_options |= FTS_LOGICAL; - } - } else if (!Pflag) { - fts_options &= ~FTS_PHYSICAL; - fts_options |= FTS_LOGICAL | FTS_COMFOLLOW; - } - - myuid = getuid(); - - /* Copy the umask for explicit mode setting. */ - myumask = umask(0); - (void)umask(myumask); - - /* Save the target base in "to". */ - target = argv[--argc]; - if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path)) - errx(EXIT_FAILURE, "%s: name too long", target); - to.p_end = to.p_path + strlen(to.p_path); - have_trailing_slash = (to.p_end[-1] == '/'); - if (have_trailing_slash) - STRIP_TRAILING_SLASH(to); - to.target_end = to.p_end; - - /* Set end of argument list for fts(3). */ - argv[argc] = NULL; - - (void)signal(SIGINFO, progress); - - /* - * Cp has two distinct cases: - * - * cp [-R] source target - * cp [-R] source1 ... sourceN directory - * - * In both cases, source can be either a file or a directory. - * - * In (1), the target becomes a copy of the source. That is, if the - * source is a file, the target will be a file, and likewise for - * directories. - * - * In (2), the real target is not directory, but "directory/source". - */ - if (Pflag) - r = lstat(to.p_path, &to_stat); - else - r = stat(to.p_path, &to_stat); - if (r == -1 && errno != ENOENT) { - err(EXIT_FAILURE, "%s", to.p_path); - /* NOTREACHED */ - } - if (r == -1 || !S_ISDIR(to_stat.st_mode)) { - /* - * Case (1). Target is not a directory. - */ - if (argc > 1) - usage(); - /* - * Need to detect the case: - * cp -R dir foo - * Where dir is a directory and foo does not exist, where - * we want pathname concatenations turned on but not for - * the initial mkdir(). - */ - if (r == -1) { - if (rflag || (Rflag && (Lflag || Hflag))) - r = stat(*argv, &tmp_stat); - else - r = lstat(*argv, &tmp_stat); - if (r == -1) { - err(EXIT_FAILURE, "%s", *argv); - /* NOTREACHED */ - } - - if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag)) - type = DIR_TO_DNE; - else - type = FILE_TO_FILE; - } else - type = FILE_TO_FILE; - - if (have_trailing_slash && type == FILE_TO_FILE) { - if (r == -1) - errx(1, "directory %s does not exist", - to.p_path); - else - errx(1, "%s is not a directory", to.p_path); - } - } else { - /* - * Case (2). Target is a directory. - */ - type = FILE_TO_DIR; - } - - /* - * make "cp -rp src/ dst" behave like "cp -rp src dst" not - * like "cp -rp src/. dst" - */ - for (src = argv; *src; src++) { - size_t len = strlen(*src); - while (len-- > 1 && (*src)[len] == '/') - (*src)[len] = '\0'; - } - - exit(copy(argv, type, fts_options)); - /* NOTREACHED */ -} - -static int dnestack[MAXPATHLEN]; /* unlikely we'll have more nested dirs */ -static ssize_t dnesp; -static void -pushdne(int dne) -{ - - dnestack[dnesp++] = dne; - assert(dnesp < MAXPATHLEN); -} - -static int -popdne(void) -{ - int rv; - - rv = dnestack[--dnesp]; - assert(dnesp >= 0); - return rv; -} - -static int -copy(char *argv[], enum op type, int fts_options) -{ - struct stat to_stat; - FTS *ftsp; - FTSENT *curr; - int base, dne, sval; - int this_failed, any_failed; - size_t nlen; - char *p, *target_mid; - - base = 0; /* XXX gcc -Wuninitialized (see comment below) */ - - if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL) - err(EXIT_FAILURE, "%s", argv[0]); - /* NOTREACHED */ - for (any_failed = 0; (curr = fts_read(ftsp)) != NULL;) { - this_failed = 0; - switch (curr->fts_info) { - case FTS_NS: - case FTS_DNR: - case FTS_ERR: - warnx("%s: %s", curr->fts_path, - strerror(curr->fts_errno)); - this_failed = any_failed = 1; - continue; - case FTS_DC: /* Warn, continue. */ - warnx("%s: directory causes a cycle", curr->fts_path); - this_failed = any_failed = 1; - continue; - } - - /* - * If we are in case (2) or (3) above, we need to append the - * source name to the target name. - */ - if (type != FILE_TO_FILE) { - if ((curr->fts_namelen + - to.target_end - to.p_path + 1) > MAXPATHLEN) { - warnx("%s/%s: name too long (not copied)", - to.p_path, curr->fts_name); - this_failed = any_failed = 1; - continue; - } - - /* - * Need to remember the roots of traversals to create - * correct pathnames. If there's a directory being - * copied to a non-existent directory, e.g. - * cp -R a/dir noexist - * the resulting path name should be noexist/foo, not - * noexist/dir/foo (where foo is a file in dir), which - * is the case where the target exists. - * - * Also, check for "..". This is for correct path - * concatentation for paths ending in "..", e.g. - * cp -R .. /tmp - * Paths ending in ".." are changed to ".". This is - * tricky, but seems the easiest way to fix the problem. - * - * XXX - * Since the first level MUST be FTS_ROOTLEVEL, base - * is always initialized. - */ - if (curr->fts_level == FTS_ROOTLEVEL) { - if (type != DIR_TO_DNE) { - p = strrchr(curr->fts_path, '/'); - base = (p == NULL) ? 0 : - (int)(p - curr->fts_path + 1); - - if (!strcmp(&curr->fts_path[base], - "..")) - base += 1; - } else - base = curr->fts_pathlen; - } - - p = &curr->fts_path[base]; - nlen = curr->fts_pathlen - base; - target_mid = to.target_end; - if (*p != '/' && target_mid[-1] != '/') - *target_mid++ = '/'; - *target_mid = 0; - - if (target_mid - to.p_path + nlen >= PATH_MAX) { - warnx("%s%s: name too long (not copied)", - to.p_path, p); - this_failed = any_failed = 1; - continue; - } - (void)strncat(target_mid, p, nlen); - to.p_end = target_mid + nlen; - *to.p_end = 0; - STRIP_TRAILING_SLASH(to); - } - - sval = Pflag ? lstat(to.p_path, &to_stat) : stat(to.p_path, &to_stat); - /* Not an error but need to remember it happened */ - if (sval == -1) - dne = 1; - else { - if (to_stat.st_dev == curr->fts_statp->st_dev && - to_stat.st_ino == curr->fts_statp->st_ino) { - warnx("%s and %s are identical (not copied).", - to.p_path, curr->fts_path); - this_failed = any_failed = 1; - if (S_ISDIR(curr->fts_statp->st_mode)) - (void)fts_set(ftsp, curr, FTS_SKIP); - continue; - } - if (!S_ISDIR(curr->fts_statp->st_mode) && - S_ISDIR(to_stat.st_mode)) { - warnx("cannot overwrite directory %s with non-directory %s", - to.p_path, curr->fts_path); - this_failed = any_failed = 1; - continue; - } - dne = 0; - } - - switch (curr->fts_statp->st_mode & S_IFMT) { - case S_IFLNK: - /* Catch special case of a non dangling symlink */ - if((fts_options & FTS_LOGICAL) || - ((fts_options & FTS_COMFOLLOW) && curr->fts_level == 0)) { - if (copy_file(curr, dne)) - this_failed = any_failed = 1; - } else { - if (copy_link(curr, !dne)) - this_failed = any_failed = 1; - } - break; - case S_IFDIR: - if (!Rflag && !rflag) { - if (curr->fts_info == FTS_D) - warnx("%s is a directory (not copied).", - curr->fts_path); - (void)fts_set(ftsp, curr, FTS_SKIP); - this_failed = any_failed = 1; - break; - } - - /* - * Directories get noticed twice: - * In the first pass, create it if needed. - * In the second pass, after the children have been copied, set the permissions. - */ - if (curr->fts_info == FTS_D) /* First pass */ - { - /* - * If the directory doesn't exist, create the new - * one with the from file mode plus owner RWX bits, - * modified by the umask. Trade-off between being - * able to write the directory (if from directory is - * 555) and not causing a permissions race. If the - * umask blocks owner writes, we fail.. - */ - pushdne(dne); - if (dne) { - if (mkdir(to.p_path, - curr->fts_statp->st_mode | S_IRWXU) < 0) - err(EXIT_FAILURE, "%s", - to.p_path); - /* NOTREACHED */ - } else if (!S_ISDIR(to_stat.st_mode)) { - errno = ENOTDIR; - err(EXIT_FAILURE, "%s", - to.p_path); - /* NOTREACHED */ - } - } - else if (curr->fts_info == FTS_DP) /* Second pass */ - { - /* - * If not -p and directory didn't exist, set it to be - * the same as the from directory, umodified by the - * umask; arguably wrong, but it's been that way - * forever. - */ - if (pflag && setfile(curr->fts_statp, 0)) - this_failed = any_failed = 1; - else if ((dne = popdne())) - (void)chmod(to.p_path, - curr->fts_statp->st_mode); - } - else - { - warnx("directory %s encountered when not expected.", - curr->fts_path); - this_failed = any_failed = 1; - break; - } - - break; - case S_IFBLK: - case S_IFCHR: - if (Rflag) { - if (copy_special(curr->fts_statp, !dne)) - this_failed = any_failed = 1; - } else - if (copy_file(curr, dne)) - this_failed = any_failed = 1; - break; - case S_IFIFO: - if (Rflag) { - if (copy_fifo(curr->fts_statp, !dne)) - this_failed = any_failed = 1; - } else - if (copy_file(curr, dne)) - this_failed = any_failed = 1; - break; - default: - if (copy_file(curr, dne)) - this_failed = any_failed = 1; - break; - } - if (vflag && !this_failed) - (void)printf("%s -> %s\n", curr->fts_path, to.p_path); - } - if (errno) { - err(EXIT_FAILURE, "fts_read"); - /* NOTREACHED */ - } - (void)fts_close(ftsp); - return (any_failed); -} diff --git a/toolbox/upstream-netbsd/bin/cp/extern.h b/toolbox/upstream-netbsd/bin/cp/extern.h deleted file mode 100644 index e393844..0000000 --- a/toolbox/upstream-netbsd/bin/cp/extern.h +++ /dev/null @@ -1,61 +0,0 @@ -/* $NetBSD: extern.h,v 1.17 2012/01/04 15:58:37 christos Exp $ */ - -/*- - * Copyright (c) 1991, 1993, 1994 - * 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. - * 3. 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. - * - * @(#)extern.h 8.2 (Berkeley) 4/1/94 - */ - -#ifndef _EXTERN_H_ -#define _EXTERN_H_ - -typedef struct { - char *p_end; /* pointer to NULL at end of path */ - char *target_end; /* pointer to end of target base */ - char p_path[MAXPATHLEN + 1]; /* pointer to the start of a path */ -} PATH_T; - -extern PATH_T to; -extern uid_t myuid; -extern int Rflag, rflag, Hflag, Lflag, Pflag, fflag, iflag, lflag, pflag, Nflag; -extern mode_t myumask; -extern sig_atomic_t pinfo; - -#include <sys/cdefs.h> - -__BEGIN_DECLS -int copy_fifo(struct stat *, int); -int copy_file(FTSENT *, int); -int copy_link(FTSENT *, int); -int copy_special(struct stat *, int); -int set_utimes(const char *, struct stat *); -int setfile(struct stat *, int); -void usage(void) __attribute__((__noreturn__)); -__END_DECLS - -#endif /* !_EXTERN_H_ */ diff --git a/toolbox/upstream-netbsd/bin/cp/utils.c b/toolbox/upstream-netbsd/bin/cp/utils.c deleted file mode 100644 index d8f900a..0000000 --- a/toolbox/upstream-netbsd/bin/cp/utils.c +++ /dev/null @@ -1,444 +0,0 @@ -/* $NetBSD: utils.c,v 1.42 2013/12/11 06:00:11 dholland Exp $ */ - -/*- - * Copyright (c) 1991, 1993, 1994 - * 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. - * 3. 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. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94"; -#else -__RCSID("$NetBSD: utils.c,v 1.42 2013/12/11 06:00:11 dholland Exp $"); -#endif -#endif /* not lint */ - -#include <sys/mman.h> -#include <sys/param.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/extattr.h> - -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <fts.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "extern.h" - -#define MMAP_MAX_SIZE (8 * 1048576) -#define MMAP_MAX_WRITE (64 * 1024) - -int -set_utimes(const char *file, struct stat *fs) -{ - static struct timeval tv[2]; - -#ifdef __ANDROID__ - tv[0].tv_sec = fs->st_atime; - tv[0].tv_usec = 0; - tv[1].tv_sec = fs->st_mtime; - tv[1].tv_usec = 0; - - if (utimes(file, tv)) { - warn("utimes: %s", file); - return 1; - } -#else - TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); - TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); - - if (lutimes(file, tv)) { - warn("lutimes: %s", file); - return (1); - } -#endif - return (0); -} - -struct finfo { - const char *from; - const char *to; - size_t size; -}; - -static void -progress(const struct finfo *fi, size_t written) -{ - int pcent = (int)((100.0 * written) / fi->size); - - pinfo = 0; - (void)fprintf(stderr, "%s => %s %zu/%zu bytes %d%% written\n", - fi->from, fi->to, written, fi->size, pcent); -} - -int -copy_file(FTSENT *entp, int dne) -{ - static char buf[MAXBSIZE]; - struct stat to_stat, *fs; - int ch, checkch, from_fd, rcount, rval, to_fd, tolnk, wcount; - char *p; - size_t ptotal = 0; - - if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) { - warn("%s", entp->fts_path); - return (1); - } - - to_fd = -1; - fs = entp->fts_statp; - tolnk = ((Rflag && !(Lflag || Hflag)) || Pflag); - - /* - * If the file exists and we're interactive, verify with the user. - * If the file DNE, set the mode to be the from file, minus setuid - * bits, modified by the umask; arguably wrong, but it makes copying - * executables work right and it's been that way forever. (The - * other choice is 666 or'ed with the execute bits on the from file - * modified by the umask.) - */ - if (!dne) { - struct stat sb; - int sval; - - if (iflag) { - (void)fprintf(stderr, "overwrite %s? ", to.p_path); - checkch = ch = getchar(); - while (ch != '\n' && ch != EOF) - ch = getchar(); - if (checkch != 'y' && checkch != 'Y') { - (void)close(from_fd); - return (0); - } - } - - sval = tolnk ? - lstat(to.p_path, &sb) : stat(to.p_path, &sb); - if (sval == -1) { - warn("stat: %s", to.p_path); - (void)close(from_fd); - return (1); - } - - if (!(tolnk && S_ISLNK(sb.st_mode))) - to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0); - } else - to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, - fs->st_mode & ~(S_ISUID | S_ISGID)); - - if (to_fd == -1 && (fflag || tolnk)) { - /* - * attempt to remove existing destination file name and - * create a new file - */ - (void)unlink(to.p_path); - to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, - fs->st_mode & ~(S_ISUID | S_ISGID)); - } - - if (to_fd == -1) { - warn("%s", to.p_path); - (void)close(from_fd); - return (1); - } - - rval = 0; - - /* if hard linking then simply close the open fds, link and return */ - if (lflag) { - (void)close(from_fd); - (void)close(to_fd); - (void)unlink(to.p_path); - if (link(entp->fts_path, to.p_path)) { - warn("%s", to.p_path); - return (1); - } - return (0); - } - - /* - * There's no reason to do anything other than close the file - * now if it's empty, so let's not bother. - */ -#ifndef __ANDROID__ // Files in /proc report length 0. mmap will fail but we'll fall back to read. - if (fs->st_size > 0) { -#endif - struct finfo fi; - - fi.from = entp->fts_path; - fi.to = to.p_path; - fi.size = (size_t)fs->st_size; - - /* - * Mmap and write if less than 8M (the limit is so - * we don't totally trash memory on big files). - * This is really a minor hack, but it wins some CPU back. - */ - bool use_read; - - use_read = true; - if (fs->st_size <= MMAP_MAX_SIZE) { - size_t fsize = (size_t)fs->st_size; - p = mmap(NULL, fsize, PROT_READ, MAP_FILE|MAP_SHARED, - from_fd, (off_t)0); - if (p != MAP_FAILED) { - size_t remainder; - - use_read = false; - - (void) madvise(p, (size_t)fs->st_size, - MADV_SEQUENTIAL); - - /* - * Write out the data in small chunks to - * avoid locking the output file for a - * long time if the reading the data from - * the source is slow. - */ - remainder = fsize; - do { - ssize_t chunk; - - chunk = (remainder > MMAP_MAX_WRITE) ? - MMAP_MAX_WRITE : remainder; - if (write(to_fd, &p[fsize - remainder], - chunk) != chunk) { - warn("%s", to.p_path); - rval = 1; - break; - } - remainder -= chunk; - ptotal += chunk; - if (pinfo) - progress(&fi, ptotal); - } while (remainder > 0); - - if (munmap(p, fsize) < 0) { - warn("%s", entp->fts_path); - rval = 1; - } - } - } - - if (use_read) { - while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) { - wcount = write(to_fd, buf, (size_t)rcount); - if (rcount != wcount || wcount == -1) { - warn("%s", to.p_path); - rval = 1; - break; - } - ptotal += wcount; - if (pinfo) - progress(&fi, ptotal); - } - if (rcount < 0) { - warn("%s", entp->fts_path); - rval = 1; - } - } -#ifndef __ANDROID__ - } -#endif - -#ifndef __ANDROID__ - if (pflag && (fcpxattr(from_fd, to_fd) != 0)) - warn("%s: error copying extended attributes", to.p_path); -#endif - - (void)close(from_fd); - - if (rval == 1) { - (void)close(to_fd); - return (1); - } - - if (pflag && setfile(fs, to_fd)) - rval = 1; - /* - * If the source was setuid or setgid, lose the bits unless the - * copy is owned by the same user and group. - */ -#define RETAINBITS \ - (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) - if (!pflag && dne - && fs->st_mode & (S_ISUID | S_ISGID) && fs->st_uid == myuid) { - if (fstat(to_fd, &to_stat)) { - warn("%s", to.p_path); - rval = 1; - } else if (fs->st_gid == to_stat.st_gid && - fchmod(to_fd, fs->st_mode & RETAINBITS & ~myumask)) { - warn("%s", to.p_path); - rval = 1; - } - } - if (close(to_fd)) { - warn("%s", to.p_path); - rval = 1; - } - /* set the mod/access times now after close of the fd */ - if (pflag && set_utimes(to.p_path, fs)) { - rval = 1; - } - return (rval); -} - -int -copy_link(FTSENT *p, int exists) -{ - int len; - char target[MAXPATHLEN]; - - if ((len = readlink(p->fts_path, target, sizeof(target)-1)) == -1) { - warn("readlink: %s", p->fts_path); - return (1); - } - target[len] = '\0'; - if (exists && unlink(to.p_path)) { - warn("unlink: %s", to.p_path); - return (1); - } - if (symlink(target, to.p_path)) { - warn("symlink: %s", target); - return (1); - } - return (pflag ? setfile(p->fts_statp, 0) : 0); -} - -int -copy_fifo(struct stat *from_stat, int exists) -{ - if (exists && unlink(to.p_path)) { - warn("unlink: %s", to.p_path); - return (1); - } - if (mkfifo(to.p_path, from_stat->st_mode)) { - warn("mkfifo: %s", to.p_path); - return (1); - } - return (pflag ? setfile(from_stat, 0) : 0); -} - -int -copy_special(struct stat *from_stat, int exists) -{ - if (exists && unlink(to.p_path)) { - warn("unlink: %s", to.p_path); - return (1); - } - if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) { - warn("mknod: %s", to.p_path); - return (1); - } - return (pflag ? setfile(from_stat, 0) : 0); -} - - -/* - * Function: setfile - * - * Purpose: - * Set the owner/group/permissions for the "to" file to the information - * in the stat structure. If fd is zero, also call set_utimes() to set - * the mod/access times. If fd is non-zero, the caller must do a utimes - * itself after close(fd). - */ -int -setfile(struct stat *fs, int fd) -{ - int rval, islink; - - rval = 0; - islink = S_ISLNK(fs->st_mode); - fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; - - /* - * Changing the ownership probably won't succeed, unless we're root - * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting - * the mode; current BSD behavior is to remove all setuid bits on - * chown. If chown fails, lose setuid/setgid bits. - */ - if (fd ? fchown(fd, fs->st_uid, fs->st_gid) : - lchown(to.p_path, fs->st_uid, fs->st_gid)) { - if (errno != EPERM) { - warn("chown: %s", to.p_path); - rval = 1; - } - fs->st_mode &= ~(S_ISUID | S_ISGID); - } -#ifdef __ANDROID__ - if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) { -#else - if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) { -#endif - warn("chmod: %s", to.p_path); - rval = 1; - } - -#ifndef __ANDROID__ - if (!islink && !Nflag) { - unsigned long fflags = fs->st_flags; - /* - * XXX - * NFS doesn't support chflags; ignore errors unless - * there's reason to believe we're losing bits. - * (Note, this still won't be right if the server - * supports flags and we were trying to *remove* flags - * on a file that we copied, i.e., that we didn't create.) - */ - errno = 0; - if ((fd ? fchflags(fd, fflags) : - chflags(to.p_path, fflags)) == -1) - if (errno != EOPNOTSUPP || fs->st_flags != 0) { - warn("chflags: %s", to.p_path); - rval = 1; - } - } -#endif - /* if fd is non-zero, caller must call set_utimes() after close() */ - if (fd == 0 && set_utimes(to.p_path, fs)) - rval = 1; - return (rval); -} - -void -usage(void) -{ - (void)fprintf(stderr, - "usage: %s [-R [-H | -L | -P]] [-f | -i] [-alNpv] src target\n" - " %s [-R [-H | -L | -P]] [-f | -i] [-alNpv] src1 ... srcN directory\n", - getprogname(), getprogname()); - exit(1); - /* NOTREACHED */ -} diff --git a/toolbox/upstream-netbsd/bin/kill/kill.c b/toolbox/upstream-netbsd/bin/kill/kill.c deleted file mode 100644 index 0592577..0000000 --- a/toolbox/upstream-netbsd/bin/kill/kill.c +++ /dev/null @@ -1,253 +0,0 @@ -/* $NetBSD: kill.c,v 1.27 2011/08/29 14:51:18 joerg Exp $ */ - -/* - * Copyright (c) 1988, 1993, 1994 - * 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. - * 3. 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. - */ - -#include <sys/cdefs.h> -#if !defined(lint) && !defined(SHELL) -__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\ - The Regents of the University of California. All rights reserved."); -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)kill.c 8.4 (Berkeley) 4/28/95"; -#else -__RCSID("$NetBSD: kill.c,v 1.27 2011/08/29 14:51:18 joerg Exp $"); -#endif -#endif /* not lint */ - -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <limits.h> -#include <inttypes.h> -#include <string.h> -#include <termios.h> -#include <unistd.h> -#include <locale.h> -#include <sys/ioctl.h> - -#ifdef SHELL /* sh (aka ash) builtin */ -int killcmd(int, char *argv[]); -#define main killcmd -#include "../../bin/sh/bltin/bltin.h" -#endif /* SHELL */ - -__dead static void nosig(char *); -static void printsignals(FILE *); -static int signame_to_signum(char *); -__dead static void usage(void); - -int -main(int argc, char *argv[]) -{ - int errors; - intmax_t numsig, pid; - char *ep; - - setprogname(argv[0]); - setlocale(LC_ALL, ""); - if (argc < 2) - usage(); - - numsig = SIGTERM; - - argc--, argv++; - if (strcmp(*argv, "-l") == 0) { - argc--, argv++; - if (argc > 1) - usage(); - if (argc == 1) { - if (isdigit((unsigned char)**argv) == 0) - usage(); - numsig = strtoimax(*argv, &ep, 10); - /* check for correctly parsed number */ - if (*ep != '\0' || numsig == INTMAX_MIN || numsig == INTMAX_MAX) { - errx(EXIT_FAILURE, "illegal signal number: %s", - *argv); - /* NOTREACHED */ - } - if (numsig >= 128) - numsig -= 128; - /* and whether it fits into signals range */ - if (numsig <= 0 || numsig >= NSIG) - nosig(*argv); - printf("%s\n", sys_signame[(int) numsig]); - exit(0); - } - printsignals(stdout); - exit(0); - } - - if (!strcmp(*argv, "-s")) { - argc--, argv++; - if (argc < 1) { - warnx("option requires an argument -- s"); - usage(); - } - if (strcmp(*argv, "0")) { - if ((numsig = signame_to_signum(*argv)) < 0) - nosig(*argv); - } else - numsig = 0; - argc--, argv++; - } else if (**argv == '-') { - char *sn = *argv + 1; - if (isalpha((unsigned char)*sn)) { - if ((numsig = signame_to_signum(sn)) < 0) - nosig(sn); - } else if (isdigit((unsigned char)*sn)) { - numsig = strtoimax(sn, &ep, 10); - /* check for correctly parsed number */ - if (*ep || numsig == INTMAX_MIN || numsig == INTMAX_MAX ) { - errx(EXIT_FAILURE, "illegal signal number: %s", - sn); - /* NOTREACHED */ - } - /* and whether it fits into signals range */ - if (numsig < 0 || numsig >= NSIG) - nosig(sn); - } else - nosig(sn); - argc--, argv++; - } - - if (argc == 0) - usage(); - - for (errors = 0; argc; argc--, argv++) { -#ifdef SHELL - extern int getjobpgrp(const char *); - if (*argv[0] == '%') { - pid = getjobpgrp(*argv); - if (pid == 0) { - warnx("illegal job id: %s", *argv); - errors = 1; - continue; - } - } else -#endif - { - pid = strtoimax(*argv, &ep, 10); - /* make sure the pid is a number and fits into pid_t */ - if (!**argv || *ep || pid == INTMAX_MIN || - pid == INTMAX_MAX || pid != (pid_t) pid) { - - warnx("illegal process id: %s", *argv); - errors = 1; - continue; - } - } - if (kill((pid_t) pid, (int) numsig) == -1) { - warn("%s", *argv); - errors = 1; - } -#ifdef SHELL - /* Wakeup the process if it was suspended, so it can - exit without an explicit 'fg'. */ - if (numsig == SIGTERM || numsig == SIGHUP) - kill((pid_t) pid, SIGCONT); -#endif - } - - exit(errors); - /* NOTREACHED */ -} - -static int -signame_to_signum(char *sig) -{ - int n; - - if (strncasecmp(sig, "sig", 3) == 0) - sig += 3; - for (n = 1; n < NSIG; n++) { - if (!strcasecmp(sys_signame[n], sig)) - return (n); - } - return (-1); -} - -static void -nosig(char *name) -{ - - warnx("unknown signal %s; valid signals:", name); - printsignals(stderr); - exit(1); - /* NOTREACHED */ -} - -static void -printsignals(FILE *fp) -{ - int sig; - int len, nl; - const char *name; - int termwidth = 80; - - if (isatty(fileno(fp))) { - struct winsize win; - if (ioctl(fileno(fp), TIOCGWINSZ, &win) == 0 && win.ws_col > 0) - termwidth = win.ws_col; - } - - for (len = 0, sig = 1; sig < NSIG; sig++) { - name = sys_signame[sig]; - nl = 1 + strlen(name); - - if (len + nl >= termwidth) { - fprintf(fp, "\n"); - len = 0; - } else - if (len != 0) - fprintf(fp, " "); - len += nl; - fprintf(fp, "%s", name); - } - if (len != 0) - fprintf(fp, "\n"); -} - -static void -usage(void) -{ - - fprintf(stderr, "usage: %s [-s signal_name] pid ...\n" - " %s -l [exit_status]\n" - " %s -signal_name pid ...\n" - " %s -signal_number pid ...\n", - getprogname(), getprogname(), getprogname(), getprogname()); - exit(1); - /* NOTREACHED */ -} diff --git a/toolbox/upstream-netbsd/bin/ln/ln.c b/toolbox/upstream-netbsd/bin/ln/ln.c deleted file mode 100644 index 9127477..0000000 --- a/toolbox/upstream-netbsd/bin/ln/ln.c +++ /dev/null @@ -1,230 +0,0 @@ -/* $NetBSD: ln.c,v 1.35 2011/08/29 14:38:30 joerg Exp $ */ - -/* - * Copyright (c) 1987, 1993, 1994 - * 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. - * 3. 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. - */ - -#include <sys/cdefs.h> -#ifndef lint -__COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\ - The Regents of the University of California. All rights reserved."); -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)ln.c 8.2 (Berkeley) 3/31/94"; -#else -__RCSID("$NetBSD: ln.c,v 1.35 2011/08/29 14:38:30 joerg Exp $"); -#endif -#endif /* not lint */ - -#include <sys/param.h> -#include <sys/stat.h> - -#include <err.h> -#include <errno.h> -#include <locale.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -static int fflag; /* Unlink existing files. */ -static int hflag; /* Check new name for symlink first. */ -static int iflag; /* Interactive mode. */ -static int sflag; /* Symbolic, not hard, link. */ -static int vflag; /* Verbose output */ - - /* System link call. */ -static int (*linkf)(const char *, const char *); -static char linkch; - -static int linkit(const char *, const char *, int); -__dead static void usage(void); - -int -main(int argc, char *argv[]) -{ - struct stat sb; - int ch, exitval; - char *sourcedir; - - setprogname(argv[0]); - (void)setlocale(LC_ALL, ""); - - while ((ch = getopt(argc, argv, "fhinsv")) != -1) - switch (ch) { - case 'f': - fflag = 1; - iflag = 0; - break; - case 'h': - case 'n': - hflag = 1; - break; - case 'i': - iflag = 1; - fflag = 0; - break; - case 's': - sflag = 1; - break; - case 'v': - vflag = 1; - break; - case '?': - default: - usage(); - /* NOTREACHED */ - } - - argv += optind; - argc -= optind; - - if (sflag) { - linkf = symlink; - linkch = '-'; - } else { - linkf = link; - linkch = '='; - } - - switch(argc) { - case 0: - usage(); - /* NOTREACHED */ - case 1: /* ln target */ - exit(linkit(argv[0], ".", 1)); - /* NOTREACHED */ - case 2: /* ln target source */ - exit(linkit(argv[0], argv[1], 0)); - /* NOTREACHED */ - } - - /* ln target1 target2 directory */ - sourcedir = argv[argc - 1]; - if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) { - /* we were asked not to follow symlinks, but found one at - the target--simulate "not a directory" error */ - errno = ENOTDIR; - err(EXIT_FAILURE, "%s", sourcedir); - /* NOTREACHED */ - } - if (stat(sourcedir, &sb)) { - err(EXIT_FAILURE, "%s", sourcedir); - /* NOTREACHED */ - } - if (!S_ISDIR(sb.st_mode)) { - usage(); - /* NOTREACHED */ - } - for (exitval = 0; *argv != sourcedir; ++argv) - exitval |= linkit(*argv, sourcedir, 1); - exit(exitval); - /* NOTREACHED */ -} - -static int -linkit(const char *target, const char *source, int isdir) -{ - struct stat sb; - const char *p; - char path[MAXPATHLEN]; - int ch, exists, first; - - if (!sflag) { - /* If target doesn't exist, quit now. */ - if (stat(target, &sb)) { - warn("%s", target); - return (1); - } - } - - /* If the source is a directory (and not a symlink if hflag), - append the target's name. */ - if (isdir || - (!lstat(source, &sb) && S_ISDIR(sb.st_mode)) || - (!hflag && !stat(source, &sb) && S_ISDIR(sb.st_mode))) { - if ((p = strrchr(target, '/')) == NULL) - p = target; - else - ++p; - (void)snprintf(path, sizeof(path), "%s/%s", source, p); - source = path; - } - - exists = !lstat(source, &sb); - - /* - * If the file exists, then unlink it forcibly if -f was specified - * and interactively if -i was specified. - */ - if (fflag && exists) { - if (unlink(source)) { - warn("%s", source); - return (1); - } - } else if (iflag && exists) { - fflush(stdout); - (void)fprintf(stderr, "replace %s? ", source); - - first = ch = getchar(); - while (ch != '\n' && ch != EOF) - ch = getchar(); - if (first != 'y' && first != 'Y') { - (void)fprintf(stderr, "not replaced\n"); - return (1); - } - - if (unlink(source)) { - warn("%s", source); - return (1); - } - } - - /* Attempt the link. */ - if ((*linkf)(target, source)) { - warn("%s", source); - return (1); - } - if (vflag) - (void)printf("%s %c> %s\n", source, linkch, target); - - return (0); -} - -static void -usage(void) -{ - - (void)fprintf(stderr, - "usage:\t%s [-fhinsv] file1 file2\n\t%s [-fhinsv] file ... directory\n", - getprogname(), getprogname()); - exit(1); - /* NOTREACHED */ -} diff --git a/toolbox/upstream-netbsd/bin/mv/mv.c b/toolbox/upstream-netbsd/bin/mv/mv.c deleted file mode 100644 index 4be6c30..0000000 --- a/toolbox/upstream-netbsd/bin/mv/mv.c +++ /dev/null @@ -1,396 +0,0 @@ -/* $NetBSD: mv.c,v 1.43 2011/08/29 14:46:54 joerg Exp $ */ - -/* - * Copyright (c) 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Ken Smith of The State University of New York at Buffalo. - * - * 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. - * 3. 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. - */ - -#include <sys/cdefs.h> -#ifndef lint -__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\ - The Regents of the University of California. All rights reserved."); -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)mv.c 8.2 (Berkeley) 4/2/94"; -#else -__RCSID("$NetBSD: mv.c,v 1.43 2011/08/29 14:46:54 joerg Exp $"); -#endif -#endif /* not lint */ - -#include <sys/param.h> -#include <sys/time.h> -#include <sys/wait.h> -#include <sys/stat.h> -#include <sys/extattr.h> - -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <grp.h> -#include <locale.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "pathnames.h" - -static int fflg, iflg, vflg; -static int stdin_ok; - -static int copy(char *, char *); -static int do_move(char *, char *); -static int fastcopy(char *, char *, struct stat *); -__dead static void usage(void); - -int -main(int argc, char *argv[]) -{ - int ch, len, rval; - char *p, *endp; - struct stat sb; - char path[MAXPATHLEN + 1]; - size_t baselen; - - setprogname(argv[0]); - (void)setlocale(LC_ALL, ""); - - while ((ch = getopt(argc, argv, "ifv")) != -1) - switch (ch) { - case 'i': - fflg = 0; - iflg = 1; - break; - case 'f': - iflg = 0; - fflg = 1; - break; - case 'v': - vflg = 1; - break; - default: - usage(); - } - argc -= optind; - argv += optind; - - if (argc < 2) - usage(); - - stdin_ok = isatty(STDIN_FILENO); - - /* - * If the stat on the target fails or the target isn't a directory, - * try the move. More than 2 arguments is an error in this case. - */ - if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) { - if (argc > 2) - usage(); - exit(do_move(argv[0], argv[1])); - } - - /* It's a directory, move each file into it. */ - baselen = strlcpy(path, argv[argc - 1], sizeof(path)); - if (baselen >= sizeof(path)) - errx(1, "%s: destination pathname too long", argv[argc - 1]); - endp = &path[baselen]; - if (!baselen || *(endp - 1) != '/') { - *endp++ = '/'; - ++baselen; - } - for (rval = 0; --argc; ++argv) { - p = *argv + strlen(*argv) - 1; - while (*p == '/' && p != *argv) - *p-- = '\0'; - if ((p = strrchr(*argv, '/')) == NULL) - p = *argv; - else - ++p; - - if ((baselen + (len = strlen(p))) >= MAXPATHLEN) { - warnx("%s: destination pathname too long", *argv); - rval = 1; - } else { - memmove(endp, p, len + 1); - if (do_move(*argv, path)) - rval = 1; - } - } - exit(rval); - /* NOTREACHED */ -} - -static int -do_move(char *from, char *to) -{ - struct stat sb; - char modep[15]; - - /* - * (1) If the destination path exists, the -f option is not specified - * and either of the following conditions are true: - * - * (a) The permissions of the destination path do not permit - * writing and the standard input is a terminal. - * (b) The -i option is specified. - * - * the mv utility shall write a prompt to standard error and - * read a line from standard input. If the response is not - * affirmative, mv shall do nothing more with the current - * source file... - */ - if (!fflg && !access(to, F_OK)) { - int ask = 1; - int ch; - - if (iflg) { - if (access(from, F_OK)) { - warn("rename %s", from); - return (1); - } - (void)fprintf(stderr, "overwrite %s? ", to); - } else if (stdin_ok && access(to, W_OK) && !stat(to, &sb)) { - if (access(from, F_OK)) { - warn("rename %s", from); - return (1); - } - strmode(sb.st_mode, modep); - (void)fprintf(stderr, "override %s%s%s/%s for %s? ", - modep + 1, modep[9] == ' ' ? "" : " ", - user_from_uid(sb.st_uid, 0), - group_from_gid(sb.st_gid, 0), to); - } else - ask = 0; - if (ask) { - if ((ch = getchar()) != EOF && ch != '\n') { - int ch2; - while ((ch2 = getchar()) != EOF && ch2 != '\n') - continue; - } - if (ch != 'y' && ch != 'Y') - return (0); - } - } - - /* - * (2) If rename() succeeds, mv shall do nothing more with the - * current source file. If it fails for any other reason than - * EXDEV, mv shall write a diagnostic message to the standard - * error and do nothing more with the current source file. - * - * (3) If the destination path exists, and it is a file of type - * directory and source_file is not a file of type directory, - * or it is a file not of type directory, and source file is - * a file of type directory, mv shall write a diagnostic - * message to standard error, and do nothing more with the - * current source file... - */ - if (!rename(from, to)) { - if (vflg) - printf("%s -> %s\n", from, to); - return (0); - } - - if (errno != EXDEV) { - warn("rename %s to %s", from, to); - return (1); - } - - /* - * (4) If the destination path exists, mv shall attempt to remove it. - * If this fails for any reason, mv shall write a diagnostic - * message to the standard error and do nothing more with the - * current source file... - */ - if (!lstat(to, &sb)) { - if ((S_ISDIR(sb.st_mode)) ? rmdir(to) : unlink(to)) { - warn("can't remove %s", to); - return (1); - } - } - - /* - * (5) The file hierarchy rooted in source_file shall be duplicated - * as a file hierarchy rooted in the destination path... - */ - if (lstat(from, &sb)) { - warn("%s", from); - return (1); - } - - return (S_ISREG(sb.st_mode) ? - fastcopy(from, to, &sb) : copy(from, to)); -} - -static int -fastcopy(char *from, char *to, struct stat *sbp) -{ - struct timeval tval[2]; - static blksize_t blen; - static char *bp; - int nread, from_fd, to_fd; - - if ((from_fd = open(from, O_RDONLY, 0)) < 0) { - warn("%s", from); - return (1); - } - if ((to_fd = - open(to, O_CREAT | O_TRUNC | O_WRONLY, sbp->st_mode)) < 0) { - warn("%s", to); - (void)close(from_fd); - return (1); - } - if (!blen && !(bp = malloc(blen = sbp->st_blksize))) { - warn(NULL); - blen = 0; - (void)close(from_fd); - (void)close(to_fd); - return (1); - } - while ((nread = read(from_fd, bp, blen)) > 0) - if (write(to_fd, bp, nread) != nread) { - warn("%s", to); - goto err; - } - if (nread < 0) { - warn("%s", from); -err: if (unlink(to)) - warn("%s: remove", to); - (void)close(from_fd); - (void)close(to_fd); - return (1); - } - -#ifndef __ANDROID__ - if (fcpxattr(from_fd, to_fd) == -1) - warn("%s: error copying extended attributes", to); -#endif - - (void)close(from_fd); -#ifdef BSD4_4 - TIMESPEC_TO_TIMEVAL(&tval[0], &sbp->st_atimespec); - TIMESPEC_TO_TIMEVAL(&tval[1], &sbp->st_mtimespec); -#else - tval[0].tv_sec = sbp->st_atime; - tval[1].tv_sec = sbp->st_mtime; - tval[0].tv_usec = 0; - tval[1].tv_usec = 0; -#endif -#ifdef __SVR4 - if (utimes(to, tval)) -#else - if (futimes(to_fd, tval)) -#endif - warn("%s: set times", to); - if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) { - if (errno != EPERM) - warn("%s: set owner/group", to); - sbp->st_mode &= ~(S_ISUID | S_ISGID); - } - if (fchmod(to_fd, sbp->st_mode)) - warn("%s: set mode", to); -#ifndef __ANDROID__ - if (fchflags(to_fd, sbp->st_flags) && (errno != EOPNOTSUPP)) - warn("%s: set flags (was: 0%07o)", to, sbp->st_flags); -#endif - - if (close(to_fd)) { - warn("%s", to); - return (1); - } - - if (unlink(from)) { - warn("%s: remove", from); - return (1); - } - - if (vflg) - printf("%s -> %s\n", from, to); - - return (0); -} - -static int -copy(char *from, char *to) -{ - pid_t pid; - int status; - - if ((pid = vfork()) == 0) { - execl(_PATH_CP, "mv", vflg ? "-PRpv" : "-PRp", "--", from, to, NULL); - warn("%s", _PATH_CP); - _exit(1); - } - if (waitpid(pid, &status, 0) == -1) { - warn("%s: waitpid", _PATH_CP); - return (1); - } - if (!WIFEXITED(status)) { - warnx("%s: did not terminate normally", _PATH_CP); - return (1); - } - if (WEXITSTATUS(status)) { - warnx("%s: terminated with %d (non-zero) status", - _PATH_CP, WEXITSTATUS(status)); - return (1); - } - if (!(pid = vfork())) { - execl(_PATH_RM, "mv", "-rf", "--", from, NULL); - warn("%s", _PATH_RM); - _exit(1); - } - if (waitpid(pid, &status, 0) == -1) { - warn("%s: waitpid", _PATH_RM); - return (1); - } - if (!WIFEXITED(status)) { - warnx("%s: did not terminate normally", _PATH_RM); - return (1); - } - if (WEXITSTATUS(status)) { - warnx("%s: terminated with %d (non-zero) status", - _PATH_RM, WEXITSTATUS(status)); - return (1); - } - return (0); -} - -static void -usage(void) -{ - (void)fprintf(stderr, "usage: %s [-fiv] source target\n" - " %s [-fiv] source ... directory\n", getprogname(), - getprogname()); - exit(1); - /* NOTREACHED */ -} diff --git a/toolbox/upstream-netbsd/bin/mv/pathnames.h b/toolbox/upstream-netbsd/bin/mv/pathnames.h deleted file mode 100644 index 7838946..0000000 --- a/toolbox/upstream-netbsd/bin/mv/pathnames.h +++ /dev/null @@ -1,45 +0,0 @@ -/* $NetBSD: pathnames.h,v 1.8 2004/08/19 22:26:07 christos Exp $ */ - -/* - * Copyright (c) 1989, 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. - * 3. 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. - * - * @(#)pathnames.h 8.1 (Berkeley) 5/31/93 - */ - -#ifdef __ANDROID__ -#define _PATH_RM "/system/bin/rm" -#define _PATH_CP "/system/bin/cp" -#else -#ifdef RESCUEDIR -#define _PATH_RM RESCUEDIR "/rm" -#define _PATH_CP RESCUEDIR "/cp" -#else -#define _PATH_RM "/bin/rm" -#define _PATH_CP "/bin/cp" -#endif -#endif diff --git a/toolbox/upstream-netbsd/bin/rm/rm.c b/toolbox/upstream-netbsd/bin/rm/rm.c deleted file mode 100644 index f183810..0000000 --- a/toolbox/upstream-netbsd/bin/rm/rm.c +++ /dev/null @@ -1,625 +0,0 @@ -/* $NetBSD: rm.c,v 1.53 2013/04/26 18:43:22 christos Exp $ */ - -/*- - * Copyright (c) 1990, 1993, 1994, 2003 - * 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. - * 3. 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. - */ - -#include <sys/cdefs.h> -#ifndef lint -__COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\ - The Regents of the University of California. All rights reserved."); -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)rm.c 8.8 (Berkeley) 4/27/95"; -#else -__RCSID("$NetBSD: rm.c,v 1.53 2013/04/26 18:43:22 christos Exp $"); -#endif -#endif /* not lint */ - -#include <sys/param.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <fts.h> -#include <grp.h> -#include <locale.h> -#include <pwd.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -static int dflag, eval, fflag, iflag, Pflag, stdin_ok, vflag, Wflag; -static int xflag; -static sig_atomic_t pinfo; - -static int check(char *, char *, struct stat *); -static void checkdot(char **); -static void progress(int); -static void rm_file(char **); -static int rm_overwrite(char *, struct stat *); -static void rm_tree(char **); -__dead static void usage(void); - -/* - * For the sake of the `-f' flag, check whether an error number indicates the - * failure of an operation due to an non-existent file, either per se (ENOENT) - * or because its filename argument was illegal (ENAMETOOLONG, ENOTDIR). - */ -#define NONEXISTENT(x) \ - ((x) == ENOENT || (x) == ENAMETOOLONG || (x) == ENOTDIR) - -/* - * rm -- - * This rm is different from historic rm's, but is expected to match - * POSIX 1003.2 behavior. The most visible difference is that -f - * has two specific effects now, ignore non-existent files and force - * file removal. - */ -int -main(int argc, char *argv[]) -{ - int ch, rflag; - - setprogname(argv[0]); - (void)setlocale(LC_ALL, ""); - - Pflag = rflag = xflag = 0; - while ((ch = getopt(argc, argv, "dfiPRrvWx")) != -1) - switch (ch) { - case 'd': - dflag = 1; - break; - case 'f': - fflag = 1; - iflag = 0; - break; - case 'i': - fflag = 0; - iflag = 1; - break; - case 'P': - Pflag = 1; - break; - case 'R': - case 'r': /* Compatibility. */ - rflag = 1; - break; - case 'v': - vflag = 1; - break; - case 'x': - xflag = 1; - break; -#ifndef __ANDROID__ - case 'W': - Wflag = 1; - break; -#endif - case '?': - default: - usage(); - } - argc -= optind; - argv += optind; - - if (argc < 1) { - if (fflag) - return 0; - usage(); - } - - (void)signal(SIGINFO, progress); - - checkdot(argv); - - if (*argv) { - stdin_ok = isatty(STDIN_FILENO); - - if (rflag) - rm_tree(argv); - else - rm_file(argv); - } - - exit(eval); - /* NOTREACHED */ -} - -static void -rm_tree(char **argv) -{ - FTS *fts; - FTSENT *p; - int flags, needstat, rval; - - /* - * Remove a file hierarchy. If forcing removal (-f), or interactive - * (-i) or can't ask anyway (stdin_ok), don't stat the file. - */ - needstat = !fflag && !iflag && stdin_ok; - - /* - * If the -i option is specified, the user can skip on the pre-order - * visit. The fts_number field flags skipped directories. - */ -#define SKIPPED 1 - - flags = FTS_PHYSICAL; - if (!needstat) - flags |= FTS_NOSTAT; -#ifndef __ANDROID__ - if (Wflag) - flags |= FTS_WHITEOUT; -#endif - if (xflag) - flags |= FTS_XDEV; - if ((fts = fts_open(argv, flags, NULL)) == NULL) - err(1, "fts_open failed"); - while ((p = fts_read(fts)) != NULL) { - - switch (p->fts_info) { - case FTS_DNR: - if (!fflag || p->fts_errno != ENOENT) { - warnx("%s: %s", p->fts_path, - strerror(p->fts_errno)); - eval = 1; - } - continue; - case FTS_ERR: - errx(EXIT_FAILURE, "%s: %s", p->fts_path, - strerror(p->fts_errno)); - /* NOTREACHED */ - case FTS_NS: - /* - * FTS_NS: assume that if can't stat the file, it - * can't be unlinked. - */ - if (fflag && NONEXISTENT(p->fts_errno)) - continue; - if (needstat) { - warnx("%s: %s", p->fts_path, - strerror(p->fts_errno)); - eval = 1; - continue; - } - break; - case FTS_D: - /* Pre-order: give user chance to skip. */ - if (!fflag && !check(p->fts_path, p->fts_accpath, - p->fts_statp)) { - (void)fts_set(fts, p, FTS_SKIP); - p->fts_number = SKIPPED; - } - continue; - case FTS_DP: - /* Post-order: see if user skipped. */ - if (p->fts_number == SKIPPED) - continue; - break; - default: - if (!fflag && - !check(p->fts_path, p->fts_accpath, p->fts_statp)) - continue; - } - - rval = 0; - /* - * If we can't read or search the directory, may still be - * able to remove it. Don't print out the un{read,search}able - * message unless the remove fails. - */ - switch (p->fts_info) { - case FTS_DP: - case FTS_DNR: - rval = rmdir(p->fts_accpath); - if (rval != 0 && fflag && errno == ENOENT) - continue; - break; - -#ifndef __ANDROID__ - case FTS_W: - rval = undelete(p->fts_accpath); - if (rval != 0 && fflag && errno == ENOENT) - continue; - break; -#endif - - default: - if (Pflag) { - if (rm_overwrite(p->fts_accpath, NULL)) - continue; - } - rval = unlink(p->fts_accpath); - if (rval != 0 && fflag && NONEXISTENT(errno)) - continue; - break; - } - if (rval != 0) { - warn("%s", p->fts_path); - eval = 1; - } else if (vflag || pinfo) { - pinfo = 0; - (void)printf("%s\n", p->fts_path); - } - } - if (errno) - err(1, "fts_read"); - fts_close(fts); -} - -static void -rm_file(char **argv) -{ - struct stat sb; - int rval; - char *f; - - /* - * Remove a file. POSIX 1003.2 states that, by default, attempting - * to remove a directory is an error, so must always stat the file. - */ - while ((f = *argv++) != NULL) { - /* Assume if can't stat the file, can't unlink it. */ - if (lstat(f, &sb)) { -#ifndef __ANDROID__ - if (Wflag) { - sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR; - } else { -#endif - if (!fflag || !NONEXISTENT(errno)) { - warn("%s", f); - eval = 1; - } - continue; -#ifndef __ANDROID__ - } - } else if (Wflag) { - warnx("%s: %s", f, strerror(EEXIST)); - eval = 1; - continue; -#endif - } - - if (S_ISDIR(sb.st_mode) && !dflag) { - warnx("%s: is a directory", f); - eval = 1; - continue; - } - if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb)) - continue; -#ifndef __ANDROID__ - if (S_ISWHT(sb.st_mode)) - rval = undelete(f); - else if (S_ISDIR(sb.st_mode)) -#else - if (S_ISDIR(sb.st_mode)) -#endif - rval = rmdir(f); - else { - if (Pflag) { - if (rm_overwrite(f, &sb)) - continue; - } - rval = unlink(f); - } - if (rval && (!fflag || !NONEXISTENT(errno))) { - warn("%s", f); - eval = 1; - } - if (vflag && rval == 0) - (void)printf("%s\n", f); - } -} - -/* - * rm_overwrite -- - * Overwrite the file 3 times with varying bit patterns. - * - * This is an expensive way to keep people from recovering files from your - * non-snapshotted FFS filesystems using fsdb(8). Really. No more. Only - * regular files are deleted, directories (and therefore names) will remain. - * Also, this assumes a fixed-block file system (like FFS, or a V7 or a - * System V file system). In a logging file system, you'll have to have - * kernel support. - * - * A note on standards: U.S. DoD 5220.22-M "National Industrial Security - * Program Operating Manual" ("NISPOM") is often cited as a reference - * for clearing and sanitizing magnetic media. In fact, a matrix of - * "clearing" and "sanitization" methods for various media was given in - * Chapter 8 of the original 1995 version of NISPOM. However, that - * matrix was *removed from the document* when Chapter 8 was rewritten - * in Change 2 to the document in 2001. Recently, the Defense Security - * Service has made a revised clearing and sanitization matrix available - * in Microsoft Word format on the DSS web site. The standardization - * status of this matrix is unclear. Furthermore, one must be very - * careful when referring to this matrix: it is intended for the "clearing" - * prior to reuse or "sanitization" prior to disposal of *entire media*, - * not individual files and the only non-physically-destructive method of - * "sanitization" that is permitted for magnetic disks of any kind is - * specifically noted to be prohibited for media that have contained - * Top Secret data. - * - * It is impossible to actually conform to the exact procedure given in - * the matrix if one is overwriting a file, not an entire disk, because - * the procedure requires examination and comparison of the disk's defect - * lists. Any program that claims to securely erase *files* while - * conforming to the standard, then, is not correct. We do as much of - * what the standard requires as can actually be done when erasing a - * file, rather than an entire disk; but that does not make us conformant. - * - * Furthermore, the presence of track caches, disk and controller write - * caches, and so forth make it extremely difficult to ensure that data - * have actually been written to the disk, particularly when one tries - * to repeatedly overwrite the same sectors in quick succession. We call - * fsync(), but controllers with nonvolatile cache, as well as IDE disks - * that just plain lie about the stable storage of data, will defeat this. - * - * Finally, widely respected research suggests that the given procedure - * is nowhere near sufficient to prevent the recovery of data using special - * forensic equipment and techniques that are well-known. This is - * presumably one reason that the matrix requires physical media destruction, - * rather than any technique of the sort attempted here, for secret data. - * - * Caveat Emptor. - * - * rm_overwrite will return 0 on success. - */ - -static int -rm_overwrite(char *file, struct stat *sbp) -{ - struct stat sb, sb2; - int fd, randint; - char randchar; - - fd = -1; - if (sbp == NULL) { - if (lstat(file, &sb)) - goto err; - sbp = &sb; - } - if (!S_ISREG(sbp->st_mode)) - return 0; - - /* flags to try to defeat hidden caching by forcing seeks */ - if ((fd = open(file, O_RDWR|O_SYNC|O_RSYNC|O_NOFOLLOW, 0)) == -1) - goto err; - - if (fstat(fd, &sb2)) { - goto err; - } - - if (sb2.st_dev != sbp->st_dev || sb2.st_ino != sbp->st_ino || - !S_ISREG(sb2.st_mode)) { - errno = EPERM; - goto err; - } - -#define RAND_BYTES 1 -#define THIS_BYTE 0 - -#define WRITE_PASS(mode, byte) do { \ - off_t len; \ - size_t wlen, i; \ - char buf[8 * 1024]; \ - \ - if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET)) \ - goto err; \ - \ - if (mode == THIS_BYTE) \ - memset(buf, byte, sizeof(buf)); \ - for (len = sbp->st_size; len > 0; len -= wlen) { \ - if (mode == RAND_BYTES) { \ - for (i = 0; i < sizeof(buf); \ - i+= sizeof(u_int32_t)) \ - *(int *)(buf + i) = arc4random(); \ - } \ - wlen = len < (off_t)sizeof(buf) ? (size_t)len : sizeof(buf); \ - if ((size_t)write(fd, buf, wlen) != wlen) \ - goto err; \ - } \ - sync(); /* another poke at hidden caches */ \ -} while (/* CONSTCOND */ 0) - -#define READ_PASS(byte) do { \ - off_t len; \ - size_t rlen; \ - char pattern[8 * 1024]; \ - char buf[8 * 1024]; \ - \ - if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET)) \ - goto err; \ - \ - memset(pattern, byte, sizeof(pattern)); \ - for(len = sbp->st_size; len > 0; len -= rlen) { \ - rlen = len < (off_t)sizeof(buf) ? (size_t)len : sizeof(buf); \ - if((size_t)read(fd, buf, rlen) != rlen) \ - goto err; \ - if(memcmp(buf, pattern, rlen)) \ - goto err; \ - } \ - sync(); /* another poke at hidden caches */ \ -} while (/* CONSTCOND */ 0) - - /* - * DSS sanitization matrix "clear" for magnetic disks: - * option 'c' "Overwrite all addressable locations with a single - * character." - */ - randint = arc4random(); - randchar = *(char *)&randint; - WRITE_PASS(THIS_BYTE, randchar); - - /* - * DSS sanitization matrix "sanitize" for magnetic disks: - * option 'd', sub 2 "Overwrite all addressable locations with a - * character, then its complement. Verify "complement" character - * was written successfully to all addressable locations, then - * overwrite all addressable locations with random characters; or - * verify third overwrite of random characters." The rest of the - * text in d-sub-2 specifies requirements for overwriting spared - * sectors; we cannot conform to it when erasing only a file, thus - * we do not conform to the standard. - */ - - /* 1. "a character" */ - WRITE_PASS(THIS_BYTE, 0xff); - - /* 2. "its complement" */ - WRITE_PASS(THIS_BYTE, 0x00); - - /* 3. "Verify 'complement' character" */ - READ_PASS(0x00); - - /* 4. "overwrite all addressable locations with random characters" */ - - WRITE_PASS(RAND_BYTES, 0x00); - - /* - * As the file might be huge, and we note that this revision of - * the matrix says "random characters", not "a random character" - * as the original did, we do not verify the random-character - * write; the "or" in the standard allows this. - */ - - if (close(fd) == -1) { - fd = -1; - goto err; - } - - return 0; - -err: eval = 1; - warn("%s", file); - if (fd != -1) - close(fd); - return 1; -} - -static int -check(char *path, char *name, struct stat *sp) -{ - int ch, first; - char modep[15]; - - /* Check -i first. */ - if (iflag) - (void)fprintf(stderr, "remove '%s'? ", path); - else { - /* - * If it's not a symbolic link and it's unwritable and we're - * talking to a terminal, ask. Symbolic links are excluded - * because their permissions are meaningless. Check stdin_ok - * first because we may not have stat'ed the file. - */ - if (!stdin_ok || S_ISLNK(sp->st_mode) || - !(access(name, W_OK) && (errno != ETXTBSY))) - return (1); - strmode(sp->st_mode, modep); - if (Pflag) { - warnx( - "%s: -P was specified but file could not" - " be overwritten", path); - return 0; - } - (void)fprintf(stderr, "override %s%s%s:%s for '%s'? ", - modep + 1, modep[9] == ' ' ? "" : " ", - user_from_uid(sp->st_uid, 0), - group_from_gid(sp->st_gid, 0), path); - } - (void)fflush(stderr); - - first = ch = getchar(); - while (ch != '\n' && ch != EOF) - ch = getchar(); - return (first == 'y' || first == 'Y'); -} - -/* - * POSIX.2 requires that if "." or ".." are specified as the basename - * portion of an operand, a diagnostic message be written to standard - * error and nothing more be done with such operands. - * - * Since POSIX.2 defines basename as the final portion of a path after - * trailing slashes have been removed, we'll remove them here. - */ -#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2]))) -static void -checkdot(char **argv) -{ - char *p, **save, **t; - int complained; - - complained = 0; - for (t = argv; *t;) { - /* strip trailing slashes */ - p = strrchr(*t, '\0'); - while (--p > *t && *p == '/') - *p = '\0'; - - /* extract basename */ - if ((p = strrchr(*t, '/')) != NULL) - ++p; - else - p = *t; - - if (ISDOT(p)) { - if (!complained++) - warnx("\".\" and \"..\" may not be removed"); - eval = 1; - for (save = t; (t[0] = t[1]) != NULL; ++t) - continue; - t = save; - } else - ++t; - } -} - -static void -usage(void) -{ - - (void)fprintf(stderr, "usage: %s [-f|-i] [-dPRrvWx] file ...\n", - getprogname()); - exit(1); - /* NOTREACHED */ -} - -static void -progress(int sig __unused) -{ - - pinfo++; -} diff --git a/toolbox/upstream-netbsd/bin/rmdir/rmdir.c b/toolbox/upstream-netbsd/bin/rmdir/rmdir.c deleted file mode 100644 index 03261ce..0000000 --- a/toolbox/upstream-netbsd/bin/rmdir/rmdir.c +++ /dev/null @@ -1,121 +0,0 @@ -/* $NetBSD: rmdir.c,v 1.26 2011/08/29 14:49:38 joerg Exp $ */ - -/*- - * Copyright (c) 1992, 1993, 1994 - * 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. - * 3. 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. - */ - -#include <sys/cdefs.h> -#ifndef lint -__COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\ - The Regents of the University of California. All rights reserved."); -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)rmdir.c 8.3 (Berkeley) 4/2/94"; -#else -__RCSID("$NetBSD: rmdir.c,v 1.26 2011/08/29 14:49:38 joerg Exp $"); -#endif -#endif /* not lint */ - -#include <sys/param.h> - -#include <err.h> -#include <locale.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -static int rm_path(char *); -__dead static void usage(void); - -int -main(int argc, char *argv[]) -{ - int ch, errors, pflag; - - setprogname(argv[0]); - (void)setlocale(LC_ALL, ""); - - pflag = 0; - while ((ch = getopt(argc, argv, "p")) != -1) - switch(ch) { - case 'p': - pflag = 1; - break; - case '?': - default: - usage(); - } - argc -= optind; - argv += optind; - - if (argc == 0) - usage(); - - for (errors = 0; *argv; argv++) { - /* We rely on the kernel to ignore trailing '/' characters. */ - if (rmdir(*argv) < 0) { - warn("%s", *argv); - errors = 1; - } else if (pflag) - errors |= rm_path(*argv); - } - - exit(errors); - /* NOTREACHED */ -} - -static int -rm_path(char *path) -{ - char *p; - - while ((p = strrchr(path, '/')) != NULL) { - *p = 0; - if (p[1] == 0) - /* Ignore trailing '/' on deleted name */ - continue; - - if (rmdir(path) < 0) { - warn("%s", path); - return (1); - } - } - - return (0); -} - -static void -usage(void) -{ - (void)fprintf(stderr, "usage: %s [-p] directory ...\n", getprogname()); - exit(1); - /* NOTREACHED */ -} diff --git a/toolbox/upstream-netbsd/bin/sleep/sleep.c b/toolbox/upstream-netbsd/bin/sleep/sleep.c deleted file mode 100644 index 4349af4..0000000 --- a/toolbox/upstream-netbsd/bin/sleep/sleep.c +++ /dev/null @@ -1,159 +0,0 @@ -/* $NetBSD: sleep.c,v 1.24 2011/08/29 14:51:19 joerg Exp $ */ - -/* - * Copyright (c) 1988, 1993, 1994 - * 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. - * 3. 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. - */ - -#include <sys/cdefs.h> -#ifndef lint -__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\ - The Regents of the University of California. All rights reserved."); -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)sleep.c 8.3 (Berkeley) 4/2/94"; -#else -__RCSID("$NetBSD: sleep.c,v 1.24 2011/08/29 14:51:19 joerg Exp $"); -#endif -#endif /* not lint */ - -#include <ctype.h> -#include <err.h> -#include <locale.h> -#include <math.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <time.h> -#include <unistd.h> - -__dead static void alarmhandle(int); -__dead static void usage(void); - -static volatile sig_atomic_t report_requested; -static void -report_request(int signo __unused) -{ - - report_requested = 1; -} - -int -main(int argc, char *argv[]) -{ - char *arg, *temp; - double fval, ival, val; - struct timespec ntime; - time_t original; - int ch, fracflag, rv; - - setprogname(argv[0]); - (void)setlocale(LC_ALL, ""); - - (void)signal(SIGALRM, alarmhandle); - - while ((ch = getopt(argc, argv, "")) != -1) - switch(ch) { - default: - usage(); - } - argc -= optind; - argv += optind; - - if (argc != 1) - usage(); - - /* - * Okay, why not just use atof for everything? Why bother - * checking if there is a fraction in use? Because the old - * sleep handled the full range of integers, that's why, and a - * double can't handle a large long. This is fairly useless - * given how large a number a double can hold on most - * machines, but now we won't ever have trouble. If you want - * 1000000000.9 seconds of sleep, well, that's your - * problem. Why use an isdigit() check instead of checking for - * a period? Because doing it this way means locales will be - * handled transparently by the atof code. - */ - fracflag = 0; - arg = *argv; - for (temp = arg; *temp != '\0'; temp++) - if (!isdigit((unsigned char)*temp)) - fracflag++; - - if (fracflag) { - val = atof(arg); - if (val <= 0) - usage(); - ival = floor(val); - fval = (1000000000 * (val-ival)); - ntime.tv_sec = ival; - ntime.tv_nsec = fval; - } - else { - ntime.tv_sec = atol(arg); - if (ntime.tv_sec <= 0) - return EXIT_SUCCESS; - ntime.tv_nsec = 0; - } - - original = ntime.tv_sec; - signal(SIGINFO, report_request); - while ((rv = nanosleep(&ntime, &ntime)) != 0) { - if (report_requested) { - /* Reporting does not bother with nanoseconds. */ - warnx("about %d second(s) left out of the original %d", - (int)ntime.tv_sec, (int)original); - report_requested = 0; - } else - break; - } - - if (rv == -1) - err(EXIT_FAILURE, "nanosleep failed"); - - return EXIT_SUCCESS; - /* NOTREACHED */ -} - -static void -usage(void) -{ - (void)fprintf(stderr, "usage: %s seconds\n", getprogname()); - exit(EXIT_FAILURE); - /* NOTREACHED */ -} - -/* ARGSUSED */ -static void -alarmhandle(int i) -{ - _exit(EXIT_SUCCESS); - /* NOTREACHED */ -} diff --git a/toolbox/upstream-netbsd/bin/sync/sync.c b/toolbox/upstream-netbsd/bin/sync/sync.c deleted file mode 100644 index 2b9c367..0000000 --- a/toolbox/upstream-netbsd/bin/sync/sync.c +++ /dev/null @@ -1,59 +0,0 @@ -/* $NetBSD: sync.c,v 1.13 2008/07/20 00:52:40 lukem Exp $ */ - -/* - * Copyright (c) 1987, 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. - * 3. 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. - */ - -#include <sys/cdefs.h> -#ifndef lint -__COPYRIGHT("@(#) Copyright (c) 1987, 1993\ - The Regents of the University of California. All rights reserved."); -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)sync.c 8.1 (Berkeley) 5/31/93"; -#else -__RCSID("$NetBSD: sync.c,v 1.13 2008/07/20 00:52:40 lukem Exp $"); -#endif -#endif /* not lint */ - -#include <stdlib.h> -#include <unistd.h> - -int main(int, char *[]); - -/* ARGSUSED */ -int -main(int argc, char *argv[]) -{ - setprogname(argv[0]); - sync(); - exit(0); - /* NOTREACHED */ -} diff --git a/toolbox/upstream-netbsd/sbin/chown/chown.c b/toolbox/upstream-netbsd/sbin/chown/chown.c deleted file mode 100644 index ee46eee..0000000 --- a/toolbox/upstream-netbsd/sbin/chown/chown.c +++ /dev/null @@ -1,302 +0,0 @@ -/* $NetBSD: chown.c,v 1.8 2012/10/24 01:12:51 enami Exp $ */ - -/* - * Copyright (c) 1988, 1993, 1994, 2003 - * 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. - * 3. 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. - */ - -#include <sys/cdefs.h> -#ifndef lint -__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994, 2003\ - The Regents of the University of California. All rights reserved."); -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)chown.c 8.8 (Berkeley) 4/4/94"; -#else -__RCSID("$NetBSD: chown.c,v 1.8 2012/10/24 01:12:51 enami Exp $"); -#endif -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/stat.h> - -#include <ctype.h> -#include <dirent.h> -#include <err.h> -#include <errno.h> -#include <locale.h> -#include <fts.h> -#include <grp.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <getopt.h> - -static void a_gid(const char *); -static void a_uid(const char *); -static id_t id(const char *, const char *); -__dead static void usage(void); - -static uid_t uid; -static gid_t gid; -static int ischown; -static const char *myname; - -struct option chown_longopts[] = { - { "reference", required_argument, 0, - 1 }, - { NULL, 0, 0, - 0 }, -}; - -int -main(int argc, char **argv) -{ - FTS *ftsp; - FTSENT *p; - int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval, vflag; - char *cp, *reference; - int (*change_owner)(const char *, uid_t, gid_t); - - setprogname(*argv); - - (void)setlocale(LC_ALL, ""); - - myname = getprogname(); - ischown = (myname[2] == 'o'); - reference = NULL; - - Hflag = Lflag = Rflag = fflag = hflag = vflag = 0; - while ((ch = getopt_long(argc, argv, "HLPRfhv", - chown_longopts, NULL)) != -1) - switch (ch) { - case 1: - reference = optarg; - break; - case 'H': - Hflag = 1; - Lflag = 0; - break; - case 'L': - Lflag = 1; - Hflag = 0; - break; - case 'P': - Hflag = Lflag = 0; - break; - case 'R': - Rflag = 1; - break; - case 'f': - fflag = 1; - break; - case 'h': - /* - * In System V the -h option causes chown/chgrp to - * change the owner/group of the symbolic link. - * 4.4BSD's symbolic links didn't have owners/groups, - * so it was an undocumented noop. - * In NetBSD 1.3, lchown(2) is introduced. - */ - hflag = 1; - break; - case 'v': - vflag = 1; - break; - case '?': - default: - usage(); - } - argv += optind; - argc -= optind; - - if (argc == 0 || (argc == 1 && reference == NULL)) - usage(); - - fts_options = FTS_PHYSICAL; - if (Rflag) { - if (Hflag) - fts_options |= FTS_COMFOLLOW; - if (Lflag) { - if (hflag) - errx(EXIT_FAILURE, - "the -L and -h options " - "may not be specified together."); - fts_options &= ~FTS_PHYSICAL; - fts_options |= FTS_LOGICAL; - } - } else if (!hflag) - fts_options |= FTS_COMFOLLOW; - - uid = (uid_t)-1; - gid = (gid_t)-1; - if (reference == NULL) { - if (ischown) { - if ((cp = strchr(*argv, ':')) != NULL) { - *cp++ = '\0'; - a_gid(cp); - } -#ifdef SUPPORT_DOT - else if ((cp = strrchr(*argv, '.')) != NULL) { - if (uid_from_user(*argv, &uid) == -1) { - *cp++ = '\0'; - a_gid(cp); - } - } -#endif - a_uid(*argv); - } else - a_gid(*argv); - argv++; - } else { - struct stat st; - - if (stat(reference, &st) == -1) - err(EXIT_FAILURE, "Cannot stat `%s'", reference); - if (ischown) - uid = st.st_uid; - gid = st.st_gid; - } - - if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL) - err(EXIT_FAILURE, "fts_open"); - - for (rval = EXIT_SUCCESS; (p = fts_read(ftsp)) != NULL;) { - change_owner = chown; - switch (p->fts_info) { - case FTS_D: - if (!Rflag) /* Change it at FTS_DP. */ - fts_set(ftsp, p, FTS_SKIP); - continue; - case FTS_DNR: /* Warn, chown, continue. */ - warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); - rval = EXIT_FAILURE; - break; - case FTS_ERR: /* Warn, continue. */ - case FTS_NS: - warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); - rval = EXIT_FAILURE; - continue; - case FTS_SL: /* Ignore unless -h. */ - /* - * All symlinks we found while doing a physical - * walk end up here. - */ - if (!hflag) - continue; - /* - * Note that if we follow a symlink, fts_info is - * not FTS_SL but FTS_F or whatever. And we should - * use lchown only for FTS_SL and should use chown - * for others. - */ - change_owner = lchown; - break; - case FTS_SLNONE: /* Ignore. */ - /* - * The only symlinks that end up here are ones that - * don't point to anything. Note that if we are - * doing a phisycal walk, we never reach here unless - * we asked to follow explicitly. - */ - continue; - default: - break; - } - - if ((*change_owner)(p->fts_accpath, uid, gid) && !fflag) { - warn("%s", p->fts_path); - rval = EXIT_FAILURE; - } else { - if (vflag) - printf("%s\n", p->fts_path); - } - } - if (errno) - err(EXIT_FAILURE, "fts_read"); - exit(rval); - /* NOTREACHED */ -} - -static void -a_gid(const char *s) -{ - struct group *gr; - - if (*s == '\0') /* Argument was "uid[:.]". */ - return; - gr = *s == '#' ? NULL : getgrnam(s); - if (gr == NULL) - gid = id(s, "group"); - else - gid = gr->gr_gid; - return; -} - -static void -a_uid(const char *s) -{ - if (*s == '\0') /* Argument was "[:.]gid". */ - return; - if (*s == '#' || uid_from_user(s, &uid) == -1) { - uid = id(s, "user"); - } - return; -} - -static id_t -id(const char *name, const char *type) -{ - id_t val; - char *ep; - - errno = 0; - if (*name == '#') - name++; - val = (id_t)strtoul(name, &ep, 10); - if (errno) - err(EXIT_FAILURE, "%s", name); - if (*ep != '\0') - errx(EXIT_FAILURE, "%s: invalid %s name", name, type); - return (val); -} - -static void -usage(void) -{ - - (void)fprintf(stderr, - "Usage: %s [-R [-H | -L | -P]] [-fhv] %s file ...\n" - "\t%s [-R [-H | -L | -P]] [-fhv] --reference=rfile file ...\n", - myname, ischown ? "owner:group|owner|:group" : "group", - myname); - exit(EXIT_FAILURE); -} diff --git a/toolbox/upstream-netbsd/usr.bin/grep/file.c b/toolbox/upstream-netbsd/usr.bin/grep/file.c index da03d71..cf4a0fa 100644 --- a/toolbox/upstream-netbsd/usr.bin/grep/file.c +++ b/toolbox/upstream-netbsd/usr.bin/grep/file.c @@ -78,7 +78,9 @@ static inline int grep_refill(struct file *f) { ssize_t nr; +#ifndef __ANDROID__ int bzerr; +#endif bufpos = buffer; bufrem = 0; diff --git a/toolbox/upstream-netbsd/usr.bin/printenv/printenv.c b/toolbox/upstream-netbsd/usr.bin/printenv/printenv.c deleted file mode 100644 index e15384f..0000000 --- a/toolbox/upstream-netbsd/usr.bin/printenv/printenv.c +++ /dev/null @@ -1,102 +0,0 @@ -/* $NetBSD: printenv.c,v 1.12 2011/09/06 18:26:55 joerg Exp $ */ - -/* - * Copyright (c) 1987, 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. - * 3. 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. - */ - -#include <sys/cdefs.h> -#ifndef lint -__COPYRIGHT("@(#) Copyright (c) 1987, 1993\ - The Regents of the University of California. All rights reserved."); -#endif /* not lint */ - -#ifndef lint -/*static char sccsid[] = "from: @(#)printenv.c 8.2 (Berkeley) 5/4/95";*/ -__RCSID("$NetBSD: printenv.c,v 1.12 2011/09/06 18:26:55 joerg Exp $"); -#endif /* not lint */ - -#include <sys/types.h> - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <err.h> - -__dead static void usage(void); - -/* - * printenv - * - * Bill Joy, UCB - * February, 1979 - */ -int -main(int argc, char *argv[]) -{ - extern char **environ; - char *cp, **ep; - size_t len; - int ch; - - while ((ch = getopt(argc, argv, "")) != -1) - switch(ch) { - case '?': - default: - usage(); - } - argc -= optind; - argv += optind; - - if (argc == 0) { - for (ep = environ; *ep; ep++) - (void)printf("%s\n", *ep); - exit(0); - } - if (argc != 1) - usage(); - if (strchr(*argv, '=') != NULL) - errx(1, "Invalid environment variable %s", *argv); - len = strlen(*argv); - for (ep = environ; *ep; ep++) - if (!memcmp(*ep, *argv, len)) { - cp = *ep + len; - if (!*cp || *cp == '=') { - (void)printf("%s\n", *cp ? cp + 1 : cp); - exit(0); - } - } - exit(1); -} - -static void -usage(void) -{ - (void)fprintf(stderr, "Usage: printenv [name]\n"); - exit(1); -} diff --git a/toolbox/uptime.c b/toolbox/uptime.c index 3fb4606..ebfb15e 100644 --- a/toolbox/uptime.c +++ b/toolbox/uptime.c @@ -29,71 +29,33 @@ * SUCH DAMAGE. */ -#include <sys/time.h> -#include <linux/ioctl.h> -#include <linux/rtc.h> -#include <linux/android_alarm.h> -#include <fcntl.h> +#include <errno.h> #include <stdio.h> +#include <string.h> #include <time.h> - static void format_time(int time, char* buffer) { - int seconds, minutes, hours, days; - - seconds = time % 60; + int seconds = time % 60; time /= 60; - minutes = time % 60; + int minutes = time % 60; time /= 60; - hours = time % 24; - days = time / 24; + int hours = time % 24; + int days = time / 24; - if (days > 0) - sprintf(buffer, "%d days, %02d:%02d:%02d", days, hours, minutes, seconds); - else + if (days > 0) { + sprintf(buffer, "%d day%s, %02d:%02d:%02d", days, (days == 1) ? "" : "s", hours, minutes, seconds); + } else { sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds); + } } -static int elapsedRealtimeAlarm(struct timespec *ts) -{ - int fd, result; - - fd = open("/dev/alarm", O_RDONLY); - if (fd < 0) - return fd; - - result = ioctl(fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), ts); - close(fd); - - return result; -} - -int64_t elapsedRealtime() -{ - struct timespec ts; - - int result = elapsedRealtimeAlarm(&ts); - if (result < 0) - result = clock_gettime(CLOCK_BOOTTIME, &ts); - - if (result == 0) - return ts.tv_sec; - return -1; -} - -int uptime_main(int argc __attribute__((unused)), - char *argv[] __attribute__((unused))) -{ - float up_time, idle_time; - char up_string[100], idle_string[100], sleep_string[100]; - int elapsed; - struct timespec up_timespec; - +int uptime_main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) { FILE* file = fopen("/proc/uptime", "r"); if (!file) { fprintf(stderr, "Could not open /proc/uptime\n"); return -1; } + float idle_time; if (fscanf(file, "%*f %f", &idle_time) != 1) { fprintf(stderr, "Could not parse /proc/uptime\n"); fclose(file); @@ -101,18 +63,21 @@ int uptime_main(int argc __attribute__((unused)), } fclose(file); - if (clock_gettime(CLOCK_MONOTONIC, &up_timespec) < 0) { - fprintf(stderr, "Could not get monotonic time\n"); + struct timespec up_timespec; + if (clock_gettime(CLOCK_MONOTONIC, &up_timespec) == -1) { + fprintf(stderr, "Could not get monotonic time: %s\n", strerror(errno)); return -1; } - up_time = up_timespec.tv_sec + up_timespec.tv_nsec / 1e9; + float up_time = up_timespec.tv_sec + up_timespec.tv_nsec / 1e9; - elapsed = elapsedRealtime(); - if (elapsed < 0) { - fprintf(stderr, "elapsedRealtime failed\n"); + struct timespec elapsed_timespec; + if (clock_gettime(CLOCK_BOOTTIME, &elapsed_timespec) == -1) { + fprintf(stderr, "Could not get boot time: %s\n", strerror(errno)); return -1; } + int elapsed = elapsed_timespec.tv_sec; + char up_string[100], idle_string[100], sleep_string[100]; format_time(elapsed, up_string); format_time((int)idle_time, idle_string); format_time((int)(elapsed - up_time), sleep_string); diff --git a/toolbox/vmstat.c b/toolbox/vmstat.c deleted file mode 100644 index 4086ed0..0000000 --- a/toolbox/vmstat.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (c) 2008, The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - */ - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/param.h> -#include <unistd.h> - -struct state { - long procs_r; - long procs_b; - - long mem_free; - long mem_mapped; - long mem_anon; - long mem_slab; - - long sys_in; - long sys_cs; - long sys_flt; - - long cpu_us; - long cpu_ni; - long cpu_sy; - long cpu_id; - long cpu_wa; - long cpu_ir; - long cpu_si; -}; - -#define MAX_LINE 256 - -char line[MAX_LINE]; - -static void read_state(struct state *s); -static int read_meminfo(struct state *s); -static int read_stat(struct state *s); -static int read_vmstat(struct state *s); -static void print_header(void); -static void print_line(struct state *old, struct state *new); -static void usage(char *cmd); - -int vmstat_main(int argc, char *argv[]) { - struct state s[2]; - int iterations, delay, header_interval; - int toggle, count; - int i; - - iterations = -1; - delay = 1; - header_interval = 20; - - for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "-n")) { - if (i >= argc - 1) { - fprintf(stderr, "Option -n requires an argument.\n"); - exit(EXIT_FAILURE); - } - iterations = atoi(argv[++i]); - continue; - } - if (!strcmp(argv[i], "-d")) { - if (i >= argc - 1) { - fprintf(stderr, "Option -d requires an argument.\n"); - exit(EXIT_FAILURE); - } - delay = atoi(argv[++i]); - continue; - } - if (!strcmp(argv[i], "-r")) { - if (i >= argc - 1) { - fprintf(stderr, "Option -r requires an argument.\n"); - exit(EXIT_FAILURE); - } - header_interval = atoi(argv[++i]); - continue; - } - if (!strcmp(argv[i], "-h")) { - usage(argv[0]); - exit(EXIT_SUCCESS); - } - fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]); - usage(argv[0]); - exit(EXIT_FAILURE); - } - - toggle = 0; - count = 0; - - if (!header_interval) - print_header(); - read_state(&s[1 - toggle]); - while ((iterations < 0) || (iterations-- > 0)) { - sleep(delay); - read_state(&s[toggle]); - if (header_interval) { - if (count == 0) - print_header(); - count = (count + 1) % header_interval; - } - print_line(&s[1 - toggle], &s[toggle]); - toggle = 1 - toggle; - } - - return 0; -} - -static void read_state(struct state *s) { - int error; - - error = read_meminfo(s); - if (error) { - fprintf(stderr, "vmstat: could not read /proc/meminfo: %s\n", strerror(error)); - exit(EXIT_FAILURE); - } - - error = read_stat(s); - if (error) { - fprintf(stderr, "vmstat: could not read /proc/stat: %s\n", strerror(error)); - exit(EXIT_FAILURE); - } - - error = read_vmstat(s); - if (error) { - fprintf(stderr, "vmstat: could not read /proc/vmstat: %s\n", strerror(error)); - exit(EXIT_FAILURE); - } -} - -static int read_meminfo(struct state *s) { - FILE *f; - - f = fopen("/proc/meminfo", "r"); - if (!f) return errno; - - while (fgets(line, MAX_LINE, f)) { - sscanf(line, "MemFree: %ld kB", &s->mem_free); - sscanf(line, "AnonPages: %ld kB", &s->mem_anon); - sscanf(line, "Mapped: %ld kB", &s->mem_mapped); - sscanf(line, "Slab: %ld kB", &s->mem_slab); - } - - fclose(f); - - return 0; -} - -static int read_stat(struct state *s) { - FILE *f; - - f = fopen("/proc/stat", "r"); - if (!f) return errno; - - while (fgets(line, MAX_LINE, f)) { - if (!strncmp(line, "cpu ", 4)) { - sscanf(line, "cpu %ld %ld %ld %ld %ld %ld %ld", - &s->cpu_us, &s->cpu_ni, &s->cpu_sy, &s->cpu_id, &s->cpu_wa, - &s->cpu_ir, &s->cpu_si); - } - sscanf(line, "intr %ld", &s->sys_in); - sscanf(line, "ctxt %ld", &s->sys_cs); - sscanf(line, "procs_running %ld", &s->procs_r); - sscanf(line, "procs_blocked %ld", &s->procs_b); - } - - fclose(f); - - return 0; -} - -static int read_vmstat(struct state *s) { - FILE *f; - - f = fopen("/proc/vmstat", "r"); - if (!f) return errno; - - while (fgets(line, MAX_LINE, f)) { - sscanf(line, "pgmajfault %ld", &s->sys_flt); - } - - fclose(f); - - return 0; -} - -static void print_header(void) { - printf("%-5s %-27s %-14s %-17s\n", "procs", "memory", "system", "cpu"); - printf("%2s %2s %6s %6s %6s %6s %4s %4s %4s %2s %2s %2s %2s %2s %2s\n", "r", "b", "free", "mapped", "anon", "slab", "in", "cs", "flt", "us", "ni", "sy", "id", "wa", "ir"); -} - -/* Jiffies to percent conversion */ -#define JP(jif) ((jif) * 100 / (HZ)) -#define NORM(var) ((var) = (((var) > 99) ? (99) : (var))) - -static void print_line(struct state *old, struct state *new) { - int us, ni, sy, id, wa, ir; - us = JP(new->cpu_us - old->cpu_us); NORM(us); - ni = JP(new->cpu_ni - old->cpu_ni); NORM(ni); - sy = JP(new->cpu_sy - old->cpu_sy); NORM(sy); - id = JP(new->cpu_id - old->cpu_id); NORM(id); - wa = JP(new->cpu_wa - old->cpu_wa); NORM(wa); - ir = JP(new->cpu_ir - old->cpu_ir); NORM(ir); - printf("%2ld %2ld %6ld %6ld %6ld %6ld %4ld %4ld %4ld %2d %2d %2d %2d %2d %2d\n", - new->procs_r ? (new->procs_r - 1) : 0, new->procs_b, - new->mem_free, new->mem_mapped, new->mem_anon, new->mem_slab, - new->sys_in - old->sys_in, new->sys_cs - old->sys_cs, new->sys_flt - old->sys_flt, - us, ni, sy, id, wa, ir); -} - -static void usage(char *cmd) { - fprintf(stderr, "Usage: %s [ -h ] [ -n iterations ] [ -d delay ] [ -r header_repeat ]\n" - " -n iterations How many rows of data to print.\n" - " -d delay How long to sleep between rows.\n" - " -r header_repeat How many rows to print before repeating\n" - " the header. Zero means never repeat.\n" - " -h Displays this help screen.\n", - cmd); -} diff --git a/toolbox/watchprops.c b/toolbox/watchprops.c index 0d05aba..cd62922 100644 --- a/toolbox/watchprops.c +++ b/toolbox/watchprops.c @@ -1,5 +1,6 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <time.h> #include <errno.h> diff --git a/toolbox/wipe.c b/toolbox/wipe.c deleted file mode 100644 index 650a0d6..0000000 --- a/toolbox/wipe.c +++ /dev/null @@ -1,176 +0,0 @@ -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <dirent.h> -#include <string.h> -#include <errno.h> -#include <sys/types.h> -#include <cutils/android_reboot.h> -#include <sys/stat.h> - -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif - - -/* Directories created by init defined in system/rootdir/init.rc */ -static char *INIT_DIRS[] = { - "/system/etc/ppp", - "/data/misc", - "/data/local", - "/data/local/tmp", - "/data/data", - "/data/app_private", - "/data/app", - NULL -}; - -static void wipe (const char *path); - -static int usage() -{ - fprintf(stderr, "wipe <system|data|all>\n\n" - "system means '/system'\n" - "data means '/data'\n"); - - return -1; -} - -int wipe_main (int argc, char *argv[]) -{ - char *whatToWipe; - - if (argc != 2) return usage(); - - whatToWipe = argv[1]; - - if (0 == strcmp (whatToWipe, "system")) { - fprintf(stdout, "Wiping /system\n"); - wipe ("/system"); - fprintf(stdout, "Done wiping /android\n"); - } else if (0 == strcmp (whatToWipe, "data")) { - fprintf(stdout, "Wiping /data\n"); - wipe ("/data"); - fprintf(stdout, "Done wiping /data\n"); - } else if (0 == strcmp (whatToWipe, "all")) { - fprintf(stdout, "Wiping /system and /data\n"); - wipe ("/system"); - wipe ("/data"); - fprintf(stdout, "Done wiping /system and /data\n"); - } else if (0 == strcmp(whatToWipe, "nuke")) { - int ret; - fprintf(stdout, "Nuking the device...\n"); - wipe ("/system"); - wipe ("/data"); - fprintf(stdout, "Device nuked! Rebooting...\n"); - ret = android_reboot(ANDROID_RB_RESTART, 0, 0); - if (ret < 0) { - fprintf(stderr, "Reboot failed, %s\n", strerror(errno)); - return 1; - } - } else { - return usage(); - } - - return 0; -} - -static char nameBuffer[PATH_MAX]; -static struct stat statBuffer; - -static void wipe (const char *path) -{ - DIR *dir; - struct dirent *de; - int ret; - - dir = opendir(path); - - if (dir == NULL) { - fprintf (stderr, "Error opendir'ing %s '%s'\n", - path, strerror(errno)); - return; - } - - char *filenameOffset; - - strcpy(nameBuffer, path); - strcat(nameBuffer, "/"); - - filenameOffset = nameBuffer + strlen(nameBuffer); - - for (;;) { - de = readdir(dir); - - if (de == NULL) { - break; - } - - if (0 == strcmp(de->d_name, ".") - || 0 == strcmp(de->d_name, "..") - || 0 == strcmp(de->d_name, "lost+found") - ) { - continue; - } - - strcpy(filenameOffset, de->d_name); - - ret = lstat (nameBuffer, &statBuffer); - - if (ret != 0) { - fprintf(stderr, "stat() error on '%s' '%s'\n", - nameBuffer, strerror(errno)); - } - - if(S_ISDIR(statBuffer.st_mode)) { - int i; - char *newpath; - -#if 0 - closedir(dir); -#endif - - newpath = strdup(nameBuffer); - wipe(newpath); - - /* Leave directories created by init, they have special permissions. */ - for (i = 0; INIT_DIRS[i]; i++) { - if (strcmp(INIT_DIRS[i], newpath) == 0) { - break; - } - } - if (INIT_DIRS[i] == NULL) { - ret = rmdir(newpath); - if (ret != 0) { - fprintf(stderr, "rmdir() error on '%s' '%s'\n", - newpath, strerror(errno)); - } - } - - free(newpath); - -#if 0 - dir = opendir(path); - if (dir == NULL) { - fprintf (stderr, "Error opendir'ing %s '%s'\n", - path, strerror(errno)); - return; - } -#endif - - strcpy(nameBuffer, path); - strcat(nameBuffer, "/"); - - } else { - ret = unlink(nameBuffer); - - if (ret != 0) { - fprintf(stderr, "unlink() error on '%s' '%s'\n", - nameBuffer, strerror(errno)); - } - } - } - - closedir(dir); - -} diff --git a/tzdatacheck/Android.mk b/tzdatacheck/Android.mk new file mode 100644 index 0000000..0e25f7d --- /dev/null +++ b/tzdatacheck/Android.mk @@ -0,0 +1,21 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +# ======================================================== +# Executable +# ======================================================== +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= tzdatacheck.cpp +LOCAL_MODULE := tzdatacheck +LOCAL_SHARED_LIBRARIES := libbase libcutils liblog +LOCAL_CFLAGS := -Werror +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= tzdatacheck.cpp +LOCAL_MODULE := tzdatacheck +LOCAL_SHARED_LIBRARIES := libbase libcutils liblog +LOCAL_CFLAGS := -Werror +include $(BUILD_HOST_EXECUTABLE) + diff --git a/tzdatacheck/tzdatacheck.cpp b/tzdatacheck/tzdatacheck.cpp new file mode 100644 index 0000000..31f7b55 --- /dev/null +++ b/tzdatacheck/tzdatacheck.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2015 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 <ftw.h> +#include <libgen.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <iostream> +#include <memory> +#include <string> +#include <vector> + +#include "base/logging.h" + +static const char* TZDATA_FILENAME = "/tzdata"; +// tzdata file header (as much as we need for the version): +// byte[11] tzdata_version -- e.g. "tzdata2012f" +static const int TZ_HEADER_LENGTH = 11; + +static void usage() { + std::cerr << "Usage: tzdatacheck SYSTEM_TZ_DIR DATA_TZ_DIR\n" + "\n" + "Compares the headers of two tzdata files. If the one in SYSTEM_TZ_DIR is the\n" + "same or a higher version than the one in DATA_TZ_DIR the DATA_TZ_DIR is renamed\n" + "and then deleted.\n"; + exit(1); +} + +/* + * Opens a file and fills headerBytes with the first byteCount bytes from the file. It is a fatal + * error if the file is too small or cannot be opened. If the file does not exist false is returned. + * If the bytes were read successfully then true is returned. + */ +static bool readHeader(const std::string& tzDataFileName, char* headerBytes, size_t byteCount) { + FILE* tzDataFile = fopen(tzDataFileName.c_str(), "r"); + if (tzDataFile == nullptr) { + if (errno == ENOENT) { + return false; + } else { + PLOG(FATAL) << "Error opening tzdata file " << tzDataFileName; + } + } + size_t bytesRead = fread(headerBytes, 1, byteCount, tzDataFile); + if (bytesRead != byteCount) { + LOG(FATAL) << tzDataFileName << " is too small. " << byteCount << " bytes required"; + } + fclose(tzDataFile); + return true; +} + +/* Checks the contents of headerBytes. It is a fatal error if it not a tzdata header. */ +static void checkValidHeader(const std::string& fileName, char* headerBytes) { + if (strncmp("tzdata", headerBytes, 6) != 0) { + LOG(FATAL) << fileName << " does not start with the expected bytes (tzdata)"; + } +} + +/* Return the parent directory of dirName. */ +static std::string getParentDir(const std::string& dirName) { + std::unique_ptr<char> mutable_dirname(strdup(dirName.c_str())); + return dirname(mutable_dirname.get()); +} + +/* Deletes a single file, symlink or directory. Called from nftw(). */ +static int deleteFn(const char* fpath, const struct stat*, int typeflag, struct FTW*) { + LOG(DEBUG) << "Inspecting " << fpath; + switch (typeflag) { + case FTW_F: + case FTW_SL: + LOG(DEBUG) << "Unlinking " << fpath; + if (unlink(fpath)) { + PLOG(WARNING) << "Failed to unlink file/symlink " << fpath; + } + break; + case FTW_D: + case FTW_DP: + LOG(DEBUG) << "Removing dir " << fpath; + if (rmdir(fpath)) { + PLOG(WARNING) << "Failed to remove dir " << fpath; + } + break; + default: + LOG(WARNING) << "Unsupported file type " << fpath << ": " << typeflag; + break; + } + return 0; +} + +/* + * Deletes dirToDelete and returns true if it is successful in removing or moving the directory out + * of the way. If dirToDelete does not exist this function does nothing and returns true. + * + * During deletion, this function first renames the directory to a temporary name. If the temporary + * directory cannot be created, or the directory cannot be renamed, false is returned. After the + * rename, deletion of files and subdirs beneath the directory is performed on a "best effort" + * basis. Symlinks beneath the directory are not followed. + */ +static bool deleteDir(const std::string& dirToDelete) { + // Check whether the dir exists. + struct stat buf; + if (stat(dirToDelete.c_str(), &buf) == 0) { + if (!S_ISDIR(buf.st_mode)) { + LOG(WARNING) << dirToDelete << " is not a directory"; + return false; + } + } else { + if (errno == ENOENT) { + PLOG(INFO) << "Directory does not exist: " << dirToDelete; + return true; + } else { + PLOG(WARNING) << "Unable to stat " << dirToDelete; + return false; + } + } + + // First, rename dirToDelete. + std::string tempDirNameTemplate = getParentDir(dirToDelete); + tempDirNameTemplate += "/tempXXXXXX"; + + // Create an empty directory with the temporary name. For this we need a non-const char*. + std::vector<char> tempDirName(tempDirNameTemplate.length() + 1); + strcpy(&tempDirName[0], tempDirNameTemplate.c_str()); + if (mkdtemp(&tempDirName[0]) == nullptr) { + PLOG(WARNING) << "Unable to create a temporary directory: " << tempDirNameTemplate; + return false; + } + + // Rename dirToDelete to tempDirName. + int rc = rename(dirToDelete.c_str(), &tempDirName[0]); + if (rc == -1) { + PLOG(WARNING) << "Unable to rename directory from " << dirToDelete << " to " + << &tempDirName[0]; + return false; + } + + // Recursively delete contents of tempDirName. + rc = nftw(&tempDirName[0], deleteFn, 10 /* openFiles */, + FTW_DEPTH | FTW_MOUNT | FTW_PHYS); + if (rc == -1) { + LOG(INFO) << "Could not delete directory: " << &tempDirName[0]; + } + return true; +} + +/* + * After a platform update it is likely that timezone data found on the system partition will be + * newer than the version found in the data partition. This tool detects this case and removes the + * version in /data along with any update metadata. + * + * Note: This code is related to code in com.android.server.updates.TzDataInstallReceiver. The + * paths for the metadata and current timezone data must match. + * + * Typically on device the two args will be: + * /system/usr/share/zoneinfo /data/misc/zoneinfo + * + * See usage() for usage notes. + */ +int main(int argc, char* argv[]) { + if (argc != 3) { + usage(); + } + + const char* systemZoneInfoDir = argv[1]; + const char* dataZoneInfoDir = argv[2]; + + std::string dataCurrentDirName(dataZoneInfoDir); + dataCurrentDirName += "/current"; + std::string dataTzDataFileName(dataCurrentDirName); + dataTzDataFileName += TZDATA_FILENAME; + + std::vector<char> dataTzDataHeader; + dataTzDataHeader.reserve(TZ_HEADER_LENGTH); + + bool dataFileExists = readHeader(dataTzDataFileName, dataTzDataHeader.data(), TZ_HEADER_LENGTH); + if (!dataFileExists) { + LOG(INFO) << "tzdata file " << dataTzDataFileName << " does not exist. No action required."; + return 0; + } + checkValidHeader(dataTzDataFileName, dataTzDataHeader.data()); + + std::string systemTzDataFileName(systemZoneInfoDir); + systemTzDataFileName += TZDATA_FILENAME; + std::vector<char> systemTzDataHeader; + systemTzDataHeader.reserve(TZ_HEADER_LENGTH); + bool systemFileExists = + readHeader(systemTzDataFileName, systemTzDataHeader.data(), TZ_HEADER_LENGTH); + if (!systemFileExists) { + LOG(FATAL) << systemTzDataFileName << " does not exist or could not be opened"; + } + checkValidHeader(systemTzDataFileName, systemTzDataHeader.data()); + + if (strncmp(&systemTzDataHeader[0], &dataTzDataHeader[0], TZ_HEADER_LENGTH) < 0) { + LOG(INFO) << "tzdata file " << dataTzDataFileName << " is the newer than " + << systemTzDataFileName << ". No action required."; + } else { + // We have detected the case this tool is intended to prevent. Go fix it. + LOG(INFO) << "tzdata file " << dataTzDataFileName << " is the same as or older than " + << systemTzDataFileName << "; fixing..."; + + // Delete the update metadata + std::string dataUpdatesDirName(dataZoneInfoDir); + dataUpdatesDirName += "/updates"; + LOG(INFO) << "Removing: " << dataUpdatesDirName; + bool deleted = deleteDir(dataUpdatesDirName); + if (!deleted) { + LOG(WARNING) << "Deletion of install metadata " << dataUpdatesDirName + << " was not successful"; + } + + // Delete the TZ data + LOG(INFO) << "Removing: " << dataCurrentDirName; + deleted = deleteDir(dataCurrentDirName); + if (!deleted) { + LOG(WARNING) << "Deletion of tzdata " << dataCurrentDirName << " was not successful"; + } + } + + return 0; +} |