liblog: add __android_log_close() am: 2d14969155 am: 3b2fa3eaef
am: 7b16dcf969
Change-Id: Id17cdb4600a081c5fc0442cb244d65021dd0dbb6
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)/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)
diff --git a/README b/README
deleted file mode 100644
index 0083247..0000000
--- a/README
+++ /dev/null
@@ -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)
+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
+
+# 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)
+ LOCAL_LDLIBS += -lrt -ldl -lpthread
+endif
+
+ifeq ($(HOST_OS),darwin)
+ LOCAL_LDLIBS += -framework CoreFoundation -framework IOKit
+endif
+
+include $(BUILD_HOST_NATIVE_TEST)
+
# adb host tool
# =========================================================
include $(CLEAR_VARS)
-# Default to a virtual (sockets) usb interface
-USB_SRCS :=
-EXTRA_SRCS :=
-
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
-endif
-
-ifeq ($(HOST_OS),freebsd)
- USB_SRCS := usb_libusb.c
- EXTRA_SRCS := get_my_path_freebsd.c
- LOCAL_LDLIBS += -lpthread -lusb
+ 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
+ adb_main.cpp \
+ console.cpp \
+ commandline.cpp \
+ adb_client.cpp \
+ services.cpp \
+ file_sync_client.cpp \
-LOCAL_C_INCLUDES += external/openssl/include
+LOCAL_CFLAGS += \
+ -Wall -Werror \
+ -Wno-unused-parameter \
+ -D_GNU_SOURCE \
+ -DADB_HOST=1 \
-ifneq ($(USE_SYSDEPS_WIN32),)
- LOCAL_SRC_FILES += sysdeps_win32.c
-else
- LOCAL_SRC_FILES += fdevent.c
-endif
-
-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 @@
include $(CLEAR_VARS)
-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_CLANG := true
-LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter -Werror
-LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
+LOCAL_SRC_FILES := \
+ 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_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_C_INCLUDES += system/extras/ext4_utils
-LOCAL_STATIC_LIBRARIES := liblog \
- libfs_mgr \
- libcutils \
- libc \
- libmincrypt \
- libselinux \
- libext4_utils_static
+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
diff --git a/adb/adb.c b/adb/adb.c
deleted file mode 100644
index 10a1e0d..0000000
--- a/adb/adb.c
+++ /dev/null
@@ -1,1725 +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.
- */
-
-#define TRACE_TAG TRACE_ADB
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <stddef.h>
-#include <string.h>
-#include <time.h>
-#include <sys/time.h>
-#include <stdint.h>
-
-#include "sysdeps.h"
-#include "adb.h"
-#include "adb_auth.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
-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;
-#endif
-
-void fatal(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- fprintf(stderr, "error: ");
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
- va_end(ap);
- exit(-1);
-}
-
-void fatal_errno(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- fprintf(stderr, "error: %s: ", strerror(errno));
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
- va_end(ap);
- exit(-1);
-}
-
-int adb_trace_mask;
-
-/* 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;
-
- static const struct {
- const char* tag;
- int flag;
- } tags[] = {
- { "1", 0 },
- { "all", 0 },
- { "adb", TRACE_ADB },
- { "sockets", TRACE_SOCKETS },
- { "packets", TRACE_PACKETS },
- { "rwx", TRACE_RWX },
- { "usb", TRACE_USB },
- { "sync", TRACE_SYNC },
- { "sysdeps", TRACE_SYSDEPS },
- { "transport", TRACE_TRANSPORT },
- { "jdwp", TRACE_JDWP },
- { "services", TRACE_SERVICES },
- { "auth", TRACE_AUTH },
- { NULL, 0 }
- };
-
- if (p == NULL)
- return;
-
- /* use a comma/column/semi-colum/space separated list */
- while (*p) {
- int len, tagn;
-
- q = strpbrk(p, " ,:;");
- if (q == NULL) {
- q = p + strlen(p);
- }
- len = q - p;
-
- for (tagn = 0; tags[tagn].tag != NULL; tagn++)
- {
- int taglen = strlen(tags[tagn].tag);
-
- if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
- {
- int flag = tags[tagn].flag;
- if (flag == 0) {
- adb_trace_mask = ~0;
- return;
- }
- adb_trace_mask |= (1 << flag);
- break;
- }
- }
- p = q;
- 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;
-}
-
-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));
- }
-}
-#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;
-}
-
-void put_apacket(apacket *p)
-{
- free(p);
-}
-
-void handle_online(atransport *t)
-{
- D("adb: online\n");
- t->online = 1;
-}
-
-void handle_offline(atransport *t)
-{
- D("adb: offline\n");
- //Close the associated usb
- t->online = 0;
- run_transport_disconnects(t);
-}
-
-#if DEBUG_PACKETS
-#define DUMPMAX 32
-void print_packet(const char *label, apacket *p)
-{
- char *tag;
- char *x;
- unsigned count;
-
- switch(p->msg.command){
- case A_SYNC: tag = "SYNC"; break;
- case A_CNXN: tag = "CNXN" ; break;
- case A_OPEN: tag = "OPEN"; break;
- case A_OKAY: tag = "OKAY"; break;
- case A_CLSE: tag = "CLSE"; break;
- case A_WRTE: tag = "WRTE"; break;
- case A_AUTH: tag = "AUTH"; break;
- default: tag = "????"; break;
- }
-
- fprintf(stderr, "%s: %s %08x %08x %04x \"",
- label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
- count = p->msg.data_length;
- x = (char*) p->data;
- if(count > DUMPMAX) {
- count = DUMPMAX;
- tag = "\n";
- } else {
- tag = "\"\n";
- }
- while(count-- > 0){
- if((*x >= ' ') && (*x < 127)) {
- fputc(*x, stderr);
- } else {
- fputc('.', stderr);
- }
- x++;
- }
- fputs(tag, stderr);
-}
-#endif
-
-static void send_ready(unsigned local, unsigned remote, atransport *t)
-{
- D("Calling send_ready \n");
- apacket *p = get_apacket();
- p->msg.command = A_OKAY;
- p->msg.arg0 = local;
- p->msg.arg1 = remote;
- send_packet(p, t);
-}
-
-static void send_close(unsigned local, unsigned remote, atransport *t)
-{
- D("Calling send_close \n");
- apacket *p = get_apacket();
- p->msg.command = A_CLSE;
- p->msg.arg0 = local;
- p->msg.arg1 = remote;
- send_packet(p, t);
-}
-
-static size_t fill_connect_data(char *buf, size_t bufsize)
-{
-#if ADB_HOST
- return snprintf(buf, bufsize, "host::") + 1;
-#else
- static const char *cnxn_props[] = {
- "ro.product.name",
- "ro.product.model",
- "ro.product.device",
- };
- static const int num_cnxn_props = ARRAY_SIZE(cnxn_props);
- int i;
- size_t remaining = bufsize;
- size_t len;
-
- len = snprintf(buf, remaining, "%s::", adb_device_banner);
- remaining -= len;
- buf += len;
- for (i = 0; i < num_cnxn_props; i++) {
- char value[PROPERTY_VALUE_MAX];
- property_get(cnxn_props[i], value, "");
- len = snprintf(buf, remaining, "%s=%s;", cnxn_props[i], value);
- remaining -= len;
- buf += len;
- }
-
- return bufsize - remaining + 1;
-#endif
-}
-
-#if !ADB_HOST
-static void send_msg_with_header(int fd, const char* msg, size_t msglen) {
- char header[5];
- if (msglen > 0xffff)
- msglen = 0xffff;
- snprintf(header, sizeof(header), "%04x", (unsigned)msglen);
- writex(fd, header, 4);
- writex(fd, msg, msglen);
-}
-#endif
-
-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);
-}
-
-static void send_connect(atransport *t)
-{
- D("Calling send_connect \n");
- apacket *cp = get_apacket();
- cp->msg.command = A_CNXN;
- cp->msg.arg0 = A_VERSION;
- cp->msg.arg1 = MAX_PAYLOAD;
- cp->msg.data_length = fill_connect_data((char *)cp->data,
- sizeof(cp->data));
- 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 (t == NULL) {
- return "unknown";
- }
-
- switch(t->connection_state) {
- case CS_BOOTLOADER:
- return "bootloader";
- case CS_DEVICE:
- return "device";
- case CS_RECOVERY:
- return "recovery";
- case CS_SIDELOAD:
- return "sideload";
- case CS_OFFLINE:
- return "offline";
- case CS_UNAUTHORIZED:
- return "unauthorized";
- default:
- return "unknown";
- }
-}
-
-/* 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
- * was malloc'ed and needs to freed. *dst will be set to a dup of src.
- */
-static void qual_overwrite(char **dst, const char *src)
-{
- if (!dst)
- return;
-
- free(*dst);
- *dst = NULL;
-
- if (!src || !*src)
- return;
-
- *dst = strdup(src);
-}
-
-void parse_banner(char *banner, atransport *t)
-{
- static const char *prop_seps = ";";
- static const char key_val_sep = '=';
- char *cp;
- char *type;
-
- D("parse_banner: %s\n", banner);
- type = banner;
- cp = strchr(type, ':');
- if (cp) {
- *cp++ = 0;
- /* Nothing is done with second field. */
- cp = strchr(cp, ':');
- if (cp) {
- char *save;
- char *key;
- key = adb_strtok_r(cp + 1, prop_seps, &save);
- while (key) {
- cp = strchr(key, key_val_sep);
- if (cp) {
- *cp++ = '\0';
- if (!strcmp(key, "ro.product.name"))
- qual_overwrite(&t->product, cp);
- else if (!strcmp(key, "ro.product.model"))
- qual_overwrite(&t->model, cp);
- else if (!strcmp(key, "ro.product.device"))
- qual_overwrite(&t->device, cp);
- }
- key = adb_strtok_r(NULL, prop_seps, &save);
- }
- }
- }
-
- if(!strcmp(type, "bootloader")){
- D("setting connection_state to CS_BOOTLOADER\n");
- t->connection_state = CS_BOOTLOADER;
- update_transports();
- return;
- }
-
- if(!strcmp(type, "device")) {
- D("setting connection_state to CS_DEVICE\n");
- t->connection_state = CS_DEVICE;
- update_transports();
- return;
- }
-
- if(!strcmp(type, "recovery")) {
- D("setting connection_state to CS_RECOVERY\n");
- t->connection_state = CS_RECOVERY;
- update_transports();
- return;
- }
-
- if(!strcmp(type, "sideload")) {
- D("setting connection_state to CS_SIDELOAD\n");
- t->connection_state = CS_SIDELOAD;
- update_transports();
- return;
- }
-
- t->connection_state = CS_HOST;
-}
-
-void handle_packet(apacket *p, atransport *t)
-{
- asocket *s;
-
- D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
- ((char*) (&(p->msg.command)))[1],
- ((char*) (&(p->msg.command)))[2],
- ((char*) (&(p->msg.command)))[3]);
- print_packet("recv", p);
-
- switch(p->msg.command){
- case A_SYNC:
- if(p->msg.arg0){
- send_packet(p, t);
- if(HOST) send_connect(t);
- } else {
- t->connection_state = CS_OFFLINE;
- handle_offline(t);
- send_packet(p, t);
- }
- return;
-
- case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
- /* XXX verify version, etc */
- if(t->connection_state != CS_OFFLINE) {
- t->connection_state = CS_OFFLINE;
- handle_offline(t);
- }
-
- parse_banner((char*) p->data, t);
-
- if (HOST || !auth_enabled) {
- handle_online(t);
- if(!HOST) send_connect(t);
- } else {
- send_auth_request(t);
- }
- break;
-
- case A_AUTH:
- if (p->msg.arg0 == ADB_AUTH_TOKEN) {
- t->connection_state = CS_UNAUTHORIZED;
- t->key = adb_auth_nextkey(t->key);
- if (t->key) {
- send_auth_response(p->data, p->msg.data_length, t);
- } else {
- /* No more private keys to try, send the public key */
- send_auth_publickey(t);
- }
- } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
- if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
- adb_auth_verified(t);
- t->failed_auth_attempts = 0;
- } else {
- if (t->failed_auth_attempts++ > 10)
- adb_sleep_ms(1000);
- send_auth_request(t);
- }
- } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
- adb_auth_confirm_key(p->data, p->msg.data_length, t);
- }
- break;
-
- case A_OPEN: /* OPEN(local-id, 0, "destination") */
- if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
- char *name = (char*) p->data;
- name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
- s = create_local_service_socket(name);
- if(s == 0) {
- send_close(0, p->msg.arg0, t);
- } else {
- s->peer = create_remote_socket(p->msg.arg0, t);
- s->peer->peer = s;
- send_ready(s->id, s->peer->id, t);
- s->ready(s);
- }
- }
- break;
-
- case A_OKAY: /* READY(local-id, remote-id, "") */
- if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
- if((s = find_local_socket(p->msg.arg1, 0))) {
- if(s->peer == 0) {
- /* On first READY message, create the connection. */
- s->peer = create_remote_socket(p->msg.arg0, t);
- s->peer->peer = s;
- s->ready(s);
- } else if (s->peer->id == p->msg.arg0) {
- /* Other READY messages must use the same local-id */
- s->ready(s);
- } else {
- D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s\n",
- p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial);
- }
- }
- }
- break;
-
- case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */
- if (t->online && p->msg.arg1 != 0) {
- if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
- /* According to protocol.txt, p->msg.arg0 might be 0 to indicate
- * a failed OPEN only. However, due to a bug in previous ADB
- * versions, CLOSE(0, remote-id, "") was also used for normal
- * CLOSE() operations.
- *
- * This is bad because it means a compromised adbd could
- * send packets to close connections between the host and
- * other devices. To avoid this, only allow this if the local
- * socket has a peer on the same transport.
- */
- if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) {
- D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s\n",
- p->msg.arg1, t->serial, s->peer->transport->serial);
- } else {
- s->close(s);
- }
- }
- }
- break;
-
- case A_WRTE: /* WRITE(local-id, remote-id, <data>) */
- if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
- if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
- unsigned rid = p->msg.arg0;
- p->len = p->msg.data_length;
-
- if(s->enqueue(s, p) == 0) {
- D("Enqueue the socket\n");
- send_ready(s->id, rid, t);
- }
- return;
- }
- }
- break;
-
- default:
- printf("handle_packet: what is %08x?!\n", p->msg.command);
- }
-
- 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
- /* 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 */
- /* security attribute */
- HANDLE pipe_read, pipe_write;
- HANDLE stdout_handle, stderr_handle;
- SECURITY_ATTRIBUTES sa;
- STARTUPINFO startup;
- PROCESS_INFORMATION pinfo;
- char program_path[ MAX_PATH ];
- int ret;
-
- sa.nLength = sizeof(sa);
- sa.lpSecurityDescriptor = NULL;
- sa.bInheritHandle = TRUE;
-
- /* create pipe, and ensure its read handle isn't inheritable */
- ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
- if (!ret) {
- fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
- return -1;
- }
-
- SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
-
- /* Some programs want to launch an adb command and collect its output by
- * calling CreateProcess with inheritable stdout/stderr handles, then
- * using read() to get its output. When this happens, the stdout/stderr
- * handles passed to the adb client process will also be inheritable.
- * When starting the adb server here, care must be taken to reset them
- * to non-inheritable.
- * Otherwise, something bad happens: even if the adb command completes,
- * the calling process is stuck while read()-ing from the stdout/stderr
- * descriptors, because they're connected to corresponding handles in the
- * adb server process (even if the latter never uses/writes to them).
- */
- stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE );
- stderr_handle = GetStdHandle( STD_ERROR_HANDLE );
- if (stdout_handle != INVALID_HANDLE_VALUE) {
- SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 );
- }
- if (stderr_handle != INVALID_HANDLE_VALUE) {
- SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 );
- }
-
- ZeroMemory( &startup, sizeof(startup) );
- startup.cb = sizeof(startup);
- startup.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
- startup.hStdOutput = pipe_write;
- startup.hStdError = GetStdHandle( STD_ERROR_HANDLE );
- startup.dwFlags = STARTF_USESTDHANDLES;
-
- ZeroMemory( &pinfo, sizeof(pinfo) );
-
- /* get path of current program */
- GetModuleFileName( NULL, program_path, sizeof(program_path) );
-
- ret = CreateProcess(
- program_path, /* program path */
- "adb fork-server server",
- /* the fork-server argument will set the
- debug = 2 in the child */
- NULL, /* process handle is not inheritable */
- NULL, /* thread handle is not inheritable */
- TRUE, /* yes, inherit some handles */
- DETACHED_PROCESS, /* the new process doesn't have a console */
- NULL, /* use parent's environment block */
- NULL, /* use parent's starting directory */
- &startup, /* startup info, i.e. std handles */
- &pinfo );
-
- CloseHandle( pipe_write );
-
- if (!ret) {
- fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
- CloseHandle( pipe_read );
- return -1;
- }
-
- CloseHandle( pinfo.hProcess );
- CloseHandle( pinfo.hThread );
-
- /* wait for the "OK\n" message */
- {
- char temp[3];
- DWORD count;
-
- ret = ReadFile( pipe_read, temp, 3, &count, NULL );
- CloseHandle( pipe_read );
- if ( !ret ) {
- fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
- return -1;
- }
- if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
- fprintf(stderr, "ADB server didn't ACK\n" );
- return -1;
- }
- }
-#elif defined(HAVE_FORKEXEC)
- char path[PATH_MAX];
- int fd[2];
-
- // set up a pipe so the child can tell us when it is ready.
- // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
- if (pipe(fd)) {
- fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
- return -1;
- }
- get_my_path(path, PATH_MAX);
- pid_t pid = fork();
- if(pid < 0) return -1;
-
- if (pid == 0) {
- // child side of the fork
-
- // redirect stderr to the pipe
- // we use stderr instead of stdout due to stdout's buffering behavior.
- adb_close(fd[0]);
- dup2(fd[1], STDERR_FILENO);
- adb_close(fd[1]);
-
- char str_port[30];
- snprintf(str_port, sizeof(str_port), "%d", server_port);
- // child process
- int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL);
- // this should not return
- fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
- } else {
- // parent side of the fork
-
- char temp[3];
-
- temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
- // wait for the "OK\n" message
- adb_close(fd[1]);
- int ret = adb_read(fd[0], temp, 3);
- int saved_errno = errno;
- adb_close(fd[0]);
- if (ret < 0) {
- fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno);
- return -1;
- }
- if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
- fprintf(stderr, "ADB server didn't ACK\n" );
- return -1;
- }
-
- 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();
-
- return 0;
-}
-
-// Try to handle a network forwarding request.
-// This returns 1 on success, 0 on failure, and -1 to indicate this is not
-// a forwarding-related request.
-int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd)
-{
- if (!strcmp(service, "list-forward")) {
- // 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) {
- sendfailmsg(reply_fd, "not enough memory");
- return 1;
- }
- (void) format_listeners(buffer, buffer_size + 1);
-#if ADB_HOST
- send_msg_with_okay(reply_fd, buffer, buffer_size);
-#else
- send_msg_with_header(reply_fd, buffer, buffer_size);
-#endif
- free(buffer);
- return 1;
- }
-
- if (!strcmp(service, "killforward-all")) {
- remove_all_listeners();
-#if ADB_HOST
- /* On the host: 1st OKAY is connect, 2nd OKAY is status */
- adb_write(reply_fd, "OKAY", 4);
-#endif
- adb_write(reply_fd, "OKAY", 4);
- return 1;
- }
-
- if (!strncmp(service, "forward:",8) ||
- !strncmp(service, "killforward:",12)) {
- char *local, *remote, *err;
- int r;
- atransport *transport;
-
- int createForward = strncmp(service, "kill", 4);
- int no_rebind = 0;
-
- local = strchr(service, ':') + 1;
-
- // Handle forward:norebind:<local>... here
- if (createForward && !strncmp(local, "norebind:", 9)) {
- no_rebind = 1;
- local = strchr(local, ':') + 1;
- }
-
- remote = strchr(local,';');
-
- if (createForward) {
- // Check forward: parameter format: '<local>;<remote>'
- if(remote == 0) {
- sendfailmsg(reply_fd, "malformed forward spec");
- return 1;
- }
-
- *remote++ = 0;
- if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) {
- sendfailmsg(reply_fd, "malformed forward spec");
- return 1;
- }
- } else {
- // Check killforward: parameter format: '<local>'
- if (local[0] == 0) {
- sendfailmsg(reply_fd, "malformed forward spec");
- return 1;
- }
- }
-
- transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
- if (!transport) {
- sendfailmsg(reply_fd, err);
- return 1;
- }
-
- if (createForward) {
- r = install_listener(local, remote, transport, no_rebind);
- } else {
- r = remove_listener(local, transport);
- }
- if(r == 0) {
-#if ADB_HOST
- /* On the host: 1st OKAY is connect, 2nd OKAY is status */
- writex(reply_fd, "OKAY", 4);
-#endif
- writex(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");
- }
- return 1;
- }
- return 0;
-}
-
-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);
- adb_write(reply_fd, "OKAY", 4);
- usb_cleanup();
- exit(0);
- }
-
-#if ADB_HOST
- // "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"))) {
- type = kTransportUsb;
- } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
- type = kTransportLocal;
- } else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
- type = kTransportAny;
- } else if (!strncmp(service, "transport:", strlen("transport:"))) {
- service += strlen("transport:");
- serial = service;
- }
-
- transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
-
- if (transport) {
- s->transport = transport;
- adb_write(reply_fd, "OKAY", 4);
- } else {
- sendfailmsg(reply_fd, error_string);
- }
- return 1;
- }
-
- // return a list of all connected devices
- if (!strncmp(service, "devices", 7)) {
- char buffer[4096];
- int use_long = !strcmp(service+7, "-l");
- if (use_long || service[7] == 0) {
- memset(buffer, 0, sizeof(buffer));
- D("Getting device list \n");
- list_transports(buffer, sizeof(buffer), use_long);
- D("Wrote device list \n");
- send_msg_with_okay(reply_fd, buffer, strlen(buffer));
- return 0;
- }
- }
-
- // remove TCP transport
- if (!strncmp(service, "disconnect:", 11)) {
- char buffer[4096];
- memset(buffer, 0, sizeof(buffer));
- char* serial = service + 11;
- if (serial[0] == 0) {
- // disconnect from all TCP devices
- unregister_all_tcp_transports();
- } else {
- char hostbuf[100];
- // assume port 5555 if no port is specified
- if (!strchr(serial, ':')) {
- snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial);
- serial = hostbuf;
- }
- atransport *t = find_transport(serial);
-
- if (t) {
- unregister_transport(t);
- } else {
- snprintf(buffer, sizeof(buffer), "No such device %s", serial);
- }
- }
-
- send_msg_with_okay(reply_fd, buffer, strlen(buffer));
- return 0;
- }
-
- // returns our value for ADB_SERVER_VERSION
- if (!strcmp(service, "version")) {
- char version[12];
- snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
- send_msg_with_okay(reply_fd, version, strlen(version));
- return 0;
- }
-
- if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
- 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) {
- out = transport->devpath;
- }
- send_msg_with_okay(reply_fd, out, strlen(out));
- return 0;
- }
- // indicates a new emulator instance has started
- if (!strncmp(service,"emulator:",9)) {
- int port = atoi(service+9);
- local_connect(port);
- /* we don't even need to send a reply */
- return 0;
- }
-
- if(!strncmp(service,"get-state",strlen("get-state"))) {
- transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
- char *state = connection_state_name(transport);
- send_msg_with_okay(reply_fd, state, strlen(state));
- return 0;
- }
-#endif // ADB_HOST
-
- int ret = handle_forward_request(service, ttype, serial, reply_fd);
- if (ret >= 0)
- 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
-}
diff --git a/adb/adb.cpp b/adb/adb.cpp
new file mode 100644
index 0000000..de82cd4
--- /dev/null
+++ b/adb/adb.cpp
@@ -0,0 +1,1012 @@
+/*
+ * 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.
+ */
+
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
+#include "adb.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <string>
+
+#include <base/stringprintf.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 <sys/capability.h>
+#include <sys/mount.h>
+#endif
+
+#if ADB_TRACE
+ADB_MUTEX_DEFINE( D_lock );
+#endif
+
+int HOST = 0;
+
+#if !ADB_HOST
+const char *adb_device_banner = "device";
+#endif
+
+void fatal(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "error: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ exit(-1);
+}
+
+void fatal_errno(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "error: %s: ", strerror(errno));
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ exit(-1);
+}
+
+#if !ADB_HOST
+void start_device_log(void) {
+ struct tm now;
+ time_t t;
+ tzset();
+ time(&t);
+ localtime_r(&t, &now);
+
+ 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;
+ int flag;
+ } tags[] = {
+ { "1", 0 },
+ { "all", 0 },
+ { "adb", TRACE_ADB },
+ { "sockets", TRACE_SOCKETS },
+ { "packets", TRACE_PACKETS },
+ { "rwx", TRACE_RWX },
+ { "usb", TRACE_USB },
+ { "sync", TRACE_SYNC },
+ { "sysdeps", TRACE_SYSDEPS },
+ { "transport", TRACE_TRANSPORT },
+ { "jdwp", TRACE_JDWP },
+ { "services", TRACE_SERVICES },
+ { "auth", TRACE_AUTH },
+ { NULL, 0 }
+ };
+
+ if (trace_setting.empty()) {
+ return;
+ }
+
+ // Use a comma/colon/semi-colon/space separated list
+ const char* p = trace_setting.c_str();
+ while (*p) {
+ int len, tagn;
+
+ const char* q = strpbrk(p, " ,:;");
+ if (q == NULL) {
+ q = p + strlen(p);
+ }
+ len = q - p;
+
+ for (tagn = 0; tags[tagn].tag != NULL; tagn++) {
+ int taglen = strlen(tags[tagn].tag);
+
+ if (len == taglen && !memcmp(tags[tagn].tag, p, len)) {
+ int flag = tags[tagn].flag;
+ if (flag == 0) {
+ adb_trace_mask = ~0;
+ return;
+ }
+ adb_trace_mask |= (1 << flag);
+ break;
+ }
+ }
+ p = q;
+ if (*p)
+ p++;
+ }
+
+#if !ADB_HOST
+ start_device_log();
+#endif
+}
+
+apacket* get_apacket(void)
+{
+ apacket* p = reinterpret_cast<apacket*>(malloc(sizeof(apacket)));
+ if (p == nullptr) {
+ fatal("failed to allocate an apacket");
+ }
+
+ memset(p, 0, sizeof(apacket) - MAX_PAYLOAD);
+ return p;
+}
+
+void put_apacket(apacket *p)
+{
+ free(p);
+}
+
+void handle_online(atransport *t)
+{
+ D("adb: online\n");
+ t->online = 1;
+}
+
+void handle_offline(atransport *t)
+{
+ D("adb: offline\n");
+ //Close the associated usb
+ t->online = 0;
+ run_transport_disconnects(t);
+}
+
+#if DEBUG_PACKETS
+#define DUMPMAX 32
+void print_packet(const char *label, apacket *p)
+{
+ char *tag;
+ char *x;
+ unsigned count;
+
+ switch(p->msg.command){
+ case A_SYNC: tag = "SYNC"; break;
+ case A_CNXN: tag = "CNXN" ; break;
+ case A_OPEN: tag = "OPEN"; break;
+ case A_OKAY: tag = "OKAY"; break;
+ case A_CLSE: tag = "CLSE"; break;
+ case A_WRTE: tag = "WRTE"; break;
+ case A_AUTH: tag = "AUTH"; break;
+ default: tag = "????"; break;
+ }
+
+ fprintf(stderr, "%s: %s %08x %08x %04x \"",
+ label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
+ count = p->msg.data_length;
+ x = (char*) p->data;
+ if(count > DUMPMAX) {
+ count = DUMPMAX;
+ tag = "\n";
+ } else {
+ tag = "\"\n";
+ }
+ while(count-- > 0){
+ if((*x >= ' ') && (*x < 127)) {
+ fputc(*x, stderr);
+ } else {
+ fputc('.', stderr);
+ }
+ x++;
+ }
+ fputs(tag, stderr);
+}
+#endif
+
+static void send_ready(unsigned local, unsigned remote, atransport *t)
+{
+ D("Calling send_ready \n");
+ apacket *p = get_apacket();
+ p->msg.command = A_OKAY;
+ p->msg.arg0 = local;
+ p->msg.arg1 = remote;
+ send_packet(p, t);
+}
+
+static void send_close(unsigned local, unsigned remote, atransport *t)
+{
+ D("Calling send_close \n");
+ apacket *p = get_apacket();
+ p->msg.command = A_CLSE;
+ p->msg.arg0 = local;
+ p->msg.arg1 = remote;
+ send_packet(p, t);
+}
+
+static size_t fill_connect_data(char *buf, size_t bufsize)
+{
+#if ADB_HOST
+ return snprintf(buf, bufsize, "host::") + 1;
+#else
+ static const char *cnxn_props[] = {
+ "ro.product.name",
+ "ro.product.model",
+ "ro.product.device",
+ };
+ static const int num_cnxn_props = ARRAY_SIZE(cnxn_props);
+ int i;
+ size_t remaining = bufsize;
+ size_t len;
+
+ len = snprintf(buf, remaining, "%s::", adb_device_banner);
+ remaining -= len;
+ buf += len;
+ for (i = 0; i < num_cnxn_props; i++) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get(cnxn_props[i], value, "");
+ len = snprintf(buf, remaining, "%s=%s;", cnxn_props[i], value);
+ remaining -= len;
+ buf += len;
+ }
+
+ return bufsize - remaining + 1;
+#endif
+}
+
+#if !ADB_HOST
+static void send_msg_with_header(int fd, const char* msg, size_t msglen) {
+ char header[5];
+ if (msglen > 0xffff)
+ msglen = 0xffff;
+ snprintf(header, sizeof(header), "%04x", (unsigned)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);
+ WriteFdExactly(fd, header, 8);
+ WriteFdExactly(fd, msg, msglen);
+}
+#endif // ADB_HOST
+
+void send_connect(atransport *t)
+{
+ D("Calling send_connect \n");
+ apacket *cp = get_apacket();
+ cp->msg.command = A_CNXN;
+ cp->msg.arg0 = A_VERSION;
+ cp->msg.arg1 = MAX_PAYLOAD;
+ cp->msg.data_length = fill_connect_data((char *)cp->data,
+ sizeof(cp->data));
+ send_packet(cp, t);
+}
+
+#if ADB_HOST
+static const char* connection_state_name(atransport *t)
+{
+ if (t == NULL) {
+ return "unknown";
+ }
+
+ switch(t->connection_state) {
+ case CS_BOOTLOADER:
+ return "bootloader";
+ case CS_DEVICE:
+ return "device";
+ case CS_RECOVERY:
+ return "recovery";
+ case CS_SIDELOAD:
+ return "sideload";
+ case CS_OFFLINE:
+ return "offline";
+ case CS_UNAUTHORIZED:
+ return "unauthorized";
+ default:
+ 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
+ * was malloc'ed and needs to freed. *dst will be set to a dup of src.
+ */
+static void qual_overwrite(char **dst, const char *src)
+{
+ if (!dst)
+ return;
+
+ free(*dst);
+ *dst = NULL;
+
+ if (!src || !*src)
+ return;
+
+ *dst = strdup(src);
+}
+
+void parse_banner(char *banner, atransport *t)
+{
+ static const char *prop_seps = ";";
+ static const char key_val_sep = '=';
+ char *cp;
+ char *type;
+
+ D("parse_banner: %s\n", banner);
+ type = banner;
+ cp = strchr(type, ':');
+ if (cp) {
+ *cp++ = 0;
+ /* Nothing is done with second field. */
+ cp = strchr(cp, ':');
+ if (cp) {
+ char *save;
+ char *key;
+ key = adb_strtok_r(cp + 1, prop_seps, &save);
+ while (key) {
+ cp = strchr(key, key_val_sep);
+ if (cp) {
+ *cp++ = '\0';
+ if (!strcmp(key, "ro.product.name"))
+ qual_overwrite(&t->product, cp);
+ else if (!strcmp(key, "ro.product.model"))
+ qual_overwrite(&t->model, cp);
+ else if (!strcmp(key, "ro.product.device"))
+ qual_overwrite(&t->device, cp);
+ }
+ key = adb_strtok_r(NULL, prop_seps, &save);
+ }
+ }
+ }
+
+ if(!strcmp(type, "bootloader")){
+ D("setting connection_state to CS_BOOTLOADER\n");
+ t->connection_state = CS_BOOTLOADER;
+ update_transports();
+ return;
+ }
+
+ if(!strcmp(type, "device")) {
+ D("setting connection_state to CS_DEVICE\n");
+ t->connection_state = CS_DEVICE;
+ update_transports();
+ return;
+ }
+
+ if(!strcmp(type, "recovery")) {
+ D("setting connection_state to CS_RECOVERY\n");
+ t->connection_state = CS_RECOVERY;
+ update_transports();
+ return;
+ }
+
+ if(!strcmp(type, "sideload")) {
+ D("setting connection_state to CS_SIDELOAD\n");
+ t->connection_state = CS_SIDELOAD;
+ update_transports();
+ return;
+ }
+
+ t->connection_state = CS_HOST;
+}
+
+void handle_packet(apacket *p, atransport *t)
+{
+ asocket *s;
+
+ D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
+ ((char*) (&(p->msg.command)))[1],
+ ((char*) (&(p->msg.command)))[2],
+ ((char*) (&(p->msg.command)))[3]);
+ print_packet("recv", p);
+
+ switch(p->msg.command){
+ case A_SYNC:
+ if(p->msg.arg0){
+ send_packet(p, t);
+ if(HOST) send_connect(t);
+ } else {
+ t->connection_state = CS_OFFLINE;
+ handle_offline(t);
+ send_packet(p, t);
+ }
+ return;
+
+ case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
+ /* XXX verify version, etc */
+ if(t->connection_state != CS_OFFLINE) {
+ t->connection_state = CS_OFFLINE;
+ handle_offline(t);
+ }
+
+ parse_banner((char*) p->data, t);
+
+ if (HOST || !auth_enabled) {
+ handle_online(t);
+ if(!HOST) send_connect(t);
+ } else {
+ send_auth_request(t);
+ }
+ break;
+
+ case A_AUTH:
+ if (p->msg.arg0 == ADB_AUTH_TOKEN) {
+ t->connection_state = CS_UNAUTHORIZED;
+ t->key = adb_auth_nextkey(t->key);
+ if (t->key) {
+ send_auth_response(p->data, p->msg.data_length, t);
+ } else {
+ /* No more private keys to try, send the public key */
+ send_auth_publickey(t);
+ }
+ } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
+ if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
+ adb_auth_verified(t);
+ t->failed_auth_attempts = 0;
+ } else {
+ if (t->failed_auth_attempts++ > 10)
+ adb_sleep_ms(1000);
+ send_auth_request(t);
+ }
+ } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
+ adb_auth_confirm_key(p->data, p->msg.data_length, t);
+ }
+ break;
+
+ case A_OPEN: /* OPEN(local-id, 0, "destination") */
+ if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
+ char *name = (char*) p->data;
+ name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
+ s = create_local_service_socket(name);
+ if(s == 0) {
+ send_close(0, p->msg.arg0, t);
+ } else {
+ s->peer = create_remote_socket(p->msg.arg0, t);
+ s->peer->peer = s;
+ send_ready(s->id, s->peer->id, t);
+ s->ready(s);
+ }
+ }
+ break;
+
+ case A_OKAY: /* READY(local-id, remote-id, "") */
+ if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
+ if((s = find_local_socket(p->msg.arg1, 0))) {
+ if(s->peer == 0) {
+ /* On first READY message, create the connection. */
+ s->peer = create_remote_socket(p->msg.arg0, t);
+ s->peer->peer = s;
+ s->ready(s);
+ } else if (s->peer->id == p->msg.arg0) {
+ /* Other READY messages must use the same local-id */
+ s->ready(s);
+ } else {
+ D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s\n",
+ p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial);
+ }
+ }
+ }
+ break;
+
+ case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */
+ if (t->online && p->msg.arg1 != 0) {
+ if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
+ /* According to protocol.txt, p->msg.arg0 might be 0 to indicate
+ * a failed OPEN only. However, due to a bug in previous ADB
+ * versions, CLOSE(0, remote-id, "") was also used for normal
+ * CLOSE() operations.
+ *
+ * This is bad because it means a compromised adbd could
+ * send packets to close connections between the host and
+ * other devices. To avoid this, only allow this if the local
+ * socket has a peer on the same transport.
+ */
+ if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) {
+ D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s\n",
+ p->msg.arg1, t->serial, s->peer->transport->serial);
+ } else {
+ s->close(s);
+ }
+ }
+ }
+ break;
+
+ case A_WRTE: /* WRITE(local-id, remote-id, <data>) */
+ if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
+ if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
+ unsigned rid = p->msg.arg0;
+ p->len = p->msg.data_length;
+
+ if(s->enqueue(s, p) == 0) {
+ D("Enqueue the socket\n");
+ send_ready(s->id, rid, t);
+ }
+ return;
+ }
+ }
+ break;
+
+ default:
+ printf("handle_packet: what is %08x?!\n", p->msg.command);
+ }
+
+ put_apacket(p);
+}
+
+#if ADB_HOST
+
+int launch_server(int server_port)
+{
+#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 */
+ /* security attribute */
+ HANDLE pipe_read, pipe_write;
+ HANDLE stdout_handle, stderr_handle;
+ SECURITY_ATTRIBUTES sa;
+ STARTUPINFO startup;
+ PROCESS_INFORMATION pinfo;
+ char program_path[ MAX_PATH ];
+ int ret;
+
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ /* create pipe, and ensure its read handle isn't inheritable */
+ ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
+ if (!ret) {
+ fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
+ return -1;
+ }
+
+ SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
+
+ /* Some programs want to launch an adb command and collect its output by
+ * calling CreateProcess with inheritable stdout/stderr handles, then
+ * using read() to get its output. When this happens, the stdout/stderr
+ * handles passed to the adb client process will also be inheritable.
+ * When starting the adb server here, care must be taken to reset them
+ * to non-inheritable.
+ * Otherwise, something bad happens: even if the adb command completes,
+ * the calling process is stuck while read()-ing from the stdout/stderr
+ * descriptors, because they're connected to corresponding handles in the
+ * adb server process (even if the latter never uses/writes to them).
+ */
+ stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE );
+ stderr_handle = GetStdHandle( STD_ERROR_HANDLE );
+ if (stdout_handle != INVALID_HANDLE_VALUE) {
+ SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 );
+ }
+ if (stderr_handle != INVALID_HANDLE_VALUE) {
+ SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 );
+ }
+
+ ZeroMemory( &startup, sizeof(startup) );
+ startup.cb = sizeof(startup);
+ startup.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
+ startup.hStdOutput = pipe_write;
+ startup.hStdError = GetStdHandle( STD_ERROR_HANDLE );
+ startup.dwFlags = STARTF_USESTDHANDLES;
+
+ ZeroMemory( &pinfo, sizeof(pinfo) );
+
+ /* 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 */
+ args,
+ /* the fork-server argument will set the
+ debug = 2 in the child */
+ NULL, /* process handle is not inheritable */
+ NULL, /* thread handle is not inheritable */
+ TRUE, /* yes, inherit some handles */
+ DETACHED_PROCESS, /* the new process doesn't have a console */
+ NULL, /* use parent's environment block */
+ NULL, /* use parent's starting directory */
+ &startup, /* startup info, i.e. std handles */
+ &pinfo );
+
+ CloseHandle( pipe_write );
+
+ if (!ret) {
+ fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
+ CloseHandle( pipe_read );
+ return -1;
+ }
+
+ CloseHandle( pinfo.hProcess );
+ CloseHandle( pinfo.hThread );
+
+ /* wait for the "OK\n" message */
+ {
+ char temp[3];
+ DWORD count;
+
+ ret = ReadFile( pipe_read, temp, 3, &count, NULL );
+ CloseHandle( pipe_read );
+ if ( !ret ) {
+ fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
+ return -1;
+ }
+ if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
+ fprintf(stderr, "ADB server didn't ACK\n" );
+ return -1;
+ }
+ }
+#else /* !defined(_WIN32) */
+ char path[PATH_MAX];
+ int fd[2];
+
+ // set up a pipe so the child can tell us when it is ready.
+ // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
+ if (pipe(fd)) {
+ fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
+ return -1;
+ }
+ get_my_path(path, PATH_MAX);
+ pid_t pid = fork();
+ if(pid < 0) return -1;
+
+ if (pid == 0) {
+ // child side of the fork
+
+ // redirect stderr to the pipe
+ // we use stderr instead of stdout due to stdout's buffering behavior.
+ adb_close(fd[0]);
+ dup2(fd[1], STDERR_FILENO);
+ adb_close(fd[1]);
+
+ char str_port[30];
+ snprintf(str_port, sizeof(str_port), "%d", server_port);
+ // child process
+ int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL);
+ // this should not return
+ fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
+ } else {
+ // parent side of the fork
+
+ char temp[3];
+
+ temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
+ // wait for the "OK\n" message
+ adb_close(fd[1]);
+ int ret = adb_read(fd[0], temp, 3);
+ int saved_errno = errno;
+ adb_close(fd[0]);
+ if (ret < 0) {
+ fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno);
+ return -1;
+ }
+ if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
+ fprintf(stderr, "ADB server didn't ACK\n" );
+ return -1;
+ }
+
+ setsid();
+ }
+#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
+// a forwarding-related request.
+int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd)
+{
+ if (!strcmp(service, "list-forward")) {
+ // Create the list of forward redirections.
+ int buffer_size = format_listeners(NULL, 0);
+ // Add one byte for the trailing zero.
+ char* buffer = reinterpret_cast<char*>(malloc(buffer_size + 1));
+ if (buffer == nullptr) {
+ sendfailmsg(reply_fd, "not enough memory");
+ return 1;
+ }
+ (void) format_listeners(buffer, buffer_size + 1);
+#if ADB_HOST
+ send_msg_with_okay(reply_fd, buffer, buffer_size);
+#else
+ send_msg_with_header(reply_fd, buffer, buffer_size);
+#endif
+ free(buffer);
+ return 1;
+ }
+
+ if (!strcmp(service, "killforward-all")) {
+ remove_all_listeners();
+#if ADB_HOST
+ /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+ adb_write(reply_fd, "OKAY", 4);
+#endif
+ adb_write(reply_fd, "OKAY", 4);
+ return 1;
+ }
+
+ if (!strncmp(service, "forward:",8) ||
+ !strncmp(service, "killforward:",12)) {
+ char *local, *remote;
+ atransport *transport;
+
+ int createForward = strncmp(service, "kill", 4);
+ int no_rebind = 0;
+
+ local = strchr(service, ':') + 1;
+
+ // Handle forward:norebind:<local>... here
+ if (createForward && !strncmp(local, "norebind:", 9)) {
+ no_rebind = 1;
+ local = strchr(local, ':') + 1;
+ }
+
+ remote = strchr(local,';');
+
+ if (createForward) {
+ // Check forward: parameter format: '<local>;<remote>'
+ if(remote == 0) {
+ sendfailmsg(reply_fd, "malformed forward spec");
+ return 1;
+ }
+
+ *remote++ = 0;
+ if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) {
+ sendfailmsg(reply_fd, "malformed forward spec");
+ return 1;
+ }
+ } else {
+ // Check killforward: parameter format: '<local>'
+ if (local[0] == 0) {
+ sendfailmsg(reply_fd, "malformed forward spec");
+ return 1;
+ }
+ }
+
+ std::string error_msg;
+ transport = acquire_one_transport(CS_ANY, ttype, serial, &error_msg);
+ if (!transport) {
+ 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 == INSTALL_STATUS_OK) {
+#if ADB_HOST
+ /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+ WriteFdExactly(reply_fd, "OKAY", 4);
+#endif
+ WriteFdExactly(reply_fd, "OKAY", 4);
+ return 1;
+ }
+
+ 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;
+}
+
+int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
+{
+ if(!strcmp(service, "kill")) {
+ fprintf(stderr,"adb server killed by remote request\n");
+ fflush(stdout);
+ adb_write(reply_fd, "OKAY", 4);
+ usb_cleanup();
+ exit(0);
+ }
+
+#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"))) {
+ transport_type type = kTransportAny;
+
+ if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
+ type = kTransportUsb;
+ } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
+ type = kTransportLocal;
+ } else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
+ type = kTransportAny;
+ } else if (!strncmp(service, "transport:", strlen("transport:"))) {
+ service += strlen("transport:");
+ serial = service;
+ }
+
+ 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_msg.c_str());
+ }
+ return 1;
+ }
+
+ // return a list of all connected devices
+ if (!strncmp(service, "devices", 7)) {
+ char buffer[4096];
+ int use_long = !strcmp(service+7, "-l");
+ if (use_long || service[7] == 0) {
+ memset(buffer, 0, sizeof(buffer));
+ D("Getting device list \n");
+ list_transports(buffer, sizeof(buffer), use_long);
+ D("Wrote device list \n");
+ send_msg_with_okay(reply_fd, buffer, strlen(buffer));
+ return 0;
+ }
+ }
+
+ // remove TCP transport
+ if (!strncmp(service, "disconnect:", 11)) {
+ char buffer[4096];
+ memset(buffer, 0, sizeof(buffer));
+ char* serial = service + 11;
+ if (serial[0] == 0) {
+ // disconnect from all TCP devices
+ unregister_all_tcp_transports();
+ } else {
+ char hostbuf[100];
+ // assume port 5555 if no port is specified
+ if (!strchr(serial, ':')) {
+ snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial);
+ serial = hostbuf;
+ }
+ atransport *t = find_transport(serial);
+
+ if (t) {
+ unregister_transport(t);
+ } else {
+ snprintf(buffer, sizeof(buffer), "No such device %s", serial);
+ }
+ }
+
+ send_msg_with_okay(reply_fd, buffer, strlen(buffer));
+ return 0;
+ }
+
+ // returns our value for ADB_SERVER_VERSION
+ if (!strcmp(service, "version")) {
+ char version[12];
+ snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
+ send_msg_with_okay(reply_fd, version, strlen(version));
+ return 0;
+ }
+
+ if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
+ 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"))) {
+ 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));
+ return 0;
+ }
+ // indicates a new emulator instance has started
+ if (!strncmp(service,"emulator:",9)) {
+ int port = atoi(service+9);
+ local_connect(port);
+ /* we don't even need to send a reply */
+ return 0;
+ }
+
+ if(!strncmp(service,"get-state",strlen("get-state"))) {
+ transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+ const char *state = connection_state_name(transport);
+ send_msg_with_okay(reply_fd, state, strlen(state));
+ return 0;
+ }
+#endif // ADB_HOST
+
+ int ret = handle_forward_request(service, ttype, serial, reply_fd);
+ if (ret >= 0)
+ return ret - 1;
+ return -1;
+}
diff --git a/adb/adb.h b/adb/adb.h
index 44e5981..cb2cf60 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -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 @@
** 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 @@
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_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 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 @@
#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 @@
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 @@
#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 @@
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 @@
#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 @@
#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
similarity index 87%
rename from adb/adb_auth_client.c
rename to 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 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 @@
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 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 @@
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 @@
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 @@
}
}
-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
similarity index 80%
rename from adb/adb_auth_host.c
rename to 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 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 @@
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 @@
}
}
-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 @@
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
similarity index 85%
rename from adb/adb_client.c
rename to 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
TRACE_SERVICES,
TRACE_AUTH,
TRACE_FDEVENT,
-} AdbTrace;
+} ;
#if ADB_TRACE
@@ -73,8 +75,9 @@
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 @@
} 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/adb/usb_vendors.h b/adb/adb_utils.h
similarity index 70%
copy from adb/usb_vendors.h
copy to adb/adb_utils.h
index cee23a1..4b64afa 100644
--- a/adb/usb_vendors.h
+++ b/adb/adb_utils.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,14 @@
* limitations under the License.
*/
-#ifndef __USB_VENDORS_H
-#define __USB_VENDORS_H
+#ifndef _ADB_UTILS_H_
+#define _ADB_UTILS_H_
-extern int vendorIds[];
-extern unsigned vendorIdCount;
+#include <string>
-void usb_vendors_init(void);
+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
similarity index 71%
rename from adb/commandline.c
rename to 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>
-#include <errno.h>
-#include <unistd.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#include <assert.h>
+#define TRACE_TAG TRACE_ADB
#include "sysdeps.h"
-#ifdef HAVE_TERMIO_H
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <string>
+
+#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 @@
" 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 @@
" 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 @@
"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 @@
);
}
-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);
- if(tcgetattr(fd, &tio)) return;
- if(tcgetattr(fd, &tio_save)) return;
+#else
+static termios g_saved_terminal_state;
- tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
+static void stdin_raw_init(int fd) {
+ if (tcgetattr(fd, &g_saved_terminal_state)) return;
- /* no timeout but request at least one character per read */
+ termios tio;
+ if (tcgetattr(fd, &tio)) return;
+
+ cfmakeraw(&tio);
+
+ // 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 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 @@
}
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 @@
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 @@
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 @@
}
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 @@
}
}
-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 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 @@
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 @@
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 @@
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 @@
* - 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 @@
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 @@
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 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 @@
* 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 @@
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 @@
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 @@
}
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];
+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);
- char *log_tags;
- char *quoted;
-
- 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 @@
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 @@
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 @@
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 @@
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 @@
* 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;
+ return hint;
}
- /* 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 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 "";
}
- 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;
+ 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_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;
+ // 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 "";
}
-//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;
+
+ 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_buf;
+ 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 @@
}
}
-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 persist = 0;
int r;
transport_type ttype = kTransportAny;
- char* serial = NULL;
- char* server_port_str = 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".
- */
- gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
- if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
- gProductOutPath = 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 @@
}
/* 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 @@
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 @@
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 @@
}
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,221 +1102,19 @@
} 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 */
-
- if(!strcmp(argv[0], "devices")) {
- char *tmp;
- char *listopt;
- if (argc < 2)
- listopt = "";
- else if (argc == 2 && !strcmp(argv[1], "-l"))
- listopt = argv[1];
- else {
- fprintf(stderr, "Usage: adb devices [-l]\n");
- return 1;
- }
- snprintf(buf, sizeof buf, "host:%s%s", argv[0], listopt);
- tmp = adb_query(buf);
- if(tmp) {
- printf("List of devices attached \n");
- printf("%s\n", tmp);
- return 0;
- } else {
- return 1;
- }
- }
-
- if(!strcmp(argv[0], "connect")) {
- char *tmp;
- if (argc != 2) {
- fprintf(stderr, "Usage: adb connect <host>[:<port>]\n");
- return 1;
- }
- snprintf(buf, sizeof buf, "host:connect:%s", argv[1]);
- tmp = adb_query(buf);
- if(tmp) {
- printf("%s\n", tmp);
- return 0;
- } else {
- return 1;
- }
- }
-
- if(!strcmp(argv[0], "disconnect")) {
- char *tmp;
- if (argc > 2) {
- fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n");
- return 1;
- }
- if (argc == 2) {
- snprintf(buf, sizeof buf, "host:disconnect:%s", argv[1]);
- } else {
- snprintf(buf, sizeof buf, "host:disconnect:");
- }
- tmp = adb_query(buf);
- if(tmp) {
- printf("%s\n", tmp);
- return 0;
- } else {
- return 1;
- }
- }
-
- 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;
-
- char h = (argv[0][0] == 'h');
-
- if (h) {
- printf("\x1b[41;33m");
- fflush(stdout);
- }
-
- if(argc < 2) {
- D("starting interactive shell\n");
- r = interactive_shell();
- if (h) {
- printf("\x1b[0m");
- fflush(stdout);
- }
- return r;
- }
-
- snprintf(buf, sizeof(buf), "shell:%s", 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);
- }
-
- for(;;) {
- D("interactive shell loop. buff=%s\n", buf);
- fd = adb_connect(buf);
- if(fd >= 0) {
- D("about to read_and_dump(fd=%d)\n", fd);
- read_and_dump(fd);
- D("read_and_dump() done.\n");
- adb_close(fd);
- r = 0;
- } else {
- fprintf(stderr,"error: %s\n", adb_error());
- r = -1;
- }
-
- if(persist) {
- fprintf(stderr,"\n- waiting for device -\n");
- adb_sleep_ms(1000);
- do_cmd(ttype, serial, "wait-for-device", 0);
- } else {
- if (h) {
- printf("\x1b[0m");
- fflush(stdout);
- }
- D("interactive shell loop. return r=%d\n", r);
- return r;
- }
- }
- }
-
- 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]);
- 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);
- }
-
- fd = adb_connect(buf);
- if (fd < 0) {
- fprintf(stderr, "error: %s\n", adb_error());
- return -1;
- }
-
- if (exec_in) {
- copy_to_file(STDIN_FILENO, fd);
- } else {
- copy_to_file(fd, STDOUT_FILENO);
- }
-
- adb_close(fd);
- return 0;
- }
-
- if(!strcmp(argv[0], "kill-server")) {
- int fd;
- fd = _adb_connect("host:kill");
- if(fd == -1) {
- fprintf(stderr,"* server not running *\n");
- return 1;
- }
- return 0;
- }
-
- 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")) {
- char command[100];
- if (!strcmp(argv[0], "reboot-bootloader"))
- snprintf(command, sizeof(command), "reboot:bootloader");
- else if (argc > 1)
- snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
- 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;
- }
-
- 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];
+ /* 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";
@@ -1490,17 +1136,198 @@
/* Allow a command to be run after wait-for-device,
* e.g. 'adb wait-for-device shell'.
*/
- if(argc > 1) {
- argc--;
- argv++;
- goto top;
+ if (argc == 1) {
+ return 0;
+ }
+
+ /* Fall through */
+ argc--;
+ argv++;
+ }
+
+ /* adb_connect() commands */
+ if (!strcmp(argv[0], "devices")) {
+ char *tmp;
+ const char *listopt;
+ if (argc < 2)
+ listopt = "";
+ else if (argc == 2 && !strcmp(argv[1], "-l"))
+ listopt = argv[1];
+ else {
+ fprintf(stderr, "Usage: adb devices [-l]\n");
+ return 1;
+ }
+ snprintf(buf, sizeof buf, "host:%s%s", argv[0], listopt);
+ tmp = adb_query(buf);
+ if (tmp) {
+ printf("List of devices attached \n");
+ printf("%s\n", tmp);
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ else if (!strcmp(argv[0], "connect")) {
+ char *tmp;
+ if (argc != 2) {
+ fprintf(stderr, "Usage: adb connect <host>[:<port>]\n");
+ return 1;
+ }
+ snprintf(buf, sizeof buf, "host:connect:%s", argv[1]);
+ tmp = adb_query(buf);
+ if (tmp) {
+ printf("%s\n", tmp);
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ else if (!strcmp(argv[0], "disconnect")) {
+ char *tmp;
+ if (argc > 2) {
+ fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n");
+ return 1;
+ }
+ if (argc == 2) {
+ snprintf(buf, sizeof buf, "host:disconnect:%s", argv[1]);
+ } else {
+ snprintf(buf, sizeof buf, "host:disconnect:");
+ }
+ tmp = adb_query(buf);
+ if (tmp) {
+ printf("%s\n", tmp);
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ else if (!strcmp(argv[0], "emu")) {
+ return adb_send_emulator_command(argc, argv);
+ }
+ else if (!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
+ char h = (argv[0][0] == 'h');
+
+ if (h) {
+ printf("\x1b[41;33m");
+ fflush(stdout);
+ }
+
+ if (argc < 2) {
+ D("starting interactive shell\n");
+ r = interactive_shell();
+ if (h) {
+ printf("\x1b[0m");
+ fflush(stdout);
+ }
+ return r;
+ }
+
+ std::string cmd = "shell:";
+ cmd += argv[1];
+ argc -= 2;
+ argv += 2;
+ while (argc-- > 0) {
+ cmd += " " + escape_arg(*argv++);
+ }
+
+ 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");
+ adb_close(fd);
+ r = 0;
+ } else {
+ fprintf(stderr,"error: %s\n", adb_error());
+ r = -1;
+ }
+
+ if (persist) {
+ fprintf(stderr,"\n- waiting for device -\n");
+ adb_sleep_ms(1000);
+ do_cmd(ttype, serial, "wait-for-device", 0);
+ } else {
+ if (h) {
+ printf("\x1b[0m");
+ fflush(stdout);
+ }
+ D("interactive shell loop. return r=%d\n", r);
+ return r;
+ }
+ }
+ }
+ else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
+ int exec_in = !strcmp(argv[0], "exec-in");
+
+ std::string cmd = "exec:";
+ cmd += argv[1];
+ argc -= 2;
+ argv += 2;
+ while (argc-- > 0) {
+ cmd += " " + escape_arg(*argv++);
+ }
+
+ int fd = adb_connect(cmd.c_str());
+ if (fd < 0) {
+ fprintf(stderr, "error: %s\n", adb_error());
+ return -1;
+ }
+
+ if (exec_in) {
+ copy_to_file(STDIN_FILENO, fd);
+ } else {
+ copy_to_file(fd, STDOUT_FILENO);
+ }
+
+ adb_close(fd);
+ return 0;
+ }
+ else if (!strcmp(argv[0], "kill-server")) {
+ int fd;
+ fd = _adb_connect("host:kill");
+ if (fd == -1) {
+ fprintf(stderr,"* server not running *\n");
+ return 1;
}
return 0;
}
-
- if(!strcmp(argv[0], "forward") ||
- !strcmp(argv[0], "reverse"))
- {
+ else if (!strcmp(argv[0], "sideload")) {
+ if (argc != 2) return usage();
+ if (adb_sideload_host(argv[1])) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ 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")) {
+ snprintf(command, sizeof(command), "reboot:bootloader");
+ } else if (argc > 1) {
+ snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
+ } else {
+ snprintf(command, sizeof(command), "%s:", argv[0]);
+ }
+ return adb_connect_command(command);
+ }
+ else if (!strcmp(argv[0], "bugreport")) {
+ if (argc != 1) return usage();
+ do_cmd(ttype, serial, "shell", "bugreport", 0);
+ return 0;
+ }
+ /* adb_command() wrapper commands */
+ 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 @@
{
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 @@
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 @@
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 @@
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 @@
}
#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 @@
return adb_commandline(argc, argv);
}
-int find_sync_dirs(const char *srcarg,
- char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out)
+static int pm_command(transport_type transport, const char* serial,
+ int argc, const char** argv)
{
- char *android_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL;
- struct stat st;
+ std::string cmd = "shell:pm";
- 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;
- }
+ while (argc-- > 0) {
+ cmd += " " + escape_arg(*argv++);
}
- 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;
+ return send_shell_command(transport, serial, cmd);
}
-static int pm_command(transport_type transport, char* serial,
- int argc, char** argv)
-{
- char buf[4096];
-
- snprintf(buf, sizeof(buf), "shell:pm");
-
- while(argc-- > 0) {
- char *quoted = escape_arg(*argv++);
- strncat(buf, " ", sizeof(buf) - 1);
- strncat(buf, quoted, sizeof(buf) - 1);
- free(quoted);
- }
-
- send_shellcommand(transport, serial, buf);
- return 0;
-}
-
-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 @@
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 @@
}
}
-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 @@
// 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 @@
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 @@
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 @@
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 @@
// 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 @@
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
similarity index 93%
rename from adb/console.c
rename to adb/console.cpp
index b813d33..452ee41 100644
--- a/adb/console.c
+++ b/adb/console.cpp
@@ -24,7 +24,7 @@
}
-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/disable_verity_service.c b/adb/disable_verity_service.c
deleted file mode 100644
index ed3da52..0000000
--- a/adb/disable_verity_service.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * 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 "sysdeps.h"
-
-#define TRACE_TAG TRACE_ADB
-#include "adb.h"
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <inttypes.h>
-
-#include "cutils/properties.h"
-#include "ext4_sb.h"
-#include <fs_mgr.h>
-
-#define FSTAB_PREFIX "/fstab."
-struct fstab *fstab;
-
-__attribute__((__format__(printf, 2, 3))) __nonnull((2))
-static void write_console(int fd, const char* format, ...)
-{
- char buffer[256];
- va_list args;
- va_start (args, format);
- vsnprintf (buffer, sizeof(buffer), format, args);
- va_end (args);
-
- adb_write(fd, buffer, strnlen(buffer, sizeof(buffer)));
-}
-
-static int get_target_device_size(int fd, const char *blk_device,
- uint64_t *device_size)
-{
- int data_device;
- struct ext4_super_block sb;
- struct fs_info info;
-
- info.len = 0; /* Only len is set to 0 to ask the device for real size. */
-
- data_device = adb_open(blk_device, O_RDONLY | O_CLOEXEC);
- if (data_device < 0) {
- write_console(fd, "Error opening block device (%s)\n", strerror(errno));
- return -1;
- }
-
- if (lseek64(data_device, 1024, SEEK_SET) < 0) {
- write_console(fd, "Error seeking to superblock\n");
- adb_close(data_device);
- return -1;
- }
-
- if (adb_read(data_device, &sb, sizeof(sb)) != sizeof(sb)) {
- write_console(fd, "Error reading superblock\n");
- adb_close(data_device);
- return -1;
- }
-
- ext4_parse_sb(&sb, &info);
- *device_size = info.len;
-
- adb_close(data_device);
- return 0;
-}
-
-static int disable_verity(int fd, const char *block_device,
- const char* mount_point)
-{
- uint32_t magic_number;
- const uint32_t voff = VERITY_METADATA_MAGIC_DISABLE;
- uint64_t device_length;
- int device;
- int retval = -1;
-
- device = adb_open(block_device, O_RDWR | O_CLOEXEC);
- if (device == -1) {
- write_console(fd, "Could not open block device %s (%s).\n",
- block_device, strerror(errno));
- write_console(fd, "Maybe run adb remount?\n");
- goto errout;
- }
-
- // find the start of the verity metadata
- if (get_target_device_size(fd, (char*)block_device, &device_length) < 0) {
- write_console(fd, "Could not get target device size.\n");
- goto errout;
- }
-
- if (lseek64(device, device_length, SEEK_SET) < 0) {
- write_console(fd,
- "Could not seek to start of verity metadata block.\n");
- goto errout;
- }
-
- // check the magic number
- if (adb_read(device, &magic_number, sizeof(magic_number))
- != sizeof(magic_number)) {
- write_console(fd, "Couldn't read magic number!\n");
- goto errout;
- }
-
- if (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) {
- write_console(fd,
- "Couldn't find verity metadata at offset %"PRIu64"!\n",
- device_length);
- goto errout;
- }
-
- if (lseek64(device, device_length, SEEK_SET) < 0) {
- write_console(fd,
- "Could not seek to start of verity metadata block.\n");
- 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);
- goto errout;
- }
-
- write_console(fd, "Verity disabled on %s\n", mount_point);
- retval = 0;
-errout:
- if (device != -1)
- adb_close(device);
- return retval;
-}
-
-void disable_verity_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;
- }
-
- 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/fdevent.c b/adb/fdevent.cpp
similarity index 96%
rename from adb/fdevent.c
rename to 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 "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 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 @@
}
#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 @@
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 @@
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 @@
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 @@
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 @@
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_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
similarity index 84%
rename from adb/file_sync_client.c
rename to 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 @@
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 @@
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 @@
return -1;
}
-typedef struct syncsendbuf syncsendbuf;
-
struct syncsendbuf {
unsigned id;
unsigned size;
@@ -149,12 +147,12 @@
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 @@
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 @@
{
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
}
}
-typedef struct copyinfo copyinfo;
-
struct copyinfo
{
copyinfo *next;
@@ -573,7 +564,6 @@
unsigned int mode;
unsigned int size;
int flag;
- //char data[0];
};
copyinfo *mkcopyinfo(const char *spath, const char *dpath,
@@ -585,7 +575,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
-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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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_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
similarity index 80%
rename from adb/file_sync_service.c
rename to 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>
-#include <stdio.h>
-#include <string.h>
+#define TRACE_TAG TRACE_SYNC
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <utime.h>
-#include <unistd.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);
-}
+#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 <unistd.h>
+#include <utime.h>
-static bool is_on_vendor(const char *name) {
- const char *VENDOR = "/vendor/";
- return (strncmp(VENDOR, name, strlen(VENDOR)) == 0);
+#include "adb.h"
+#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
-#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;
-
- /* copy user permission bits to "group" and "other" permissions */
- mode |= ((mode >> 3) & 0070);
- mode |= ((mode >> 3) & 0007);
-
- 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);
+ if (is_link) {
+ return handle_send_link(s, path, buffer);
}
- return ret;
+ uid_t uid = -1;
+ gid_t gid = -1;
+ uint64_t cap = 0;
+
+ /* copy user permission bits to "group" and "other" permissions */
+ mode |= ((mode >> 3) & 0070);
+ mode |= ((mode >> 3) & 0007);
+
+ 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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
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
similarity index 89%
rename from adb/framebuffer_service.c
rename to 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 <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
#include <errno.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include "fdevent.h"
-#include "adb.h"
-
+#include <fcntl.h>
#include <linux/fb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "sysdeps.h"
+
+#include "adb.h"
+#include "adb_io.h"
+#include "fdevent.h"
/* TODO:
** - sync with vsync to avoid tearing
@@ -60,28 +62,30 @@
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 @@
}
/* 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
similarity index 97%
rename from adb/get_my_path_darwin.c
rename to 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_freebsd.c b/adb/get_my_path_freebsd.c
deleted file mode 100644
index b06ec66..0000000
--- a/adb/get_my_path_freebsd.c
+++ /dev/null
@@ -1,36 +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/types.h>
-#include <unistd.h>
-#include <limits.h>
-#include <stdio.h>
-
-void
-get_my_path(char *exe, size_t maxLen)
-{
- char proc[64];
-
- snprintf(proc, sizeof(proc), "/proc/%d/file", getpid());
-
- int err = readlink(proc, exe, maxLen - 1);
-
- exe[err > 0 ? err : 0] = '\0';
-}
-
diff --git a/adb/get_my_path_linux.c b/adb/get_my_path_linux.cpp
similarity index 97%
rename from adb/get_my_path_linux.c
rename to 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
similarity index 97%
rename from adb/get_my_path_windows.c
rename to 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
similarity index 94%
rename from adb/jdwp_service.c
rename to 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 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 @@
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 @@
__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 @@
#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 @@
** 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 @@
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 @@
** to the client...
**/
-typedef struct JdwpTracker JdwpTracker;
-
struct JdwpTracker {
asocket socket;
JdwpTracker* next;
@@ -695,7 +713,7 @@
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 @@
}
#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/usb_vendors.h b/adb/qemu_tracing.h
similarity index 62%
copy from adb/usb_vendors.h
copy to adb/qemu_tracing.h
index cee23a1..ff42d4f 100644
--- a/adb/usb_vendors.h
+++ b/adb/qemu_tracing.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,15 @@
* limitations under the License.
*/
-#ifndef __USB_VENDORS_H
-#define __USB_VENDORS_H
+/*
+ * Implements ADB tracing inside the emulator.
+ */
-extern int vendorIds[];
-extern unsigned vendorIdCount;
+#ifndef __QEMU_TRACING_H
+#define __QEMU_TRACING_H
-void usb_vendors_init(void);
+/* 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
+#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
similarity index 72%
rename from adb/usb_vendors.h
rename to 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
similarity index 77%
rename from adb/services.c
rename to adb/services.cpp
index 21b08dc..e6c84a4 100644
--- a/adb/services.c
+++ b/adb/services.cpp
@@ -14,31 +14,36 @@
* limitations under the License.
*/
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
+#define TRACE_TAG TRACE_SERVICES
#include "sysdeps.h"
-#define TRACE_TAG TRACE_SERVICES
-#include "adb.h"
-#include "file_sync_service.h"
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.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>
+#ifndef _WIN32
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
#endif
-typedef struct stinfo stinfo;
+#include <base/stringprintf.h>
+
+#if !ADB_HOST
+#include "base/file.h"
+#include "cutils/android_reboot.h"
+#include "cutils/properties.h"
+#endif
+
+#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 @@
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 @@
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 @@
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 @@
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 @@
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;
}
- // 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:
+
+ 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();
+ }
+ }
+
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 @@
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 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 @@
} 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 @@
adb_close(sv[1]);
return sv[0];
}
-#endif /* !HAVE_WIN32_PROC */
+#endif /* !defined(_WIN32) */
}
#endif /* !ABD_HOST */
@@ -311,7 +375,7 @@
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 @@
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 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 @@
}
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 @@
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 @@
}
}
} 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 @@
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 @@
}
// 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 @@
{
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 @@
// 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 @@
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/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp
new file mode 100644
index 0000000..b75ed4c
--- /dev/null
+++ b/adb/set_verity_enable_state_service.cpp
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.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 "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, ...)
+{
+ char buffer[256];
+ va_list args;
+ va_start (args, format);
+ vsnprintf (buffer, sizeof(buffer), format, args);
+ va_end (args);
+
+ adb_write(fd, buffer, strnlen(buffer, sizeof(buffer)));
+}
+
+static int get_target_device_size(int fd, const char *blk_device,
+ uint64_t *device_size)
+{
+ int data_device;
+ struct ext4_super_block sb;
+ struct fs_info info;
+
+ info.len = 0; /* Only len is set to 0 to ask the device for real size. */
+
+ data_device = adb_open(blk_device, O_RDONLY | O_CLOEXEC);
+ if (data_device < 0) {
+ write_console(fd, "Error opening block device (%s)\n", strerror(errno));
+ return -1;
+ }
+
+ if (lseek64(data_device, 1024, SEEK_SET) < 0) {
+ write_console(fd, "Error seeking to superblock\n");
+ adb_close(data_device);
+ return -1;
+ }
+
+ if (adb_read(data_device, &sb, sizeof(sb)) != sizeof(sb)) {
+ write_console(fd, "Error reading superblock\n");
+ adb_close(data_device);
+ return -1;
+ }
+
+ ext4_parse_sb(&sb, &info);
+ *device_size = info.len;
+
+ adb_close(data_device);
+ return 0;
+}
+
+/* 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 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",
+ block_device, strerror(errno));
+ write_console(fd, "Maybe run adb remount?\n");
+ goto errout;
+ }
+
+ // find the start of the verity metadata
+ if (get_target_device_size(fd, (char*)block_device, &device_length) < 0) {
+ write_console(fd, "Could not get target device size.\n");
+ goto errout;
+ }
+
+ if (lseek64(device, device_length, SEEK_SET) < 0) {
+ write_console(fd,
+ "Could not seek to start of verity metadata block.\n");
+ goto errout;
+ }
+
+ // check the magic number
+ if (adb_read(device, &magic_number, sizeof(magic_number))
+ != sizeof(magic_number)) {
+ write_console(fd, "Couldn't read magic number!\n");
+ goto errout;
+ }
+
+ if (!enable && magic_number == VERITY_METADATA_MAGIC_DISABLE) {
+ write_console(fd, "Verity already disabled on %s\n", mount_point);
+ goto errout;
+ }
+
+ 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",
+ device_length);
+ goto errout;
+ }
+
+ if (lseek64(device, device_length, SEEK_SET) < 0) {
+ write_console(fd,
+ "Could not seek to start of verity metadata block.\n");
+ goto errout;
+ }
+
+ 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 %s on %s\n",
+ enable ? "enabled" : "disabled",
+ mount_point);
+ retval = 0;
+errout:
+ if (device != -1)
+ adb_close(device);
+ return retval;
+}
+
+void set_verity_enabled_state_service(int fd, void* cookie)
+{
+ 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");
+ }
+
+errout:
+ adb_close(fd);
+}
diff --git a/adb/sockets.c b/adb/sockets.cpp
similarity index 89%
rename from adb/sockets.c
rename to adb/sockets.cpp
index faa9564..f468029 100644
--- a/adb/sockets.c
+++ b/adb/sockets.cpp
@@ -14,21 +14,24 @@
* limitations under the License.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <ctype.h>
+#define TRACE_TAG TRACE_SOCKETS
#include "sysdeps.h"
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.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 @@
char buf[9];
int len;
len = strlen(reason);
- 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 (len > 0xffff) {
+ len = 0xffff;
+ }
-//extern int online;
+ snprintf(buf, sizeof buf, "FAIL%04x", len);
+ if (!WriteFdExactly(fd, buf, 8)) {
+ return -1;
+ }
+
+ return WriteFdExactly(fd, reason, len) ? 0 : -1;
+}
static unsigned local_socket_next_id = 1;
@@ -196,10 +203,9 @@
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_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 @@
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) {
+ if (r == -1) {
+ /* returning here is ok because FDE_READ will
+ ** be processed in the next iteration loop
+ */
+ if (errno == EAGAIN) {
+ return;
+ }
+ } else if (r > 0) {
p->ptr += r;
p->len -= r;
continue;
}
- if(r < 0) {
- /* returning here is ok because FDE_READ will
- ** be processed in the next iteration loop
- */
- if(errno == EAGAIN) return;
- if(errno == EINTR) 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 @@
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 @@
}
}
/* 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 @@
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 @@
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 @@
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 @@
/* 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_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 @@
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 @@
}
#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 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 <ctype.h>
+#include <direct.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <process.h>
+#include <sys/stat.h>
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
-#include <process.h>
-#include <fcntl.h>
-#include <io.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <ctype.h>
-#include <direct.h>
+
+#include "fdevent.h"
#define OS_PATH_SEPARATOR '\\'
#define OS_PATH_SEPARATOR_STR "\\"
@@ -77,13 +94,16 @@
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 @@
#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 @@
#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_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 @@
#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 @@
#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 @@
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 @@
{
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
similarity index 60%
rename from adb/sysdeps_win32.c
rename to 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 @@
/**************************************************************************/
/**************************************************************************/
-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 @@
return 0;
}
-/* forward definitions */
-static const FHClassRec _fh_file_class;
-static const FHClassRec _fh_socket_class;
-
/**************************************************************************/
/**************************************************************************/
/***** *****/
@@ -211,23 +258,17 @@
/**************************************************************************/
/**************************************************************************/
-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 @@
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 @@
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 @@
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 @@
{
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 @@
/**************************************************************************/
/**************************************************************************/
-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 @@
}
}
-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 @@
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 @@
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 @@
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 @@
}
-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 @@
};
-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 @@
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 @@
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 @@
}
/* 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
similarity index 100%
rename from adb/test_track_devices.c
rename to adb/test_track_devices.cpp
diff --git a/adb/test_track_jdwp.c b/adb/test_track_jdwp.cpp
similarity index 100%
rename from adb/test_track_jdwp.c
rename to 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
similarity index 86%
rename from adb/transport.c
rename to adb/transport.cpp
index f35880c..d395a80 100644
--- a/adb/transport.c
+++ b/adb/transport.cpp
@@ -14,15 +14,18 @@
* limitations under the License.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
+#define TRACE_TAG TRACE_TRANSPORT
#include "sysdeps.h"
+#include "transport.h"
-#define TRACE_TAG TRACE_TRANSPORT
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
#include "adb.h"
static void transport_unref(atransport *t);
@@ -41,7 +44,7 @@
#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 @@
}
#endif
-void
-kick_transport(atransport* t)
+void kick_transport(atransport* t)
{
if (t && !t->kicked)
{
@@ -85,8 +87,25 @@
}
}
-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 @@
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 @@
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 @@
static void *input_thread(void *_t)
{
- atransport *t = _t;
+ atransport *t = reinterpret_cast<atransport*>(_t);
apacket *p;
int active = 0;
@@ -387,7 +406,6 @@
* 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 @@
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 @@
/* 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 @@
}
#endif // ADB_HOST
-typedef struct tmsg tmsg;
struct tmsg
{
atransport *transport;
@@ -629,7 +644,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
} 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 @@
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 @@
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 @@
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 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 @@
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 @@
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 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 @@
#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
similarity index 90%
rename from adb/transport_local.c
rename to 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 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 @@
{
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 @@
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
similarity index 68%
rename from adb/transport_usb.c
rename to 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 @@
return -1;
}
- fix_endians(p);
-
if(check_header(p)) {
D("remote usb: check_header failed\n");
return -1;
@@ -83,8 +56,6 @@
{
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 @@
#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
similarity index 90%
rename from adb/usb_linux.c
rename to 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 <dirent.h>
-#include <fcntl.h>
-#include <errno.h>
+#include "sysdeps.h"
+
#include <ctype.h>
-
+#include <dirent.h>
+#include <errno.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 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 @@
// 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 @@
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 @@
}
fail:
adb_mutex_unlock(&h->lock);
+ D("-- usb_bulk_read --\n");
return res;
}
@@ -439,6 +447,7 @@
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 @@
return n;
}
+ D("-- usb_write --\n");
return 0;
}
@@ -542,7 +552,7 @@
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 @@
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 @@
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 @@
** 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 @@
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 @@
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
similarity index 65%
rename from adb/usb_linux_client.c
rename to 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>
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/functionfs.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <errno.h>
+#define TRACE_TAG TRACE_USB
#include "sysdeps.h"
-#define TRACE_TAG TRACE_USB
+#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 <unistd.h>
+
#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 @@
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 @@
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_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 @@
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 @@
}
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 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 @@
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 @@
{
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 @@
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 @@
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 @@
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 @@
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_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 @@
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
similarity index 84%
rename from adb/usb_osx.c
rename to 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 @@
{
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 @@
runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
- memset(notificationIterators, 0, sizeof(notificationIterators));
+ //* 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);
- //* 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);
-
- 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 @@
HRESULT result;
SInt32 score;
UInt32 locationId;
+ UInt8 if_class, subclass, protocol;
UInt16 vendor;
UInt16 product;
UInt8 serialIndex;
@@ -146,9 +133,9 @@
}
//* 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 @@
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 @@
}
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 @@
//* 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 @@
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 @@
void* RunLoopThread(void* unused)
{
- unsigned i;
-
InitUSB();
currentRunLoop = CFRunLoopGetCurrent();
@@ -398,9 +394,7 @@
CFRunLoopRun();
currentRunLoop = 0;
- for (i = 0; i < vendorIdCount; i++) {
- IOObjectRelease(notificationIterators[i]);
- }
+ IOObjectRelease(notificationIterator);
IONotificationPortDestroy(notificationPort);
DBG("RunLoopThread done\n");
@@ -415,9 +409,6 @@
{
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 @@
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
similarity index 98%
rename from adb/usb_windows.c
rename to 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>
-#include <adb_api.h>
-#include <stdio.h>
-#include <stdlib.h>
+#define TRACE_TAG TRACE_USB
#include "sysdeps.h"
-#define TRACE_TAG TRACE_USB
+#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 "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 @@
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_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/adb/usb_vendors.h b/base/test_main.cpp
similarity index 66%
copy from adb/usb_vendors.h
copy to base/test_main.cpp
index cee23a1..546923d 100644
--- a/adb/usb_vendors.h
+++ b/base/test_main.cpp
@@ -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
+#include <gtest/gtest.h>
-extern int vendorIds[];
-extern unsigned vendorIdCount;
+#include "base/logging.h"
-void usb_vendors_init(void);
-
-#endif
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ android::base::InitLogging(argv, android::base::StderrLogger);
+ return RUN_ALL_TESTS();
+}
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
new file mode 100644
index 0000000..1f6d3cf
--- /dev/null
+++ b/base/test_utils.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 "test_utils.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+TemporaryFile::TemporaryFile() {
+ init("/data/local/tmp");
+ if (fd == -1) {
+ init("/tmp");
+ }
+}
+
+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/adb/usb_vendors.h b/base/test_utils.h
similarity index 67%
copy from adb/usb_vendors.h
copy to base/test_utils.h
index cee23a1..132d3a7 100644
--- a/adb/usb_vendors.h
+++ b/base/test_utils.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,19 @@
* limitations under the License.
*/
-#ifndef __USB_VENDORS_H
-#define __USB_VENDORS_H
+#ifndef TEST_UTILS_H
+#define TEST_UTILS_H
-extern int vendorIds[];
-extern unsigned vendorIdCount;
+class TemporaryFile {
+ public:
+ TemporaryFile();
+ ~TemporaryFile();
-void usb_vendors_init(void);
+ int fd;
+ char filename[1024];
-#endif
+ 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_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 @@
LOCAL_SRC_FILES:= \
backtrace.cpp \
debuggerd.cpp \
+ elf_utils.cpp \
getevent.cpp \
tombstone.cpp \
utility.cpp \
@@ -12,7 +13,7 @@
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 @@
-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_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 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 @@
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 @@
} 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 7be64f1..d3ef9a8 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 @@
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 @@
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;
@@ -184,6 +241,9 @@
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;
@@ -201,6 +261,85 @@
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);
@@ -211,6 +350,24 @@
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.
@@ -397,7 +554,7 @@
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);
@@ -451,7 +608,11 @@
}
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/adb/usb_vendors.h b/debuggerd/elf_utils.h
similarity index 67%
copy from adb/usb_vendors.h
copy to debuggerd/elf_utils.h
index cee23a1..11d0a43 100644
--- a/adb/usb_vendors.h
+++ b/debuggerd/elf_utils.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,14 @@
* limitations under the License.
*/
-#ifndef __USB_VENDORS_H
-#define __USB_VENDORS_H
+#ifndef _DEBUGGERD_ELF_UTILS_H
+#define _DEBUGGERD_ELF_UTILS_H
-extern int vendorIds[];
-extern unsigned vendorIdCount;
+#include <stdint.h>
+#include <string>
-void usb_vendors_init(void);
+class Backtrace;
-#endif
+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_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 3eeff34..c0340ef 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_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;
+ line = " ";
+ if (i == 0 && label >= 0) {
+ // Print the label once.
+ line += android::base::StringPrintf("#%02d ", label);
+ } else {
+ line += " ";
}
+ line += android::base::StringPrintf("%" PRIPTR " %" PRIPTR, *sp, stack_data[i]);
- const backtrace_map_t* map = backtrace->FindMap(stack_content);
- const char* map_name;
- if (!map) {
- map_name = "";
- } else {
- map_name = map->name.c_str();
- }
- uintptr_t offset = 0;
- std::string func_name(backtrace->GetFunctionName(stack_content, &offset));
- if (!func_name.empty()) {
- if (!i && label >= 0) {
+ 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,6 +318,75 @@
}
}
+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::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);
+ }
+
+ _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;
+ }
+ }
+
+ std::string line;
+ for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
+ 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 += '-';
+ }
+ 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 (print_fault_address_marker) {
+ _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " after any mapped regions\n",
+ addr);
+ }
+}
+
static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log) {
if (backtrace->NumFrames()) {
_LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
@@ -335,53 +397,6 @@
}
}
-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) {
- 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;
- }
-
- 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);
- }
-
- BacktraceMap::const_iterator prev = map->begin();
- 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);
- }
- prev = it;
- bool in_map = has_fault_address && (addr >= (*it).start) && (addr < (*it).end);
- dump_map(log, &*it, in_map);
- }
- if (has_fault_address && (addr >= (*prev).end)) {
- _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);
-
- dump_memory_and_code(log, backtrace->Tid());
- dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid());
-}
-
// Return true if some thread is not detached cleanly
static bool dump_sibling_thread_report(
log_t* log, pid_t pid, pid_t tid, int* total_sleep_time_usec, BacktraceMap* map) {
@@ -425,9 +440,10 @@
_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 @@
}
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 @@
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 12df1e6..ee96a34 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -132,12 +132,6 @@
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];
@@ -184,7 +178,6 @@
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
@@ -198,7 +191,6 @@
*asc_out++ = '.';
}
}
-#endif
p += sizeof(long);
}
*asc_out = '\0';
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 9f46982..86a4b1e 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 @@
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 @@
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 @@
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_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
similarity index 95%
rename from fastboot/bootimg.c
rename to 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 @@
unsigned ramdisk_actual;
unsigned second_actual;
unsigned page_mask;
- boot_img_hdr *hdr;
page_mask = page_size - 1;
@@ -57,9 +56,8 @@
*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/socket_client.h b/fastboot/bootimg_utils.h
similarity index 66%
rename from fastbootd/socket_client.h
rename to fastboot/bootimg_utils.h
index 4481ff2..b1a86cd 100644
--- a/fastbootd/socket_client.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,9 +26,24 @@
* SUCH DAMAGE.
*/
-#ifndef _FASTBOOTD_SOCKET_CLIENT_H
-#define _FASTBOOTD_SOCKET_CLIENT_H
+#ifndef _FASTBOOT_BOOTIMG_UTILS_H_
+#define _FASTBOOT_BOOTIMG_UTILS_H_
-void run_socket_client();
+#include <bootimg.h>
+
+#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
similarity index 89%
rename from fastboot/fastboot.c
rename to 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 @@
{"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 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 @@
// 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 @@
" 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 @@
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 @@
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 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 @@
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 @@
}
}
- fb_queue_require(prod, name, invert, n, out);
+ fb_queue_require(prod, var, invert, n, out);
return 0;
}
@@ -551,21 +538,17 @@
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 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 @@
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'");
-
- 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);
+ ZipArchiveHandle zip;
+ int error = OpenArchive(filename, &zip);
+ if (error != 0) {
+ die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
}
- setup_requirements(data, sz);
+ unsigned sz;
+ void* data = unzip_file(zip, "android-info.txt", &sz);
+ if (data == 0) {
+ die("update package '%s' has no android-info.txt", filename);
+ }
- for (i = 0; i < ARRAY_SIZE(images); i++) {
- fd = unzip_to_file(zip, images[i].img_name);
+ setup_requirements(reinterpret_cast<char*>(data), sz);
+
+ 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 @@
* program exits.
*/
}
+
+ CloseArchive(zip);
}
void do_send_signature(char *fn)
@@ -800,24 +766,22 @@
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);
- 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++) {
+ unsigned sz;
+ void* data = load_file(fname, &sz);
+ if (data == 0) die("could not load android-info.txt: %s", strerror(errno));
+
+ 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 @@
unsigned sz;
int status;
int c;
+ int longindex;
const struct option longopts[] = {
{"base", required_argument, 0, 'b'},
@@ -996,13 +961,14 @@
{"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 @@
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 @@
} 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 @@
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 @@
------------------
* 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 @@
}
}
-#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 @@
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_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 @@
} 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 @@
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/debug.h b/fastbootd/debug.h
deleted file mode 100644
index 74620b8..0000000
--- a/fastbootd/debug.h
+++ /dev/null
@@ -1,42 +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_DEBUG_H_
-#define _FASTBOOTD_DEBUG_H_
-
-#include <stdio.h>
-
-#include <cutils/klog.h>
-
-#define ERR 0
-#define WARN 1
-#define INFO 2
-#define VERBOSE 3
-#define DEBUG 4
-
-extern unsigned int debug_level;
-
-//#define DLOG(fmt, ...) printf(fmt, ##__VA_ARGS__)
-#define DLOG(fmt, ...) KLOG_INFO("fastbootd", fmt, ##__VA_ARGS__)
-
-#define D(level, fmt, ...) \
- do { \
- if (debug_level == level || debug_level > level) { \
- DLOG("%s:%d " fmt "\n", __BASE_FILE__, __LINE__, ##__VA_ARGS__); \
- } \
- } while (0)
-
-#endif
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/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/trigger.h b/fastbootd/trigger.h
deleted file mode 100644
index d2d9573..0000000
--- a/fastbootd/trigger.h
+++ /dev/null
@@ -1,40 +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_TRIGGER_H_
-#define __FASTBOOTD_TRIGGER_H_
-
-#include "commands/partitions.h"
-#include "vendor_trigger.h"
-
-int load_trigger();
-
-#endif
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 @@
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_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 @@
* 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 @@
* 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 @@
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 @@
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 @@
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 @@
/* 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 @@
{ "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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
// 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 @@
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;
+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;
}
- ret = PROP_NAME_MAX - strlen(key);
- if (ret < 0) {
- ERROR("Verified property name is too long");
+
+ 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 @@
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 @@
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 @@
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 @@
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 @@
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_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 @@
#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 @@
_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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
int min_capacity;
bool level_only;
- gr_surface surface;
+ GRSurface* surface;
};
struct animation {
@@ -115,7 +115,7 @@
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 @@
}
/* 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 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 @@
/* 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 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 @@
{
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
* 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 @@
* 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 @@
* 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 @@
#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 @@
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_timeout(pid_t tid, int fd, int timeout_secs);
-#ifdef __cplusplus
-}
-#endif
+__END_DECLS
#endif /* __CUTILS_DEBUGGER_H */
diff --git a/include/cutils/dir_hash.h b/include/cutils/dir_hash.h
deleted file mode 100644
index fbb4d02..0000000
--- a/include/cutils/dir_hash.h
+++ /dev/null
@@ -1,26 +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.
- */
-
-typedef enum {
- SHA_1,
-} HashAlgorithm;
-
-int get_file_hash(HashAlgorithm algorithm, const char *path,
- char *output_string, size_t max_output_string);
-
-int get_recursive_hash_manifest(HashAlgorithm algorithm,
- const char *directory_path,
- char **output_string);
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 @@
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 @@
/* 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 @@
}
#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 @@
#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 @@
*/
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 @@
/* 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 @@
/***********************************************************************/
/***********************************************************************/
-#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 @@
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 @@
/***********************************************************************/
/***********************************************************************/
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
typedef pthread_mutex_t mutex_t;
@@ -98,10 +97,10 @@
{
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 @@
{
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 @@
#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 @@
* 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 @@
#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 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 @@
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 @@
* 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_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_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 @@
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 e3b7ec1..e10e8f7 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 @@
// ---------------------------------------------------------------------
+#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 @@
#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 @@
#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 @@
#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 @@
#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 @@
#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 @@
* 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 @@
#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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
#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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
*/
#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,6 +555,22 @@
#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
+
#define android_errorWriteLog(tag, subTag) \
__android_log_error_write(tag, subTag, -1, NULL, 0)
@@ -541,7 +578,6 @@
__android_log_error_write(tag, subTag, uid, data, dataLen)
// 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)
@@ -552,11 +588,15 @@
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;
@@ -567,6 +607,12 @@
uint32_t dataLen);
/*
+ * 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 @@
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 @@
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 @@
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 @@
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 @@
}
#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_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_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 @@
#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 @@
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.
-*/
+/* Rules for directories and files has moved to system/code/libcutils/fs_config.c */
-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 },
-};
+__BEGIN_DECLS
-/* 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" },
+/*
+ * 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);
- /* the following file is INTENTIONALLY set-gid and not set-uid.
- * Do not change. */
- { 02750, AID_ROOT, AID_INET, 0, "system/bin/netcfg" },
+ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc);
- /* 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" },
+__END_DECLS
- /* 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;
-
- if (path[0] == '/') {
- path++;
- }
-
- 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;
-
-#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 @@
/*
* "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 @@
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 @@
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
* - 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 @@
* - 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 @@
* - 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 @@
*
* 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 @@
* 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 @@
*
* 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 @@
};
/**
+ * 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 @@
};
/**
- * 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 {
/*
- * Arbitrary colorspace with manually defined characteristics.
- * Colorspace definition must be communicated separately.
+ * 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 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
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 @@
* 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.
+ * (*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)
- *
+ * 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 @@
}
/*
+ * 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 @@
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 @@
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 @@
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 @@
// ------------------------------------------------------------------
// 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 @@
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 /* __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
-#endif /* !HAVE_OFF64_T */
-
-#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 @@
void broadcast();
private:
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
pthread_cond_t mCond;
#else
void* mState;
@@ -83,7 +83,7 @@
// ---------------------------------------------------------------------------
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
inline Condition::Condition() {
pthread_cond_init(&mCond, NULL);
@@ -113,15 +113,15 @@
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 @@
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 @@
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 @@
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 @@
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 @@
PRIVATE = 0,
SHARED = 1
};
-
+
Mutex();
Mutex(const char* name);
Mutex(int type, const char* name = NULL);
@@ -58,6 +59,16 @@
// 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 @@
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 @@
// ---------------------------------------------------------------------------
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
inline Mutex::Mutex() {
pthread_mutex_init(&mMutex, NULL);
@@ -117,8 +128,17 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
*/
#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 @@
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 @@
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 f8f0aee..4e17cc3 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 @@
};
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 @@
* 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 @@
* 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 @@
* 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 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
+
+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
+ libinit \
+ libfs_mgr \
+ libsquashfs_utils \
+ liblogwrap \
+ libcutils \
+ libbase \
+ libext4_utils_static \
+ libutils \
+ liblog \
+ libc \
+ libselinux \
+ libmincrypt \
+ libc++_static \
+ libdl \
+ libsparse_static \
+ libz
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+# 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
similarity index 79%
rename from init/builtins.c
rename to 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 <fcntl.h>
-#include <unistd.h>
-#include <string.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 <fcntl.h>
+#include <net/if.h>
+#include <stdio.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 @@
ifr.ifr_flags &= ~IFF_UP;
ret = ioctl(s, SIOCSIFFLAGS, &ifr);
-
+
done:
close(s);
return ret;
@@ -200,18 +103,6 @@
}
}
-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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 ret = -1;
int child_ret = -1;
int status;
- const char *prop;
struct fstab *fstab;
if (nargs != 2) {
@@ -519,7 +425,7 @@
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 @@
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 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
} 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
similarity index 86%
rename from init/devices.c
rename to 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 @@
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 @@
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 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 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 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 @@
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 @@
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 @@
;
}
- 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 @@
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 @@
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 @@
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 @@
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 @@
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 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 @@
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 @@
static void handle_firmware_event(struct uevent *uevent)
{
pid_t pid;
- int ret;
if(strcmp(uevent->subsystem, "firmware"))
return;
@@ -938,7 +886,9 @@
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 @@
**
** 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 @@
}
}
-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 @@
/* 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 @@
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 @@
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
similarity index 62%
rename from init/init.c
rename to 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/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/stat.h>
+#include <sys/types.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 @@
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 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 @@
/* 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 @@
return -1;
}
-static void zap_stdio(void)
+void zap_stdio(void)
{
int fd;
fd = open("/dev/null", O_RDWR);
@@ -166,36 +186,26 @@
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 @@
return;
}
+ char* scon = NULL;
if (is_selinux_enabled() > 0) {
if (svc->seclabel) {
scon = strdup(svc->seclabel);
@@ -220,7 +231,7 @@
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 @@
}
}
- NOTICE("starting '%s'\n", svc->name);
+ NOTICE("Starting service '%s'...\n", svc->name);
- pid = fork();
-
+ pid_t pid = fork();
if (pid == 0) {
struct socketinfo *si;
struct svcenvinfo *ei;
@@ -257,9 +267,9 @@
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 @@
zap_stdio();
}
-#if 0
- for (n = 0; svc->args[n]; n++) {
- INFO("args[%d] = '%s'\n", n, svc->args[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]);
+ }
}
- for (n = 0; ENV[n]; n++) {
- INFO("env[%d] = '%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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
}
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 @@
if (urandom_fd != -1) {
close(urandom_fd);
}
- memset(buf, 0, sizeof(buf));
return result;
}
@@ -670,18 +711,17 @@
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 @@
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 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));
+ std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dir), closedir);
+ if (!dir)
+ return;
- /* save a copy for init's usage during boot */
- property_get("ro.bootmode", tmp);
- strlcpy(bootmode, tmp, sizeof(bootmode));
+ struct dirent *dp;
+ while ((dp = readdir(dir.get())) != NULL) {
+ if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible"))
+ continue;
- /* 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);
+ file_name = android::base::StringPrintf("%s/%s", android_dir, dp->d_name);
- snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
- property_set("ro.revision", tmp);
+ android::base::ReadFileToString(file_name, &dt_file);
+ std::replace(dt_file.begin(), dt_file.end(), ',', '.');
- /* 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::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 @@
* 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 @@
return 0;
}
-#if BOOTCHART
-static int bootchart_init_action(int nargs, char **args)
-{
- 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;
-}
-#endif
-
-static const struct selinux_opt seopts_prop[] = {
- { SELABEL_OPT_PATH, "/property_contexts" },
- { SELABEL_OPT_PATH, "/data/security/current/property_contexts" },
- { 0, NULL }
-};
-
-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;
-}
-
-void selinux_init_all_handles(void)
+static void selinux_init_all_handles(void)
{
sehandle = selinux_android_file_context_handle();
selinux_android_set_sehandle(sehandle);
sehandle_prop = selinux_android_prop_context_handle();
}
+enum selinux_enforcing_status { SELINUX_DISABLED, SELINUX_PERMISSIVE, SELINUX_ENFORCING };
+
+static selinux_enforcing_status selinux_status_from_cmdline() {
+ selinux_enforcing_status status = SELINUX_ENFORCING;
+
+ 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 (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;
}
- 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;
- }
-#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 (ALLOW_DISABLE_SELINUX) {
+ return selinux_status_from_cmdline() == SELINUX_ENFORCING;
}
-
- 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);
- }
-
-#endif
return true;
}
@@ -952,223 +927,196 @@
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);
+ add_environment("PATH", _PATH_DEFPATH);
- 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);
+ bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);
- /* indicate that booting is in progress to background fw loaders, etc */
- close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));
+ // 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.
- */
+ // 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);
+ }
- INFO("property init\n");
+ signal_handler_init();
+
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 <sys/types.h>
+
#include <cutils/list.h>
-
-#include <sys/stat.h>
-
-void handle_control_message(const char *msg, const char *arg);
+#include <cutils/iosched_policy.h>
struct command
{
@@ -37,6 +36,11 @@
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 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 @@
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 @@
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 @@
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_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
similarity index 71%
rename from init/init_parser.c
rename to 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 <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdarg.h>
#include <string.h>
-#include <stddef.h>
-#include <ctype.h>
+#include <unistd.h>
#include "init.h"
#include "parser.h"
@@ -73,14 +75,53 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
-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(fn, data);
- DUMP();
+ parse_config(path, data);
+ dump_parser_state();
+
+ NOTICE("(Parsing %s took %.2fs.)\n", path, t.duration());
return 0;
}
@@ -504,83 +543,94 @@
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);
+ 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;
- 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);
- }
+ /* 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 @@
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 @@
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_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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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_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_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 @@
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 @@
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
similarity index 77%
rename from init/keychords.c
rename to init/keychords.cpp
index 4a64042..10d9573 100644
--- a/init/keychords.c
+++ b/init/keychords.cpp
@@ -40,7 +40,7 @@
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 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 @@
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 @@
}
}
-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_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_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_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 @@
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 @@
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 @@
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 @@
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;
+}
diff --git a/init/log.h b/init/log.h
index e9cb65a..b804d1f 100644
--- a/init/log.h
+++ b/init/log.h
@@ -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
similarity index 73%
rename from init/parser.c
rename to 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 @@
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
similarity index 71%
rename from init/property_service.c
rename to 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;
+void property_init() {
+ if (property_area_initialized) {
+ return;
+ }
- if(__system_property_area_init())
- return -1;
+ property_area_initialized = true;
- if(init_workspace(&pa_workspace, 0))
- return -1;
+ if (__system_property_area_init()) {
+ return;
+ }
- fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
-
- 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 @@
return 1;
char *tctx = NULL;
- const char *class = "property_service";
- const char *perm = "set";
int result = 0;
if (!sctx)
@@ -111,7 +101,7 @@
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_perms(const char *name, char *sctx)
{
- int i;
- unsigned int app_id;
-
if(!strncmp(name, "ro.", 3))
name +=3;
@@ -165,7 +152,7 @@
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 @@
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 @@
__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 @@
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 @@
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 @@
* 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;
-
- data = read_file(fn, &sz);
-
- if(data != 0) {
- load_properties(data, filter);
- free(data);
+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());
}
-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;
- }
-
- // 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;
- }
-
- 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);
- }
- close(fd);
- }
- closedir(dir);
- } else {
- ERROR("Unable to open persistent property directory %s errno: %d\n", PERSISTENT_PROPERTY_DIR, errno);
- }
-
+static void load_persistent_properties() {
persistent_properties_loaded = 1;
+
+ 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;
+ }
+
+ 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;
+ }
+
+ // 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;
+ }
+
+ 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;
+ }
+
+ // 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;
+ }
+
+ 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_init(void)
-{
- init_property_area();
-}
-
-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 @@
load_persistent_properties();
}
-void start_property_service(void)
-{
- int fd;
+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);
+ }
- 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);
+ listen(property_set_fd, 8);
- listen(fd, 8);
- property_set_fd = fd;
-}
-
-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 @@
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 @@
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 @@
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 @@
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 @@
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:
-service-exited-<name>
- Triggers of this form occur when the specified service exits.
+ on property:test.a=1 && property:test.b=1
+ setprop test.c 1
+
+ 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 @@
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 @@
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_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.
+rm <path>
+ Calls unlink(2) on the given path. You might want to
+ use "exec -- rm ..." instead (provided the system partition is
+ already mounted).
-setenforce 0|1
- Set the SELinux system-wide enforcing status.
- 0 is permissive (i.e. log but do not deny), 1 is enforcing.
-
-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 an event. Used to queue an action from another
action.
-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.
+verity_load_state
+ Internal implementation detail used to load dm-verity state.
-write <path> <string>
- Open the file at <path> and write a string to it with write(2)
- without appending.
+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.
+
+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 @@
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 @@
State of a named service ("stopped", "running", "restarting")
-Example init.conf
------------------
+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.
-# not complete -- just providing some examples of usage
-#
-on boot
- export PATH /sbin:/system/sbin:/system/bin
- export LD_LIBRARY_PATH /system/lib
+On the emulator, use the -bootchart <timeout> option to boot with bootcharting
+activated for <timeout> seconds.
- mkdir /dev
- mkdir /proc
- mkdir /sys
+On a device, create /data/bootchart/start with a command like the following:
- mount tmpfs tmpfs /dev
- mkdir /dev/pts
- mkdir /dev/socket
- mount devpts devpts /dev/pts
- mount proc proc /proc
- mount sysfs sysfs /sys
+ adb shell 'echo $TIMEOUT > /data/bootchart/start'
- write /proc/cpu/alignment 4
+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:
- ifup lo
+ adb shell 'echo 1 > /data/bootchart/stop'
- hostname localhost
- domainname localhost
+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.
- mount yaffs2 mtd@system /system
- mount yaffs2 mtd@userdata /data
+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:
- import /system/etc/init.conf
+ sudo apt-get install pybootchartgui
+ # grab-bootchart.sh uses $ANDROID_SERIAL.
+ $ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
- class_start default
+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.
-service adbd /sbin/adbd
- user adb
- group adb
-service usbd /system/bin/usbd -r
- user usbd
- group usbd
- socket usbd 666
-
-service zygote /system/bin/app_process -Xzygote /system/bin --zygote
- socket zygote 666
-
-service runtime /system/bin/runtime
- user system
- group system
-
-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
similarity index 74%
rename from init/ueventd.c
rename to 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 @@
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;
+ NOTICE("ueventd started!\n");
+
+ selinux_callback cb;
+ cb.func_log = selinux_klog_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
- 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);
-
- 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
similarity index 88%
rename from init/ueventd_parser.c
rename to init/ueventd_parser.cpp
index e447006..7a4841f 100644
--- a/init/ueventd_parser.c
+++ b/init/ueventd_parser.cpp
@@ -67,9 +67,7 @@
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 @@
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_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_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 @@
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 @@
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
similarity index 73%
rename from init/util.c
rename to 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 @@
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;
+bool read_file(const char* path, std::string* content) {
+ content->clear();
+
+ 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.
struct stat sb;
-
- data = 0;
- fd = open(fn, O_RDONLY);
- if(fd < 0) return 0;
-
- // for security reasons, disallow world-writable
- // or group-writable files
- if (fstat(fd, &sb) < 0) {
- ERROR("fstat failed for '%s'\n", fn);
- goto oops;
+ 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;
+ bool okay = android::base::ReadFdToString(fd, content);
+ TEMP_FAILURE_RETRY(close(fd));
+ if (okay) {
+ content->append("\n", 1);
+ }
+ return okay;
+}
- 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;
-
-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 @@
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 @@
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;
+time_t gettime() {
+ timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ return now.tv_sec;
+}
- ret = clock_gettime(CLOCK_MONOTONIC, &ts);
- if (ret < 0) {
- ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
- return 0;
- }
-
- 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 @@
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;
+ // 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);
+ }
+ if (fd == -1) {
+ exit(1);
}
}
- exit(1);
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ if (fd > 2) {
+ close(fd);
+ }
}
-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;
- }
- 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;
- }
- 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);
- }
- }
-
-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 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
similarity index 75%
rename from init/watchdogd.c
rename to 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");
+ int interval = 10;
+ if (argc >= 2) interval = atoi(argv[1]);
- if (argc >= 2)
- interval = atoi(argv[1]);
+ int margin = 10;
+ if (argc >= 3) margin = atoi(argv[2]);
- if (argc >= 3)
- margin = atoi(argv[2]);
+ NOTICE("watchdogd started (interval %d, margin %d)!\n", interval, margin);
- timeout = 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 @@
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 @@
$($(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
old mode 100755
new mode 100644
index 9588dd6..54cace9
--- 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 @@
# 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_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_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_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_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 4693600..0000000
--- a/libbacktrace/BacktraceImpl.cpp
+++ /dev/null
@@ -1,191 +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);
-}
-
-std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
- std::string func_name = impl_->GetFunctionNameRaw(pc, offset);
- 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
old mode 100755
new mode 100644
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() {
}
-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 @@
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* 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/libbacktrace/BacktracePtrace.h b/libbacktrace/BacktracePtrace.h
new file mode 100644
index 0000000..1d49811
--- /dev/null
+++ b/libbacktrace/BacktracePtrace.h
@@ -0,0 +1,37 @@
+/*
+ * 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_PTRACE_H
+#define _LIBBACKTRACE_BACKTRACE_PTRACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <backtrace/Backtrace.h>
+
+class BacktraceMap;
+
+class BacktracePtrace : public Backtrace {
+public:
+ BacktracePtrace(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
+ virtual ~BacktracePtrace() {}
+
+ size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes);
+
+ bool ReadWord(uintptr_t ptr, word_t* out_value);
+};
+
+#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 @@
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
similarity index 70%
rename from libbacktrace/BacktraceThread.h
rename to 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 @@
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
old mode 100755
new mode 100644
index b176aaf..67e583f
--- 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;
- }
+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;
}
- else {
- GetUnwContextFromUcontext(ucontext);
- }
- return UnwindFromContext(num_ignore_frames, false);
+ return "";
}
void UnwindCurrent::GetUnwContextFromUcontext(const ucontext_t* ucontext) {
@@ -76,90 +65,67 @@
#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;
- }
- 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_);
- if (ret < 0) {
- if (!within_handler) {
- BACK_LOGW("unw_init_local failed %d", ret);
+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;
}
- delete cursor;
+ } else {
+ GetUnwContextFromUcontext(ucontext);
+ }
+
+ // The cursor structure is pretty large, do not put it on the stack.
+ std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t);
+ int ret = unw_init_local(cursor.get(), &context_);
+ if (ret < 0) {
+ 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;
+ 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) {
+ 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();
+ UnwindCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : BacktraceCurrent(pid, tid, map) {}
+ virtual ~UnwindCurrent() {}
- virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
+ std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
- virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+private:
+ void GetUnwContextFromUcontext(const ucontext_t* ucontext);
- bool UnwindFromContext(size_t num_ignore_frames, bool within_handler);
+ bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;
- void GetUnwContextFromUcontext(const ucontext_t* context);
-
-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 @@
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 @@
}
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 @@
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 @@
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 @@
}
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 @@
}
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 <stdint.h>
+#include <sys/types.h>
+
#include <string>
-#include "BacktraceImpl.h"
-
+#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 @@
pid_t tid;
int32_t state;
pthread_t threadId;
+ void* data;
};
struct dump_thread_t {
@@ -82,15 +85,16 @@
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 @@
}
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 @@
break;
}
}
- ASSERT_LT(static_cast<size_t>(0), frame_num);
- ASSERT_LE(static_cast<size_t>(3), frame_num);
+ 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");
- 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_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 @@
}
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 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 @@
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 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 @@
}
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_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_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 @@
}
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 @@
// 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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
android_atomic_acquire_store(1, &dump->done);
- return NULL;
+ return nullptr;
}
TEST(libbacktrace, thread_multiple_dump) {
@@ -614,11 +652,11 @@
// 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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
#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_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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
# 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 @@
}
-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.
*/
+/* generic C version for any machine */
+
#include <cutils/memory.h>
-/* 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);
-
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
old mode 100644
new mode 100755
index f8b79bd..cb2ff14
--- 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
old mode 100644
new mode 100755
index 6249fce..f4326dc
--- 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
similarity index 95%
rename from libcutils/arch-x86/cache_wrapper.S
rename to 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
similarity index 98%
rename from libcutils/arch-x86_64/android_memset16_SSE2-atom.S
rename to 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 @@
.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 @@
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
similarity index 98%
rename from libcutils/arch-x86_64/android_memset32_SSE2-atom.S
rename to 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 @@
.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 @@
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_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 @@
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 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;
+ memset(&msg, 0, sizeof(msg));
+ msg.tid = tid;
+ msg.action = action;
-#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;
- }
-
- 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 @@
}
}
- 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 @@
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 @@
return fp;
}
-#else /*not HAVE_FUNOPEN*/
-FILE* open_memstream(char** bufp, size_t* sizep)
-{
- abort();
-}
-#endif /*HAVE_FUNOPEN*/
@@ -378,4 +370,4 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 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 @@
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 @@
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 @@
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 @@
}
/* 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 @@
{
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 @@
{
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
similarity index 62%
rename from libcutils/memory.c
rename to 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 @@
*/
#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 @@
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 $(CLEAR_VARS)
LOCAL_MODULE := libcutils_test_static
LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_SRC_FILES := $(test_src_files)
-LOCAL_STATIC_LIBRARIES := \
- libc \
- libcutils \
- liblog \
- libstlport_static \
- libutils \
-
+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_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_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"
-#ifdef HAVE_PTHREADS
+#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
+
void* thread_store_get( thread_store_t* store )
{
if (!store->has_tls)
@@ -24,8 +40,8 @@
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 @@
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 @@
} else while (store->lock_init != -2) {
Sleep(10); /* 10ms */
}
-
+
EnterCriticalSection( &store->lock );
if (!store->has_tls) {
store->tls = TlsAlloc();
@@ -76,7 +108,7 @@
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
similarity index 72%
rename from libcutils/trace.c
rename to 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 @@
// 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 @@
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 @@
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 @@
* 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 @@
0,
};
- *user = -1;
+ *uid = -1;
ssize_t n = recvmsg(socket, &hdr, 0);
if (n <= 0) {
return n;
@@ -73,14 +77,18 @@
}
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 @@
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_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 @@
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 @@
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 @@
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 1a63761..9087f76 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 log_event_write.c
else
@@ -25,28 +33,20 @@
# 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 @@
# ========================================================
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 $(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 @@
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 @@
} 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 @@
{
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 @@
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 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 @@
* 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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
/* 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 @@
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 @@
++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 @@
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 @@
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 @@
*/
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 @@
*/
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 @@
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 @@
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 @@
#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 @@
++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 @@
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 @@
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 6451abe..a9e9255 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 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 enum {
kLogUninitialized, kLogNotAvailable, kLogAvailable
} g_log_status = kLogUninitialized;
+
int __android_log_dev_available(void)
{
if (g_log_status == kLogUninitialized) {
@@ -83,15 +90,6 @@
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 @@
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 @@
}
} 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 (last_pid == (pid_t) -1) {
+ last_pid = getpid();
}
-
- if (logd_fd < 0) {
- return -EBADF;
- }
-
/*
* 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 @@
*/
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;
- 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.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);
+ }
+ }
+ }
+
+ 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 @@
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 @@
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
@@ -323,7 +363,7 @@
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
@@ -332,16 +372,21 @@
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
@@ -350,43 +395,7 @@
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)
@@ -414,6 +423,12 @@
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;
@@ -479,7 +494,7 @@
}
__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 0b97d85..abdbd03 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__))
@@ -154,9 +141,7 @@
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);
@@ -182,52 +167,14 @@
}
}
-#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)
@@ -255,6 +202,10 @@
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;
@@ -320,7 +271,7 @@
}
__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 @@
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 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 @@
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_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 @@
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 @@
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 @@
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 * 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 @@
* 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 @@
/*
* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 61e226e..fb95417 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -122,7 +122,7 @@
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)));
// Check that we can close and reopen the logger
log_time ts(CLOCK_MONOTONIC);
@@ -231,7 +231,7 @@
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;
@@ -451,7 +451,7 @@
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;
@@ -513,7 +513,7 @@
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;
@@ -560,12 +560,12 @@
// >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);
}
@@ -603,7 +603,7 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
// 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_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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
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 @@
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 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 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_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 @@
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_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 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 @@
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 @@
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_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 cfd2b370..d770302 100644
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -201,8 +201,8 @@
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 @@
#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 @@
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 @@
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 @@
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
similarity index 100%
rename from include/pixelflinger/format.h
rename to libpixelflinger/include/pixelflinger/format.h
diff --git a/include/pixelflinger/pixelflinger.h b/libpixelflinger/include/pixelflinger/pixelflinger.h
similarity index 100%
rename from include/pixelflinger/pixelflinger.h
rename to libpixelflinger/include/pixelflinger/pixelflinger.h
diff --git a/include/private/pixelflinger/ggl_context.h b/libpixelflinger/include/private/pixelflinger/ggl_context.h
similarity index 100%
rename from include/private/pixelflinger/ggl_context.h
rename to libpixelflinger/include/private/pixelflinger/ggl_context.h
diff --git a/include/private/pixelflinger/ggl_fixed.h b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
similarity index 99%
rename from include/private/pixelflinger/ggl_fixed.h
rename to 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 @@
);
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 @@
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 @@
#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 @@
#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 @@
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 @@
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 @@
{
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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_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 @@
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 @@
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 @@
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_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_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 @@
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 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 @@
}
}
- 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 @@
{
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_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 @@
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 @@
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 @@
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 @@
*
* @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 @@
*
* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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_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_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 @@
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 @@
}
/*
+ * 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 @@
* 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 @@
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 @@
if (parseNdUserOptMessage(nh))
return true;
+ } else if (nh->nlmsg_type == LOCAL_NFLOG_PACKET) {
+ if (parseNfPacketMessage(nh))
+ return true;
+
}
}
@@ -588,7 +636,8 @@
}
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 @@
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 @@
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 @@
Tokenizer.cpp \
Unicode.cpp \
VectorImpl.cpp \
- misc.cpp
+ misc.cpp \
host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) -Werror
@@ -53,13 +50,6 @@
endif
endif
-host_commonLdlibs :=
-
-ifeq ($(TARGET_OS),linux)
-host_commonLdlibs += -lrt -ldl
-endif
-
-
# For the host
# =====================================================
include $(CLEAR_VARS)
@@ -67,6 +57,9 @@
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 @@
endif
LOCAL_CFLAGS += -Werror
-LOCAL_C_INCLUDES += \
- bionic/libc \
- external/zlib
-
LOCAL_STATIC_LIBRARIES := \
libcutils
@@ -103,8 +92,6 @@
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_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_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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
}
// 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 @@
if (cc != 0)
ALOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno));
return cc;
-#else
- return -1;
-#endif // HAVE_MADVISE
}
+
+#else
+int FileMap::advise(MapAdvice /* advice */)
+{
+ return -1;
+}
+#endif
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 94b8231..75dfa29 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -431,7 +431,7 @@
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 @@
*/
#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 @@
} else {
set_sched_policy(0, SP_FOREGROUND);
}
-
+
if (name) {
androidSetThreadName(name);
free(name);
@@ -103,7 +100,7 @@
};
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 @@
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 @@
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 @@
}
// ----------------------------------------------------------------------------
-#elif defined(HAVE_WIN32_THREADS)
+#else // !defined(_WIN32)
// ----------------------------------------------------------------------------
/*
@@ -271,9 +268,7 @@
}
// ----------------------------------------------------------------------------
-#else
-#error "Threads not supported"
-#endif
+#endif // !defined(_WIN32)
// ----------------------------------------------------------------------------
@@ -306,21 +301,12 @@
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 @@
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 @@
* ===========================================================================
*/
-#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 @@
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 @@
* ===========================================================================
*/
-#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 @@
//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 @@
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 @@
// 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 @@
{
WinCondition* condState = (WinCondition*) mState;
HANDLE hMutex = (HANDLE) mutex.mState;
-
+
return ((WinCondition*)mState)->wait(condState, hMutex, NULL);
}
@@ -659,9 +643,7 @@
ReleaseMutex(condState->internalMutex);
}
-#else
-#error "condition variables not supported on this platform"
-#endif
+#endif // !defined(_WIN32)
// ----------------------------------------------------------------------------
@@ -704,7 +686,7 @@
mStatus = NO_ERROR;
mExitPending = false;
mThread = thread_id_t(-1);
-
+
// hold a strong reference on ourself
mHoldSelf = this;
@@ -718,7 +700,7 @@
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
}
-
+
if (res == false) {
mStatus = UNKNOWN_ERROR; // something happened!
mRunning = false;
@@ -727,7 +709,7 @@
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 @@
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 @@
return WOULD_BLOCK;
}
-
+
mExitPending = true;
while (mRunning == true) {
@@ -864,7 +846,7 @@
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() {
- if (mFileMap) {
- mFileMap->release();
- }
+ delete mFileMap;
if (mOwnBuffer) {
delete[] mBuffer;
}
@@ -74,7 +72,7 @@
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 f5e28d4..2b5293e 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -25,17 +25,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
@@ -48,8 +41,9 @@
// 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 @@
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 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 @@
-# Build the unit tests.
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
+#
+# 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.
-test_src_files := \
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libutils_tests
+
+LOCAL_SRC_FILES := \
BasicHashtable_test.cpp \
BlobCache_test.cpp \
BitSet_test.cpp \
@@ -11,24 +29,12 @@
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 @@
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 @@
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 @@
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 @@
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)
+
+source_files := zip_archive.cc
+
include $(CLEAR_VARS)
-
-source_files := \
- zip_archive.h \
- zip_archive.cc
-
-includes := external/zlib
-
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 @@
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
new file mode 100644
index 0000000..773380c
--- /dev/null
+++ b/libziparchive/testdata/declaredlength.zip
Binary files differ
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 @@
#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 @@
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 @@
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 @@
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 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 @@
* 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 @@
* 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 @@
*/
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 @@
* 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 @@
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 @@
* 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 @@
* 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 @@
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 @@
}
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 @@
* 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 @@
// 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 @@
}
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 @@
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 @@
// 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 @@
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 @@
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 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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
/* 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 @@
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 @@
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 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 @@
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 @@
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 @@
}
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 @@
'\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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 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 @@
}
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 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 @@
/* 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 @@
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);
}
- err = rename (file0, file1);
+ if (!file0 || !file1) {
+ perror("while rotating log files");
+ break;
+ }
+
+ err = rename(file0, file1);
if (err < 0 && errno != ENOENT) {
perror("while rotating log files");
@@ -101,11 +114,10 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
" -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 @@
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 @@
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 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 @@
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 @@
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 @@
*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 @@
}
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 @@
if (!setLogSize) {
fprintf(stderr, "ERROR: -G <num><multiplier>\n");
- exit(1);
+ return EXIT_FAILURE;
}
}
break;
@@ -449,101 +503,76 @@
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++;
+ 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("radio") == LOG_ID_RADIO) {
- dev->next = new log_device_t("radio", false, 'r');
- if (dev->next) {
- dev = 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;
}
- }
- 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;
- }
- }
- 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++;
- }
+ 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{ }
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 @@
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 @@
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 @@
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 @@
unsigned long mTail;
unsigned int mLogMask;
pid_t mPid;
- log_time mStart;
+ uint64_t mStart;
public:
FlushCommand(LogReader &mReader,
@@ -39,7 +39,7 @@
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 @@
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 @@
}
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 @@
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 @@
// 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);
+ event->header.tag = htole32(AUDITD_LOG_TAG);
+ event->type = EVENT_TYPE_STRING;
+ event->length = htole32(l);
+ memcpy(event->data, str, l);
- logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid, newstr,
- (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
- free(newstr);
+ rc = logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
+ reinterpret_cast<char *>(event),
+ (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+ free(event);
- notify = true;
+ if (rc >= 0) {
+ notify = true;
+ }
}
// log to main
@@ -188,7 +190,7 @@
}
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 @@
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 @@
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 @@
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 @@
}
}
-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 @@
// 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 @@
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 @@
}
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 @@
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 @@
}
}
+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 @@
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 @@
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 @@
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 @@
}
// 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 @@
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) {
- kick = true;
- if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) {
- break;
- }
- worst_sizes -= len;
- } else if (pruneRows == 0) {
+ if (pruneRows == 0) {
break;
}
+
+ if (e->getUid() == worst) {
+ kick = true;
+ if (worst_sizes < second_worst_sizes) {
+ 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 @@
}
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);
}
-
- it = mLogElements.erase(it);
- stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
- delete e;
- pruneRows--;
- } else {
- it++;
+ break;
}
+
+ 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;
- }
- it = mLogElements.erase(it);
- stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
- delete e;
- pruneRows--;
- } else {
- it++;
+
+ 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);
+ }
+ break;
+ }
+
+ it = erase(it);
+ pruneRows--;
}
}
@@ -436,28 +580,51 @@
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 @@
}
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 @@
pthread_mutex_t mLogElementsLock;
LogStatistics stats;
- bool dgramQlenStatistics;
PruneList mPrune;
@@ -47,13 +46,14 @@
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 @@
// *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 @@
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 @@
, 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 @@
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 @@
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 @@
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 @@
{ }
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 @@
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 @@
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 @@
}
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 @@
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 @@
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;
- }
- 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;
+LogStatistics::LogStatistics()
+ : enable(false) {
+ log_id_for_each(id) {
+ mSizes[id] = 0;
+ mElements[id] = 0;
+ mSizesTotal[id] = 0;
+ mElementsTotal[id] = 0;
}
}
-// 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) {
+namespace android {
+
+// 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 @@
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 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);
- } else {
- push_back(p);
- }
- 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;
- }
- }
- }
-}
-
-size_t UidStatistics::sizes(pid_t pid) {
- if (pid == pid_all) {
- return sizes();
- }
-
- PidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- PidStatistics *p = *it;
- if (pid == p->getPid()) {
- return p->sizes();
- }
- }
- return 0;
-}
-
-size_t UidStatistics::elements(pid_t pid) {
- if (pid == pid_all) {
- return elements();
- }
-
- PidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- PidStatistics *p = *it;
- if (pid == p->getPid()) {
- return p->elements();
- }
- }
- 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();
- }
- }
- 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();
- }
- }
- return elements;
-}
-
-LidStatistics::LidStatistics() {
- Uids.clear();
-}
-
-LidStatistics::~LidStatistics() {
- UidStatisticsCollection::iterator it;
- for (it = begin(); it != end();) {
- delete (*it);
- it = Uids.erase(it);
- }
-}
-
-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;
- }
-
- 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;
- }
- }
- 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;
- }
-
- UidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- UidStatistics *u = *it;
- if (uid == u->getUid()) {
- u->subtract(size, pid);
- return;
- }
- }
-}
-
-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;
- }
- }
- }
-}
-
-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);
- }
- }
- 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;
-}
-
-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;
-}
-
-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);
- }
- }
- 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];
-}
-
-unsigned long long LogStatistics::minimum(unsigned short bucket) {
- if (mMinimum[bucket].tv_sec == mMinimum[bucket].tv_sec_max) {
- return 0;
- }
- return mMinimum[bucket].nsec();
-}
-
-void LogStatistics::recordDiff(log_time diff, unsigned short bucket) {
- if ((diff.tv_sec || diff.tv_nsec) && (mMinimum[bucket] > diff)) {
- mMinimum[bucket] = diff;
- }
-}
-
-void LogStatistics::add(unsigned short size,
- log_id_t log_id, uid_t uid, pid_t pid) {
+void LogStatistics::add(LogBufferElement *e) {
+ log_id_t log_id = e->getLogId();
+ unsigned short size = e->getMsgLen();
mSizes[log_id] += size;
++mElements[log_id];
- if (!mStatistics) {
+
+ 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 {
+ UidEntry &entry = table.editEntryAt(index);
+ entry.add(size);
+ entry.add_dropped(dropped);
+ }
+
+ mSizesTotal[log_id] += size;
+ ++mElementsTotal[log_id];
+
+ if (!enable) {
return;
}
- id(log_id).add(size, uid, pid);
+
+ 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);
+ }
}
-void LogStatistics::subtract(unsigned short size,
- log_id_t log_id, uid_t uid, pid_t pid) {
+void LogStatistics::subtract(LogBufferElement *e) {
+ log_id_t log_id = e->getLogId();
+ unsigned short size = e->getMsgLen();
mSizes[log_id] -= size;
--mElements[log_id];
- if (!mStatistics) {
+
+ 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);
+ }
+ }
+
+ if (!enable) {
return;
}
- id(log_id).subtract(size, uid, pid);
+
+ 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);
+ }
+ }
}
-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);
+// 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;
+
+ 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);
}
- size_t sizes = 0;
- log_id_for_each(i) {
- sizes += id(i).sizes(uid, pid);
+
+ if (!enable) {
+ return;
}
- return sizes;
+
+ 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);
+ }
}
-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);
+// caller must own and free character string
+char *LogStatistics::uidToName(uid_t uid) {
+ // Local hard coded favourites
+ if (uid == AID_LOGD) {
+ return strdup("auditd");
}
- size_t elements = 0;
- log_id_for_each(i) {
- elements += id(i).elements(uid, pid);
+
+ // Android hard coded
+ const struct android_id_info *info = android_ids;
+
+ for (size_t i = 0; i < android_id_count; ++i) {
+ if (info->aid == uid) {
+ return strdup(info->name);
+ }
+ ++info;
}
- return elements;
+
+ // Parse /data/system/packages.list
+ char *name = android::uidToName(uid);
+ if (name) {
+ return name;
+ }
+
+ // report uid -> pid(s) -> pidToName if unique
+ ssize_t index = -1;
+ while ((index = pidTable.next(index)) != -1) {
+ const PidEntry &entry = pidTable.entryAt(index);
+
+ if (entry.getUid() == uid) {
+ const char *n = entry.getName();
+
+ if (n) {
+ if (!name) {
+ name = strdup(n);
+ } else if (strcmp(name, n)) {
+ free(name);
+ return NULL;
+ }
+ }
+ }
+ }
+
+ // No one
+ return name;
}
-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);
+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;
+
+ 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);
+
+ 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());
}
- 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);
- }
- 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 @@
*buf = NULL;
}
- android::String8 string(" span -> size/num");
- size_t oldLength;
- short spaces = 2;
+ // Report on total logging, current and for all time
- log_id_for_each(i) {
- if (!(logMask & (1 << i))) {
+ android::String8 output("size/num");
+ size_t oldLength;
+ short spaces = 1;
+
+ 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();
-
- LidStatistics &l = id(i);
- l.sort();
-
- UidStatisticsCollection::iterator iu;
- for (iu = l.begin(); iu != l.end(); ++iu) {
- (*iu)->sort();
- }
+ output.appendFormat("%*s%s", spaces, "", android_log_id_to_name(id));
+ spaces += spaces_total + oldLength - output.length();
}
- 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);
+ spaces = 4;
+ output.appendFormat("\nTotal");
- 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();
+ log_id_for_each(id) {
+ if (!(logMask & (1 << id))) {
+ continue;
}
- spaces = 1;
+ oldLength = output.length();
+ if (spaces < 0) {
+ spaces = 0;
+ }
+ 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;
- }
-
- 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 (q == pids.end()) {
- pids.push_back(p);
- }
- }
- }
-
- 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;
-
- size_t sizes = p->sizes();
- if (sizes < threshold) {
- 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;
}
- 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;
- }
- }
- }
-
- if (!header) {
- string.appendFormat("\n\nChattiest clients:\n"
- "log id %-*s PID[?] name",
- spaces_total, "size/total");
- header = 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 : "");
- }
-
- pids.clear();
- }
-
- 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;
- }
- 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));
+ 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 {
- string.appendFormat("%llun", duration);
+ name.appendFormat(
+ "Logging for your UID in %s log buffer:",
+ android_log_id_to_name(id));
}
- spaces -= string.length() - oldLength;
+ android::String8 size("Size");
+ android::String8 pruned("Pruned");
+ if (!worstUidEnabledForLogid(id)) {
+ pruned.setTo("");
+ }
+ format_line(output, name, size, pruned);
+
+ name.setTo("UID PACKAGE");
+ size.setTo("BYTES");
+ pruned.setTo("LINES");
+ if (!worstUidEnabledForLogid(id)) {
+ pruned.setTo("");
+ }
+ format_line(output, name, size, pruned);
+
+ headerPrinted = true;
}
- spaces += spaces_time;
+
+ 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);
+ }
+
+ android::String8 size("");
+ size.appendFormat("%zu", entry->getSizes());
+
+ android::String8 pruned("");
+ size_t dropped = entry->getDropped();
+ if (dropped) {
+ pruned.appendFormat("%zu", dropped);
+ }
+
+ format_line(output, name, size, pruned);
}
}
- log_id_for_each(i) {
- if (!(logMask & (1 << i))) {
- continue;
- }
-
- 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())) {
+ 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;
}
- PidStatisticsCollection::iterator pt = up->begin();
- if (pt == up->end()) {
- continue;
+ 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);
+
+ name.setTo(" PID/UID COMMAND LINE");
+ size.setTo("BYTES");
+ pruned.setTo("LINES");
+ format_line(output, name, size, pruned);
+
+ headerPrinted = true;
}
- 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;
+ 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);
+ }
}
- bool oneline = ++pt == up->end();
- --pt;
+ android::String8 size("");
+ size.appendFormat("%zu", entry->getSizes());
- if (!oneline) {
- first = true;
- } else if (!first && (spaces > 0)) {
- string.appendFormat("%*s", spaces, "");
- }
- 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;
- }
- string.appendFormat("%*s%zu/%zu", spaces, "", up->sizes(), els);
- spaces -= string.length() - oldLength;
- }
- spaces += spaces_current;
-
- first = !first;
-
- 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;
- }
-
- if (!first && (spaces > 0)) {
- string.appendFormat("%*s", spaces, "");
- }
- spaces = 0;
-
- 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;
-
- first = !first;
- }
-
- 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;
- }
+ format_line(output, name, size, pruned);
}
}
- *buf = strdup(string.string());
+ *buf = strdup(output.string());
+}
+
+namespace android {
+
+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
+}
+
}
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();
- }
+ 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();
+ }
+ return uid;
+}
+
+// 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;
+ std::unique_ptr<const TEntry *[]> sort(size_t n) {
+ if (!n) {
+ std::unique_ptr<const TEntry *[]> sorted(NULL);
+ return sorted;
+ }
- PidStatistics(pid_t pid, char *name = NULL);
- PidStatistics(const PidStatistics ©);
- ~PidStatistics();
+ const TEntry **retval = new const TEntry* [n];
+ memset(retval, 0, sizeof(*retval) * n);
- pid_t getPid() const { return pid; }
- bool pidGone();
- char *getName() const { return name; }
- void setName(char *name);
+ 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;
+ }
- 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);
+ // 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;
+ }
- 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);
+ 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;
+ UidEntry(uid_t uid):uid(uid),size(0),dropped(0) { }
- void insert(PidStatisticsCollection::iterator i, PidStatistics *p)
- { Pids.insert(i, p); }
- void push_back(PidStatistics *p) { Pids.push_back(p); }
+ inline const uid_t&getKey() const { return uid; }
+ size_t getSizes() const { return size; }
+ size_t getDropped() const { return dropped; }
- 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; }
-
- void add(unsigned short size, pid_t pid);
- void subtract(unsigned short size, pid_t pid);
- void sort();
-
- 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;
+struct PidEntry {
+ const pid_t pid;
+ uid_t uid;
+ char *name;
+ size_t size;
+ size_t dropped;
-class LidStatistics {
- UidStatisticsCollection Uids;
+ 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); }
-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);
+ 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 @@
, 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 @@
lock();
while (me->threadRunning && !me->isError_Locked()) {
- log_time start = me->mStart;
+ uint64_t start = me->mStart;
unlock();
@@ -148,6 +146,8 @@
break;
}
+ me->cleanSkip_Locked();
+
pthread_cond_wait(&me->threadTriggeredCondition, ×Lock);
}
@@ -159,17 +159,17 @@
}
// 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 @@
}
// 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 @@
}
if (me->isError_Locked()) {
- goto skip;
+ goto stop;
}
if (!me->mTail) {
@@ -223,7 +223,7 @@
}
ok:
- if (!me->skipAhead) {
+ if (!me->skipAhead[element->getLogId()]) {
LogTimeEntry::unlock();
return true;
}
@@ -232,4 +232,14 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
}
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 @@
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.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 @@
*/
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 @@
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 @@
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;
- int fdDmesg = -1;
- if (auditd && property_get_bool("logd.auditd.dmesg", true)) {
- fdDmesg = open("/dev/kmsg", O_WRONLY);
+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;
+ }
+
+ 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 @@
// LogBuffer is the object which is responsible for holding all
// log entries.
- LogBuffer *logBuf = new LogBuffer(times);
+ logBuf = new LogBuffer(times);
- if (property_get_bool("logd.statistics.dgram_qlen", false)) {
- logBuf->enableDgramQlenStatistics();
- }
+ signal(SIGHUP, reinit_signal_handler);
+
{
char property[PROPERTY_VALUE_MAX];
property_get("ro.build.type", property, "");
@@ -192,16 +352,36 @@
// 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 @@
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 @@
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 @@
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 34b10d2..c00c590 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -14,13 +14,6 @@
# 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 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 @@
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 @@
# 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 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 @@
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
@@ -311,12 +301,24 @@
# 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.
@@ -437,6 +439,8 @@
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
@@ -445,6 +449,7 @@
class_start main
on property:vold.decrypt=trigger_restart_framework
+ installkey /data
class_start main
class_start late_start
@@ -478,7 +483,10 @@
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
@@ -592,7 +600,6 @@
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 @@
# 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 @@
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 @@
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_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 613dcbb..dd84584 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 @@
* 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 @@
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 @@
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 @@
* 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 @@
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 @@
{
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 @@
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 @@
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 @@
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 @@
return -errno;
}
out.size = res;
+ out.padding = 0;
fuse_reply(fuse, hdr->unique, &out, sizeof(out));
return NO_STATUS;
}
@@ -1460,17 +1482,42 @@
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 @@
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 @@
"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 @@
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):
$(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
-ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS)
+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 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 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)
+
+
+# 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 @@
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 (!strcmp(argv[optind], "-")) {
+ if (optind + 2 > argc) {
+ usage();
+ }
+
+ 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 @@
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 @@
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 @@
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 @@
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;
-#include <pwd.h>
-#include <grp.h>
+#define STRLIST_INITIALIZER { 0, 0, NULL }
-#include <linux/kdev_t.h>
-#include <limits.h>
+/* 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)
-#include "dynarray.h"
+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();
+
+ a->items = new_items;
+ a->capacity = new_cap;
+}
+
+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);
+ }
+}
+
// bits for flags argument
#define LIST_LONG (1 << 0)
@@ -200,7 +296,7 @@
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 655806d..da78ddd 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 @@
__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 @@
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 <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
-#include <ctype.h>
-#include <fcntl.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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
{ 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 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 @@
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 @@
}
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;
+}