Merge "ADB on linux: Handle USB SuperSpeed extra Descriptors"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 0254bd2..e78fc88 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -53,3 +53,4 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/reboot)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/default.prop)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/default.prop)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/lmkd_intermediates/import_includes)
diff --git a/adb/Android.mk b/adb/Android.mk
index 50e28a6..7136afb 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -24,6 +24,7 @@
USB_SRCS := usb_osx.c
EXTRA_SRCS := get_my_path_darwin.c
LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
+ LOCAL_CFLAGS += -Wno-sizeof-pointer-memaccess -Wno-unused-parameter
endif
ifeq ($(HOST_OS),freebsd)
@@ -39,13 +40,11 @@
ifneq ($(strip $(USE_CYGWIN)),)
# Pure cygwin case
LOCAL_LDLIBS += -lpthread -lgdi32
- LOCAL_C_INCLUDES += /usr/include/w32api/ddk
endif
ifneq ($(strip $(USE_MINGW)),)
# MinGW under Linux case
LOCAL_LDLIBS += -lws2_32 -lgdi32
USE_SYSDEPS_WIN32 := 1
- LOCAL_C_INCLUDES += /usr/i586-mingw32msvc/include/ddk
endif
LOCAL_C_INCLUDES += development/host/windows/usb/api/
endif
@@ -64,9 +63,6 @@
file_sync_client.c \
$(EXTRA_SRCS) \
$(USB_SRCS) \
- usb_vendors.c
-
-LOCAL_C_INCLUDES += external/openssl/include
ifneq ($(USE_SYSDEPS_WIN32),)
LOCAL_SRC_FILES += sysdeps_win32.c
@@ -79,11 +75,12 @@
LOCAL_MODULE := adb
LOCAL_MODULE_TAGS := debug
-LOCAL_STATIC_LIBRARIES := libzipfile libunz libcrypto_static $(EXTRA_STATIC_LIBS)
+LOCAL_STATIC_LIBRARIES := libzipfile libz libcrypto_static $(EXTRA_STATIC_LIBS)
ifeq ($(USE_SYSDEPS_WIN32),)
LOCAL_STATIC_LIBRARIES += libcutils
endif
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_HOST_EXECUTABLE)
$(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
@@ -102,7 +99,6 @@
LOCAL_SRC_FILES := \
adb.c \
- backup_service.c \
fdevent.c \
transport.c \
transport_local.c \
@@ -116,8 +112,13 @@
remount_service.c \
usb_linux_client.c
-LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter -Werror
-LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
+LOCAL_CFLAGS := \
+ -O2 \
+ -g \
+ -DADB_HOST=0 \
+ -D_XOPEN_SOURCE \
+ -D_GNU_SOURCE \
+ -Wall -Wno-unused-parameter -Werror -Wno-deprecated-declarations \
ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1
@@ -130,6 +131,7 @@
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
LOCAL_STATIC_LIBRARIES := liblog libcutils libc libmincrypt libselinux
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_EXECUTABLE)
@@ -152,7 +154,6 @@
file_sync_client.c \
get_my_path_linux.c \
usb_linux.c \
- usb_vendors.c \
fdevent.c
LOCAL_CFLAGS := \
@@ -164,13 +165,12 @@
-D_XOPEN_SOURCE \
-D_GNU_SOURCE
-LOCAL_C_INCLUDES += external/openssl/include
-
LOCAL_MODULE := adb
-LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils
+LOCAL_STATIC_LIBRARIES := libzipfile libz libcutils liblog
LOCAL_SHARED_LIBRARIES := libcrypto
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_EXECUTABLE)
endif
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT
index 7f85dc3..63000f2 100644
--- a/adb/SERVICES.TXT
+++ b/adb/SERVICES.TXT
@@ -240,3 +240,20 @@
This starts the file synchronisation service, used to implement "adb push"
and "adb pull". Since this service is pretty complex, it will be detailed
in a companion document named SYNC.TXT
+
+reverse:<forward-command>
+ This implements the 'adb reverse' feature, i.e. the ability to reverse
+ socket connections from a device to the host. <forward-command> is one
+ of the forwarding commands that are described above, as in:
+
+ list-forward
+ forward:<local>;<remote>
+ forward:norebind:<local>;<remote>
+ killforward-all
+ killforward:<local>
+
+ Note that in this case, <local> corresponds to the socket on the device
+ and <remote> corresponds to the socket on the host.
+
+ The output of reverse:list-forward is the same as host:list-forward
+ except that <serial> will be just 'host'.
diff --git a/adb/adb.c b/adb/adb.c
index 0e41b34..1834472 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -37,12 +37,10 @@
#include <cutils/properties.h>
#include <private/android_filesystem_config.h>
#include <sys/capability.h>
-#include <linux/prctl.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
@@ -318,7 +316,19 @@
#endif
}
-static void send_msg_with_okay(int fd, char* msg, size_t msglen) {
+#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
+
+#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;
@@ -326,6 +336,7 @@
writex(fd, header, 8);
writex(fd, msg, msglen);
}
+#endif // ADB_HOST
static void send_connect(atransport *t)
{
@@ -403,6 +414,7 @@
send_connect(t);
}
+#if ADB_HOST
static char *connection_state_name(atransport *t)
{
if (t == NULL) {
@@ -426,6 +438,7 @@
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
@@ -932,7 +945,7 @@
return INSTALL_STATUS_INTERNAL_ERROR;
}
-#ifdef HAVE_WIN32_PROC
+#if defined(_WIN32)
static BOOL WINAPI ctrlc_handler(DWORD type)
{
exit(STATUS_CONTROL_C_EXIT);
@@ -947,7 +960,7 @@
void start_logging(void)
{
-#ifdef HAVE_WIN32_PROC
+#if defined(_WIN32)
char temp[ MAX_PATH ];
FILE* fnul;
FILE* flog;
@@ -1055,7 +1068,7 @@
int launch_server(int server_port)
{
-#ifdef HAVE_WIN32_PROC
+#if defined(_WIN32)
/* we need to start the server in the background */
/* we create a PIPE that will be used to wait for the server's "OK" */
/* message since the pipe handles must be inheritable, we use a */
@@ -1154,7 +1167,7 @@
return -1;
}
}
-#elif defined(HAVE_FORKEXEC)
+#else /* !defined(_WIN32) */
char path[PATH_MAX];
int fd[2];
@@ -1205,12 +1218,10 @@
setsid();
}
-#else
-#error "cannot implement background server start on this platform"
-#endif
+#endif /* !defined(_WIN32) */
return 0;
}
-#endif
+#endif /* ADB_HOST */
/* Constructs a local name of form tcp:port.
* target_str points to the target string, it's content will be overwritten.
@@ -1292,9 +1303,9 @@
#endif
atexit(adb_cleanup);
-#ifdef HAVE_WIN32_PROC
+#if defined(_WIN32)
SetConsoleCtrlHandler( ctrlc_handler, TRUE );
-#elif defined(HAVE_FORKEXEC)
+#else
// No SIGCHLD. Let the service subproc handle its children.
signal(SIGPIPE, SIG_IGN);
#endif
@@ -1307,7 +1318,6 @@
#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();
@@ -1333,30 +1343,28 @@
" 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_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();
- /* 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_MOUNT to allow unmounting the SD card before rebooting
- ** 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_MOUNT, AID_NET_BW_STATS };
- if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
- exit(1);
- }
-
/* then switch user and group to "shell" */
if (setgid(AID_SHELL) != 0) {
exit(1);
@@ -1411,10 +1419,10 @@
if (is_daemon)
{
// inform our parent that we are up and running.
-#ifdef HAVE_WIN32_PROC
+#if defined(_WIN32)
DWORD count;
WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL );
-#elif defined(HAVE_FORKEXEC)
+#else
fprintf(stderr, "OK\n");
#endif
start_logging();
@@ -1428,10 +1436,122 @@
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);
@@ -1441,6 +1561,7 @@
}
#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
@@ -1546,99 +1667,6 @@
/* we don't even need to send a reply */
return 0;
}
-#endif // ADB_HOST
-
- 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);
- (void) format_listeners(buffer, buffer_size+1);
- send_msg_with_okay(reply_fd, buffer, buffer_size);
- free(buffer);
- return 0;
- }
-
- if (!strcmp(service,"killforward-all")) {
- remove_all_listeners();
- adb_write(reply_fd, "OKAYOKAY", 8);
- return 0;
- }
-
- 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 0;
- }
-
- *remote++ = 0;
- if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
- sendfailmsg(reply_fd, "malformed forward spec");
- return 0;
- }
- } else {
- // Check killforward: parameter format: '<local>'
- if (local[0] == 0) {
- sendfailmsg(reply_fd, "malformed forward spec");
- return 0;
- }
- }
-
- transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
- if (!transport) {
- sendfailmsg(reply_fd, err);
- return 0;
- }
-
- if (createForward) {
- r = install_listener(local, remote, transport, no_rebind);
- } else {
- r = remove_listener(local, transport);
- }
- if(r == 0) {
- /* 1st OKAY is connect, 2nd OKAY is status */
- writex(reply_fd, "OKAYOKAY", 8);
- return 0;
- }
-
- 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 0;
- }
if(!strncmp(service,"get-state",strlen("get-state"))) {
transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
@@ -1646,6 +1674,11 @@
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 6f5c93c..6f5f997 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -19,6 +19,7 @@
#include <limits.h>
+#include "adb_trace.h"
#include "transport.h" /* readx(), writex() */
#define MAX_PAYLOAD 4096
@@ -36,7 +37,7 @@
#define ADB_VERSION_MAJOR 1 // Used for help/version information
#define ADB_VERSION_MINOR 0 // Used for help/version information
-#define ADB_SERVER_VERSION 31 // Increment this when we want to force users to start a new adb server
+#define ADB_SERVER_VERSION 32 // Increment this when we want to force users to start a new adb server
typedef struct amessage amessage;
typedef struct apacket apacket;
@@ -323,12 +324,9 @@
int create_jdwp_connection_fd(int jdwp_pid);
#endif
+int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd);
+
#if !ADB_HOST
-typedef enum {
- BACKUP,
- RESTORE
-} BackupOperation;
-int backup_service(BackupOperation operation, char* args);
void framebuffer_service(int fd, void *cookie);
void remount_service(int fd, void *cookie);
#endif
@@ -340,85 +338,6 @@
int check_header(apacket *p);
int check_data(apacket *p);
-/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
-
-#define ADB_TRACE 1
-
-/* IMPORTANT: if you change the following list, don't
- * forget to update the corresponding 'tags' table in
- * the adb_trace_init() function implemented in adb.c
- */
-typedef enum {
- TRACE_ADB = 0, /* 0x001 */
- TRACE_SOCKETS,
- TRACE_PACKETS,
- TRACE_TRANSPORT,
- TRACE_RWX, /* 0x010 */
- TRACE_USB,
- TRACE_SYNC,
- TRACE_SYSDEPS,
- TRACE_JDWP, /* 0x100 */
- TRACE_SERVICES,
- TRACE_AUTH,
-} AdbTrace;
-
-#if ADB_TRACE
-
-#if !ADB_HOST
-/*
- * When running inside the emulator, guest's adbd can connect to 'adb-debug'
- * qemud service that can display adb trace messages (on condition that emulator
- * has been started with '-debug adb' option).
- */
-
-/* Delivers a trace message to the emulator via QEMU pipe. */
-void adb_qemu_trace(const char* fmt, ...);
-/* Macro to use to send ADB trace messages to the emulator. */
-#define DQ(...) adb_qemu_trace(__VA_ARGS__)
-#else
-#define DQ(...) ((void)0)
-#endif /* !ADB_HOST */
-
- extern int adb_trace_mask;
- extern unsigned char adb_trace_output_count;
- void adb_trace_init(void);
-
-# define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
-
- /* you must define TRACE_TAG before using this macro */
-# define D(...) \
- do { \
- if (ADB_TRACING) { \
- 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; \
- } \
- } while (0)
-# define DR(...) \
- do { \
- if (ADB_TRACING) { \
- int save_errno = errno; \
- adb_mutex_lock(&D_lock); \
- errno = save_errno; \
- fprintf(stderr, __VA_ARGS__ ); \
- fflush(stderr); \
- adb_mutex_unlock(&D_lock); \
- errno = save_errno; \
- } \
- } while (0)
-#else
-# define D(...) ((void)0)
-# define DR(...) ((void)0)
-# define ADB_TRACING 0
-#endif
-
-
#if !DEBUG_PACKETS
#define print_packet(tag,p) do {} while (0)
#endif
@@ -456,7 +375,6 @@
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 connection_state(atransport *t);
@@ -474,6 +392,11 @@
extern int HOST;
extern int SHELL_EXIT_NOTIFY_FD;
+typedef enum {
+ SUBPROC_PTY = 0,
+ SUBPROC_RAW = 1,
+} subproc_mode;
+
#define CHUNK_SIZE (64*1024)
#if !ADB_HOST
diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.c
index f8d7306..55e9dca 100644
--- a/adb/adb_auth_client.c
+++ b/adb/adb_auth_client.c
@@ -57,7 +57,7 @@
char *sep;
int ret;
- f = fopen(file, "r");
+ f = fopen(file, "re");
if (!f) {
D("Can't open '%s'\n", file);
return;
@@ -126,7 +126,7 @@
FILE *f;
int ret;
- f = fopen("/dev/urandom", "r");
+ f = fopen("/dev/urandom", "re");
if (!f)
return 0;
@@ -175,7 +175,7 @@
if (events & FDE_READ) {
ret = unix_read(fd, response, sizeof(response));
- if (ret < 0) {
+ if (ret <= 0) {
D("Framework disconnect\n");
if (usb_transport)
fdevent_remove(&usb_transport->auth_fde);
@@ -257,6 +257,7 @@
D("Failed to get adbd socket\n");
return;
}
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
ret = listen(fd, 4);
if (ret < 0) {
diff --git a/adb/adb_auth_host.c b/adb/adb_auth_host.c
index 783774a..c72fe42 100644
--- a/adb/adb_auth_host.c
+++ b/adb/adb_auth_host.c
@@ -45,6 +45,10 @@
#include <openssl/rsa.h>
#include <openssl/sha.h>
+#if defined(OPENSSL_IS_BORINGSSL)
+#include <openssl/base64.h>
+#endif
+
#define TRACE_TAG TRACE_AUTH
#define ANDROID_PATH ".android"
@@ -132,43 +136,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 = NULL;
+ 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 = malloc(encoded_length);
+ if (encoded == NULL) {
+ 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)
diff --git a/adb/adb_client.c b/adb/adb_client.c
index 1e47486..eb1720d 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -279,7 +279,7 @@
fd = _adb_connect(service);
if(fd == -1) {
- fprintf(stderr,"error: %s\n", __adb_error);
+ D("_adb_connect error: %s\n", __adb_error);
} else if(fd == -2) {
fprintf(stderr,"** daemon still not running\n");
}
@@ -296,6 +296,7 @@
{
int fd = adb_connect(service);
if(fd < 0) {
+ fprintf(stderr, "error: %s\n", adb_error());
return -1;
}
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
new file mode 100644
index 0000000..8a5d9f8
--- /dev/null
+++ b/adb/adb_trace.h
@@ -0,0 +1,143 @@
+/*
+ * 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 __ADB_TRACE_H
+#define __ADB_TRACE_H
+
+#if !ADB_HOST
+#include <android/log.h>
+#endif
+
+/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
+#define ADB_TRACE 1
+
+/* IMPORTANT: if you change the following list, don't
+ * forget to update the corresponding 'tags' table in
+ * the adb_trace_init() function implemented in adb.c
+ */
+typedef enum {
+ TRACE_ADB = 0, /* 0x001 */
+ TRACE_SOCKETS,
+ TRACE_PACKETS,
+ TRACE_TRANSPORT,
+ TRACE_RWX, /* 0x010 */
+ TRACE_USB,
+ TRACE_SYNC,
+ TRACE_SYSDEPS,
+ TRACE_JDWP, /* 0x100 */
+ TRACE_SERVICES,
+ TRACE_AUTH,
+ TRACE_FDEVENT,
+} AdbTrace;
+
+#if ADB_TRACE
+
+#if !ADB_HOST
+/*
+ * When running inside the emulator, guest's adbd can connect to 'adb-debug'
+ * qemud service that can display adb trace messages (on condition that emulator
+ * has been started with '-debug adb' option).
+ */
+
+/* Delivers a trace message to the emulator via QEMU pipe. */
+void adb_qemu_trace(const char* fmt, ...);
+/* Macro to use to send ADB trace messages to the emulator. */
+#define DQ(...) adb_qemu_trace(__VA_ARGS__)
+#else
+#define DQ(...) ((void)0)
+#endif /* !ADB_HOST */
+
+extern int adb_trace_mask;
+extern unsigned char adb_trace_output_count;
+void adb_trace_init(void);
+
+# define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
+
+/* you must define TRACE_TAG before using this macro */
+#if ADB_HOST
+# define D(...) \
+ do { \
+ if (ADB_TRACING) { \
+ 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; \
+ } \
+ } while (0)
+# define DR(...) \
+ do { \
+ if (ADB_TRACING) { \
+ int save_errno = errno; \
+ adb_mutex_lock(&D_lock); \
+ errno = save_errno; \
+ fprintf(stderr, __VA_ARGS__ ); \
+ fflush(stderr); \
+ adb_mutex_unlock(&D_lock); \
+ errno = save_errno; \
+ } \
+ } 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; \
+ } while (0)
+#else
+# define D(...) \
+ do { \
+ if (ADB_TRACING) { \
+ __android_log_print( \
+ ANDROID_LOG_INFO, \
+ __FUNCTION__, \
+ __VA_ARGS__ ); \
+ } \
+ } while (0)
+# define DR(...) \
+ do { \
+ if (ADB_TRACING) { \
+ __android_log_print( \
+ ANDROID_LOG_INFO, \
+ __FUNCTION__, \
+ __VA_ARGS__ ); \
+ } \
+ } while (0)
+# define DD(...) \
+ do { \
+ __android_log_print( \
+ ANDROID_LOG_INFO, \
+ __FUNCTION__, \
+ __VA_ARGS__ ); \
+ } while (0)
+#endif /* ADB_HOST */
+#else
+# define D(...) ((void)0)
+# define DR(...) ((void)0)
+# define DD(...) ((void)0)
+# define ADB_TRACING 0
+#endif /* ADB_TRACE */
+
+#endif /* __ADB_TRACE_H */
diff --git a/adb/backup_service.c b/adb/backup_service.c
deleted file mode 100644
index 654e0f3..0000000
--- a/adb/backup_service.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * 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 <unistd.h>
-#include <stdio.h>
-
-#include "sysdeps.h"
-
-#define TRACE_TAG TRACE_ADB
-#include "adb.h"
-
-typedef struct {
- pid_t pid;
- int fd;
-} backup_harvest_params;
-
-// socketpair but do *not* mark as close_on_exec
-static int backup_socketpair(int sv[2]) {
- int rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv );
- if (rc < 0)
- return -1;
-
- return 0;
-}
-
-// harvest the child process then close the read end of the socketpair
-static void* backup_child_waiter(void* args) {
- int status;
- backup_harvest_params* params = (backup_harvest_params*) args;
-
- waitpid(params->pid, &status, 0);
- adb_close(params->fd);
- free(params);
- return NULL;
-}
-
-/* returns the data socket passing the backup data here for forwarding */
-int backup_service(BackupOperation op, char* args) {
- pid_t pid;
- int s[2];
- char* operation;
-
- // Command string depends on our invocation
- if (op == BACKUP) {
- operation = "backup";
- } else {
- operation = "restore";
- }
-
- D("backup_service(%s, %s)\n", operation, args);
-
- // set up the pipe from the subprocess to here
- // parent will read s[0]; child will write s[1]
- if (backup_socketpair(s)) {
- D("can't create backup/restore socketpair\n");
- fprintf(stderr, "unable to create backup/restore socketpair\n");
- return -1;
- }
-
- D("Backup/restore socket pair: (send=%d, receive=%d)\n", s[1], s[0]);
- close_on_exec(s[0]); // only the side we hold on to
-
- // spin off the child process to run the backup command
- pid = fork();
- if (pid < 0) {
- // failure
- D("can't fork for %s\n", operation);
- fprintf(stderr, "unable to fork for %s\n", operation);
- adb_close(s[0]);
- adb_close(s[1]);
- return -1;
- }
-
- // Great, we're off and running.
- if (pid == 0) {
- // child -- actually run the backup here
- char* p;
- int argc;
- char portnum[16];
- char** bu_args;
-
- // fixed args: [0] is 'bu', [1] is the port number, [2] is the 'operation' string
- argc = 3;
- for (p = (char*)args; p && *p; ) {
- argc++;
- while (*p && *p != ':') p++;
- if (*p == ':') p++;
- }
-
- bu_args = (char**) alloca(argc*sizeof(char*) + 1);
-
- // run through again to build the argv array
- argc = 0;
- bu_args[argc++] = "bu";
- snprintf(portnum, sizeof(portnum), "%d", s[1]);
- bu_args[argc++] = portnum;
- bu_args[argc++] = operation;
- for (p = (char*)args; p && *p; ) {
- bu_args[argc++] = p;
- while (*p && *p != ':') p++;
- if (*p == ':') {
- *p = 0;
- p++;
- }
- }
- bu_args[argc] = NULL;
-
- // Close the half of the socket that we don't care about, route 'bu's console
- // to the output socket, and off we go
- adb_close(s[0]);
-
- // off we go
- execvp("/system/bin/bu", (char * const *)bu_args);
- // oops error - close up shop and go home
- fprintf(stderr, "Unable to exec 'bu', bailing\n");
- exit(-1);
- } else {
- adb_thread_t t;
- backup_harvest_params* params;
-
- // parent, i.e. adbd -- close the sending half of the socket
- D("fork() returned pid %d\n", pid);
- adb_close(s[1]);
-
- // spin a thread to harvest the child process
- params = (backup_harvest_params*) malloc(sizeof(backup_harvest_params));
- params->pid = pid;
- params->fd = s[0];
- if (adb_thread_create(&t, backup_child_waiter, params)) {
- adb_close(s[0]);
- free(params);
- D("Unable to create child harvester\n");
- return -1;
- }
- }
-
- // we'll be reading from s[0] as the data is sent by the child process
- return s[0];
-}
diff --git a/adb/commandline.c b/adb/commandline.c
index 241cefc..23e9ea4 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -15,6 +15,7 @@
*/
#include <stdio.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
@@ -28,7 +29,7 @@
#include "sysdeps.h"
-#ifdef HAVE_TERMIO_H
+#if !defined(_WIN32)
#include <termios.h>
#endif
@@ -41,8 +42,9 @@
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 **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 const char *gProductOutPath = NULL;
@@ -110,9 +112,10 @@
" adb push [-p] <local> <remote>\n"
" - copy file/dir to device\n"
" ('-p' to display the transfer progress)\n"
- " adb pull [-p] <remote> [<local>]\n"
+ " adb pull [-p] [-a] <remote> [<local>]\n"
" - copy file/dir from device\n"
" ('-p' to display the transfer progress)\n"
+ " ('-a' means copy timestamp and mode)\n"
" adb sync [ <directory> ] - copy host->device only if changed\n"
" (-l means list but don't copy)\n"
" (see 'adb help all')\n"
@@ -136,13 +139,29 @@
" if <local> is already forwarded\n"
" adb forward --remove <local> - remove a specific forward socket connection\n"
" adb forward --remove-all - remove all forward socket connections\n"
+ " adb reverse --list - list all reverse socket connections from device\n"
+ " adb reverse <remote> <local> - reverse socket connections\n"
+ " reverse specs are one of:\n"
+ " tcp:<port>\n"
+ " localabstract:<unix domain socket name>\n"
+ " localreserved:<unix domain socket name>\n"
+ " localfilesystem:<unix domain socket name>\n"
+ " adb reverse --norebind <remote> <local>\n"
+ " - same as 'adb reverse <remote> <local>' but fails\n"
+ " if <remote> is already reversed.\n"
+ " adb reverse --remove <remote>\n"
+ " - remove a specific reversed socket connection\n"
+ " adb reverse --remove-all - remove all reversed socket connections from device\n"
" adb jdwp - list PIDs of processes hosting a JDWP transport\n"
- " adb install [-l] [-r] [-s] [--algo <algorithm name> --key <hex-encoded key> --iv <hex-encoded iv>] <file>\n"
+ " adb install [-lrtsd] <file>\n"
+ " adb install-multiple [-lrtsdp] <file...>\n"
" - push this package file to the device and install it\n"
- " ('-l' means forward-lock the app)\n"
- " ('-r' means reinstall the app, keeping its data)\n"
- " ('-s' means install on SD card instead of internal storage)\n"
- " ('--algo', '--key', and '--iv' mean the file is encrypted already)\n"
+ " (-l: forward lock application)\n"
+ " (-r: replace existing application)\n"
+ " (-t: allow test packages)\n"
+ " (-s: install application on sdcard)\n"
+ " (-d: allow version code downgrade)\n"
+ " (-p: partial application install)\n"
" adb uninstall [-k] <package> - remove this app package from the device\n"
" ('-k' means keep the data and cache directories)\n"
" adb bugreport - return all information from the device\n"
@@ -181,7 +200,7 @@
" 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 partition on the device read-write\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 reboot-bootloader - reboots the device into the bootloader\n"
" adb root - restarts the adbd daemon with root permissions\n"
@@ -197,9 +216,9 @@
"adb sync notes: adb sync [ <directory> ]\n"
" <localdir> can be interpreted in several ways:\n"
"\n"
- " - If <directory> is not specified, both /system and /data partitions will be updated.\n"
+ " - If <directory> is not specified, /system, /vendor (if present), and /data partitions will be updated.\n"
"\n"
- " - If it is \"system\" or \"data\", only the corresponding partition\n"
+ " - If it is \"system\", \"vendor\" or \"data\", only the corresponding partition\n"
" is updated.\n"
"\n"
"environmental variables:\n"
@@ -216,7 +235,18 @@
return 1;
}
-#ifdef HAVE_TERMIO_H
+#if defined(_WIN32)
+
+// Windows does not have <termio.h>.
+static void stdin_raw_init(int fd) {
+
+}
+
+static void stdin_raw_restore(int fd) {
+
+}
+
+#else
static struct termios tio_save;
static void stdin_raw_init(int fd)
@@ -265,6 +295,24 @@
}
}
+static void read_status_line(int fd, char* buf, size_t count)
+{
+ count--;
+ while (count > 0) {
+ int len = adb_read(fd, buf, count);
+ if (len == 0) {
+ break;
+ } else if (len < 0) {
+ if (errno == EINTR) continue;
+ break;
+ }
+
+ buf += len;
+ count -= len;
+ }
+ *buf = '\0';
+}
+
static void copy_to_file(int inFd, int outFd) {
const size_t BUFSIZE = 32 * 1024;
char* buf = (char*) malloc(BUFSIZE);
@@ -272,8 +320,17 @@
long total = 0;
D("copy_to_file(%d -> %d)\n", inFd, outFd);
+
+ if (inFd == STDIN_FILENO) {
+ stdin_raw_init(STDIN_FILENO);
+ }
+
for (;;) {
- len = adb_read(inFd, buf, BUFSIZE);
+ if (inFd == STDIN_FILENO) {
+ len = unix_read(inFd, buf, BUFSIZE);
+ } else {
+ len = adb_read(inFd, buf, BUFSIZE);
+ }
if (len == 0) {
D("copy_to_file() : read 0 bytes; exiting\n");
break;
@@ -286,9 +343,19 @@
D("copy_to_file() : error %d\n", errno);
break;
}
- adb_write(outFd, buf, len);
+ if (outFd == STDOUT_FILENO) {
+ fwrite(buf, 1, len, stdout);
+ fflush(stdout);
+ } else {
+ adb_write(outFd, buf, len);
+ }
total += len;
}
+
+ if (inFd == STDIN_FILENO) {
+ stdin_raw_restore(STDIN_FILENO);
+ }
+
D("copy_to_file() finished after %lu bytes\n", total);
free(buf);
}
@@ -329,9 +396,7 @@
case '.':
if(state == 2) {
fprintf(stderr,"\n* disconnect *\n");
-#ifdef HAVE_TERMIO_H
stdin_raw_restore(fdi);
-#endif
exit(0);
}
default:
@@ -363,14 +428,10 @@
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;
}
@@ -467,6 +528,115 @@
return status;
}
+#define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE)
+
+/*
+ * The sideload-host protocol serves the data in a file (given on the
+ * command line) to the client, using a simple protocol:
+ *
+ * - The connect message includes the total number of bytes in the
+ * file and a block size chosen by us.
+ *
+ * - The other side sends the desired block number as eight decimal
+ * digits (eg "00000023" for block 23). Blocks are numbered from
+ * zero.
+ *
+ * - We send back the data of the requested block. The last block is
+ * likely to be partial; when the last block is requested we only
+ * send the part of the block that exists, it's not padded up to the
+ * block size.
+ *
+ * - When the other side sends "DONEDONE" instead of a block number,
+ * we hang up.
+ */
+int adb_sideload_host(const char* fn) {
+ uint8_t* data;
+ unsigned sz;
+ size_t xfer = 0;
+ int status;
+
+ printf("loading: '%s'", fn);
+ fflush(stdout);
+ data = load_file(fn, &sz);
+ if (data == 0) {
+ printf("\n");
+ fprintf(stderr, "* cannot read '%s' *\n", fn);
+ return -1;
+ }
+
+ char buf[100];
+ sprintf(buf, "sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
+ int fd = adb_connect(buf);
+ if (fd < 0) {
+ // Try falling back to the older sideload method. Maybe this
+ // is an older device that doesn't support sideload-host.
+ printf("\n");
+ status = adb_download_buffer("sideload", fn, data, sz, 1);
+ goto done;
+ }
+
+ int opt = SIDELOAD_HOST_BLOCK_SIZE;
+ opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
+
+ int last_percent = -1;
+ for (;;) {
+ if (readx(fd, buf, 8)) {
+ fprintf(stderr, "* failed to read command: %s\n", adb_error());
+ status = -1;
+ goto done;
+ }
+
+ if (strncmp("DONEDONE", buf, 8) == 0) {
+ status = 0;
+ break;
+ }
+
+ buf[8] = '\0';
+ int block = strtol(buf, NULL, 10);
+
+ size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
+ if (offset >= sz) {
+ fprintf(stderr, "* attempt to read past end: %s\n", adb_error());
+ status = -1;
+ goto done;
+ }
+ uint8_t* start = data + offset;
+ size_t offset_end = offset + SIDELOAD_HOST_BLOCK_SIZE;
+ size_t to_write = SIDELOAD_HOST_BLOCK_SIZE;
+ if (offset_end > sz) {
+ to_write = sz - offset;
+ }
+
+ if(writex(fd, start, to_write)) {
+ adb_status(fd);
+ fprintf(stderr,"* failed to write data '%s' *\n", adb_error());
+ status = -1;
+ goto done;
+ }
+ xfer += to_write;
+
+ // For normal OTA packages, we expect to transfer every byte
+ // twice, plus a bit of overhead (one read during
+ // verification, one read of each byte for installation, plus
+ // extra access to things like the zip central directory).
+ // This estimate of the completion becomes 100% when we've
+ // transferred ~2.13 (=100/47) times the package size.
+ int percent = (int)(xfer * 47LL / (sz ? sz : 1));
+ if (percent != last_percent) {
+ printf("\rserving: '%s' (~%d%%) ", fn, percent);
+ fflush(stdout);
+ last_percent = percent;
+ }
+ }
+
+ printf("\rTotal xfer: %.2fx%*s\n", (double)xfer / (sz ? sz : 1), (int)strlen(fn)+10, "");
+
+ done:
+ if (fd >= 0) adb_close(fd);
+ free(data);
+ return status;
+}
+
static void status_window(transport_type ttype, const char* serial)
{
char command[4096];
@@ -511,39 +681,45 @@
}
}
-/** duplicate string and quote all \ " ( ) chars + space character. */
-static char *
-dupAndQuote(const char *s)
+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;
- ts = s;
-
alloc_len = 0;
-
- for( ;*ts != '\0'; ts++) {
+ for (ts = s; *ts != '\0'; ts++) {
alloc_len++;
- if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
+ if (should_escape(*ts)) {
alloc_len++;
}
}
- ret = (char *)malloc(alloc_len + 1);
-
- ts = s;
- dest = ret;
-
- for ( ;*ts != '\0'; ts++) {
- if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
- *dest++ = '\\';
- }
-
- *dest++ = *ts;
+ 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;
@@ -558,7 +734,7 @@
*/
int ppp(int argc, char **argv)
{
-#ifdef HAVE_WIN32_PROC
+#if defined(_WIN32)
fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
return -1;
#else
@@ -621,7 +797,7 @@
adb_close(fd);
return 0;
}
-#endif /* !HAVE_WIN32_PROC */
+#endif /* !defined(_WIN32) */
}
static int send_shellcommand(transport_type transport, char* serial, char* buf)
@@ -650,30 +826,24 @@
char buf[4096];
char *log_tags;
- char *quoted_log_tags;
+ char *quoted;
log_tags = getenv("ANDROID_LOG_TAGS");
- quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
-
+ quoted = escape_arg(log_tags == NULL ? "" : log_tags);
snprintf(buf, sizeof(buf),
- "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
- quoted_log_tags);
+ "shell:export ANDROID_LOG_TAGS=\"%s\"; exec logcat", quoted);
+ free(quoted);
- free(quoted_log_tags);
-
- if (!strcmp(argv[0],"longcat")) {
- strncat(buf, " -v long", sizeof(buf)-1);
+ if (!strcmp(argv[0], "longcat")) {
+ strncat(buf, " -v long", sizeof(buf) - 1);
}
argc -= 1;
argv += 1;
while(argc-- > 0) {
- char *quoted;
-
- quoted = dupAndQuote (*argv++);
-
- strncat(buf, " ", sizeof(buf)-1);
- strncat(buf, quoted, sizeof(buf)-1);
+ quoted = escape_arg(*argv++);
+ strncat(buf, " ", sizeof(buf) - 1);
+ strncat(buf, quoted, sizeof(buf) - 1);
free(quoted);
}
@@ -925,13 +1095,19 @@
return path_buf;
}
-
-static void parse_push_pull_args(char** arg, int narg, char const** path1, char const** path2,
- int* show_progress) {
+static void parse_push_pull_args(char **arg, int narg, char const **path1, char const **path2,
+ int *show_progress, int *copy_attrs) {
*show_progress = 0;
+ *copy_attrs = 0;
- if ((narg > 0) && !strcmp(*arg, "-p")) {
- *show_progress = 1;
+ while (narg > 0) {
+ if (!strcmp(*arg, "-p")) {
+ *show_progress = 1;
+ } else if (!strcmp(*arg, "-a")) {
+ *copy_attrs = 1;
+ } else {
+ break;
+ }
++arg;
--narg;
}
@@ -955,7 +1131,6 @@
int is_server = 0;
int persist = 0;
int r;
- int quote;
transport_type ttype = kTransportAny;
char* serial = NULL;
char* server_port_str = NULL;
@@ -1176,19 +1351,14 @@
return r;
}
- snprintf(buf, sizeof buf, "shell:%s", argv[1]);
+ snprintf(buf, sizeof(buf), "shell:%s", argv[1]);
argc -= 2;
argv += 2;
- while(argc-- > 0) {
- strcat(buf, " ");
-
- /* quote empty strings and strings with spaces */
- quote = (**argv == 0 || strchr(*argv, ' '));
- if (quote)
- strcat(buf, "\"");
- strcat(buf, *argv++);
- if (quote)
- strcat(buf, "\"");
+ while (argc-- > 0) {
+ char *quoted = escape_arg(*argv++);
+ strncat(buf, " ", sizeof(buf) - 1);
+ strncat(buf, quoted, sizeof(buf) - 1);
+ free(quoted);
}
for(;;) {
@@ -1220,6 +1390,36 @@
}
}
+ 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");
@@ -1232,7 +1432,7 @@
if(!strcmp(argv[0], "sideload")) {
if(argc != 2) return usage();
- if(adb_download("sideload", argv[1], 1)) {
+ if (adb_sideload_host(argv[1])) {
return 1;
} else {
return 0;
@@ -1299,8 +1499,11 @@
return 0;
}
- if(!strcmp(argv[0], "forward")) {
+ if(!strcmp(argv[0], "forward") ||
+ !strcmp(argv[0], "reverse"))
+ {
char host_prefix[64];
+ char reverse = (char) !strcmp(argv[0], "reverse");
char remove = 0;
char remove_all = 0;
char list = 0;
@@ -1329,15 +1532,19 @@
}
// Determine the <host-prefix> for this command.
- if (serial) {
- snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
- serial);
- } else if (ttype == kTransportUsb) {
- snprintf(host_prefix, sizeof host_prefix, "host-usb");
- } else if (ttype == kTransportLocal) {
- snprintf(host_prefix, sizeof host_prefix, "host-local");
+ if (reverse) {
+ snprintf(host_prefix, sizeof host_prefix, "reverse");
} else {
- snprintf(host_prefix, sizeof host_prefix, "host");
+ if (serial) {
+ snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
+ serial);
+ } else if (ttype == kTransportUsb) {
+ snprintf(host_prefix, sizeof host_prefix, "host-usb");
+ } else if (ttype == kTransportLocal) {
+ snprintf(host_prefix, sizeof host_prefix, "host-local");
+ } else {
+ snprintf(host_prefix, sizeof host_prefix, "host");
+ }
}
// Implement forward --list
@@ -1395,12 +1602,13 @@
if(!strcmp(argv[0], "push")) {
int show_progress = 0;
+ int copy_attrs = 0; // unused
const char* lpath = NULL, *rpath = NULL;
- parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress);
+ parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress, ©_attrs);
if ((lpath != NULL) && (rpath != NULL)) {
- return do_sync_push(lpath, rpath, 0 /* no verify APK */, show_progress);
+ return do_sync_push(lpath, rpath, show_progress);
}
return usage();
@@ -1408,29 +1616,35 @@
if(!strcmp(argv[0], "pull")) {
int show_progress = 0;
+ int copy_attrs = 0;
const char* rpath = NULL, *lpath = ".";
- parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress);
+ parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress, ©_attrs);
if (rpath != NULL) {
- return do_sync_pull(rpath, lpath, show_progress);
+ return do_sync_pull(rpath, lpath, show_progress, copy_attrs);
}
return usage();
}
- if(!strcmp(argv[0], "install")) {
+ if (!strcmp(argv[0], "install")) {
if (argc < 2) return usage();
return install_app(ttype, serial, argc, argv);
}
- if(!strcmp(argv[0], "uninstall")) {
+ if (!strcmp(argv[0], "install-multiple")) {
+ if (argc < 2) return usage();
+ return install_multiple_app(ttype, serial, argc, argv);
+ }
+
+ 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;
+ char *srcarg, *android_srcpath, *data_srcpath, *vendor_srcpath;
int listonly = 0;
int ret;
@@ -1450,15 +1664,18 @@
} else {
return usage();
}
- ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
+ 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);
free(android_srcpath);
+ free(vendor_srcpath);
free(data_srcpath);
return ret;
}
@@ -1535,9 +1752,10 @@
return 1;
}
+#define MAX_ARGV_LENGTH 16
static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
{
- char *argv[16];
+ char *argv[MAX_ARGV_LENGTH];
int argc;
va_list ap;
@@ -1554,7 +1772,9 @@
}
argv[argc++] = cmd;
- while((argv[argc] = va_arg(ap, char*)) != 0) argc++;
+ while(argc < MAX_ARGV_LENGTH &&
+ (argv[argc] = va_arg(ap, char*)) != 0) argc++;
+ assert(argc < MAX_ARGV_LENGTH);
va_end(ap);
#if 0
@@ -1569,25 +1789,30 @@
}
int find_sync_dirs(const char *srcarg,
- char **android_srcdir_out, char **data_srcdir_out)
+ char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out)
{
- char *android_srcdir, *data_srcdir;
+ char *android_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL;
+ struct stat st;
if(srcarg == NULL) {
android_srcdir = product_file("system");
data_srcdir = product_file("data");
+ vendor_srcdir = product_file("vendor");
+ /* Check if vendor partition exists */
+ if (lstat(vendor_srcdir, &st) || !S_ISDIR(st.st_mode))
+ vendor_srcdir = NULL;
} else {
/* srcarg may be "data", "system" or NULL.
* if srcarg is NULL, then both data and system are synced
*/
if(strcmp(srcarg, "system") == 0) {
android_srcdir = product_file("system");
- data_srcdir = NULL;
} else if(strcmp(srcarg, "data") == 0) {
- android_srcdir = NULL;
data_srcdir = product_file("data");
+ } else if(strcmp(srcarg, "vendor") == 0) {
+ vendor_srcdir = product_file("vendor");
} else {
- /* It's not "system" or "data".
+ /* It's not "system", "vendor", or "data".
*/
return 1;
}
@@ -1598,11 +1823,15 @@
else
free(android_srcdir);
- if(data_srcdir_out != NULL)
- *data_srcdir_out = data_srcdir;
+ if(vendor_srcdir_out != NULL)
+ *vendor_srcdir_out = vendor_srcdir;
else
- free(data_srcdir);
+ free(vendor_srcdir);
+ if(data_srcdir_out != NULL)
+ *data_srcdir_out = data_srcdir;
+ else
+ free(data_srcdir);
return 0;
}
@@ -1614,12 +1843,9 @@
snprintf(buf, sizeof(buf), "shell:pm");
while(argc-- > 0) {
- char *quoted;
-
- quoted = dupAndQuote(*argv++);
-
- strncat(buf, " ", sizeof(buf)-1);
- strncat(buf, quoted, sizeof(buf)-1);
+ char *quoted = escape_arg(*argv++);
+ strncat(buf, " ", sizeof(buf) - 1);
+ strncat(buf, quoted, sizeof(buf) - 1);
free(quoted);
}
@@ -1650,8 +1876,8 @@
char buf[4096];
char* quoted;
- snprintf(buf, sizeof(buf), "shell:rm ");
- quoted = dupAndQuote(filename);
+ snprintf(buf, sizeof(buf), "shell:rm -f ");
+ quoted = escape_arg(filename);
strncat(buf, quoted, sizeof(buf)-1);
free(quoted);
@@ -1670,115 +1896,186 @@
}
}
-static int check_file(const char* filename)
-{
- struct stat st;
-
- if (filename == NULL) {
- return 0;
- }
-
- if (stat(filename, &st) != 0) {
- fprintf(stderr, "can't find '%s' to install\n", filename);
- return 1;
- }
-
- if (!S_ISREG(st.st_mode)) {
- fprintf(stderr, "can't install '%s' because it's not a file\n", filename);
- return 1;
- }
-
- return 0;
-}
-
int install_app(transport_type transport, char* serial, int argc, char** argv)
{
static const char *const DATA_DEST = "/data/local/tmp/%s";
static const char *const SD_DEST = "/sdcard/tmp/%s";
const char* where = DATA_DEST;
- char apk_dest[PATH_MAX];
- char verification_dest[PATH_MAX];
- char* apk_file;
- char* verification_file = NULL;
- int file_arg = -1;
- int err;
int i;
- int verify_apk = 1;
+ struct stat sb;
for (i = 1; i < argc; i++) {
- if (*argv[i] != '-') {
- file_arg = i;
- break;
- } else if (!strcmp(argv[i], "-i")) {
- // Skip the installer package name.
- i++;
- } else if (!strcmp(argv[i], "-s")) {
+ if (!strcmp(argv[i], "-s")) {
where = SD_DEST;
- } else if (!strcmp(argv[i], "--algo")) {
- verify_apk = 0;
- i++;
- } else if (!strcmp(argv[i], "--iv")) {
- verify_apk = 0;
- i++;
- } else if (!strcmp(argv[i], "--key")) {
- verify_apk = 0;
- i++;
}
}
- if (file_arg < 0) {
- fprintf(stderr, "can't find filename in arguments\n");
- return 1;
- } else if (file_arg + 2 < argc) {
- fprintf(stderr, "too many files specified; only takes APK file and verifier file\n");
- return 1;
+ // Find last APK argument.
+ // All other arguments passed through verbatim.
+ int last_apk = -1;
+ for (i = argc - 1; i >= 0; i--) {
+ char* file = argv[i];
+ char* dot = strrchr(file, '.');
+ if (dot && !strcasecmp(dot, ".apk")) {
+ if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
+ fprintf(stderr, "Invalid APK file: %s\n", file);
+ return -1;
+ }
+
+ last_apk = i;
+ break;
+ }
}
- apk_file = argv[file_arg];
-
- if (file_arg != argc - 1) {
- verification_file = argv[file_arg + 1];
+ if (last_apk == -1) {
+ fprintf(stderr, "Missing APK file\n");
+ return -1;
}
- if (check_file(apk_file) || check_file(verification_file)) {
- return 1;
- }
-
+ char* apk_file = argv[last_apk];
+ char apk_dest[PATH_MAX];
snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
- if (verification_file != NULL) {
- snprintf(verification_dest, sizeof(verification_dest), where, get_basename(verification_file));
-
- if (!strcmp(apk_dest, verification_dest)) {
- fprintf(stderr, "APK and verification file can't have the same name\n");
- return 1;
- }
- }
-
- err = do_sync_push(apk_file, apk_dest, verify_apk, 0 /* no show progress */);
+ int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */);
if (err) {
goto cleanup_apk;
} else {
- argv[file_arg] = apk_dest; /* destination name, not source location */
- }
-
- if (verification_file != NULL) {
- err = do_sync_push(verification_file, verification_dest, 0 /* no verify APK */,
- 0 /* no show progress */);
- if (err) {
- goto cleanup_apk;
- } else {
- argv[file_arg + 1] = verification_dest; /* destination name, not source location */
- }
+ argv[last_apk] = apk_dest; /* destination name, not source location */
}
pm_command(transport, serial, argc, argv);
cleanup_apk:
- if (verification_file != NULL) {
- delete_file(transport, serial, verification_dest);
+ delete_file(transport, serial, apk_dest);
+ return err;
+}
+
+int install_multiple_app(transport_type transport, char* serial, int argc, char** argv)
+{
+ char buf[1024];
+ int i;
+ struct stat sb;
+ unsigned long long 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];
+ char* dot = strrchr(file, '.');
+ if (dot && !strcasecmp(dot, ".apk")) {
+ if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
+ fprintf(stderr, "Invalid APK file: %s\n", file);
+ return -1;
+ }
+
+ total_size += sb.st_size;
+ first_apk = i;
+ } else {
+ break;
+ }
}
- delete_file(transport, serial, apk_dest);
+ if (first_apk == -1) {
+ fprintf(stderr, "Missing APK file\n");
+ return 1;
+ }
- return err;
+ snprintf(buf, sizeof(buf), "exec:pm install-create -S %lld", total_size);
+ 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);
+ }
+
+ // Create install session
+ int fd = adb_connect(buf);
+ if (fd < 0) {
+ fprintf(stderr, "Connect error for create: %s\n", adb_error());
+ return -1;
+ }
+ read_status_line(fd, buf, sizeof(buf));
+ adb_close(fd);
+
+ int session_id = -1;
+ if (!strncmp("Success", buf, 7)) {
+ char* start = strrchr(buf, '[');
+ char* end = strrchr(buf, ']');
+ if (start && end) {
+ *end = '\0';
+ session_id = strtol(start + 1, NULL, 10);
+ }
+ }
+ if (session_id < 0) {
+ fprintf(stderr, "Failed to create session\n");
+ fputs(buf, stderr);
+ return -1;
+ }
+
+ // Valid session, now stream the APKs
+ int success = 1;
+ for (i = first_apk; i < argc; i++) {
+ 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));
+
+ int localFd = adb_open(file, O_RDONLY);
+ if (localFd < 0) {
+ fprintf(stderr, "Failed to open %s: %s\n", file, adb_error());
+ success = 0;
+ goto finalize_session;
+ }
+
+ int remoteFd = adb_connect(buf);
+ if (remoteFd < 0) {
+ fprintf(stderr, "Connect error for write: %s\n", adb_error());
+ adb_close(localFd);
+ success = 0;
+ goto finalize_session;
+ }
+
+ copy_to_file(localFd, remoteFd);
+ read_status_line(remoteFd, buf, sizeof(buf));
+
+ adb_close(localFd);
+ adb_close(remoteFd);
+
+ if (strncmp("Success", buf, 7)) {
+ fprintf(stderr, "Failed to write %s\n", file);
+ fputs(buf, stderr);
+ success = 0;
+ goto finalize_session;
+ }
+ }
+
+finalize_session:
+ // Commit session if we streamed everything okay; otherwise abandon
+ if (success) {
+ snprintf(buf, sizeof(buf), "exec:pm install-commit %d", session_id);
+ } else {
+ snprintf(buf, sizeof(buf), "exec:pm install-abandon %d", session_id);
+ }
+
+ fd = adb_connect(buf);
+ if (fd < 0) {
+ fprintf(stderr, "Connect error for finalize: %s\n", adb_error());
+ return -1;
+ }
+ read_status_line(fd, buf, sizeof(buf));
+ adb_close(fd);
+
+ if (!strncmp("Success", buf, 7)) {
+ fputs(buf, stderr);
+ return 0;
+ } else {
+ fprintf(stderr, "Failed to finalize session\n");
+ fputs(buf, stderr);
+ return -1;
+ }
}
diff --git a/adb/fdevent.c b/adb/fdevent.c
index 5c374a7..43e600c 100644
--- a/adb/fdevent.c
+++ b/adb/fdevent.c
@@ -28,10 +28,12 @@
#include <stdarg.h>
#include <stddef.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
@@ -57,16 +59,6 @@
#define FATAL(x...) fatal(__FUNCTION__, x)
#if DEBUG
-#define D(...) \
- do { \
- adb_mutex_lock(&D_lock); \
- int save_errno = errno; \
- fprintf(stderr, "%s::%s():", __FILE__, __FUNCTION__); \
- errno = save_errno; \
- fprintf(stderr, __VA_ARGS__); \
- adb_mutex_unlock(&D_lock); \
- errno = save_errno; \
- } while(0)
static void dump_fde(fdevent *fde, const char *info)
{
adb_mutex_lock(&D_lock);
@@ -78,7 +70,6 @@
adb_mutex_unlock(&D_lock);
}
#else
-#define D(...) ((void)0)
#define dump_fde(fde, info) do { } while(0)
#endif
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index dc4e77f..ad59e81 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -25,6 +25,7 @@
#include <limits.h>
#include <sys/types.h>
#include <zipfile/zipfile.h>
+#include <utime.h>
#include "sysdeps.h"
#include "adb.h"
@@ -139,7 +140,8 @@
static syncsendbuf send_buffer;
-int sync_readtime(int fd, const char *path, unsigned *timestamp)
+int sync_readtime(int fd, const char *path, unsigned int *timestamp,
+ unsigned int *mode)
{
syncmsg msg;
int len = strlen(path);
@@ -161,6 +163,7 @@
}
*timestamp = ltohl(msg.stat.time);
+ *mode = ltohl(msg.stat.mode);
return 0;
}
@@ -237,7 +240,7 @@
if (show_progress) {
// Determine local file size.
struct stat st;
- if (lstat(path, &st)) {
+ if (fstat(lfd, &st)) {
fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
return -1;
}
@@ -332,7 +335,7 @@
#endif
static int sync_send(int fd, const char *lpath, const char *rpath,
- unsigned mtime, mode_t mode, int verifyApk, int show_progress)
+ unsigned mtime, mode_t mode, int show_progress)
{
syncmsg msg;
int len, r;
@@ -347,63 +350,6 @@
snprintf(tmp, sizeof(tmp), ",%d", mode);
r = strlen(tmp);
- if (verifyApk) {
- int lfd;
- zipfile_t zip;
- zipentry_t entry;
- int amt;
-
- // if we are transferring an APK file, then sanity check to make sure
- // we have a real zip file that contains an AndroidManifest.xml
- // this requires that we read the entire file into memory.
- lfd = adb_open(lpath, O_RDONLY);
- if(lfd < 0) {
- fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
- return -1;
- }
-
- size = adb_lseek(lfd, 0, SEEK_END);
- if (size == -1 || -1 == adb_lseek(lfd, 0, SEEK_SET)) {
- fprintf(stderr, "error seeking in file '%s'\n", lpath);
- adb_close(lfd);
- return 1;
- }
-
- file_buffer = (char *)malloc(size);
- if (file_buffer == NULL) {
- fprintf(stderr, "could not allocate buffer for '%s'\n",
- lpath);
- adb_close(lfd);
- return 1;
- }
- amt = adb_read(lfd, file_buffer, size);
- if (amt != size) {
- fprintf(stderr, "error reading from file: '%s'\n", lpath);
- adb_close(lfd);
- free(file_buffer);
- return 1;
- }
-
- adb_close(lfd);
-
- zip = init_zipfile(file_buffer, size);
- if (zip == NULL) {
- fprintf(stderr, "file '%s' is not a valid zip file\n",
- lpath);
- free(file_buffer);
- return 1;
- }
-
- entry = lookup_zipentry(zip, "AndroidManifest.xml");
- release_zipfile(zip);
- if (entry == NULL) {
- fprintf(stderr, "file '%s' does not contain AndroidManifest.xml\n",
- lpath);
- free(file_buffer);
- return 1;
- }
- }
-
msg.req.id = ID_SEND;
msg.req.namelen = htoll(len + r);
@@ -694,30 +640,33 @@
continue;
strcpy(stat_path, lpath);
strcat(stat_path, de->d_name);
- stat(stat_path, &st);
- if (S_ISDIR(st.st_mode)) {
- ci = mkcopyinfo(lpath, rpath, name, 1);
- ci->next = dirlist;
- dirlist = ci;
- } else {
- ci = mkcopyinfo(lpath, rpath, name, 0);
- if(lstat(ci->src, &st)) {
- fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
- free(ci);
- closedir(d);
- return -1;
- }
- if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
- fprintf(stderr, "skipping special file '%s'\n", ci->src);
- free(ci);
+ if(!lstat(stat_path, &st)) {
+ if (S_ISDIR(st.st_mode)) {
+ ci = mkcopyinfo(lpath, rpath, name, 1);
+ ci->next = dirlist;
+ dirlist = ci;
} else {
- ci->time = st.st_mtime;
- ci->mode = st.st_mode;
- ci->size = st.st_size;
- ci->next = *filelist;
- *filelist = ci;
+ ci = mkcopyinfo(lpath, rpath, name, 0);
+ if(lstat(ci->src, &st)) {
+ fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
+ free(ci);
+ closedir(d);
+ return -1;
+ }
+ if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
+ fprintf(stderr, "skipping special file '%s'\n", ci->src);
+ free(ci);
+ } else {
+ ci->time = st.st_mtime;
+ ci->mode = st.st_mode;
+ ci->size = st.st_size;
+ ci->next = *filelist;
+ *filelist = ci;
+ }
}
+ } else {
+ fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
}
}
@@ -783,7 +732,7 @@
if(ci->flag == 0) {
fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
if(!listonly &&
- sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */,
+ sync_send(fd, ci->src, ci->dst, ci->time, ci->mode,
0 /* no show progress */)) {
return 1;
}
@@ -802,7 +751,7 @@
}
-int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress)
+int do_sync_push(const char *lpath, const char *rpath, int show_progress)
{
struct stat st;
unsigned mode;
@@ -849,7 +798,7 @@
rpath = tmp;
}
BEGIN();
- if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk, show_progress)) {
+ if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
return 1;
} else {
END();
@@ -931,8 +880,21 @@
return 0;
}
+static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int mode)
+{
+ struct utimbuf times = { time, time };
+ int r1 = utime(lpath, ×);
+
+ /* use umask for permissions */
+ mode_t mask=umask(0000);
+ umask(mask);
+ int r2 = chmod(lpath, mode & ~mask);
+
+ return r1 ? : r2;
+}
+
static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
- int checktimestamps)
+ int copy_attrs)
{
copyinfo *filelist = 0;
copyinfo *ci, *next;
@@ -962,26 +924,6 @@
return -1;
}
-#if 0
- if (checktimestamps) {
- for (ci = filelist; ci != 0; ci = ci->next) {
- if (sync_start_readtime(fd, ci->dst)) {
- return 1;
- }
- }
- for (ci = filelist; ci != 0; ci = ci->next) {
- unsigned int timestamp, mode, size;
- if (sync_finish_readtime(fd, ×tamp, &mode, &size))
- return 1;
- if (size == ci->size) {
- /* for links, we cannot update the atime/mtime */
- if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
- (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
- ci->flag = 1;
- }
- }
- }
-#endif
for (ci = filelist; ci != 0; ci = next) {
next = ci->next;
if (ci->flag == 0) {
@@ -989,6 +931,10 @@
if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
return 1;
}
+
+ if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
+ return 1;
+ }
pulled++;
} else {
skipped++;
@@ -1003,9 +949,9 @@
return 0;
}
-int do_sync_pull(const char *rpath, const char *lpath, int show_progress)
+int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs)
{
- unsigned mode;
+ unsigned mode, time;
struct stat st;
int fd;
@@ -1016,7 +962,7 @@
return 1;
}
- if(sync_readmode(fd, rpath, &mode)) {
+ if(sync_readtime(fd, rpath, &time, &mode)) {
return 1;
}
if(mode == 0) {
@@ -1047,13 +993,15 @@
if (sync_recv(fd, rpath, lpath, show_progress)) {
return 1;
} else {
+ if (copy_attrs && set_time_and_mode(lpath, time, mode))
+ return 1;
END();
sync_quit(fd);
return 0;
}
} else if(S_ISDIR(mode)) {
BEGIN();
- if (copy_remote_dir_local(fd, rpath, lpath, 0)) {
+ if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
return 1;
} else {
END();
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index 1d80d26..7933858 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -39,6 +39,11 @@
return (strncmp(SYSTEM, name, strlen(SYSTEM)) == 0);
}
+static bool is_on_vendor(const char *name) {
+ const char *VENDOR = "/vendor/";
+ return (strncmp(VENDOR, name, strlen(VENDOR)) == 0);
+}
+
static int mkdirs(char *name)
{
int ret;
@@ -54,7 +59,7 @@
x = adb_dirstart(x);
if(x == 0) return 0;
*x = 0;
- if (is_on_system(name)) {
+ if (is_on_system(name) || is_on_vendor(name)) {
fs_config(name, 1, &uid, &gid, &mode, &cap);
}
ret = adb_mkdir(name, mode);
@@ -178,18 +183,18 @@
unsigned int timestamp = 0;
int fd;
- fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+ fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
if(fd < 0 && errno == ENOENT) {
if(mkdirs(path) != 0) {
if(fail_errno(s))
return -1;
fd = -1;
} else {
- fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+ fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
}
}
if(fd < 0 && errno == EEXIST) {
- fd = adb_open_mode(path, O_WRONLY, mode);
+ fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode);
}
if(fd < 0) {
if(fail_errno(s))
@@ -369,7 +374,7 @@
if(*tmp == '/') {
tmp++;
}
- if (is_on_system(path)) {
+ 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);
@@ -383,7 +388,7 @@
syncmsg msg;
int fd, r;
- fd = adb_open(path, O_RDONLY);
+ fd = adb_open(path, O_RDONLY | O_CLOEXEC);
if(fd < 0) {
if(fail_errno(s)) return -1;
return 0;
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 3e7e096..c3c8574 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -17,22 +17,10 @@
#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
#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')
@@ -78,9 +66,9 @@
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 verifyApk, int show_progress);
+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_pull(const char *rpath, const char *lpath, int show_progress);
+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.c
index fa7fd98..61578aa 100644
--- a/adb/framebuffer_service.c
+++ b/adb/framebuffer_service.c
@@ -61,7 +61,7 @@
int w, h, f;
int fds[2];
- if (pipe(fds) < 0) goto pipefail;
+ if (pipe2(fds, O_CLOEXEC) < 0) goto pipefail;
pid_t pid = fork();
if (pid < 0) goto done;
@@ -76,6 +76,7 @@
exit(1);
}
+ close(fds[1]);
fd_screencap = fds[0];
/* read w, h & format */
@@ -173,10 +174,9 @@
}
done:
- TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
-
close(fds[0]);
- close(fds[1]);
+
+ TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
pipefail:
close(fd);
}
diff --git a/adb/get_my_path_darwin.c b/adb/get_my_path_darwin.c
index 5b95d15..ff1396c 100644
--- a/adb/get_my_path_darwin.c
+++ b/adb/get_my_path_darwin.c
@@ -19,12 +19,12 @@
void get_my_path(char *s, size_t maxLen)
{
- ProcessSerialNumber psn;
- GetCurrentProcess(&psn);
- CFDictionaryRef dict;
- dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
- CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
- CFSTR("CFBundleExecutable"));
- CFStringGetCString(value, s, maxLen, kCFStringEncodingUTF8);
+ CFBundleRef mainBundle = CFBundleGetMainBundle();
+ CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle);
+ CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
+ CFRelease(executableURL);
+
+ CFStringGetFileSystemRepresentation(executablePathString, s, maxLen);
+ CFRelease(executablePathString);
}
diff --git a/adb/remount_service.c b/adb/remount_service.c
index d3a649b..72d15a1 100644
--- a/adb/remount_service.c
+++ b/adb/remount_service.c
@@ -29,6 +29,7 @@
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)
@@ -39,7 +40,7 @@
const char delims[] = "\n";
char buf[4096];
- fd = unix_open("/proc/mounts", O_RDONLY);
+ fd = unix_open("/proc/mounts", O_RDONLY | O_CLOEXEC);
if (fd < 0)
return NULL;
@@ -67,34 +68,43 @@
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_system()
+static int remount(const char* dir, int* dir_ro)
{
char *dev;
int fd;
int OFF = 0;
- if (system_ro == 0) {
+ if (dir_ro == 0) {
return 0;
}
- dev = find_mount("/system");
+ dev = find_mount(dir);
if (!dev)
return -1;
- fd = unix_open(dev, O_RDONLY);
+ fd = unix_open(dev, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return -1;
ioctl(fd, BLKROSET, &OFF);
adb_close(fd);
- system_ro = mount(dev, "/system", "none", MS_REMOUNT, NULL);
+ *dir_ro = mount(dev, dir, "none", MS_REMOUNT, NULL);
free(dev);
- return system_ro;
+ return *dir_ro;
}
static void write_string(int fd, const char* str)
@@ -104,16 +114,25 @@
void remount_service(int fd, void *cookie)
{
- int ret = remount_system();
-
- if (!ret)
- write_string(fd, "remount succeeded\n");
- else {
- char buffer[200];
- snprintf(buffer, sizeof(buffer), "remount failed: %s\n", strerror(errno));
+ char buffer[200];
+ 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/services.c b/adb/services.c
index 5b63a43..bcfc163 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -116,23 +116,10 @@
{
char buf[100];
char property_val[PROPERTY_VALUE_MAX];
- int pid, ret;
+ int ret;
sync();
- /* Attempt to unmount the SD card first.
- * No need to bother checking for errors.
- */
- pid = fork();
- if (pid == 0) {
- /* ask vdc to unmount it */
- execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount",
- getenv("EXTERNAL_STORAGE"), "force", NULL);
- } else if (pid > 0) {
- /* wait until vdc succeeds or fails */
- waitpid(pid, &ret, 0);
- }
-
ret = snprintf(property_val, sizeof(property_val), "reboot,%s", (char *) arg);
if (ret >= (int) sizeof(property_val)) {
snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret);
@@ -154,6 +141,17 @@
adb_close(fd);
}
+void reverse_service(int fd, void* arg)
+{
+ const char* command = arg;
+
+ if (handle_forward_request(command, kTransportAny, NULL, fd) < 0) {
+ sendfailmsg(fd, "not a reverse forwarding command");
+ }
+ free(arg);
+ adb_close(fd);
+}
+
#endif
static int create_service_thread(void (*func)(int, void *), void *cookie)
@@ -186,25 +184,38 @@
}
#if !ADB_HOST
-static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+
+static void init_subproc_child()
{
-#ifdef HAVE_WIN32_PROC
- D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
- fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
+ setsid();
+
+ // Set OOM score adjustment to prevent killing
+ int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
+ if (fd >= 0) {
+ adb_write(fd, "0", 1);
+ adb_close(fd);
+ } else {
+ D("adb: unable to update oom_score_adj\n");
+ }
+}
+
+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);
+#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 */
- char *devname;
+#else
int ptm;
- ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
+ ptm = unix_open("/dev/ptmx", O_RDWR | O_CLOEXEC); // | O_NOCTTY);
if(ptm < 0){
printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
return -1;
}
- fcntl(ptm, F_SETFD, FD_CLOEXEC);
- if(grantpt(ptm) || unlockpt(ptm) ||
- ((devname = (char*) ptsname(ptm)) == 0)){
+ char devname[64];
+ if(grantpt(ptm) || unlockpt(ptm) || ptsname_r(ptm, devname, sizeof(devname)) != 0) {
printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
adb_close(ptm);
return -1;
@@ -217,46 +228,74 @@
return -1;
}
- if(*pid == 0){
- int pts;
+ if (*pid == 0) {
+ init_subproc_child();
- setsid();
-
- pts = unix_open(devname, O_RDWR);
- if(pts < 0) {
+ int pts = unix_open(devname, O_RDWR | O_CLOEXEC);
+ if (pts < 0) {
fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
exit(-1);
}
- dup2(pts, 0);
- dup2(pts, 1);
- dup2(pts, 2);
+ dup2(pts, STDIN_FILENO);
+ dup2(pts, STDOUT_FILENO);
+ dup2(pts, STDERR_FILENO);
adb_close(pts);
adb_close(ptm);
- // set OOM adjustment to zero
- char text[64];
- snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
- int fd = adb_open(text, O_WRONLY);
- if (fd >= 0) {
- adb_write(fd, "0", 1);
- adb_close(fd);
- } else {
- D("adb: unable to open %s\n", text);
- }
execl(cmd, cmd, arg0, arg1, NULL);
fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
cmd, strerror(errno), errno);
exit(-1);
} else {
- // Don't set child's OOM adjustment to zero.
- // Let the child do it itself, as sometimes the parent starts
- // running before the child has a /proc/pid/oom_adj.
- // """adb: unable to open /proc/644/oom_adj""" seen in some logs.
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);
+#if defined(_WIN32)
+ fprintf(stderr, "error: create_subproc_raw not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
+ return -1;
+#else
+
+ // 0 is parent socket, 1 is child socket
+ int sv[2];
+ if (unix_socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
+ printf("[ cannot create socket pair - %s ]\n", strerror(errno));
+ return -1;
+ }
+
+ *pid = fork();
+ if (*pid < 0) {
+ printf("- fork failed: %s -\n", strerror(errno));
+ adb_close(sv[0]);
+ adb_close(sv[1]);
+ return -1;
+ }
+
+ if (*pid == 0) {
+ adb_close(sv[0]);
+ init_subproc_child();
+
+ dup2(sv[1], STDIN_FILENO);
+ dup2(sv[1], STDOUT_FILENO);
+ dup2(sv[1], STDERR_FILENO);
+
+ adb_close(sv[1]);
+
+ execl(cmd, cmd, arg0, arg1, NULL);
+ fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
+ cmd, strerror(errno), errno);
+ exit(-1);
+ } else {
+ adb_close(sv[1]);
+ return sv[0];
+ }
+#endif /* !defined(_WIN32) */
}
#endif /* !ABD_HOST */
@@ -298,18 +337,32 @@
}
}
-static int create_subproc_thread(const char *name)
+static int create_subproc_thread(const char *name, const subproc_mode mode)
{
stinfo *sti;
adb_thread_t t;
int ret_fd;
- pid_t pid;
- if(name) {
- ret_fd = create_subprocess(SHELL_COMMAND, "-c", name, &pid);
+ pid_t pid = -1;
+
+ const char *arg0, *arg1;
+ if (name == 0 || *name == 0) {
+ arg0 = "-"; arg1 = 0;
} else {
- ret_fd = create_subprocess(SHELL_COMMAND, "-", 0, &pid);
+ arg0 = "-c"; arg1 = name;
}
- D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
+
+ switch (mode) {
+ case SUBPROC_PTY:
+ ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid);
+ break;
+ case SUBPROC_RAW:
+ ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid);
+ break;
+ default:
+ fprintf(stderr, "invalid subproc_mode %d\n", mode);
+ return -1;
+ }
+ D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid);
sti = malloc(sizeof(stinfo));
if(sti == 0) fatal("cannot allocate stinfo");
@@ -317,14 +370,14 @@
sti->cookie = (void*) (uintptr_t) pid;
sti->fd = ret_fd;
- if(adb_thread_create( &t, service_bootstrap_func, sti)){
+ if (adb_thread_create(&t, service_bootstrap_func, sti)) {
free(sti);
adb_close(ret_fd);
- printf("cannot create service thread\n");
+ fprintf(stderr, "cannot create service thread\n");
return -1;
}
- D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
+ D("service thread started, fd=%d pid=%d\n", ret_fd, pid);
return ret_fd;
}
#endif
@@ -363,33 +416,41 @@
#endif
#if !ADB_HOST
} else if(!strncmp("dev:", name, 4)) {
- ret = unix_open(name + 4, O_RDWR);
+ ret = unix_open(name + 4, O_RDWR | O_CLOEXEC);
} else if(!strncmp(name, "framebuffer:", 12)) {
ret = create_service_thread(framebuffer_service, 0);
} else if (!strncmp(name, "jdwp:", 5)) {
ret = create_jdwp_connection_fd(atoi(name+5));
} else if(!HOST && !strncmp(name, "shell:", 6)) {
- if(name[6]) {
- ret = create_subproc_thread(name + 6);
- } else {
- ret = create_subproc_thread(0);
- }
+ ret = create_subproc_thread(name + 6, SUBPROC_PTY);
+ } else if(!HOST && !strncmp(name, "exec:", 5)) {
+ ret = create_subproc_thread(name + 5, SUBPROC_RAW);
} else if(!strncmp(name, "sync:", 5)) {
ret = create_service_thread(file_sync_service, NULL);
} else if(!strncmp(name, "remount:", 8)) {
ret = create_service_thread(remount_service, NULL);
} else if(!strncmp(name, "reboot:", 7)) {
void* arg = strdup(name + 7);
- if(arg == 0) return -1;
+ if (arg == NULL) return -1;
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, "backup:", 7)) {
- char* arg = strdup(name+7);
+ char* arg = strdup(name + 7);
if (arg == NULL) return -1;
- ret = backup_service(BACKUP, arg);
+ 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);
} else if(!strncmp(name, "restore:", 8)) {
- ret = backup_service(RESTORE, NULL);
+ 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) {
@@ -398,6 +459,16 @@
ret = create_service_thread(restart_tcp_service, (void *) (uintptr_t) port);
} else if(!strncmp(name, "usb:", 4)) {
ret = create_service_thread(restart_usb_service, NULL);
+ } else if (!strncmp(name, "reverse:", 8)) {
+ char* cookie = strdup(name + 8);
+ if (cookie == NULL) {
+ ret = -1;
+ } else {
+ ret = create_service_thread(reverse_service, cookie);
+ if (ret < 0) {
+ free(cookie);
+ }
+ }
#endif
}
if (ret >= 0) {
@@ -460,7 +531,7 @@
snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
- fd = socket_network_client(hostbuf, port, SOCK_STREAM);
+ fd = socket_network_client_timeout(hostbuf, port, SOCK_STREAM, 10);
if (fd < 0) {
snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
return;
diff --git a/adb/sockets.c b/adb/sockets.c
index de14a22..faa9564 100644
--- a/adb/sockets.c
+++ b/adb/sockets.c
@@ -23,6 +23,10 @@
#include "sysdeps.h"
+#if !ADB_HOST
+#include <cutils/properties.h>
+#endif
+
#define TRACE_TAG TRACE_SOCKETS
#include "adb.h"
@@ -428,6 +432,9 @@
{
asocket *s;
int fd;
+#if !ADB_HOST
+ char debug[PROPERTY_VALUE_MAX];
+#endif
#if !ADB_HOST
if (!strcmp(name,"jdwp")) {
@@ -444,7 +451,11 @@
D("LS(%d): bound to '%s' via %d\n", s->id, name, fd);
#if !ADB_HOST
- if ((!strncmp(name, "root:", 5) && getuid() != 0)
+ if (!strncmp(name, "root:", 5))
+ property_get("ro.debuggable", debug, "");
+
+ if ((!strncmp(name, "root:", 5) && getuid() != 0
+ && strcmp(debug, "1") == 0)
|| !strncmp(name, "usb:", 4)
|| !strncmp(name, "tcpip:", 6)) {
D("LS(%d): enabling exit_on_close\n", s->id);
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 4033b72..cc1f839 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -26,8 +26,8 @@
#ifdef _WIN32
-#include <windows.h>
#include <winsock2.h>
+#include <windows.h>
#include <ws2tcpip.h>
#include <process.h>
#include <fcntl.h>
@@ -35,6 +35,7 @@
#include <sys/stat.h>
#include <errno.h>
#include <ctype.h>
+#include <direct.h>
#define OS_PATH_SEPARATOR '\\'
#define OS_PATH_SEPARATOR_STR "\\"
@@ -169,6 +170,8 @@
/* normally provided by <cutils/sockets.h> */
extern int socket_loopback_client(int port, int type);
extern int socket_network_client(const char *host, int port, int type);
+extern int socket_network_client_timeout(const char *host, int port, int type,
+ int timeout);
extern int socket_loopback_server(int port, int type);
extern int socket_inaddr_any_server(int port, int type);
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index b0cb048..b082c6d 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -1,6 +1,6 @@
#include "sysdeps.h"
-#include <windows.h>
#include <winsock2.h>
+#include <windows.h>
#include <stdio.h>
#include <errno.h>
#define TRACE_TAG TRACE_SYSDEPS
@@ -701,6 +701,13 @@
}
+int socket_network_client_timeout(const char *host, int port, int type, int timeout)
+{
+ // TODO: implement timeouts for Windows.
+ return socket_network_client(host, port, type);
+}
+
+
int socket_inaddr_any_server(int port, int type)
{
FH f = _fh_alloc( &_fh_socket_class );
@@ -1542,7 +1549,7 @@
* reset" event that will remain set once it was set. */
main_event = CreateEvent(NULL, TRUE, FALSE, NULL);
if (main_event == NULL) {
- D("Unable to create main event. Error: %d", GetLastError());
+ D("Unable to create main event. Error: %d", (int)GetLastError());
free(threads);
return (int)WAIT_FAILED;
}
diff --git a/adb/transport_local.c b/adb/transport_local.c
index 948cc15..6c4e220 100644
--- a/adb/transport_local.c
+++ b/adb/transport_local.c
@@ -28,21 +28,6 @@
#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
-
#if ADB_HOST
/* we keep a list of opened transports. The atransport struct knows to which
* local transport it is connected. The list is used to detect when we're
@@ -62,12 +47,6 @@
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;
@@ -90,12 +69,6 @@
{
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)) {
D("remote local: write terminated\n");
return -1;
diff --git a/adb/transport_usb.c b/adb/transport_usb.c
index ee6b637..1138ddd 100644
--- a/adb/transport_usb.c
+++ b/adb/transport_usb.c
@@ -23,33 +23,6 @@
#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 +30,6 @@
return -1;
}
- fix_endians(p);
-
if(check_header(p)) {
D("remote usb: check_header failed\n");
return -1;
@@ -83,8 +54,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 +100,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_linux.c b/adb/usb_linux.c
index 7973cb0..7d13a5d 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.c
@@ -170,7 +170,7 @@
}
// DBGX("[ scanning %s ]\n", devname);
- if((fd = unix_open(devname, O_RDONLY)) < 0) {
+ if((fd = unix_open(devname, O_RDONLY | O_CLOEXEC)) < 0) {
continue;
}
@@ -609,10 +609,10 @@
usb->mark = 1;
usb->reaper_thread = 0;
- usb->desc = unix_open(usb->fname, O_RDWR);
+ usb->desc = unix_open(usb->fname, O_RDWR | O_CLOEXEC);
if(usb->desc < 0) {
/* if we fail, see if have read-only access */
- usb->desc = unix_open(usb->fname, O_RDONLY);
+ usb->desc = unix_open(usb->fname, O_RDONLY | O_CLOEXEC);
if(usb->desc < 0) goto fail;
usb->writeable = 0;
D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc);
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c
index 8426e0e..70d2ad0 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.c
@@ -33,6 +33,7 @@
#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)
@@ -56,19 +57,33 @@
};
static const struct {
- struct usb_functionfs_descs_head header;
+ __le32 magic;
+ __le32 length;
+ __le32 flags;
+ __le32 fs_count;
+ __le32 hs_count;
+ __le32 ss_count;
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;
+ struct {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio source;
+ struct usb_ss_ep_comp_descriptor source_comp;
+ struct usb_endpoint_descriptor_no_audio sink;
+ struct usb_ss_ep_comp_descriptor sink_comp;
+ } __attribute__((packed)) ss_descs;
} __attribute__((packed)) descriptors = {
- .header = {
- .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
- .length = cpu_to_le32(sizeof(descriptors)),
- .fs_count = 3,
- .hs_count = 3,
- },
+ .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+ .length = cpu_to_le32(sizeof(descriptors)),
+ .flags = cpu_to_le32(FUNCTIONFS_HAS_FS_DESC |
+ FUNCTIONFS_HAS_HS_DESC |
+ FUNCTIONFS_HAS_SS_DESC),
+ .fs_count = 3,
+ .hs_count = 3,
+ .ss_count = 5,
.fs_descs = {
.intf = {
.bLength = sizeof(descriptors.fs_descs.intf),
@@ -121,6 +136,40 @@
.wMaxPacketSize = MAX_PACKET_SIZE_HS,
},
},
+ .ss_descs = {
+ .intf = {
+ .bLength = sizeof(descriptors.ss_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.ss_descs.source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+ },
+ .source_comp = {
+ .bLength = sizeof(descriptors.ss_descs.source_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ },
+ .sink = {
+ .bLength = sizeof(descriptors.ss_descs.sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+ },
+ .sink_comp = {
+ .bLength = sizeof(descriptors.ss_descs.sink_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ },
+ },
};
#define STR_INTERFACE_ "ADB Interface"
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index 45ce444..ba157f1 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -28,12 +28,11 @@
#define TRACE_TAG TRACE_USB
#include "adb.h"
-#include "usb_vendors.h"
#define DBG D
static IONotificationPortRef notificationPort = 0;
-static io_iterator_t* notificationIterators;
+static io_iterator_t notificationIterator;
struct usb_handle
{
@@ -61,8 +60,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 +67,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 +109,7 @@
HRESULT result;
SInt32 score;
UInt32 locationId;
+ UInt8 class, subclass, protocol;
UInt16 vendor;
UInt16 product;
UInt8 serialIndex;
@@ -156,6 +140,16 @@
continue;
}
+ kr = (*iface)->GetInterfaceClass(iface, &class);
+ kr = (*iface)->GetInterfaceSubClass(iface, &subclass);
+ kr = (*iface)->GetInterfaceProtocol(iface, &protocol);
+ 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", 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.
@@ -192,12 +186,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);
@@ -384,8 +378,6 @@
void* RunLoopThread(void* unused)
{
- unsigned i;
-
InitUSB();
currentRunLoop = CFRunLoopGetCurrent();
@@ -398,9 +390,7 @@
CFRunLoopRun();
currentRunLoop = 0;
- for (i = 0; i < vendorIdCount; i++) {
- IOObjectRelease(notificationIterators[i]);
- }
+ IOObjectRelease(notificationIterator);
IONotificationPortDestroy(notificationPort);
DBG("RunLoopThread done\n");
@@ -415,9 +405,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 +429,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)
@@ -512,14 +494,18 @@
return -1;
}
- result =
- (*handle->interface)->ReadPipe(handle->interface,
- handle->bulkIn, buf, &numBytes);
+ result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
- if (0 == result)
+ if (kIOUSBPipeStalled == result) {
+ DBG(" Pipe stalled, clearing stall.\n");
+ (*handle->interface)->ClearPipeStall(handle->interface, handle->bulkIn);
+ result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
+ }
+
+ if (kIOReturnSuccess == result)
return 0;
else {
- DBG("ERR: usb_read failed with status %d\n", result);
+ DBG("ERR: usb_read failed with status %x\n", result);
}
return -1;
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
deleted file mode 100755
index 0c46a0c..0000000
--- a/adb/usb_vendors.c
+++ /dev/null
@@ -1,352 +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>
-
-#ifdef _WIN32
-# define WIN32_LEAN_AND_MEAN
-# 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 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
-// 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
-// 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
-// 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
-// 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_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_GOOGLE,
- VENDOR_ID_HAIER,
- VENDOR_ID_HARRIS,
- VENDOR_ID_HISENSE,
- 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_SONY,
- VENDOR_ID_SONY_ERICSSON,
- VENDOR_ID_T_AND_A,
- VENDOR_ID_TECHFAITH,
- VENDOR_ID_TELEEPOCH,
- VENDOR_ID_TI,
- VENDOR_ID_TOSHIBA,
- 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_vendors.h b/adb/usb_vendors.h
deleted file mode 100644
index cee23a1..0000000
--- a/adb/usb_vendors.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __USB_VENDORS_H
-#define __USB_VENDORS_H
-
-extern int vendorIds[];
-extern unsigned vendorIdCount;
-
-void usb_vendors_init(void);
-
-#endif
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index 1309a78..b7ad913 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <winsock2.h>
#include <windows.h>
#include <winerror.h>
#include <errno.h>
diff --git a/libnetd_client/Android.mk b/adf/libadf/tests/Android.mk
similarity index 73%
rename from libnetd_client/Android.mk
rename to adf/libadf/tests/Android.mk
index 2b75626..93efafa 100644
--- a/libnetd_client/Android.mk
+++ b/adf/libadf/tests/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2014 The Android Open Source Project
+#
+# 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.
@@ -11,12 +12,11 @@
# WITHOUT 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)
+#
+LOCAL_PATH := $(my-dir)
include $(CLEAR_VARS)
-
-LOCAL_MODULE := libnetd_client
-LOCAL_SRC_FILES := FwmarkClient.cpp NetdClient.cpp
-
-include $(BUILD_SHARED_LIBRARY)
+LOCAL_SRC_FILES := adf_test.cpp
+LOCAL_MODULE := adf-unit-tests
+LOCAL_STATIC_LIBRARIES := libadf
+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..d95330d
--- /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, 0);
+ EXPECT_LT(data.n_allowed_attachments, ADF_MAX_ATTACHMENTS);
+ EXPECT_LT(data.custom_data_size, 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, 0);
+ EXPECT_LT(data.custom_data_size, 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, 0);
+ EXPECT_LT(data.n_supported_formats, ADF_MAX_SUPPORTED_FORMATS);
+ EXPECT_LT(data.custom_data_size, 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/charger/Android.mk b/charger/Android.mk
deleted file mode 100644
index 40c7d78..0000000
--- a/charger/Android.mk
+++ /dev/null
@@ -1,61 +0,0 @@
-# Copyright 2011 The Android Open Source Project
-
-ifneq ($(BUILD_TINY_ANDROID),true)
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- charger.c
-
-ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
-LOCAL_CFLAGS := -DCHARGER_DISABLE_INIT_BLANK
-endif
-
-ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
-LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
-endif
-
-LOCAL_MODULE := charger
-LOCAL_MODULE_TAGS := optional
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
-LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
-
-LOCAL_C_INCLUDES := bootable/recovery
-
-LOCAL_STATIC_LIBRARIES := libminui libpng
-ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
-LOCAL_STATIC_LIBRARIES += libsuspend
-endif
-LOCAL_STATIC_LIBRARIES += libz libstdc++ libcutils liblog libm libc
-
-include $(BUILD_EXECUTABLE)
-
-define _add-charger-image
-include $$(CLEAR_VARS)
-LOCAL_MODULE := system_core_charger_$(notdir $(1))
-LOCAL_MODULE_STEM := $(notdir $(1))
-_img_modules += $$(LOCAL_MODULE)
-LOCAL_SRC_FILES := $1
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $$(TARGET_ROOT_OUT)/res/images/charger
-include $$(BUILD_PREBUILT)
-endef
-
-_img_modules :=
-_images :=
-$(foreach _img, $(call find-subdir-subdir-files, "images", "*.png"), \
- $(eval $(call _add-charger-image,$(_img))))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := charger_res_images
-LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := $(_img_modules)
-include $(BUILD_PHONY_PACKAGE)
-
-_add-charger-image :=
-_img_modules :=
-
-endif
diff --git a/charger/charger.c b/charger/charger.c
deleted file mode 100644
index e3cadb1..0000000
--- a/charger/charger.c
+++ /dev/null
@@ -1,1017 +0,0 @@
-/*
- * 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.
- */
-
-//#define DEBUG_UEVENTS
-#define CHARGER_KLOG_LEVEL 6
-
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/input.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/poll.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <sys/socket.h>
-#include <linux/netlink.h>
-
-#include <cutils/android_reboot.h>
-#include <cutils/klog.h>
-#include <cutils/list.h>
-#include <cutils/misc.h>
-#include <cutils/uevent.h>
-
-#ifdef CHARGER_ENABLE_SUSPEND
-#include <suspend/autosuspend.h>
-#endif
-
-#include "minui/minui.h"
-
-char *locale;
-
-#ifndef max
-#define max(a,b) ((a) > (b) ? (a) : (b))
-#endif
-
-#ifndef min
-#define min(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-
-#define MSEC_PER_SEC (1000LL)
-#define NSEC_PER_MSEC (1000000LL)
-
-#define BATTERY_UNKNOWN_TIME (2 * MSEC_PER_SEC)
-#define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC)
-#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
-
-#define BATTERY_FULL_THRESH 95
-
-#define LAST_KMSG_PATH "/proc/last_kmsg"
-#define LAST_KMSG_MAX_SZ (32 * 1024)
-
-#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
-#define LOGI(x...) do { KLOG_INFO("charger", x); } while (0)
-#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
-
-struct key_state {
- bool pending;
- bool down;
- int64_t timestamp;
-};
-
-struct power_supply {
- struct listnode list;
- char name[256];
- char type[32];
- bool online;
- bool valid;
- char cap_path[PATH_MAX];
-};
-
-struct frame {
- int disp_time;
- int min_capacity;
- bool level_only;
-
- gr_surface surface;
-};
-
-struct animation {
- bool run;
-
- struct frame *frames;
- int cur_frame;
- int num_frames;
-
- int cur_cycle;
- int num_cycles;
-
- /* current capacity being animated */
- int capacity;
-};
-
-struct charger {
- int64_t next_screen_transition;
- int64_t next_key_check;
- int64_t next_pwr_check;
-
- struct key_state keys[KEY_MAX + 1];
- int uevent_fd;
-
- struct listnode supplies;
- int num_supplies;
- int num_supplies_online;
-
- struct animation *batt_anim;
- gr_surface surf_unknown;
-
- struct power_supply *battery;
-};
-
-struct uevent {
- const char *action;
- const char *path;
- const char *subsystem;
- const char *ps_name;
- const char *ps_type;
- const char *ps_online;
-};
-
-static struct frame batt_anim_frames[] = {
- {
- .disp_time = 750,
- .min_capacity = 0,
- },
- {
- .disp_time = 750,
- .min_capacity = 20,
- },
- {
- .disp_time = 750,
- .min_capacity = 40,
- },
- {
- .disp_time = 750,
- .min_capacity = 60,
- },
- {
- .disp_time = 750,
- .min_capacity = 80,
- .level_only = true,
- },
- {
- .disp_time = 750,
- .min_capacity = BATTERY_FULL_THRESH,
- },
-};
-
-static struct animation battery_animation = {
- .frames = batt_anim_frames,
- .num_frames = ARRAY_SIZE(batt_anim_frames),
- .num_cycles = 3,
-};
-
-static struct charger charger_state = {
- .batt_anim = &battery_animation,
-};
-
-static int char_width;
-static int char_height;
-
-/* current time in milliseconds */
-static int64_t curr_time_ms(void)
-{
- struct timespec tm;
- clock_gettime(CLOCK_MONOTONIC, &tm);
- return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
-}
-
-static void clear_screen(void)
-{
- gr_color(0, 0, 0, 255);
- gr_clear();
-}
-
-#define MAX_KLOG_WRITE_BUF_SZ 256
-
-static void dump_last_kmsg(void)
-{
- char *buf;
- char *ptr;
- unsigned sz = 0;
- int len;
-
- LOGI("\n");
- LOGI("*************** LAST KMSG ***************\n");
- LOGI("\n");
- buf = load_file(LAST_KMSG_PATH, &sz);
- if (!buf || !sz) {
- LOGI("last_kmsg not found. Cold reset?\n");
- goto out;
- }
-
- len = min(sz, LAST_KMSG_MAX_SZ);
- ptr = buf + (sz - len);
-
- while (len > 0) {
- int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
- char yoink;
- char *nl;
-
- nl = memrchr(ptr, '\n', cnt - 1);
- if (nl)
- cnt = nl - ptr + 1;
-
- yoink = ptr[cnt];
- ptr[cnt] = '\0';
- klog_write(6, "<6>%s", ptr);
- ptr[cnt] = yoink;
-
- len -= cnt;
- ptr += cnt;
- }
-
- free(buf);
-
-out:
- LOGI("\n");
- LOGI("************* END LAST KMSG *************\n");
- LOGI("\n");
-}
-
-static int read_file(const char *path, char *buf, size_t sz)
-{
- int fd;
- size_t cnt;
-
- fd = open(path, O_RDONLY, 0);
- if (fd < 0)
- goto err;
-
- cnt = read(fd, buf, sz - 1);
- if (cnt <= 0)
- goto err;
- buf[cnt] = '\0';
- if (buf[cnt - 1] == '\n') {
- cnt--;
- buf[cnt] = '\0';
- }
-
- close(fd);
- return cnt;
-
-err:
- if (fd >= 0)
- close(fd);
- return -1;
-}
-
-static int read_file_int(const char *path, int *val)
-{
- char buf[32];
- int ret;
- int tmp;
- char *end;
-
- ret = read_file(path, buf, sizeof(buf));
- if (ret < 0)
- return -1;
-
- tmp = strtol(buf, &end, 0);
- if (end == buf ||
- ((end < buf+sizeof(buf)) && (*end != '\n' && *end != '\0')))
- goto err;
-
- *val = tmp;
- return 0;
-
-err:
- return -1;
-}
-
-static int get_battery_capacity(struct charger *charger)
-{
- int ret;
- int batt_cap = -1;
-
- if (!charger->battery)
- return -1;
-
- ret = read_file_int(charger->battery->cap_path, &batt_cap);
- if (ret < 0 || batt_cap > 100) {
- batt_cap = -1;
- }
-
- return batt_cap;
-}
-
-static struct power_supply *find_supply(struct charger *charger,
- const char *name)
-{
- struct listnode *node;
- struct power_supply *supply;
-
- list_for_each(node, &charger->supplies) {
- supply = node_to_item(node, struct power_supply, list);
- if (!strncmp(name, supply->name, sizeof(supply->name)))
- return supply;
- }
- return NULL;
-}
-
-static struct power_supply *add_supply(struct charger *charger,
- const char *name, const char *type,
- const char *path, bool online)
-{
- struct power_supply *supply;
-
- supply = calloc(1, sizeof(struct power_supply));
- if (!supply)
- return NULL;
-
- strlcpy(supply->name, name, sizeof(supply->name));
- strlcpy(supply->type, type, sizeof(supply->type));
- snprintf(supply->cap_path, sizeof(supply->cap_path),
- "/sys/%s/capacity", path);
- supply->online = online;
- list_add_tail(&charger->supplies, &supply->list);
- charger->num_supplies++;
- LOGV("... added %s %s %d\n", supply->name, supply->type, online);
- return supply;
-}
-
-static void remove_supply(struct charger *charger, struct power_supply *supply)
-{
- if (!supply)
- return;
- list_remove(&supply->list);
- charger->num_supplies--;
- free(supply);
-}
-
-#ifdef CHARGER_ENABLE_SUSPEND
-static int request_suspend(bool enable)
-{
- if (enable)
- return autosuspend_enable();
- else
- return autosuspend_disable();
-}
-#else
-static int request_suspend(bool enable)
-{
- return 0;
-}
-#endif
-
-static void parse_uevent(const char *msg, struct uevent *uevent)
-{
- uevent->action = "";
- uevent->path = "";
- uevent->subsystem = "";
- uevent->ps_name = "";
- uevent->ps_online = "";
- uevent->ps_type = "";
-
- /* currently ignoring SEQNUM */
- while (*msg) {
-#ifdef DEBUG_UEVENTS
- LOGV("uevent str: %s\n", msg);
-#endif
- if (!strncmp(msg, "ACTION=", 7)) {
- msg += 7;
- uevent->action = msg;
- } else if (!strncmp(msg, "DEVPATH=", 8)) {
- msg += 8;
- uevent->path = msg;
- } else if (!strncmp(msg, "SUBSYSTEM=", 10)) {
- msg += 10;
- uevent->subsystem = msg;
- } else if (!strncmp(msg, "POWER_SUPPLY_NAME=", 18)) {
- msg += 18;
- uevent->ps_name = msg;
- } else if (!strncmp(msg, "POWER_SUPPLY_ONLINE=", 20)) {
- msg += 20;
- uevent->ps_online = msg;
- } else if (!strncmp(msg, "POWER_SUPPLY_TYPE=", 18)) {
- msg += 18;
- uevent->ps_type = msg;
- }
-
- /* advance to after the next \0 */
- while (*msg++)
- ;
- }
-
- LOGV("event { '%s', '%s', '%s', '%s', '%s', '%s' }\n",
- uevent->action, uevent->path, uevent->subsystem,
- uevent->ps_name, uevent->ps_type, uevent->ps_online);
-}
-
-static void process_ps_uevent(struct charger *charger, struct uevent *uevent)
-{
- int online;
- char ps_type[32];
- struct power_supply *supply = NULL;
- int i;
- bool was_online = false;
- bool battery = false;
-
- if (uevent->ps_type[0] == '\0') {
- char *path;
- int ret;
-
- if (uevent->path[0] == '\0')
- return;
- ret = asprintf(&path, "/sys/%s/type", uevent->path);
- if (ret <= 0)
- return;
- ret = read_file(path, ps_type, sizeof(ps_type));
- free(path);
- if (ret < 0)
- return;
- } else {
- strlcpy(ps_type, uevent->ps_type, sizeof(ps_type));
- }
-
- if (!strncmp(ps_type, "Battery", 7))
- battery = true;
-
- online = atoi(uevent->ps_online);
- supply = find_supply(charger, uevent->ps_name);
- if (supply) {
- was_online = supply->online;
- supply->online = online;
- }
-
- if (!strcmp(uevent->action, "add")) {
- if (!supply) {
- supply = add_supply(charger, uevent->ps_name, ps_type, uevent->path,
- online);
- if (!supply) {
- LOGE("cannot add supply '%s' (%s %d)\n", uevent->ps_name,
- uevent->ps_type, online);
- return;
- }
- /* only pick up the first battery for now */
- if (battery && !charger->battery)
- charger->battery = supply;
- } else {
- LOGE("supply '%s' already exists..\n", uevent->ps_name);
- }
- } else if (!strcmp(uevent->action, "remove")) {
- if (supply) {
- if (charger->battery == supply)
- charger->battery = NULL;
- remove_supply(charger, supply);
- supply = NULL;
- }
- } else if (!strcmp(uevent->action, "change")) {
- if (!supply) {
- LOGE("power supply '%s' not found ('%s' %d)\n",
- uevent->ps_name, ps_type, online);
- return;
- }
- } else {
- return;
- }
-
- /* allow battery to be managed in the supply list but make it not
- * contribute to online power supplies. */
- if (!battery) {
- if (was_online && !online)
- charger->num_supplies_online--;
- else if (supply && !was_online && online)
- charger->num_supplies_online++;
- }
-
- LOGI("power supply %s (%s) %s (action=%s num_online=%d num_supplies=%d)\n",
- uevent->ps_name, ps_type, battery ? "" : online ? "online" : "offline",
- uevent->action, charger->num_supplies_online, charger->num_supplies);
-}
-
-static void process_uevent(struct charger *charger, struct uevent *uevent)
-{
- if (!strcmp(uevent->subsystem, "power_supply"))
- process_ps_uevent(charger, uevent);
-}
-
-#define UEVENT_MSG_LEN 1024
-static int handle_uevent_fd(struct charger *charger, int fd)
-{
- char msg[UEVENT_MSG_LEN+2];
- int n;
-
- if (fd < 0)
- return -1;
-
- while (true) {
- struct uevent uevent;
-
- n = uevent_kernel_multicast_recv(fd, msg, UEVENT_MSG_LEN);
- if (n <= 0)
- break;
- if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
- continue;
-
- msg[n] = '\0';
- msg[n+1] = '\0';
-
- parse_uevent(msg, &uevent);
- process_uevent(charger, &uevent);
- }
-
- return 0;
-}
-
-static int uevent_callback(int fd, short revents, void *data)
-{
- struct charger *charger = data;
-
- if (!(revents & POLLIN))
- return -1;
- return handle_uevent_fd(charger, fd);
-}
-
-/* force the kernel to regenerate the change events for the existing
- * devices, if valid */
-static void do_coldboot(struct charger *charger, DIR *d, const char *event,
- bool follow_links, int max_depth)
-{
- struct dirent *de;
- int dfd, fd;
-
- dfd = dirfd(d);
-
- fd = openat(dfd, "uevent", O_WRONLY);
- if (fd >= 0) {
- write(fd, event, strlen(event));
- close(fd);
- handle_uevent_fd(charger, charger->uevent_fd);
- }
-
- while ((de = readdir(d)) && max_depth > 0) {
- DIR *d2;
-
- LOGV("looking at '%s'\n", de->d_name);
-
- if ((de->d_type != DT_DIR && !(de->d_type == DT_LNK && follow_links)) ||
- de->d_name[0] == '.') {
- LOGV("skipping '%s' type %d (depth=%d follow=%d)\n",
- de->d_name, de->d_type, max_depth, follow_links);
- continue;
- }
- LOGV("can descend into '%s'\n", de->d_name);
-
- fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
- if (fd < 0) {
- LOGE("cannot openat %d '%s' (%d: %s)\n", dfd, de->d_name,
- errno, strerror(errno));
- continue;
- }
-
- d2 = fdopendir(fd);
- if (d2 == 0)
- close(fd);
- else {
- LOGV("opened '%s'\n", de->d_name);
- do_coldboot(charger, d2, event, follow_links, max_depth - 1);
- closedir(d2);
- }
- }
-}
-
-static void coldboot(struct charger *charger, const char *path,
- const char *event)
-{
- char str[256];
-
- LOGV("doing coldboot '%s' in '%s'\n", event, path);
- DIR *d = opendir(path);
- if (d) {
- snprintf(str, sizeof(str), "%s\n", event);
- do_coldboot(charger, d, str, true, 1);
- closedir(d);
- }
-}
-
-static int draw_text(const char *str, int x, int y)
-{
- int str_len_px = gr_measure(str);
-
- if (x < 0)
- x = (gr_fb_width() - str_len_px) / 2;
- if (y < 0)
- y = (gr_fb_height() - char_height) / 2;
- gr_text(x, y, str, 0);
-
- return y + char_height;
-}
-
-static void android_green(void)
-{
- gr_color(0xa4, 0xc6, 0x39, 255);
-}
-
-/* returns the last y-offset of where the surface ends */
-static int draw_surface_centered(struct charger *charger, gr_surface surface)
-{
- int w;
- int h;
- int x;
- int y;
-
- w = gr_get_width(surface);
- h = gr_get_height(surface);
- x = (gr_fb_width() - w) / 2 ;
- y = (gr_fb_height() - h) / 2 ;
-
- LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
- gr_blit(surface, 0, 0, w, h, x, y);
- return y + h;
-}
-
-static void draw_unknown(struct charger *charger)
-{
- int y;
- if (charger->surf_unknown) {
- draw_surface_centered(charger, charger->surf_unknown);
- } else {
- android_green();
- y = draw_text("Charging!", -1, -1);
- draw_text("?\?/100", -1, y + 25);
- }
-}
-
-static void draw_battery(struct charger *charger)
-{
- struct animation *batt_anim = charger->batt_anim;
- struct frame *frame = &batt_anim->frames[batt_anim->cur_frame];
-
- if (batt_anim->num_frames != 0) {
- draw_surface_centered(charger, frame->surface);
- LOGV("drawing frame #%d min_cap=%d time=%d\n",
- batt_anim->cur_frame, frame->min_capacity,
- frame->disp_time);
- }
-}
-
-static void redraw_screen(struct charger *charger)
-{
- struct animation *batt_anim = charger->batt_anim;
-
- clear_screen();
-
- /* try to display *something* */
- if (batt_anim->capacity < 0 || batt_anim->num_frames == 0)
- draw_unknown(charger);
- else
- draw_battery(charger);
- gr_flip();
-}
-
-static void kick_animation(struct animation *anim)
-{
- anim->run = true;
-}
-
-static void reset_animation(struct animation *anim)
-{
- anim->cur_cycle = 0;
- anim->cur_frame = 0;
- anim->run = false;
-}
-
-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)
- return;
-
- /* animation is over, blank screen and leave */
- if (batt_anim->cur_cycle == batt_anim->num_cycles) {
- reset_animation(batt_anim);
- charger->next_screen_transition = -1;
- gr_fb_blank(true);
- LOGV("[%lld] animation done\n", now);
- if (charger->num_supplies_online > 0)
- request_suspend(true);
- return;
- }
-
- disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time;
-
- /* animation starting, set up the animation */
- if (batt_anim->cur_frame == 0) {
- int batt_cap;
- int ret;
-
- LOGV("[%lld] animation starting\n", now);
- batt_cap = get_battery_capacity(charger);
- if (batt_cap >= 0 && batt_anim->num_frames != 0) {
- int i;
-
- /* find first frame given current capacity */
- for (i = 1; i < batt_anim->num_frames; i++) {
- if (batt_cap < batt_anim->frames[i].min_capacity)
- break;
- }
- batt_anim->cur_frame = i - 1;
-
- /* show the first frame for twice as long */
- disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2;
- }
-
- batt_anim->capacity = batt_cap;
- }
-
- /* unblank the screen on first cycle */
- if (batt_anim->cur_cycle == 0)
- gr_fb_blank(false);
-
- /* draw the new frame (@ cur_frame) */
- redraw_screen(charger);
-
- /* if we don't have anim frames, we only have one image, so just bump
- * the cycle counter and exit
- */
- if (batt_anim->num_frames == 0 || batt_anim->capacity < 0) {
- LOGV("[%lld] animation missing or unknown battery status\n", now);
- charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;
- batt_anim->cur_cycle++;
- return;
- }
-
- /* schedule next screen transition */
- charger->next_screen_transition = now + disp_time;
-
- /* advance frame cntr to the next valid frame
- * if necessary, advance cycle cntr, and reset frame cntr
- */
- batt_anim->cur_frame++;
-
- /* if the frame is used for level-only, that is only show it when it's
- * the current level, skip it during the animation.
- */
- while (batt_anim->cur_frame < batt_anim->num_frames &&
- batt_anim->frames[batt_anim->cur_frame].level_only)
- batt_anim->cur_frame++;
- if (batt_anim->cur_frame >= batt_anim->num_frames) {
- batt_anim->cur_cycle++;
- batt_anim->cur_frame = 0;
-
- /* don't reset the cycle counter, since we use that as a signal
- * in a test above to check if animation is over
- */
- }
-}
-
-static int set_key_callback(int code, int value, void *data)
-{
- struct charger *charger = data;
- int64_t now = curr_time_ms();
- int down = !!value;
-
- if (code > KEY_MAX)
- return -1;
-
- /* ignore events that don't modify our state */
- if (charger->keys[code].down == down)
- return 0;
-
- /* only record the down even timestamp, as the amount
- * of time the key spent not being pressed is not useful */
- if (down)
- charger->keys[code].timestamp = now;
- charger->keys[code].down = down;
- charger->keys[code].pending = true;
- if (down) {
- LOGV("[%lld] key[%d] down\n", now, code);
- } else {
- int64_t duration = now - charger->keys[code].timestamp;
- int64_t secs = duration / 1000;
- int64_t msecs = duration - secs * 1000;
- LOGV("[%lld] key[%d] up (was down for %lld.%lldsec)\n", now,
- code, secs, msecs);
- }
-
- return 0;
-}
-
-static void update_input_state(struct charger *charger,
- struct input_event *ev)
-{
- if (ev->type != EV_KEY)
- return;
- set_key_callback(ev->code, ev->value, charger);
-}
-
-static void set_next_key_check(struct charger *charger,
- struct key_state *key,
- int64_t timeout)
-{
- int64_t then = key->timestamp + timeout;
-
- if (charger->next_key_check == -1 || then < charger->next_key_check)
- charger->next_key_check = then;
-}
-
-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) {
- int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
- if (now >= reboot_timeout) {
- LOGI("[%lld] rebooting\n", now);
- android_reboot(ANDROID_RB_RESTART, 0, 0);
- } else {
- /* if the key is pressed but timeout hasn't expired,
- * make sure we wake up at the right-ish time to check
- */
- set_next_key_check(charger, key, POWER_ON_KEY_TIME);
- }
- } else {
- /* if the power key got released, force screen state cycle */
- if (key->pending) {
- request_suspend(false);
- kick_animation(charger->batt_anim);
- }
- }
- }
-
- key->pending = false;
-}
-
-static void handle_input_state(struct charger *charger, int64_t now)
-{
- process_key(charger, KEY_POWER, now);
-
- if (charger->next_key_check != -1 && now > charger->next_key_check)
- charger->next_key_check = -1;
-}
-
-static void handle_power_supply_state(struct charger *charger, int64_t now)
-{
- if (charger->num_supplies_online == 0) {
- request_suspend(false);
- if (charger->next_pwr_check == -1) {
- charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
- LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld)\n",
- now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
- } else if (now >= charger->next_pwr_check) {
- LOGI("[%lld] shutting down\n", now);
- android_reboot(ANDROID_RB_POWEROFF, 0, 0);
- } else {
- /* otherwise we already have a shutdown timer scheduled */
- }
- } else {
- /* online supply present, reset shutdown timer if set */
- if (charger->next_pwr_check != -1) {
- LOGI("[%lld] device plugged in: shutdown cancelled\n", now);
- kick_animation(charger->batt_anim);
- }
- charger->next_pwr_check = -1;
- }
-}
-
-static void wait_next_event(struct charger *charger, int64_t now)
-{
- int64_t next_event = INT64_MAX;
- int64_t timeout;
- struct input_event ev;
- int ret;
-
- LOGV("[%lld] next screen: %lld next key: %lld next pwr: %lld\n", now,
- charger->next_screen_transition, charger->next_key_check,
- charger->next_pwr_check);
-
- if (charger->next_screen_transition != -1)
- next_event = charger->next_screen_transition;
- if (charger->next_key_check != -1 && charger->next_key_check < next_event)
- next_event = charger->next_key_check;
- if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
- next_event = charger->next_pwr_check;
-
- if (next_event != -1 && next_event != INT64_MAX)
- timeout = max(0, next_event - now);
- else
- timeout = -1;
- LOGV("[%lld] blocking (%lld)\n", now, timeout);
- ret = ev_wait((int)timeout);
- if (!ret)
- ev_dispatch();
-}
-
-static int input_callback(int fd, short revents, void *data)
-{
- struct charger *charger = data;
- struct input_event ev;
- int ret;
-
- ret = ev_get_input(fd, revents, &ev);
- if (ret)
- return -1;
- update_input_state(charger, &ev);
- return 0;
-}
-
-static void event_loop(struct charger *charger)
-{
- int ret;
-
- while (true) {
- int64_t now = curr_time_ms();
-
- LOGV("[%lld] event_loop()\n", now);
- handle_input_state(charger, now);
- handle_power_supply_state(charger, now);
-
- /* do screen update last in case any of the above want to start
- * screen transitions (animations, etc)
- */
- update_screen_state(charger, now);
-
- wait_next_event(charger, now);
- }
-}
-
-int main(int argc, char **argv)
-{
- int ret;
- struct charger *charger = &charger_state;
- int64_t now = curr_time_ms() - 1;
- int fd;
- int i;
-
- list_init(&charger->supplies);
-
- klog_init();
- klog_set_level(CHARGER_KLOG_LEVEL);
-
- dump_last_kmsg();
-
- LOGI("--------------- STARTING CHARGER MODE ---------------\n");
-
- gr_init();
- gr_font_size(&char_width, &char_height);
-
- ev_init(input_callback, charger);
-
- fd = uevent_open_socket(64*1024, true);
- if (fd >= 0) {
- fcntl(fd, F_SETFL, O_NONBLOCK);
- ev_add_fd(fd, uevent_callback, charger);
- }
- charger->uevent_fd = fd;
- coldboot(charger, "/sys/class/power_supply", "add");
-
- ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
- if (ret < 0) {
- LOGE("Cannot load battery_fail image\n");
- charger->surf_unknown = NULL;
- }
-
- charger->batt_anim = &battery_animation;
-
- gr_surface* scale_frames;
- int scale_count;
- ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames);
- if (ret < 0) {
- LOGE("Cannot load battery_scale image\n");
- charger->batt_anim->num_frames = 0;
- charger->batt_anim->num_cycles = 1;
- } else if (scale_count != charger->batt_anim->num_frames) {
- LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
- scale_count, charger->batt_anim->num_frames);
- charger->batt_anim->num_frames = 0;
- charger->batt_anim->num_cycles = 1;
- } else {
- for (i = 0; i < charger->batt_anim->num_frames; i++) {
- charger->batt_anim->frames[i].surface = scale_frames[i];
- }
- }
-
- ev_sync_key_state(set_key_callback, charger);
-
-#ifndef CHARGER_DISABLE_INIT_BLANK
- gr_fb_blank(true);
-#endif
-
- charger->next_screen_transition = now - 1;
- charger->next_key_check = -1;
- charger->next_pwr_check = -1;
- reset_animation(charger->batt_anim);
- kick_animation(charger->batt_anim);
-
- event_loop(charger);
-
- return 0;
-}
diff --git a/cpio/Android.mk b/cpio/Android.mk
index 5184463..575beb2 100644
--- a/cpio/Android.mk
+++ b/cpio/Android.mk
@@ -8,6 +8,8 @@
LOCAL_MODULE := mkbootfs
+LOCAL_CFLAGS := -Werror
+
include $(BUILD_HOST_EXECUTABLE)
$(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE))
diff --git a/cpio/mkbootfs.c b/cpio/mkbootfs.c
index 7d3740c..7175749 100644
--- a/cpio/mkbootfs.c
+++ b/cpio/mkbootfs.c
@@ -78,8 +78,9 @@
s->st_mode = empty_path_config->mode | (s->st_mode & ~07777);
} else {
// Use the compiled-in fs_config() function.
-
- fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode, &capabilities);
+ unsigned st_mode = s->st_mode;
+ fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &st_mode, &capabilities);
+ s->st_mode = (typeof(s->st_mode)) st_mode;
}
}
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 8be3541..1b8b98d 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -3,53 +3,47 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- backtrace.cpp \
- debuggerd.cpp \
- getevent.cpp \
- tombstone.cpp \
- utility.cpp \
+ backtrace.cpp \
+ debuggerd.cpp \
+ getevent.cpp \
+ tombstone.cpp \
+ utility.cpp \
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_x86 := x86/machine.cpp
LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp
-LOCAL_CONLYFLAGS := -std=gnu99
-LOCAL_CPPFLAGS := -std=gnu++11
-LOCAL_CFLAGS := \
- -Wall \
- -Wno-array-bounds \
- -Werror
-
-ifeq ($(ARCH_ARM_HAVE_VFP),true)
-LOCAL_CFLAGS_arm += -DWITH_VFP
-endif # ARCH_ARM_HAVE_VFP
-ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
-LOCAL_CFLAGS_arm += -DWITH_VFP_D32
-endif # ARCH_ARM_HAVE_VFP_D32
+LOCAL_CPPFLAGS := \
+ -std=gnu++11 \
+ -W -Wall -Wextra \
+ -Wunused \
+ -Werror \
LOCAL_SHARED_LIBRARIES := \
- libbacktrace \
- libc \
- libcutils \
- liblog \
- libselinux \
-
-include external/stlport/libstlport.mk
+ libbacktrace \
+ libcutils \
+ liblog \
+ libselinux \
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)
+
+
include $(CLEAR_VARS)
LOCAL_SRC_FILES := crasher.c
LOCAL_SRC_FILES_arm := arm/crashglue.S
LOCAL_SRC_FILES_arm64 := arm64/crashglue.S
LOCAL_SRC_FILES_mips := mips/crashglue.S
+LOCAL_SRC_FILES_mips64 := mips/crashglue.S
LOCAL_SRC_FILES_x86 := x86/crashglue.S
LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
@@ -58,36 +52,14 @@
#LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_SHARED_LIBRARIES := libcutils liblog libc
+# The arm emulator has VFP but not VFPv3-D32.
+ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
+LOCAL_ASFLAGS_arm += -DHAS_VFP_D32
+endif
+
LOCAL_MODULE := crasher
LOCAL_MODULE_STEM_32 := crasher
LOCAL_MODULE_STEM_64 := crasher64
LOCAL_MULTILIB := both
include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-ifeq ($(ARCH_ARM_HAVE_VFP),true)
-LOCAL_MODULE_TARGET_ARCH += arm
-LOCAL_SRC_FILES_arm := arm/vfp.S
-LOCAL_CFLAGS_arm += -DWITH_VFP
-ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
-LOCAL_CFLAGS_arm += -DWITH_VFP_D32
-endif # ARCH_ARM_HAVE_VFP_D32
-endif # ARCH_ARM_HAVE_VFP == true
-LOCAL_CFLAGS += -Werror
-
-LOCAL_SRC_FILES_arm64 := arm64/vfp.S
-LOCAL_MODULE_TARGET_ARCH += arm64
-
-LOCAL_SRC_FILES := vfp-crasher.c
-LOCAL_MODULE := vfp-crasher
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := optional
-LOCAL_SHARED_LIBRARIES := libcutils liblog libc
-
-LOCAL_MODULE_STEM_32 := vfp-crasher
-LOCAL_MODULE_STEM_64 := vfp-crasher64
-LOCAL_MULTILIB := both
-
-include $(BUILD_EXECUTABLE)
diff --git a/debuggerd/arm/crashglue.S b/debuggerd/arm/crashglue.S
index eb9d0e3..4fbfd6e 100644
--- a/debuggerd/arm/crashglue.S
+++ b/debuggerd/arm/crashglue.S
@@ -1,8 +1,5 @@
.globl crash1
.type crash1, %function
-.globl crashnostack
-.type crashnostack, %function
-
crash1:
ldr r0, =0xa5a50000
ldr r1, =0xa5a50001
@@ -18,11 +15,48 @@
ldr r11, =0xa5a50011
ldr r12, =0xa5a50012
+
+ fconstd d0, #0
+ fconstd d1, #1
+ fconstd d2, #2
+ fconstd d3, #3
+ fconstd d4, #4
+ fconstd d5, #5
+ fconstd d6, #6
+ fconstd d7, #7
+ fconstd d8, #8
+ fconstd d9, #9
+ fconstd d10, #10
+ fconstd d11, #11
+ fconstd d12, #12
+ fconstd d13, #13
+ fconstd d14, #14
+ fconstd d15, #15
+#if defined(HAS_VFP_D32)
+ fconstd d16, #16
+ fconstd d17, #17
+ fconstd d18, #18
+ fconstd d19, #19
+ fconstd d20, #20
+ fconstd d21, #21
+ fconstd d22, #22
+ fconstd d23, #23
+ fconstd d24, #24
+ fconstd d25, #25
+ fconstd d26, #26
+ fconstd d27, #27
+ fconstd d28, #28
+ fconstd d29, #29
+ fconstd d30, #30
+ fconstd d31, #31
+#endif
+
mov lr, #0
ldr lr, [lr]
b .
-
+.globl crashnostack
+.type crashnostack, %function
crashnostack:
mov sp, #0
mov r0, #0
diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp
index fd2f69b..50e78c5 100644
--- a/debuggerd/arm/machine.cpp
+++ b/debuggerd/arm/machine.cpp
@@ -27,87 +27,68 @@
#include "../utility.h"
#include "../machine.h"
-// enable to dump memory pointed to by every register
-#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
-
-#ifdef WITH_VFP
-#ifdef WITH_VFP_D32
-#define NUM_VFP_REGS 32
-#else
-#define NUM_VFP_REGS 16
-#endif
-#endif
-
-// 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, int scope_flags) {
- struct pt_regs regs;
+void dump_memory_and_code(log_t* log, pid_t tid) {
+ pt_regs regs;
if (ptrace(PTRACE_GETREGS, tid, 0, ®s)) {
return;
}
- if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
- static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
+ static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
- for (int reg = 0; reg < 14; reg++) {
- // this may not be a valid way to access, but it'll do for now
- uintptr_t addr = regs.uregs[reg];
+ for (int reg = 0; reg < 14; reg++) {
+ // this may not be a valid way to access, but it'll do for now
+ uintptr_t addr = regs.uregs[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 >= 0xc0000000) {
- continue;
- }
-
- _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
- dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
+ // Don't bother if it looks like a small int or ~= null, or if
+ // it's in the kernel area.
+ if (addr < 4096 || addr >= 0xc0000000) {
+ continue;
}
+
+ _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
+ dump_memory(log, tid, addr);
}
// explicitly allow upload of code dump logging
- _LOG(log, scope_flags, "\ncode around pc:\n");
- dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc), scope_flags);
+ _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
+ dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc));
if (regs.ARM_pc != regs.ARM_lr) {
- _LOG(log, scope_flags, "\ncode around lr:\n");
- dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr), scope_flags);
+ _LOG(log, logtype::MEMORY, "\ncode around lr:\n");
+ dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr));
}
}
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
- struct pt_regs r;
+void dump_registers(log_t* log, pid_t tid) {
+ pt_regs r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
- _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+ _LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
return;
}
- _LOG(log, scope_flags, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
+ _LOG(log, logtype::REGISTERS, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
static_cast<uint32_t>(r.ARM_r0), static_cast<uint32_t>(r.ARM_r1),
static_cast<uint32_t>(r.ARM_r2), static_cast<uint32_t>(r.ARM_r3));
- _LOG(log, scope_flags, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
+ _LOG(log, logtype::REGISTERS, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
static_cast<uint32_t>(r.ARM_r4), static_cast<uint32_t>(r.ARM_r5),
static_cast<uint32_t>(r.ARM_r6), static_cast<uint32_t>(r.ARM_r7));
- _LOG(log, scope_flags, " r8 %08x r9 %08x sl %08x fp %08x\n",
+ _LOG(log, logtype::REGISTERS, " r8 %08x r9 %08x sl %08x fp %08x\n",
static_cast<uint32_t>(r.ARM_r8), static_cast<uint32_t>(r.ARM_r9),
static_cast<uint32_t>(r.ARM_r10), static_cast<uint32_t>(r.ARM_fp));
- _LOG(log, scope_flags, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
+ _LOG(log, logtype::REGISTERS, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
static_cast<uint32_t>(r.ARM_ip), static_cast<uint32_t>(r.ARM_sp),
static_cast<uint32_t>(r.ARM_lr), static_cast<uint32_t>(r.ARM_pc),
static_cast<uint32_t>(r.ARM_cpsr));
-#ifdef WITH_VFP
- struct user_vfp vfp_regs;
- int i;
-
+ user_vfp vfp_regs;
if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
- _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+ _LOG(log, logtype::FP_REGISTERS, "cannot get FP registers: %s\n", strerror(errno));
return;
}
- for (i = 0; i < NUM_VFP_REGS; i += 2) {
- _LOG(log, scope_flags, " d%-2d %016llx d%-2d %016llx\n",
+ for (size_t i = 0; i < 32; i += 2) {
+ _LOG(log, logtype::FP_REGISTERS, " d%-2d %016llx d%-2d %016llx\n",
i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
}
- _LOG(log, scope_flags, " scr %08lx\n", vfp_regs.fpscr);
-#endif
+ _LOG(log, logtype::FP_REGISTERS, " scr %08lx\n", vfp_regs.fpscr);
}
diff --git a/debuggerd/arm/vfp.S b/debuggerd/arm/vfp.S
deleted file mode 100644
index 9744f6f..0000000
--- a/debuggerd/arm/vfp.S
+++ /dev/null
@@ -1,43 +0,0 @@
- .text
- .align 2
- .global crash
- .type crash, %function
-crash:
- fconstd d0, #0
- fconstd d1, #1
- fconstd d2, #2
- fconstd d3, #3
- fconstd d4, #4
- fconstd d5, #5
- fconstd d6, #6
- fconstd d7, #7
- fconstd d8, #8
- fconstd d9, #9
- fconstd d10, #10
- fconstd d11, #11
- fconstd d12, #12
- fconstd d13, #13
- fconstd d14, #14
- fconstd d15, #15
-#ifdef WITH_VFP_D32
- fconstd d16, #16
- fconstd d17, #17
- fconstd d18, #18
- fconstd d19, #19
- fconstd d20, #20
- fconstd d21, #21
- fconstd d22, #22
- fconstd d23, #23
- fconstd d24, #24
- fconstd d25, #25
- fconstd d26, #26
- fconstd d27, #27
- fconstd d28, #28
- fconstd d29, #29
- fconstd d30, #30
- fconstd d31, #31
-#endif
- mov r0, #0
- str r0, [r0]
- bx lr
-
diff --git a/debuggerd/arm64/crashglue.S b/debuggerd/arm64/crashglue.S
index b06b67c..e58b542 100644
--- a/debuggerd/arm64/crashglue.S
+++ b/debuggerd/arm64/crashglue.S
@@ -1,8 +1,5 @@
.globl crash1
.type crash1, %function
-.globl crashnostack
-.type crashnostack, %function
-
crash1:
ldr x0, =0xa5a50000
ldr x1, =0xa5a50001
@@ -35,11 +32,46 @@
ldr x28, =0xa5a50028
ldr x29, =0xa5a50029
+ fmov d0, -1.0 // -1 is more convincing than 0.
+ fmov d1, 1.0
+ fmov d2, 2.0
+ fmov d3, 3.0
+ fmov d4, 4.0
+ fmov d5, 5.0
+ fmov d6, 6.0
+ fmov d7, 7.0
+ fmov d8, 8.0
+ fmov d9, 9.0
+ fmov d10, 10.0
+ fmov d11, 11.0
+ fmov d12, 12.0
+ fmov d13, 13.0
+ fmov d14, 14.0
+ fmov d15, 15.0
+ fmov d16, 16.0
+ fmov d17, 17.0
+ fmov d18, 18.0
+ fmov d19, 19.0
+ fmov d20, 20.0
+ fmov d21, 21.0
+ fmov d22, 22.0
+ fmov d23, 23.0
+ fmov d24, 24.0
+ fmov d25, 25.0
+ fmov d26, 26.0
+ fmov d27, 27.0
+ fmov d28, 28.0
+ fmov d29, 29.0
+ fmov d30, 30.0
+ fmov d31, 31.0
+
mov x30, xzr
ldr x30, [x30]
b .
+.globl crashnostack
+.type crashnostack, %function
crashnostack:
mov x0, xzr
add sp, x0, xzr
diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/arm64/machine.cpp
index 2413d5e..8b17d53 100644
--- a/debuggerd/arm64/machine.cpp
+++ b/debuggerd/arm64/machine.cpp
@@ -15,107 +15,98 @@
* limitations under the License.
*/
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdio.h>
+#include <elf.h>
#include <errno.h>
+#include <inttypes.h>
+#include <string.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/uio.h>
-#include <linux/elf.h>
#include "../utility.h"
#include "../machine.h"
-/* enable to dump memory pointed to by every register */
-#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
-
-/*
- * 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, int scope_flags) {
+void dump_memory_and_code(log_t* log, pid_t tid) {
struct user_pt_regs regs;
struct iovec io;
io.iov_base = ®s;
io.iov_len = sizeof(regs);
if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, &io) == -1) {
- _LOG(log, scope_flags, "%s: ptrace failed to get registers: %s\n",
+ _LOG(log, logtype::ERROR, "%s: ptrace failed to get registers: %s\n",
__func__, strerror(errno));
return;
}
- if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
- for (int reg = 0; reg < 31; reg++) {
- uintptr_t addr = regs.regs[reg];
+ for (int reg = 0; reg < 31; reg++) {
+ uintptr_t addr = regs.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 >= (1UL<<63)) {
- continue;
- }
-
- _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near x%d:\n", reg);
- dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
+ /*
+ * Don't bother if it looks like a small int or ~= null, or if
+ * it's in the kernel area.
+ */
+ if (addr < 4096 || addr >= (1UL<<63)) {
+ continue;
}
+
+ _LOG(log, logtype::MEMORY, "\nmemory near x%d:\n", reg);
+ dump_memory(log, tid, addr);
}
- _LOG(log, scope_flags, "\ncode around pc:\n");
- dump_memory(log, tid, (uintptr_t)regs.pc, scope_flags);
+ _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
+ dump_memory(log, tid, (uintptr_t)regs.pc);
if (regs.pc != regs.sp) {
- _LOG(log, scope_flags, "\ncode around sp:\n");
- dump_memory(log, tid, (uintptr_t)regs.sp, scope_flags);
+ _LOG(log, logtype::MEMORY, "\ncode around sp:\n");
+ dump_memory(log, tid, (uintptr_t)regs.sp);
}
}
-void dump_registers(log_t* log, pid_t tid, int scope_flags)
-{
+void dump_registers(log_t* log, pid_t tid) {
struct user_pt_regs r;
struct iovec io;
io.iov_base = &r;
io.iov_len = sizeof(r);
if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRSTATUS, (void*) &io) == -1) {
- _LOG(log, scope_flags, "ptrace error: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno));
return;
}
for (int i = 0; i < 28; i += 4) {
- _LOG(log, scope_flags, " x%-2d %016lx x%-2d %016lx x%-2d %016lx x%-2d %016lx\n",
- i, (uint64_t)r.regs[i],
- i+1, (uint64_t)r.regs[i+1],
- i+2, (uint64_t)r.regs[i+2],
- i+3, (uint64_t)r.regs[i+3]);
+ _LOG(log, logtype::REGISTERS,
+ " x%-2d %016llx x%-2d %016llx x%-2d %016llx x%-2d %016llx\n",
+ i, r.regs[i],
+ i+1, r.regs[i+1],
+ i+2, r.regs[i+2],
+ i+3, r.regs[i+3]);
}
- _LOG(log, scope_flags, " x28 %016lx x29 %016lx x30 %016lx\n",
- (uint64_t)r.regs[28], (uint64_t)r.regs[29], (uint64_t)r.regs[30]);
+ _LOG(log, logtype::REGISTERS, " x28 %016llx x29 %016llx x30 %016llx\n",
+ r.regs[28], r.regs[29], r.regs[30]);
- _LOG(log, scope_flags, " sp %016lx pc %016lx\n",
- (uint64_t)r.sp, (uint64_t)r.pc);
-
+ _LOG(log, logtype::REGISTERS, " sp %016llx pc %016llx pstate %016llx\n",
+ r.sp, r.pc, r.pstate);
struct user_fpsimd_state f;
io.iov_base = &f;
io.iov_len = sizeof(f);
if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRFPREG, (void*) &io) == -1) {
- _LOG(log, scope_flags, "ptrace error: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno));
return;
}
- for (int i = 0; i < 32; i += 4) {
- _LOG(log, scope_flags, " v%-2d %016lx v%-2d %016lx v%-2d %016lx v%-2d %016lx\n",
- i, (uint64_t)f.vregs[i],
- i+1, (uint64_t)f.vregs[i+1],
- i+2, (uint64_t)f.vregs[i+2],
- i+3, (uint64_t)f.vregs[i+3]);
+ for (int i = 0; i < 32; i += 2) {
+ _LOG(log, logtype::FP_REGISTERS,
+ " v%-2d %016" PRIx64 "%016" PRIx64 " v%-2d %016" PRIx64 "%016" PRIx64 "\n",
+ i,
+ static_cast<uint64_t>(f.vregs[i] >> 64),
+ static_cast<uint64_t>(f.vregs[i]),
+ i+1,
+ static_cast<uint64_t>(f.vregs[i+1] >> 64),
+ static_cast<uint64_t>(f.vregs[i+1]));
}
+ _LOG(log, logtype::FP_REGISTERS, " fpsr %08x fpcr %08x\n", f.fpsr, f.fpcr);
}
diff --git a/debuggerd/arm64/vfp.S b/debuggerd/arm64/vfp.S
deleted file mode 100644
index bf12c22..0000000
--- a/debuggerd/arm64/vfp.S
+++ /dev/null
@@ -1,42 +0,0 @@
- .text
- .align 2
- .global crash
- .type crash, %function
-crash:
- fmov d0, XZR
- fmov d1, 1.0
- fmov d2, 2.0
- fmov d3, 3.0
- fmov d4, 4.0
- fmov d5, 5.0
- fmov d6, 6.0
- fmov d7, 7.0
- fmov d8, 8.0
- fmov d9, 9.0
- fmov d10, 10.0
- fmov d11, 11.0
- fmov d12, 12.0
- fmov d13, 13.0
- fmov d14, 14.0
- fmov d15, 15.0
- fmov d16, 16.0
- fmov d17, 17.0
- fmov d18, 18.0
- fmov d19, 19.0
- fmov d20, 20.0
- fmov d21, 21.0
- fmov d22, 22.0
- fmov d23, 23.0
- fmov d24, 24.0
- fmov d25, 25.0
- fmov d26, 26.0
- fmov d27, 27.0
- fmov d28, 28.0
- fmov d29, 29.0
- fmov d30, 30.0
- fmov d31, 31.0
-
- mov x0, xzr
- str x0, [x0]
- br x30
-
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index d388348..c2a1dbc 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -30,6 +30,7 @@
#include <UniquePtr.h>
#include "backtrace.h"
+
#include "utility.h"
static void dump_process_header(log_t* log, pid_t pid) {
@@ -49,15 +50,16 @@
localtime_r(&t, &tm);
char timestr[64];
strftime(timestr, sizeof(timestr), "%F %T", &tm);
- _LOG(log, SCOPE_AT_FAULT, "\n\n----- pid %d at %s -----\n", pid, timestr);
+ _LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, timestr);
if (procname) {
- _LOG(log, SCOPE_AT_FAULT, "Cmd line: %s\n", procname);
+ _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", procname);
}
+ _LOG(log, logtype::BACKTRACE, "ABI: '%s'\n", ABI_STRING);
}
static void dump_process_footer(log_t* log, pid_t pid) {
- _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid);
+ _LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid);
}
static void dump_thread(
@@ -79,22 +81,24 @@
}
}
- _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
+ _LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
- _LOG(log, SCOPE_AT_FAULT, "Could not attach to thread: %s\n", strerror(errno));
+ _LOG(log, logtype::BACKTRACE, "Could not attach to thread: %s\n", strerror(errno));
return;
}
- wait_for_stop(tid, total_sleep_time_usec);
+ if (!attached && wait_for_sigstop(tid, total_sleep_time_usec, detach_failed) == -1) {
+ return;
+ }
UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
if (backtrace->Unwind(0)) {
- dump_backtrace_to_log(backtrace.get(), log, SCOPE_AT_FAULT, " ");
+ dump_backtrace_to_log(backtrace.get(), log, " ");
}
if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
- LOG("ptrace detach from %d failed: %s\n", tid, strerror(errno));
+ _LOG(log, logtype::ERROR, "ptrace detach from %d failed: %s\n", tid, strerror(errno));
*detach_failed = true;
}
}
@@ -104,7 +108,6 @@
log_t log;
log.tfd = fd;
log.amfd = amfd;
- log.quiet = true;
dump_process_header(&log, pid);
dump_thread(&log, tid, true, detach_failed, total_sleep_time_usec);
@@ -133,9 +136,8 @@
dump_process_footer(&log, pid);
}
-void dump_backtrace_to_log(Backtrace* backtrace, log_t* log,
- int scope_flags, const char* prefix) {
+void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix) {
for (size_t i = 0; i < backtrace->NumFrames(); i++) {
- _LOG(log, scope_flags, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str());
+ _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str());
}
}
diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h
index 2ec8afb..da14cd4 100644
--- a/debuggerd/backtrace.h
+++ b/debuggerd/backtrace.h
@@ -29,7 +29,6 @@
int* total_sleep_time_usec);
/* Dumps the backtrace in the backtrace data structure to the log. */
-void dump_backtrace_to_log(Backtrace* backtrace, log_t* log,
- int scope_flags, const char* prefix);
+void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix);
#endif // _DEBUGGERD_BACKTRACE_H
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c
index 01ce0be..d0c3912 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.c
@@ -7,6 +7,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
+#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/wait.h>
@@ -58,7 +59,7 @@
for(;;) {
usleep(250*1000);
write(2, &c, 1);
- if(c == 'C') *((unsigned*) 0) = 42;
+ if(c == 'C') *((volatile unsigned*) 0) = 42;
}
return NULL;
}
@@ -110,12 +111,19 @@
free((void*) buf); // GCC is smart enough to warn about this, but we're doing it deliberately.
}
+static void sigsegv_non_null() {
+ int* a = (int *)(&do_action);
+ *a = 42;
+}
+
static int do_action(const char* arg)
{
fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid());
if (!strncmp(arg, "thread-", strlen("thread-"))) {
return do_action_on_thread(arg + strlen("thread-"));
+ } else if (!strcmp(arg, "SIGSEGV-non-null")) {
+ sigsegv_non_null();
} else if (!strcmp(arg, "smash-stack")) {
return smash_stack(42);
} else if (!strcmp(arg, "stack-overflow")) {
@@ -133,19 +141,29 @@
} else if (!strcmp(arg, "assert")) {
__assert("some_file.c", 123, "false");
} else if (!strcmp(arg, "assert2")) {
- __assert2("some_file.c", 123, "some_function", "false");
+ __assert2("some_file.c", 123, "some_function", "false");
} else if (!strcmp(arg, "LOG_ALWAYS_FATAL")) {
LOG_ALWAYS_FATAL("hello %s", "world");
} else if (!strcmp(arg, "LOG_ALWAYS_FATAL_IF")) {
LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
+ } else if (!strcmp(arg, "SIGFPE")) {
+ raise(SIGFPE);
+ return EXIT_SUCCESS;
} else if (!strcmp(arg, "SIGPIPE")) {
int pipe_fds[2];
pipe(pipe_fds);
close(pipe_fds[0]);
write(pipe_fds[1], "oops", 4);
return EXIT_SUCCESS;
+ } else if (!strcmp(arg, "SIGTRAP")) {
+ raise(SIGTRAP);
+ return EXIT_SUCCESS;
} else if (!strcmp(arg, "heap-usage")) {
abuse_heap();
+ } else if (!strcmp(arg, "SIGSEGV-unmapped")) {
+ char* map = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ munmap(map, sizeof(int));
+ map[0] = '8';
}
fprintf(stderr, "%s OP\n", __progname);
@@ -162,8 +180,12 @@
fprintf(stderr, " assert2 call assert() with a function\n");
fprintf(stderr, " LOG_ALWAYS_FATAL call LOG_ALWAYS_FATAL\n");
fprintf(stderr, " LOG_ALWAYS_FATAL_IF call LOG_ALWAYS_FATAL\n");
+ fprintf(stderr, " SIGFPE cause a SIGFPE\n");
fprintf(stderr, " SIGPIPE cause a SIGPIPE\n");
- fprintf(stderr, " SIGSEGV cause a SIGSEGV (synonym: crash)\n");
+ fprintf(stderr, " SIGSEGV cause a SIGSEGV at address 0x0 (synonym: crash)\n");
+ fprintf(stderr, " SIGSEGV-non-null cause a SIGSEGV at a non-zero address\n");
+ fprintf(stderr, " SIGSEGV-unmapped mmap/munmap a region of memory and then attempt to access it\n");
+ fprintf(stderr, " SIGTRAP cause a SIGTRAP\n");
fprintf(stderr, "prefix any of the above with 'thread-' to not run\n");
fprintf(stderr, "on the process' main thread.\n");
return EXIT_SUCCESS;
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 76bd7a3..318b224 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -30,7 +30,8 @@
#include <sys/stat.h>
#include <sys/poll.h>
-#include <log/logd.h>
+#include <selinux/android.h>
+
#include <log/logger.h>
#include <cutils/sockets.h>
@@ -54,98 +55,47 @@
int32_t original_si_code;
};
-static int write_string(const char* file, const char* string) {
- int len;
- int fd;
- ssize_t amt;
- fd = open(file, O_RDWR);
- len = strlen(string);
- if (fd < 0)
- return -errno;
- amt = write(fd, string, len);
- close(fd);
- return amt >= 0 ? 0 : -errno;
-}
+static void wait_for_user_action(const debugger_request_t &request) {
+ // Find out the name of the process that crashed.
+ char path[64];
+ snprintf(path, sizeof(path), "/proc/%d/exe", request.pid);
-static void init_debug_led() {
- // trout leds
- write_string("/sys/class/leds/red/brightness", "0");
- write_string("/sys/class/leds/green/brightness", "0");
- write_string("/sys/class/leds/blue/brightness", "0");
- write_string("/sys/class/leds/red/device/blink", "0");
- // sardine leds
- write_string("/sys/class/leds/left/cadence", "0,0");
-}
+ char exe[PATH_MAX];
+ int count;
+ if ((count = readlink(path, exe, sizeof(exe) - 1)) == -1) {
+ ALOGE("readlink('%s') failed: %s", path, strerror(errno));
+ strlcpy(exe, "unknown", sizeof(exe));
+ } else {
+ exe[count] = '\0';
+ }
-static void enable_debug_led() {
- // trout leds
- write_string("/sys/class/leds/red/brightness", "255");
- // sardine leds
- write_string("/sys/class/leds/left/cadence", "1,0");
-}
+ // Explain how to attach the debugger.
+ ALOGI("********************************************************\n"
+ "* Process %d has been suspended while crashing.\n"
+ "* To attach gdbserver for a gdb connection on port 5039\n"
+ "* and start gdbclient:\n"
+ "*\n"
+ "* gdbclient %s :5039 %d\n"
+ "*\n"
+ "* Wait for gdb to start, then press the VOLUME DOWN key\n"
+ "* to let the process continue crashing.\n"
+ "********************************************************",
+ request.pid, exe, request.tid);
-static void disable_debug_led() {
- // trout leds
- write_string("/sys/class/leds/red/brightness", "0");
- // sardine leds
- write_string("/sys/class/leds/left/cadence", "0,0");
-}
-
-static void wait_for_user_action(pid_t pid) {
- // First log a helpful message
- LOG( "********************************************************\n"
- "* Process %d has been suspended while crashing. To\n"
- "* attach gdbserver for a gdb connection on port 5039\n"
- "* and start gdbclient:\n"
- "*\n"
- "* gdbclient app_process :5039 %d\n"
- "*\n"
- "* Wait for gdb to start, then press HOME or VOLUME DOWN key\n"
- "* to let the process continue crashing.\n"
- "********************************************************\n",
- pid, pid);
-
- // wait for HOME or VOLUME DOWN key
+ // Wait for VOLUME DOWN.
if (init_getevent() == 0) {
- int ms = 1200 / 10;
- int dit = 1;
- int dah = 3*dit;
- int _ = -dit;
- int ___ = 3*_;
- int _______ = 7*_;
- const int codes[] = {
- dit,_,dit,_,dit,___,dah,_,dah,_,dah,___,dit,_,dit,_,dit,_______
- };
- size_t s = 0;
- input_event e;
- bool done = false;
- init_debug_led();
- enable_debug_led();
- do {
- int timeout = abs(codes[s]) * ms;
- int res = get_event(&e, timeout);
- if (res == 0) {
- if (e.type == EV_KEY
- && (e.code == KEY_HOME || e.code == KEY_VOLUMEDOWN)
- && e.value == 0) {
- done = true;
- }
- } else if (res == 1) {
- if (++s >= sizeof(codes)/sizeof(*codes))
- s = 0;
- if (codes[s] > 0) {
- enable_debug_led();
- } else {
- disable_debug_led();
+ while (true) {
+ input_event e;
+ if (get_event(&e, -1) == 0) {
+ if (e.type == EV_KEY && e.code == KEY_VOLUMEDOWN && e.value == 0) {
+ break;
}
}
- } while (!done);
+ }
uninit_getevent();
}
- // don't forget to turn debug led off
- disable_debug_led();
- LOG("debuggerd resuming process %d", pid);
+ ALOGI("debuggerd resuming process %d", request.pid);
}
static int get_process_info(pid_t tid, pid_t* out_pid, uid_t* out_uid, uid_t* out_gid) {
@@ -176,16 +126,63 @@
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);
int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
if (status != 0) {
- LOG("cannot get credentials\n");
+ ALOGE("cannot get credentials");
return -1;
}
- XLOG("reading tid\n");
+ ALOGV("reading tid");
fcntl(fd, F_SETFL, O_NONBLOCK);
pollfd pollfds[1];
@@ -194,7 +191,7 @@
pollfds[0].revents = 0;
status = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000));
if (status != 1) {
- LOG("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid);
+ ALOGE("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid);
return -1;
}
@@ -202,14 +199,11 @@
memset(&msg, 0, sizeof(msg));
status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg)));
if (status < 0) {
- LOG("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid);
+ ALOGE("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid);
return -1;
}
- if (status == sizeof(debugger_msg_t)) {
- XLOG("crash request of size %d abort_msg_address=0x%" PRIPTR "\n",
- status, msg.abort_msg_address);
- } else {
- LOG("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid);
+ if (status != sizeof(debugger_msg_t)) {
+ ALOGE("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid);
return -1;
}
@@ -227,7 +221,7 @@
struct stat s;
snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid);
if (stat(buf, &s)) {
- LOG("tid %d does not exist in pid %d. ignoring debug request\n",
+ ALOGE("tid %d does not exist in pid %d. ignoring debug request\n",
out_request->tid, out_request->pid);
return -1;
}
@@ -238,9 +232,12 @@
status = get_process_info(out_request->tid, &out_request->pid,
&out_request->uid, &out_request->gid);
if (status < 0) {
- LOG("tid %d does not exist. ignoring explicit dump request\n", out_request->tid);
+ 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;
@@ -259,13 +256,13 @@
}
static void handle_request(int fd) {
- XLOG("handle_request(%d)\n", fd);
+ ALOGV("handle_request(%d)\n", fd);
debugger_request_t request;
memset(&request, 0, sizeof(request));
int status = read_request(fd, &request);
if (!status) {
- XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n",
+ ALOGV("BOOM: pid=%d uid=%d gid=%d tid=%d\n",
request.pid, request.uid, request.gid, request.tid);
// At this point, the thread that made the request is blocked in
@@ -279,12 +276,13 @@
// See details in bionic/libc/linker/debugger.c, in function
// debugger_signal_handler().
if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) {
- LOG("ptrace attach failed: %s\n", strerror(errno));
+ ALOGE("ptrace attach failed: %s\n", strerror(errno));
} else {
bool detach_failed = false;
+ bool tid_unresponsive = false;
bool attach_gdb = should_attach_gdb(&request);
if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
- LOG("failed responding to client: %s\n", strerror(errno));
+ ALOGE("failed responding to client: %s\n", strerror(errno));
} else {
char* tombstone_path = NULL;
@@ -295,43 +293,45 @@
int total_sleep_time_usec = 0;
for (;;) {
- int signal = wait_for_signal(request.tid, &total_sleep_time_usec);
- if (signal < 0) {
+ int signal = wait_for_sigstop(request.tid, &total_sleep_time_usec, &detach_failed);
+ if (signal == -1) {
+ tid_unresponsive = true;
break;
}
switch (signal) {
case SIGSTOP:
if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
- XLOG("stopped -- dumping to tombstone\n");
+ ALOGV("stopped -- dumping to tombstone\n");
tombstone_path = engrave_tombstone(request.pid, request.tid,
signal, request.original_si_code,
- request.abort_msg_address, true, true,
+ request.abort_msg_address, true,
&detach_failed, &total_sleep_time_usec);
} else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
- XLOG("stopped -- dumping to fd\n");
+ ALOGV("stopped -- dumping to fd\n");
dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed,
&total_sleep_time_usec);
} else {
- XLOG("stopped -- continuing\n");
+ ALOGV("stopped -- continuing\n");
status = ptrace(PTRACE_CONT, request.tid, 0, 0);
if (status) {
- LOG("ptrace continue failed: %s\n", strerror(errno));
+ ALOGE("ptrace continue failed: %s\n", strerror(errno));
}
continue; // loop again
}
break;
- case SIGILL:
case SIGABRT:
case SIGBUS:
case SIGFPE:
- case SIGSEGV:
+ case SIGILL:
case SIGPIPE:
+ case SIGSEGV:
#ifdef SIGSTKFLT
case SIGSTKFLT:
#endif
- XLOG("stopped -- fatal signal\n");
+ case SIGTRAP:
+ ALOGV("stopped -- fatal signal\n");
// Send a SIGSTOP to the process to make all of
// the non-signaled threads stop moving. Without
// this we get a lot of "ptrace detach failed:
@@ -341,13 +341,12 @@
// makes the process less reliable, apparently...
tombstone_path = engrave_tombstone(request.pid, request.tid,
signal, request.original_si_code,
- request.abort_msg_address, !attach_gdb, false,
+ request.abort_msg_address, !attach_gdb,
&detach_failed, &total_sleep_time_usec);
break;
default:
- XLOG("stopped -- unexpected signal\n");
- LOG("process stopped due to unexpected signal %d\n", signal);
+ ALOGE("process stopped due to unexpected signal %d\n", signal);
break;
}
break;
@@ -363,27 +362,21 @@
free(tombstone_path);
}
- XLOG("detaching\n");
- if (attach_gdb) {
- // stop the process so we can debug
- kill(request.pid, SIGSTOP);
-
- // detach so we can attach gdbserver
- if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
- LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
- detach_failed = true;
+ if (!tid_unresponsive) {
+ ALOGV("detaching");
+ if (attach_gdb) {
+ // stop the process so we can debug
+ kill(request.pid, SIGSTOP);
}
-
- // if debug.db.uid is set, its value indicates if we should wait
- // for user action for the crashing process.
- // in this case, we log a message and turn the debug LED on
- // waiting for a gdb connection (for instance)
- wait_for_user_action(request.pid);
- } else {
- // just detach
if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
- LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
+ ALOGE("ptrace detach from %d failed: %s", request.tid, strerror(errno));
detach_failed = true;
+ } else if (attach_gdb) {
+ // if debug.db.uid is set, its value indicates if we should wait
+ // for user action for the crashing process.
+ // in this case, we log a message and turn the debug LED on
+ // waiting for a gdb connection (for instance)
+ wait_for_user_action(request);
}
}
@@ -394,7 +387,7 @@
// actual parent won't receive a death notification via wait(2). At this point
// there's not much we can do about that.
if (detach_failed) {
- LOG("debuggerd committing suicide to free the zombie!\n");
+ ALOGE("debuggerd committing suicide to free the zombie!\n");
kill(getpid(), SIGKILL);
}
}
@@ -406,52 +399,50 @@
}
static int do_server() {
- int s;
- struct sigaction act;
- int logsocket = -1;
-
- // debuggerd crashes can't be reported to debuggerd. Reset all of the
- // crash handlers.
- signal(SIGILL, SIG_DFL);
+ // debuggerd crashes can't be reported to debuggerd.
+ // Reset all of the crash handlers.
signal(SIGABRT, SIG_DFL);
signal(SIGBUS, SIG_DFL);
signal(SIGFPE, SIG_DFL);
+ signal(SIGILL, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
#ifdef SIGSTKFLT
signal(SIGSTKFLT, SIG_DFL);
#endif
+ signal(SIGTRAP, SIG_DFL);
// Ignore failed writes to closed sockets
signal(SIGPIPE, SIG_IGN);
- logsocket = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);
+ int logsocket = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);
if (logsocket < 0) {
logsocket = -1;
} else {
fcntl(logsocket, F_SETFD, FD_CLOEXEC);
}
+ struct sigaction act;
act.sa_handler = SIG_DFL;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask,SIGCHLD);
act.sa_flags = SA_NOCLDWAIT;
sigaction(SIGCHLD, &act, 0);
- s = socket_local_server(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+ int s = socket_local_server(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
if (s < 0)
return 1;
fcntl(s, F_SETFD, FD_CLOEXEC);
- LOG("debuggerd: " __DATE__ " " __TIME__ "\n");
+ ALOGI("debuggerd: " __DATE__ " " __TIME__ "\n");
for (;;) {
sockaddr addr;
socklen_t alen = sizeof(addr);
- XLOG("waiting for connection\n");
+ ALOGV("waiting for connection\n");
int fd = accept(s, &addr, &alen);
if (fd < 0) {
- XLOG("accept failed: %s\n", strerror(errno));
+ ALOGV("accept failed: %s\n", strerror(errno));
continue;
}
@@ -491,7 +482,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/machine.h b/debuggerd/machine.h
index 2f1e201..fca9fbe 100644
--- a/debuggerd/machine.h
+++ b/debuggerd/machine.h
@@ -21,7 +21,7 @@
#include "utility.h"
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags);
-void dump_registers(log_t* log, pid_t tid, int scope_flags);
+void dump_memory_and_code(log_t* log, pid_t tid);
+void dump_registers(log_t* log, pid_t tid);
#endif // _DEBUGGERD_MACHINE_H
diff --git a/debuggerd/mips/machine.cpp b/debuggerd/mips/machine.cpp
index ab34182..97834c7 100644
--- a/debuggerd/mips/machine.cpp
+++ b/debuggerd/mips/machine.cpp
@@ -27,79 +27,86 @@
#include "../utility.h"
#include "../machine.h"
-// enable to dump memory pointed to by every register
-#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
-
#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, int scope_flags) {
- pt_regs r;
+void dump_memory_and_code(log_t* log, pid_t tid) {
+ pt_regs_mips_t r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
return;
}
- if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
- static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
+ static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
- 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;
+ 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]);
+ 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 >= 0x80000000) {
- continue;
- }
-
- _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
- dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
+ // Don't bother if it looks like a small int or ~= null, or if
+ // it's in the kernel area.
+ if (addr < 4096 || addr >= 0x80000000) {
+ continue;
}
+
+ _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
+ dump_memory(log, tid, addr);
}
unsigned int pc = R(r.cp0_epc);
unsigned int ra = R(r.regs[31]);
- _LOG(log, scope_flags, "\ncode around pc:\n");
- dump_memory(log, tid, (uintptr_t)pc, scope_flags);
+ _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
+ dump_memory(log, tid, (uintptr_t)pc);
if (pc != ra) {
- _LOG(log, scope_flags, "\ncode around ra:\n");
- dump_memory(log, tid, (uintptr_t)ra, scope_flags);
+ _LOG(log, logtype::MEMORY, "\ncode around ra:\n");
+ dump_memory(log, tid, (uintptr_t)ra);
}
}
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
- pt_regs r;
+void dump_registers(log_t* log, pid_t tid) {
+ pt_regs_mips_t r;
if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
- _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
- _LOG(log, scope_flags, " zr %08x at %08x v0 %08x v1 %08x\n",
+ _LOG(log, logtype::REGISTERS, " zr %08x at %08x v0 %08x v1 %08x\n",
R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
- _LOG(log, scope_flags, " a0 %08x a1 %08x a2 %08x a3 %08x\n",
+ _LOG(log, logtype::REGISTERS, " a0 %08x a1 %08x a2 %08x a3 %08x\n",
R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
- _LOG(log, scope_flags, " t0 %08x t1 %08x t2 %08x t3 %08x\n",
+ _LOG(log, logtype::REGISTERS, " t0 %08x t1 %08x t2 %08x t3 %08x\n",
R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
- _LOG(log, scope_flags, " t4 %08x t5 %08x t6 %08x t7 %08x\n",
+ _LOG(log, logtype::REGISTERS, " t4 %08x t5 %08x t6 %08x t7 %08x\n",
R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
- _LOG(log, scope_flags, " s0 %08x s1 %08x s2 %08x s3 %08x\n",
+ _LOG(log, logtype::REGISTERS, " s0 %08x s1 %08x s2 %08x s3 %08x\n",
R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
- _LOG(log, scope_flags, " s4 %08x s5 %08x s6 %08x s7 %08x\n",
+ _LOG(log, logtype::REGISTERS, " s4 %08x s5 %08x s6 %08x s7 %08x\n",
R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
- _LOG(log, scope_flags, " t8 %08x t9 %08x k0 %08x k1 %08x\n",
+ _LOG(log, logtype::REGISTERS, " t8 %08x t9 %08x k0 %08x k1 %08x\n",
R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
- _LOG(log, scope_flags, " gp %08x sp %08x s8 %08x ra %08x\n",
+ _LOG(log, logtype::REGISTERS, " gp %08x sp %08x s8 %08x ra %08x\n",
R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
- _LOG(log, scope_flags, " hi %08x lo %08x bva %08x epc %08x\n",
+ _LOG(log, logtype::REGISTERS, " hi %08x lo %08x bva %08x epc %08x\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
old mode 100755
new mode 100644
index d0cefc7..0c1b80f
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "DEBUG"
+
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@@ -31,9 +33,10 @@
#include <private/android_filesystem_config.h>
+#include <cutils/properties.h>
#include <log/log.h>
#include <log/logger.h>
-#include <cutils/properties.h>
+#include <log/logprint.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
@@ -57,10 +60,11 @@
static bool signal_has_si_addr(int sig) {
switch (sig) {
- case SIGILL:
- case SIGFPE:
- case SIGSEGV:
case SIGBUS:
+ case SIGFPE:
+ case SIGILL:
+ case SIGSEGV:
+ case SIGTRAP:
return true;
default:
return false;
@@ -69,16 +73,17 @@
static const char* get_signame(int sig) {
switch(sig) {
- case SIGILL: return "SIGILL";
case SIGABRT: return "SIGABRT";
case SIGBUS: return "SIGBUS";
case SIGFPE: return "SIGFPE";
- case SIGSEGV: return "SIGSEGV";
+ case SIGILL: return "SIGILL";
case SIGPIPE: return "SIGPIPE";
+ case SIGSEGV: return "SIGSEGV";
#if defined(SIGSTKFLT)
case SIGSTKFLT: return "SIGSTKFLT";
#endif
case SIGSTOP: return "SIGSTOP";
+ case SIGTRAP: return "SIGTRAP";
default: return "?";
}
}
@@ -155,27 +160,23 @@
return "?";
}
-static void dump_revision_info(log_t* log) {
+static void dump_header_info(log_t* log) {
+ char fingerprint[PROPERTY_VALUE_MAX];
char revision[PROPERTY_VALUE_MAX];
+ property_get("ro.build.fingerprint", fingerprint, "unknown");
property_get("ro.revision", revision, "unknown");
- _LOG(log, SCOPE_AT_FAULT, "Revision: '%s'\n", revision);
-}
-
-static void dump_build_info(log_t* log) {
- char fingerprint[PROPERTY_VALUE_MAX];
-
- property_get("ro.build.fingerprint", fingerprint, "unknown");
-
- _LOG(log, SCOPE_AT_FAULT, "Build fingerprint: '%s'\n", fingerprint);
+ _LOG(log, logtype::HEADER, "Build fingerprint: '%s'\n", fingerprint);
+ _LOG(log, logtype::HEADER, "Revision: '%s'\n", revision);
+ _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
}
static void dump_signal_info(log_t* log, pid_t tid, int signal, int si_code) {
siginfo_t si;
memset(&si, 0, sizeof(si));
if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
- _LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
+ _LOG(log, logtype::HEADER, "cannot get siginfo: %s\n", strerror(errno));
return;
}
@@ -189,11 +190,11 @@
snprintf(addr_desc, sizeof(addr_desc), "--------");
}
- _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %s\n",
+ _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n",
signal, get_signame(signal), si.si_code, get_sigcode(signal, si.si_code), addr_desc);
}
-static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags) {
+static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) {
char path[64];
char threadnamebuf[1024];
char* threadname = NULL;
@@ -210,26 +211,28 @@
}
}
}
-
- if (IS_AT_FAULT(scope_flags)) {
- char procnamebuf[1024];
- char* procname = NULL;
-
- snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
- if ((fp = fopen(path, "r"))) {
- procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
- fclose(fp);
- }
-
- _LOG(log, SCOPE_AT_FAULT, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid,
- threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
- } else {
- _LOG(log, 0, "pid: %d, tid: %d, name: %s\n", pid, tid, threadname ? threadname : "UNKNOWN");
+ // Blacklist logd, logd.reader, logd.writer, logd.auditd, logd.control ...
+ static const char logd[] = "logd";
+ if (!strncmp(threadname, logd, sizeof(logd) - 1)
+ && (!threadname[sizeof(logd) - 1] || (threadname[sizeof(logd) - 1] == '.'))) {
+ log->should_retrieve_logcat = false;
}
+
+ char procnamebuf[1024];
+ char* procname = NULL;
+
+ snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
+ if ((fp = fopen(path, "r"))) {
+ procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
+ fclose(fp);
+ }
+
+ _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid,
+ threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
}
static void dump_stack_segment(
- Backtrace* backtrace, log_t* log, int scope_flags, uintptr_t* sp, size_t words, int label) {
+ Backtrace* backtrace, log_t* log, uintptr_t* sp, size_t words, int label) {
for (size_t i = 0; i < words; i++) {
word_t stack_content;
if (!backtrace->ReadWord(*sp, &stack_content)) {
@@ -248,27 +251,27 @@
if (!func_name.empty()) {
if (!i && label >= 0) {
if (offset) {
- _LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n",
+ _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, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s (%s)\n",
+ _LOG(log, logtype::STACK, " #%02d %" PRIPTR " %" PRIPTR " %s (%s)\n",
label, *sp, stack_content, map_name, func_name.c_str());
}
} else {
if (offset) {
- _LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n",
+ _LOG(log, logtype::STACK, " %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n",
*sp, stack_content, map_name, func_name.c_str(), offset);
} else {
- _LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s (%s)\n",
+ _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, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s\n",
+ _LOG(log, logtype::STACK, " #%02d %" PRIPTR " %" PRIPTR " %s\n",
label, *sp, stack_content, map_name);
} else {
- _LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s\n",
+ _LOG(log, logtype::STACK, " %" PRIPTR " %" PRIPTR " %s\n",
*sp, stack_content, map_name);
}
}
@@ -277,7 +280,7 @@
}
}
-static void dump_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
+static void dump_stack(Backtrace* backtrace, log_t* log) {
size_t first = 0, last;
for (size_t i = 0; i < backtrace->NumFrames(); i++) {
const backtrace_frame_data_t* frame = backtrace->GetFrame(i);
@@ -293,27 +296,22 @@
}
first--;
- scope_flags |= SCOPE_SENSITIVE;
-
// Dump a few words before the first frame.
word_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(word_t);
- dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, -1);
+ dump_stack_segment(backtrace, log, &sp, STACK_WORDS, -1);
// Dump a few words from all successive frames.
// Only log the first 3 frames, put the rest in the tombstone.
for (size_t i = first; i <= last; i++) {
const backtrace_frame_data_t* frame = backtrace->GetFrame(i);
if (sp != frame->sp) {
- _LOG(log, scope_flags, " ........ ........\n");
+ _LOG(log, logtype::STACK, " ........ ........\n");
sp = frame->sp;
}
- if (i - first == 3) {
- scope_flags &= (~SCOPE_AT_FAULT);
- }
if (i == last) {
- dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, i);
+ dump_stack_segment(backtrace, log, &sp, STACK_WORDS, i);
if (sp < frame->sp + frame->stack_size) {
- _LOG(log, scope_flags, " ........ ........\n");
+ _LOG(log, logtype::STACK, " ........ ........\n");
}
} else {
size_t words = frame->stack_size / sizeof(word_t);
@@ -322,98 +320,79 @@
} else if (words > STACK_WORDS) {
words = STACK_WORDS;
}
- dump_stack_segment(backtrace, log, scope_flags, &sp, words, i);
+ dump_stack_segment(backtrace, log, &sp, words, i);
}
}
}
-static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
+static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log) {
if (backtrace->NumFrames()) {
- _LOG(log, scope_flags, "\nbacktrace:\n");
- dump_backtrace_to_log(backtrace, log, scope_flags, " ");
+ _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
+ dump_backtrace_to_log(backtrace, log, " ");
- _LOG(log, scope_flags, "\nstack:\n");
- dump_stack(backtrace, log, scope_flags);
+ _LOG(log, logtype::STACK, "\nstack:\n");
+ dump_stack(backtrace, log);
}
}
-static void dump_map(log_t* log, const backtrace_map_t* map, const char* what, int scope_flags) {
- if (map != NULL) {
- _LOG(log, scope_flags, " %" PRIPTR "-%" PRIPTR " %c%c%c %s\n", map->start, map->end,
+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->name.c_str());
- } else {
- _LOG(log, scope_flags, " (no %s)\n", what);
- }
+ (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, int scope_flags) {
- scope_flags |= SCOPE_SENSITIVE;
+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, scope_flags, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
- return;
- }
- if (!signal_has_si_addr(si.si_signo)) {
+ _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);
- addr &= ~0xfff; // round to 4K page boundary
- if (addr == 0) { // null-pointer deref
- return;
+
+ _LOG(log, logtype::MAPS, "\nmemory map: %s\n", has_fault_address ? "(fault address prefixed with --->)" : "");
+
+ if (has_fault_address && (addr < map->begin()->start)) {
+ _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " before any mapped regions\n", addr);
}
- _LOG(log, scope_flags, "\nmemory map around fault addr %" PRIPTR ":\n",
- reinterpret_cast<uintptr_t>(si.si_addr));
-
- // Search for a match, or for a hole where the match would be. The list
- // is backward from the file content, so it starts at high addresses.
- const backtrace_map_t* cur_map = NULL;
- const backtrace_map_t* next_map = NULL;
- const backtrace_map_t* prev_map = NULL;
+ BacktraceMap::const_iterator prev = map->begin();
for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
- if (addr >= it->start && addr < it->end) {
- cur_map = &*it;
- if (it != map->begin()) {
- prev_map = &*(it-1);
- }
- if (++it != map->end()) {
- next_map = &*it;
- }
- break;
+ 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);
}
-
- // Show the map address in ascending order (like /proc/pid/maps).
- dump_map(log, prev_map, "map below", scope_flags);
- dump_map(log, cur_map, "map for address", scope_flags);
- dump_map(log, next_map, "map above", scope_flags);
+ 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, int scope_flags, int* total_sleep_time_usec) {
- wait_for_stop(backtrace->Tid(), total_sleep_time_usec);
+static void dump_thread(Backtrace* backtrace, log_t* log) {
+ dump_registers(log, backtrace->Tid());
+ dump_backtrace_and_stack(backtrace, log);
- dump_registers(log, backtrace->Tid(), scope_flags);
- dump_backtrace_and_stack(backtrace, log, scope_flags);
- if (IS_AT_FAULT(scope_flags)) {
- dump_memory_and_code(log, backtrace->Tid(), scope_flags);
- dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid(), scope_flags);
- }
+ 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) {
char task_path[64];
+
snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
DIR* d = opendir(task_path);
// Bail early if the task directory cannot be opened
if (d == NULL) {
- XLOG("Cannot open /proc/%d/task\n", pid);
+ ALOGE("Cannot open /proc/%d/task\n", pid);
return false;
}
@@ -434,19 +413,27 @@
// Skip this thread if cannot ptrace it
if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) {
+ _LOG(log, logtype::ERROR, "ptrace attach to %d failed: %s\n", new_tid, strerror(errno));
continue;
}
- _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
- dump_thread_info(log, pid, new_tid, 0);
+ if (wait_for_sigstop(new_tid, total_sleep_time_usec, &detach_failed) == -1) {
+ continue;
+ }
+
+ log->current_tid = new_tid;
+ _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
+ dump_thread_info(log, pid, new_tid);
UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
if (backtrace->Unwind(0)) {
- dump_thread(backtrace.get(), log, 0, total_sleep_time_usec);
+ dump_thread(backtrace.get(), log);
}
+ log->current_tid = log->crashed_tid;
+
if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
- LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
+ _LOG(log, logtype::ERROR, "ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
detach_failed = true;
}
}
@@ -458,17 +445,23 @@
// Reads the contents of the specified log device, filters out the entries
// that don't match the specified pid, and writes them to the tombstone file.
//
-// If "tail" is set, we only print the last few lines.
-static void dump_log_file(log_t* log, pid_t pid, const char* filename,
- unsigned int tail) {
+// If "tail" is non-zero, log the last "tail" number of lines.
+static EventTagMap* g_eventTagMap = NULL;
+
+static void dump_log_file(
+ log_t* log, pid_t pid, const char* filename, unsigned int tail) {
bool first = true;
- struct logger_list *logger_list;
+ struct logger_list* logger_list;
+
+ if (!log->should_retrieve_logcat) {
+ return;
+ }
logger_list = android_logger_list_open(
- android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid);
+ android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid);
if (!logger_list) {
- XLOG("Unable to open %s: %s\n", filename, strerror(errno));
+ ALOGE("Unable to open %s: %s\n", filename, strerror(errno));
return;
}
@@ -476,6 +469,7 @@
while (true) {
ssize_t actual = android_logger_list_read(logger_list, &log_entry);
+ struct logger_entry* entry;
if (actual < 0) {
if (actual == -EINTR) {
@@ -485,29 +479,25 @@
// non-blocking EOF; we're done
break;
} else {
- _LOG(log, 0, "Error while reading log: %s\n",
+ _LOG(log, logtype::ERROR, "Error while reading log: %s\n",
strerror(-actual));
break;
}
} else if (actual == 0) {
- _LOG(log, 0, "Got zero bytes while reading log: %s\n",
+ _LOG(log, logtype::ERROR, "Got zero bytes while reading log: %s\n",
strerror(errno));
break;
}
- // NOTE: if you XLOG something here, this will spin forever,
+ // NOTE: if you ALOGV something here, this will spin forever,
// because you will be writing as fast as you're reading. Any
// high-frequency debug diagnostics should just be written to
// the tombstone file.
- struct logger_entry* entry = &log_entry.entry_v1;
- if (entry->pid != static_cast<int32_t>(pid)) {
- // wrong pid, ignore
- continue;
- }
+ entry = &log_entry.entry_v1;
if (first) {
- _LOG(log, 0, "--------- %slog %s\n",
+ _LOG(log, logtype::LOGS, "--------- %slog %s\n",
tail ? "tail end of " : "", filename);
first = false;
}
@@ -521,18 +511,7 @@
if (!hdr_size) {
hdr_size = sizeof(log_entry.entry_v1);
}
- char* msg = (char *)log_entry.buf + hdr_size;
- unsigned char prio = msg[0];
- char* tag = msg + 1;
- msg = tag + strlen(tag) + 1;
-
- // consume any trailing newlines
- char* nl = msg + strlen(msg) - 1;
- while (nl >= msg && *nl == '\n') {
- *nl-- = '\0';
- }
-
- char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
+ char* msg = reinterpret_cast<char*>(log_entry.buf) + hdr_size;
char timeBuf[32];
time_t sec = static_cast<time_t>(entry->sec);
@@ -541,6 +520,31 @@
ptm = localtime_r(&sec, &tmBuf);
strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
+ if (log_entry.id() == LOG_ID_EVENTS) {
+ if (!g_eventTagMap) {
+ g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+ }
+ AndroidLogEntry e;
+ char buf[512];
+ android_log_processBinaryLogBuffer(entry, &e, g_eventTagMap, buf, sizeof(buf));
+ _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
+ timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
+ 'I', e.tag, e.message);
+ continue;
+ }
+
+ unsigned char prio = msg[0];
+ char* tag = msg + 1;
+ msg = tag + strlen(tag) + 1;
+
+ // consume any trailing newlines
+ char* nl = msg + strlen(msg) - 1;
+ while (nl >= msg && *nl == '\n') {
+ *nl-- = '\0';
+ }
+
+ char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
+
// Look for line breaks ('\n') and display each text line
// on a separate line, prefixed with the header, like logcat does.
do {
@@ -550,10 +554,9 @@
++nl;
}
- _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n",
+ _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
prioChar, tag, msg);
-
} while ((msg = nl));
}
@@ -562,7 +565,7 @@
// Dumps the logs generated by the specified pid to the tombstone, from both
// "system" and "main" log devices. Ideally we'd interleave the output.
-static void dump_logs(log_t* log, pid_t pid, unsigned tail) {
+static void dump_logs(log_t* log, pid_t pid, unsigned int tail) {
dump_log_file(log, pid, "system", tail);
dump_log_file(log, pid, "main", tail);
}
@@ -590,7 +593,7 @@
}
msg[sizeof(msg) - 1] = '\0';
- _LOG(log, SCOPE_AT_FAULT, "Abort message: '%s'\n", msg);
+ _LOG(log, logtype::HEADER, "Abort message: '%s'\n", msg);
}
// Dumps all information about the specified pid to the tombstone.
@@ -612,11 +615,11 @@
TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
}
- _LOG(log, SCOPE_AT_FAULT,
+ _LOG(log, logtype::HEADER,
"*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
- dump_build_info(log);
- dump_revision_info(log);
- dump_thread_info(log, pid, tid, SCOPE_AT_FAULT);
+ dump_header_info(log);
+ dump_thread_info(log, pid, tid);
+
if (signal) {
dump_signal_info(log, tid, signal, si_code);
}
@@ -625,7 +628,7 @@
UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
if (backtrace->Unwind(0)) {
dump_abort_message(backtrace.get(), log, abort_msg_address);
- dump_thread(backtrace.get(), log, SCOPE_AT_FAULT, total_sleep_time_usec);
+ dump_thread(backtrace.get(), log);
}
if (want_logs) {
@@ -678,7 +681,7 @@
if (errno != ENOENT)
continue;
- *fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0600);
+ *fd = open(path, O_CREAT | O_EXCL | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
if (*fd < 0)
continue; // raced ?
@@ -687,15 +690,15 @@
}
if (oldest < 0) {
- LOG("Failed to find a valid tombstone, default to using tombstone 0.\n");
+ ALOGE("Failed to find a valid tombstone, default to using tombstone 0.\n");
oldest = 0;
}
// we didn't find an available file, so we clobber the oldest one
snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest);
- *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+ *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
if (*fd < 0) {
- LOG("failed to open tombstone file '%s': %s\n", path, strerror(errno));
+ ALOGE("failed to open tombstone file '%s': %s\n", path, strerror(errno));
return NULL;
}
fchown(*fd, AID_SYSTEM, AID_SYSTEM);
@@ -733,14 +736,19 @@
}
char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
- uintptr_t abort_msg_address, bool dump_sibling_threads, bool quiet,
+ uintptr_t abort_msg_address, bool dump_sibling_threads,
bool* detach_failed, int* total_sleep_time_usec) {
+
+ log_t log;
+ log.current_tid = tid;
+ log.crashed_tid = tid;
+
if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) {
- LOG("failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
+ _LOG(&log, logtype::ERROR, "failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
}
if (chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM) == -1) {
- LOG("failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno));
+ _LOG(&log, logtype::ERROR, "failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno));
}
int fd = -1;
@@ -748,25 +756,25 @@
if (selinux_android_restorecon(TOMBSTONE_DIR, 0) == 0) {
path = find_and_open_tombstone(&fd);
} else {
- LOG("Failed to restore security context, not writing tombstone.\n");
+ _LOG(&log, logtype::ERROR, "Failed to restore security context, not writing tombstone.\n");
}
- if (fd < 0 && quiet) {
- LOG("Skipping tombstone write, nothing to do.\n");
+ if (fd < 0) {
+ _LOG(&log, logtype::ERROR, "Skipping tombstone write, nothing to do.\n");
*detach_failed = false;
return NULL;
}
- log_t log;
log.tfd = fd;
// Preserve amfd since it can be modified through the calls below without
// being closed.
int amfd = activity_manager_connect();
log.amfd = amfd;
- log.quiet = quiet;
*detach_failed = dump_crash(&log, pid, tid, signal, original_si_code, abort_msg_address,
dump_sibling_threads, total_sleep_time_usec);
+ ALOGI("\nTombstone written to: %s\n", path);
+
// Either of these file descriptors can be -1, any error is ignored.
close(amfd);
close(fd);
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index 3574e84..7e2b2fe 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -25,7 +25,7 @@
* Returns the path of the tombstone, which must be freed using free(). */
char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
uintptr_t abort_msg_address,
- bool dump_sibling_threads, bool quiet,
- bool* detach_failed, int* total_sleep_time_usec);
+ bool dump_sibling_threads, bool* detach_failed,
+ int* total_sleep_time_usec);
#endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index d4c252f..2baf9de 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "DEBUG"
+
#include "utility.h"
#include <errno.h>
@@ -25,10 +27,9 @@
#include <backtrace/Backtrace.h>
#include <log/log.h>
-#include <log/logd.h>
-const int sleep_time_usec = 50000; // 0.05 seconds
-const int max_total_sleep_usec = 10000000; // 10 seconds
+const int SLEEP_TIME_USEC = 50000; // 0.05 seconds
+const int MAX_TOTAL_SLEEP_USEC = 10000000; // 10 seconds
static int write_to_am(int fd, const char* buf, int len) {
int to_write = len;
@@ -36,7 +37,7 @@
int written = TEMP_FAILURE_RETRY(write(fd, buf + len - to_write, to_write));
if (written < 0) {
// hard failure
- LOG("AM write failure (%d / %s)\n", errno, strerror(errno));
+ ALOGE("AM write failure (%d / %s)\n", errno, strerror(errno));
return -1;
}
to_write -= written;
@@ -44,10 +45,24 @@
return len;
}
-void _LOG(log_t* log, int scopeFlags, const char* fmt, ...) {
- bool want_tfd_write = log && log->tfd >= 0;
- bool want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet);
- bool want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0;
+// Whitelist output desired in the logcat output.
+bool is_allowed_in_logcat(enum logtype ltype) {
+ if ((ltype == ERROR)
+ || (ltype == HEADER)
+ || (ltype == REGISTERS)
+ || (ltype == BACKTRACE)) {
+ return true;
+ }
+ return false;
+}
+
+void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
+ bool write_to_tombstone = (log->tfd != -1);
+ bool write_to_logcat = is_allowed_in_logcat(ltype)
+ && log->crashed_tid != -1
+ && log->current_tid != -1
+ && (log->crashed_tid == log->current_tid);
+ bool write_to_activitymanager = (log->amfd != -1);
char buf[512];
va_list ap;
@@ -60,13 +75,13 @@
return;
}
- if (want_tfd_write) {
+ if (write_to_tombstone) {
TEMP_FAILURE_RETRY(write(log->tfd, buf, len));
}
- if (want_log_write) {
- __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, "DEBUG", buf);
- if (want_amfd_write) {
+ if (write_to_logcat) {
+ __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, LOG_TAG, buf);
+ if (write_to_activitymanager) {
int written = write_to_am(log->amfd, buf, len);
if (written <= 0) {
// timeout or other failure on write; stop informing the activity manager
@@ -76,48 +91,44 @@
}
}
-int wait_for_signal(pid_t tid, int* total_sleep_time_usec) {
+int wait_for_sigstop(pid_t tid, int* total_sleep_time_usec, bool* detach_failed) {
+ bool allow_dead_tid = false;
for (;;) {
int status;
- pid_t n = waitpid(tid, &status, __WALL | WNOHANG);
- if (n < 0) {
- if (errno == EAGAIN)
- continue;
- LOG("waitpid failed: %s\n", strerror(errno));
- return -1;
- } else if (n > 0) {
- XLOG("waitpid: n=%d status=%08x\n", n, status);
+ pid_t n = TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL | WNOHANG));
+ if (n == -1) {
+ ALOGE("waitpid failed: tid %d, %s", tid, strerror(errno));
+ break;
+ } else if (n == tid) {
if (WIFSTOPPED(status)) {
return WSTOPSIG(status);
} else {
- LOG("unexpected waitpid response: n=%d, status=%08x\n", n, status);
- return -1;
+ ALOGE("unexpected waitpid response: n=%d, status=%08x\n", n, status);
+ // This is the only circumstance under which we can allow a detach
+ // to fail with ESRCH, which indicates the tid has exited.
+ allow_dead_tid = true;
+ break;
}
}
- if (*total_sleep_time_usec > max_total_sleep_usec) {
- LOG("timed out waiting for tid=%d to die\n", tid);
- return -1;
- }
-
- // not ready yet
- XLOG("not ready yet\n");
- usleep(sleep_time_usec);
- *total_sleep_time_usec += sleep_time_usec;
- }
-}
-
-void wait_for_stop(pid_t tid, int* total_sleep_time_usec) {
- siginfo_t si;
- while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) < 0 && errno == ESRCH) {
- if (*total_sleep_time_usec > max_total_sleep_usec) {
- LOG("timed out waiting for tid=%d to stop\n", tid);
+ if (*total_sleep_time_usec > MAX_TOTAL_SLEEP_USEC) {
+ ALOGE("timed out waiting for stop signal: tid=%d", tid);
break;
}
- usleep(sleep_time_usec);
- *total_sleep_time_usec += sleep_time_usec;
+ usleep(SLEEP_TIME_USEC);
+ *total_sleep_time_usec += SLEEP_TIME_USEC;
}
+
+ if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
+ if (allow_dead_tid && errno == ESRCH) {
+ ALOGE("tid exited before attach completed: tid %d", tid);
+ } else {
+ *detach_failed = true;
+ ALOGE("detach failed: tid %d, %s", tid, strerror(errno));
+ }
+ }
+ return -1;
}
#if defined (__mips__)
@@ -126,7 +137,7 @@
#define DUMP_MEMORY_AS_ASCII 0
#endif
-void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
+void dump_memory(log_t* log, pid_t tid, uintptr_t addr) {
char code_buffer[64];
char ascii_buffer[32];
uintptr_t p, end;
@@ -190,6 +201,6 @@
p += sizeof(long);
}
*asc_out = '\0';
- _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer);
+ _LOG(log, logtype::MEMORY, " %s %s\n", code_buffer, ascii_buffer);
}
}
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 0f88605..58a882c 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -2,16 +2,16 @@
**
** Copyright 2008, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -21,48 +21,58 @@
#include <stdbool.h>
#include <sys/types.h>
-typedef struct {
+// Figure out the abi based on defined macros.
+#if defined(__arm__)
+#define ABI_STRING "arm"
+#elif defined(__aarch64__)
+#define ABI_STRING "arm64"
+#elif defined(__mips__)
+#define ABI_STRING "mips"
+#elif defined(__i386__)
+#define ABI_STRING "x86"
+#elif defined(__x86_64__)
+#define ABI_STRING "x86_64"
+#else
+#error "Unsupported ABI"
+#endif
+
+
+struct log_t{
/* tombstone file descriptor */
int tfd;
/* Activity Manager socket file descriptor */
int amfd;
- /* if true, does not log anything to the Android logcat or Activity Manager */
- bool quiet;
-} log_t;
+ // The tid of the thread that crashed.
+ pid_t crashed_tid;
+ // The tid of the thread we are currently working with.
+ pid_t current_tid;
+ // logd daemon crash, can block asking for logcat data, allow suppression.
+ bool should_retrieve_logcat;
-/* Log information onto the tombstone. scopeFlags is a bitmask of the flags defined
- * here. */
-void _LOG(log_t* log, int scopeFlags, const char *fmt, ...)
+ log_t()
+ : tfd(-1), amfd(-1), crashed_tid(-1), current_tid(-1), should_retrieve_logcat(true) {}
+};
+
+// List of types of logs to simplify the logging decision in _LOG
+enum logtype {
+ ERROR,
+ HEADER,
+ THREAD,
+ REGISTERS,
+ FP_REGISTERS,
+ BACKTRACE,
+ MAPS,
+ MEMORY,
+ STACK,
+ LOGS
+};
+
+// Log information onto the tombstone.
+void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
__attribute__ ((format(printf, 3, 4)));
-/* The message pertains specifically to the faulting thread / process */
-#define SCOPE_AT_FAULT (1 << 0)
-/* The message contains sensitive information such as RAM contents */
-#define SCOPE_SENSITIVE (1 << 1)
+int wait_for_sigstop(pid_t, int*, bool*);
-#define IS_AT_FAULT(x) (((x) & SCOPE_AT_FAULT) != 0)
-#define IS_SENSITIVE(x) (((x) & SCOPE_SENSITIVE) != 0)
-
-/* Further helpful macros */
-#define LOG(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
-
-/* Set to 1 for normal debug traces */
-#if 0
-#define XLOG(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
-#else
-#define XLOG(fmt...) do {} while(0)
-#endif
-
-/* Set to 1 for chatty debug traces. Includes all resolved dynamic symbols */
-#if 0
-#define XLOG2(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
-#else
-#define XLOG2(fmt...) do {} while(0)
-#endif
-
-int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
-void wait_for_stop(pid_t tid, int* total_sleep_time_usec);
-
-void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags);
+void dump_memory(log_t* log, pid_t tid, uintptr_t addr);
#endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/vfp-crasher.c b/debuggerd/vfp-crasher.c
deleted file mode 100644
index 7a19cdd..0000000
--- a/debuggerd/vfp-crasher.c
+++ /dev/null
@@ -1,7 +0,0 @@
-int main()
-{
- extern void crash(void);
-
- crash();
- return 0;
-}
diff --git a/debuggerd/x86/machine.cpp b/debuggerd/x86/machine.cpp
index 141f19a..57330c1 100644
--- a/debuggerd/x86/machine.cpp
+++ b/debuggerd/x86/machine.cpp
@@ -25,21 +25,21 @@
#include "../utility.h"
#include "../machine.h"
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+void dump_memory_and_code(log_t*, pid_t) {
}
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
+void dump_registers(log_t* log, pid_t tid) {
struct pt_regs r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
- _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
- _LOG(log, scope_flags, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n",
+ _LOG(log, logtype::REGISTERS, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n",
r.eax, r.ebx, r.ecx, r.edx);
- _LOG(log, scope_flags, " esi %08lx edi %08lx\n",
+ _LOG(log, logtype::REGISTERS, " esi %08lx edi %08lx\n",
r.esi, r.edi);
- _LOG(log, scope_flags, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n",
+ _LOG(log, logtype::REGISTERS, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n",
r.xcs, r.xds, r.xes, r.xfs, r.xss);
- _LOG(log, scope_flags, " eip %08lx ebp %08lx esp %08lx flags %08lx\n",
+ _LOG(log, logtype::REGISTERS, " eip %08lx ebp %08lx esp %08lx flags %08lx\n",
r.eip, r.ebp, r.esp, r.eflags);
}
diff --git a/debuggerd/x86_64/machine.cpp b/debuggerd/x86_64/machine.cpp
index 406851a..af4f35a 100755
--- a/debuggerd/x86_64/machine.cpp
+++ b/debuggerd/x86_64/machine.cpp
@@ -27,25 +27,25 @@
#include "../utility.h"
#include "../machine.h"
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+void dump_memory_and_code(log_t*, pid_t) {
}
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
+void dump_registers(log_t* log, pid_t tid) {
struct user_regs_struct r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
- _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
- _LOG(log, scope_flags, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
+ _LOG(log, logtype::REGISTERS, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
r.rax, r.rbx, r.rcx, r.rdx);
- _LOG(log, scope_flags, " rsi %016lx rdi %016lx\n",
+ _LOG(log, logtype::REGISTERS, " rsi %016lx rdi %016lx\n",
r.rsi, r.rdi);
- _LOG(log, scope_flags, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
r.r8, r.r9, r.r10, r.r11);
- _LOG(log, scope_flags, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
r.r12, r.r13, r.r14, r.r15);
- _LOG(log, scope_flags, " cs %016lx ss %016lx\n",
+ _LOG(log, logtype::REGISTERS, " cs %016lx ss %016lx\n",
r.cs, r.ss);
- _LOG(log, scope_flags, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
+ _LOG(log, logtype::REGISTERS, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
r.rip, r.rbp, r.rsp, r.eflags);
}
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 73794a0..f03bbea 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -17,7 +17,8 @@
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
- $(LOCAL_PATH)/../../extras/ext4_utils
+ $(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_MODULE := fastboot
LOCAL_MODULE_TAGS := debug
@@ -31,6 +32,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)
@@ -39,13 +41,11 @@
ifneq ($(strip $(USE_CYGWIN)),)
# Pure cygwin case
LOCAL_LDLIBS += -lpthread
- LOCAL_C_INCLUDES += /usr/include/w32api/ddk
endif
ifneq ($(strip $(USE_MINGW)),)
# MinGW under Linux case
LOCAL_LDLIBS += -lws2_32
USE_SYSDEPS_WIN32 := 1
- LOCAL_C_INCLUDES += /usr/i586-mingw32msvc/include/ddk
endif
LOCAL_C_INCLUDES += development/host/windows/usb/api
endif
@@ -62,10 +62,24 @@
LOCAL_STATIC_LIBRARIES += libselinux
endif # HOST_OS != windows
+ifeq ($(HOST_OS),linux)
+# libf2fs_dlutils_host will dlopen("libf2fs_fmt_host_dyn")
+LOCAL_CFLAGS += -DUSE_F2FS
+LOCAL_LDFLAGS += -ldl -rdynamic -Wl,-rpath,.
+LOCAL_REQUIRED_MODULES := libf2fs_fmt_host_dyn
+# The following libf2fs_* are from system/extras/f2fs_utils,
+# and do not use code in external/f2fs-tools.
+LOCAL_STATIC_LIBRARIES += libf2fs_utils_host libf2fs_ioutils_host libf2fs_dlutils_host
+endif
+
include $(BUILD_HOST_EXECUTABLE)
-
-$(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
+my_dist_files := $(LOCAL_BUILT_MODULE)
+ifeq ($(HOST_OS),linux)
+my_dist_files += $(HOST_LIBRARY_PATH)/libf2fs_fmt_host_dyn$(HOST_SHLIB_SUFFIX)
+endif
+$(call dist-for-goals,dist_files sdk,$(my_dist_files))
+my_dist_files :=
ifeq ($(HOST_OS),linux)
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 3a140ab..959d3ad 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -32,6 +32,7 @@
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
+#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
@@ -98,11 +99,11 @@
char sig_name[13];
char part_name[9];
bool is_optional;
-} images[4] = {
+} images[] = {
{"boot.img", "boot.sig", "boot", false},
{"recovery.img", "recovery.sig", "recovery", true},
{"system.img", "system.sig", "system", false},
- {"tos.img", "tos.sig", "tos", true},
+ {"vendor.img", "vendor.sig", "vendor", true},
};
void get_my_path(char *path);
@@ -119,8 +120,8 @@
fn = "recovery.img";
} else if(!strcmp(item,"system")) {
fn = "system.img";
- } else if(!strcmp(item,"tos")) {
- fn = "tos.img";
+ } else if(!strcmp(item,"vendor")) {
+ fn = "vendor.img";
} else if(!strcmp(item,"userdata")) {
fn = "userdata.img";
} else if(!strcmp(item,"cache")) {
@@ -243,7 +244,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);
@@ -286,16 +287,17 @@
"\n"
"commands:\n"
" update <filename> reflash device from update.zip\n"
- " flashall flash boot, system, and if found,\n"
- " recovery, tos\n"
+ " flashall flash boot, system, vendor and if found,\n"
+ " recovery\n"
" flash <partition> [ <filename> ] write a file to a flash partition\n"
" erase <partition> erase a flash partition\n"
" format[:[<fs type>][:[<size>]] <partition> format a flash partition.\n"
" Can override the fs type and/or\n"
" size the bootloader reports.\n"
" getvar <variable> display a bootloader variable\n"
- " boot <kernel> [ <ramdisk> ] download and boot kernel\n"
- " flash:raw boot <kernel> [ <ramdisk> ] create bootimage and flash it\n"
+ " boot <kernel> [ <ramdisk> [ <second> ] ] download and boot kernel\n"
+ " flash:raw boot <kernel> [ <ramdisk> [ <second> ] ] create bootimage and \n"
+ " flash it\n"
" devices list all connected devices\n"
" continue continue with autoboot\n"
" reboot reboot device normally\n"
@@ -323,10 +325,11 @@
}
void *load_bootable_image(const char *kernel, const char *ramdisk,
- unsigned *sz, const char *cmdline)
+ const char *secondstage, unsigned *sz,
+ const char *cmdline)
{
- void *kdata = 0, *rdata = 0;
- unsigned ksize = 0, rsize = 0;
+ void *kdata = 0, *rdata = 0, *sdata = 0;
+ unsigned ksize = 0, rsize = 0, ssize = 0;
void *bdata;
unsigned bsize;
@@ -362,10 +365,18 @@
}
}
+ if (secondstage) {
+ sdata = load_file(secondstage, &ssize);
+ if(sdata == 0) {
+ fprintf(stderr,"cannot load '%s': %s\n", secondstage, strerror(errno));
+ return 0;
+ }
+ }
+
fprintf(stderr,"creating boot image...\n");
bdata = mkbootimg(kdata, ksize, kernel_offset,
rdata, rsize, ramdisk_offset,
- 0, 0, second_offset,
+ sdata, ssize, second_offset,
page_size, base_addr, tags_offset, &bsize);
if(bdata == 0) {
fprintf(stderr,"failed to create boot.img\n");
@@ -576,7 +587,7 @@
if (!status) {
limit = strtoul(response, NULL, 0);
if (limit > 0) {
- fprintf(stderr, "target reported max download size of %lld bytes\n",
+ fprintf(stderr, "target reported max download size of %" PRId64 " bytes\n",
limit);
}
}
@@ -977,6 +988,7 @@
unsigned sz;
int status;
int c;
+ int longindex;
const struct option longopts[] = {
{"base", required_argument, 0, 'b'},
@@ -985,13 +997,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;
}
@@ -1052,6 +1065,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();
}
@@ -1143,6 +1162,7 @@
} else if(!strcmp(*argv, "boot")) {
char *kname = 0;
char *rname = 0;
+ char *sname = 0;
skip(1);
if (argc > 0) {
kname = argv[0];
@@ -1152,7 +1172,11 @@
rname = argv[0];
skip(1);
}
- data = load_bootable_image(kname, rname, &sz, cmdline);
+ if (argc > 0) {
+ sname = argv[0];
+ skip(1);
+ }
+ data = load_bootable_image(kname, rname, sname, &sz, cmdline);
if (data == 0) return 1;
fb_queue_download("boot.img", data, sz);
fb_queue_command("boot", "booting");
@@ -1176,14 +1200,18 @@
char *pname = argv[1];
char *kname = argv[2];
char *rname = 0;
+ char *sname = 0;
require(3);
- if(argc > 3) {
- rname = argv[3];
- skip(4);
- } else {
- skip(3);
+ skip(3);
+ if (argc > 0) {
+ rname = argv[0];
+ skip(1);
}
- data = load_bootable_image(kname, rname, &sz, cmdline);
+ if (argc > 0) {
+ sname = argv[0];
+ skip(1);
+ }
+ data = load_bootable_image(kname, rname, sname, &sz, cmdline);
if (data == 0) die("cannot load bootable image");
fb_queue_flash(pname, data, sz);
} else if(!strcmp(*argv, "flashall")) {
@@ -1215,6 +1243,7 @@
}
if (wants_reboot) {
fb_queue_reboot();
+ fb_queue_wait_for_disconnect();
} else if (wants_reboot_bootloader) {
fb_queue_command("reboot-bootloader", "rebooting into bootloader");
fb_queue_wait_for_disconnect();
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.c b/fastboot/fs.c
index cd4b880..8a15e6f 100644
--- a/fastboot/fs.c
+++ b/fastboot/fs.c
@@ -1,5 +1,6 @@
#include "fastboot.h"
#include "make_ext4fs.h"
+#include "make_f2fs.h"
#include "fs.h"
#include <errno.h>
@@ -28,15 +29,23 @@
return 0;
}
+#ifdef USE_F2FS
+static int generate_f2fs_image(int fd, long long partSize)
+{
+ return make_f2fs_sparse_fd(fd, partSize, NULL, NULL);
+}
+#endif
+
static const struct fs_generator {
char *fs_type; //must match what fastboot reports for partition type
int (*generate)(int fd, long long partSize); //returns 0 or error value
} generators[] = {
-
- { "ext4", generate_ext4_image}
-
+ { "ext4", generate_ext4_image},
+#ifdef USE_F2FS
+ { "f2fs", generate_f2fs_image},
+#endif
};
const struct fs_generator* fs_get_generator(const char *fs_type)
diff --git a/fastboot/fs.h b/fastboot/fs.h
index 8388629..8444081 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -1,5 +1,5 @@
#ifndef _FS_H_
-#define _FH_H_
+#define _FS_H_
#include <stdint.h>
diff --git a/fastboot/protocol.c b/fastboot/protocol.c
index 84e9837..10a84c1 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;
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c
index a45f9f8..fabbd51 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.c
@@ -100,12 +100,12 @@
static int check(void *_desc, int len, unsigned type, int size)
{
- unsigned char *desc = _desc;
+ struct usb_descriptor_header *hdr = (struct usb_descriptor_header *)_desc;
if(len < size) return -1;
- if(desc[0] < size) return -1;
- if(desc[0] > len) return -1;
- if(desc[1] != type) return -1;
+ if(hdr->bLength < size) return -1;
+ if(hdr->bLength > len) return -1;
+ if(hdr->bDescriptorType != type) return -1;
return 0;
}
@@ -125,15 +125,15 @@
unsigned i;
unsigned e;
- if(check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE))
+ if (check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE))
return -1;
- dev = (void*) ptr;
+ dev = (struct usb_device_descriptor *)ptr;
len -= dev->bLength;
ptr += dev->bLength;
- if(check(ptr, len, USB_DT_CONFIG, USB_DT_CONFIG_SIZE))
+ if (check(ptr, len, USB_DT_CONFIG, USB_DT_CONFIG_SIZE))
return -1;
- cfg = (void*) ptr;
+ cfg = (struct usb_config_descriptor *)ptr;
len -= cfg->bLength;
ptr += cfg->bLength;
@@ -177,9 +177,19 @@
}
for(i = 0; i < cfg->bNumInterfaces; i++) {
- if(check(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE))
+
+ while (len > 0) {
+ struct usb_descriptor_header *hdr = (struct usb_descriptor_header *)ptr;
+ if (check(hdr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE) == 0)
+ break;
+ len -= hdr->bLength;
+ ptr += hdr->bLength;
+ }
+
+ if (len <= 0)
return -1;
- ifc = (void*) ptr;
+
+ ifc = (struct usb_interface_descriptor *)ptr;
len -= ifc->bLength;
ptr += ifc->bLength;
@@ -190,16 +200,25 @@
info.ifc_protocol = ifc->bInterfaceProtocol;
for(e = 0; e < ifc->bNumEndpoints; e++) {
- if(check(ptr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE))
- return -1;
- ept = (void*) ptr;
+ while (len > 0) {
+ struct usb_descriptor_header *hdr = (struct usb_descriptor_header *)ptr;
+ if (check(hdr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE) == 0)
+ break;
+ len -= hdr->bLength;
+ ptr += hdr->bLength;
+ }
+ if (len < 0) {
+ break;
+ }
+
+ ept = (struct usb_endpoint_descriptor *)ptr;
len -= ept->bLength;
ptr += ept->bLength;
- if((ept->bmAttributes & 0x03) != 0x02)
+ if((ept->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
continue;
- if(ept->bEndpointAddress & 0x80) {
+ if(ept->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
in = ept->bEndpointAddress;
} else {
out = ept->bEndpointAddress;
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/fastboot/util_osx.c b/fastboot/util_osx.c
index 26b832a..e718562 100644
--- a/fastboot/util_osx.c
+++ b/fastboot/util_osx.c
@@ -31,14 +31,15 @@
void get_my_path(char s[PATH_MAX])
{
- char *x;
- ProcessSerialNumber psn;
- GetCurrentProcess(&psn);
- CFDictionaryRef dict;
- dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
- CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
- CFSTR("CFBundleExecutable"));
- CFStringGetCString(value, s, PATH_MAX - 1, kCFStringEncodingUTF8);
+ CFBundleRef mainBundle = CFBundleGetMainBundle();
+ CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle);
+ CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
+ CFRelease(executableURL);
+
+ CFStringGetFileSystemRepresentation(executablePathString, s, PATH_MAX-1);
+ CFRelease(executablePathString);
+
+ char *x;
x = strrchr(s, '/');
if(x) x[1] = 0;
}
diff --git a/fastbootd/Android.mk b/fastbootd/Android.mk
index 6aa7400..bccac68 100644
--- a/fastbootd/Android.mk
+++ b/fastbootd/Android.mk
@@ -42,7 +42,7 @@
LOCAL_MODULE := fastbootd
LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter -DFLASH_CERT
+LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter -Wno-deprecated-declarations -DFLASH_CERT
LOCAL_LDFLAGS := -ldl
LOCAL_STATIC_LIBRARIES := \
diff --git a/fastbootd/commands/partitions.c b/fastbootd/commands/partitions.c
index 74232e6..f2c9da7 100644
--- a/fastbootd/commands/partitions.c
+++ b/fastbootd/commands/partitions.c
@@ -547,7 +547,8 @@
int GPT_parse_entry(char *string, struct GPT_entry_raw *entry)
{
char *ptr = string;
- char *key, *value;
+ char *key = NULL;
+ char *value = NULL;
while ((ptr = get_key_value(ptr, &key, &value)) != NULL) {
if (add_key_value(key, value, entry)) {
diff --git a/fastbootd/commands/virtual_partitions.c b/fastbootd/commands/virtual_partitions.c
index 813f485..9da4020 100644
--- a/fastbootd/commands/virtual_partitions.c
+++ b/fastbootd/commands/virtual_partitions.c
@@ -30,6 +30,9 @@
*/
#include "commands/virtual_partitions.h"
+
+#include <string.h>
+
#include "debug.h"
static struct virtual_partition *partitions = NULL;
diff --git a/fastbootd/transport.c b/fastbootd/transport.c
index ce8f9d0..9a16fd7 100644
--- a/fastbootd/transport.c
+++ b/fastbootd/transport.c
@@ -55,7 +55,7 @@
ftruncate(fd, len);
buffer = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (buffer == NULL) {
+ if (buffer == MAP_FAILED) {
D(ERR, "mmap(%zu) failed: %d %s", len, errno, strerror(errno));
goto err;
}
diff --git a/fastbootd/utils.h b/fastbootd/utils.h
index 3d98699..2f89582 100644
--- a/fastbootd/utils.h
+++ b/fastbootd/utils.h
@@ -29,7 +29,7 @@
* SUCH DAMAGE.
*/
-#ifndef _FASTBOOT_UTLIS_H
+#ifndef _FASTBOOT_UTILS_H
#define _FASTBOOT_UTILS_H
#include <stdio.h>
diff --git a/fastbootd/vendor_trigger_default.c b/fastbootd/vendor_trigger_default.c
index 3627024..0bcc99b 100644
--- a/fastbootd/vendor_trigger_default.c
+++ b/fastbootd/vendor_trigger_default.c
@@ -52,7 +52,7 @@
return 0;
}
-int trigger_oem_cmd(const char *arg, const char **response) {
+int trigger_oem_cmd(const char *arg, const char **response __unused) {
KLOG_DEBUG("fastbootd", "%s: %s", __func__, arg);
return 0;
}
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index dcda005..91e6c33 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -31,6 +31,7 @@
#include <linux/loop.h>
#include <private/android_filesystem_config.h>
+#include <cutils/android_reboot.h>
#include <cutils/partition_utils.h>
#include <cutils/properties.h>
#include <logwrap/logwrap.h>
@@ -46,6 +47,7 @@
#define KEY_IN_FOOTER "footer"
#define E2FSCK_BIN "/system/bin/e2fsck"
+#define F2FS_FSCK_BIN "/system/bin/fsck.f2fs"
#define MKSWAP_BIN "/system/bin/mkswap"
#define FSCK_LOG_FILE "/dev/fscklogs/log"
@@ -112,6 +114,7 @@
* fix the filesystem.
*/
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);
if (!ret) {
umount(target);
}
@@ -135,6 +138,20 @@
ERROR("Failed trying to run %s\n", E2FSCK_BIN);
}
}
+ } else if (!strcmp(fs_type, "f2fs")) {
+ char *f2fs_fsck_argv[] = {
+ F2FS_FSCK_BIN,
+ blk_device
+ };
+ INFO("Running %s on %s\n", F2FS_FSCK_BIN, blk_device);
+
+ ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv,
+ &status, true, LOG_KLOG | LOG_FILE,
+ true, FSCK_LOG_FILE);
+ if (ret < 0) {
+ /* No need to check for error in fork, we can't really handle it now */
+ ERROR("Failed trying to run %s\n", F2FS_FSCK_BIN);
+ }
}
return;
@@ -175,16 +192,27 @@
* sets the underlying block device to read-only if the mount is read-only.
* See "man 2 mount" for return values.
*/
-static int __mount(const char *source, const char *target,
- const char *filesystemtype, unsigned long mountflags,
- const void *data)
+static int __mount(const char *source, const char *target, const struct fstab_rec *rec)
{
- int ret = mount(source, target, filesystemtype, mountflags, data);
+ unsigned long mountflags = rec->flags;
+ int ret;
+ int save_errno;
+ /* We need this because sometimes we have legacy symlinks
+ * that are lingering around and need cleaning up.
+ */
+ struct stat info;
+ if (!lstat(target, &info))
+ if ((info.st_mode & S_IFMT) == S_IFLNK)
+ unlink(target);
+ mkdir(target, 0755);
+ ret = mount(source, target, rec->fs_type, mountflags, rec->fs_options);
+ 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);
}
-
+ errno = save_errno;
return ret;
}
@@ -208,16 +236,101 @@
return ret;
}
+static int device_is_debuggable() {
+ int ret = -1;
+ char value[PROP_VALUE_MAX];
+ ret = __system_property_get("ro.debuggable", value);
+ if (ret < 0)
+ return ret;
+ return strcmp(value, "1") ? 0 : 1;
+}
+
+/*
+ * Tries to mount any of the consecutive fstab entries that match
+ * the mountpoint of the one given by fstab->recs[start_idx].
+ *
+ * end_idx: On return, will be the last rec that was looked at.
+ * attempted_idx: On return, will indicate which fstab rec
+ * succeeded. In case of failure, it will be the start_idx.
+ * Returns
+ * -1 on failure with errno set to match the 1st mount failure.
+ * 0 on success.
+ */
+static int mount_with_alternatives(struct fstab *fstab, int start_idx, int *end_idx, int *attempted_idx)
+{
+ int i;
+ int mount_errno = 0;
+ int mounted = 0;
+
+ if (!end_idx || !attempted_idx || start_idx >= fstab->num_entries) {
+ errno = EINVAL;
+ if (end_idx) *end_idx = start_idx;
+ if (attempted_idx) *end_idx = start_idx;
+ return -1;
+ }
+
+ /* Hunt down an fstab entry for the same mount point that might succeed */
+ for (i = start_idx;
+ /* We required that fstab entries for the same mountpoint be consecutive */
+ i < fstab->num_entries && !strcmp(fstab->recs[start_idx].mount_point, fstab->recs[i].mount_point);
+ i++) {
+ /*
+ * Don't try to mount/encrypt the same mount point again.
+ * Deal with alternate entries for the same point which are required to be all following
+ * each other.
+ */
+ if (mounted) {
+ ERROR("%s(): skipping fstab dup mountpoint=%s rec[%d].fs_type=%s already mounted as %s.\n", __func__,
+ fstab->recs[i].mount_point, i, fstab->recs[i].fs_type, fstab->recs[*attempted_idx].fs_type);
+ continue;
+ }
+
+ if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
+ check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
+ fstab->recs[i].mount_point);
+ }
+ if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, &fstab->recs[i])) {
+ *attempted_idx = i;
+ mounted = 1;
+ if (i != start_idx) {
+ ERROR("%s(): Mounted %s on %s with fs_type=%s instead of %s\n", __func__,
+ fstab->recs[i].blk_device, fstab->recs[i].mount_point, fstab->recs[i].fs_type,
+ fstab->recs[start_idx].fs_type);
+ }
+ } else {
+ /* back up errno for crypto decisions */
+ mount_errno = errno;
+ }
+ }
+
+ /* Adjust i for the case where it was still withing the recs[] */
+ if (i < fstab->num_entries) --i;
+
+ *end_idx = i;
+ if (!mounted) {
+ *attempted_idx = start_idx;
+ errno = mount_errno;
+ return -1;
+ }
+ return 0;
+}
+
+/* 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.
+ * Returns -1 on error, and FS_MGR_MNTALL_* otherwise.
+ */
int fs_mgr_mount_all(struct fstab *fstab)
{
int i = 0;
- int encrypted = 0;
- int ret = -1;
- int mret;
- int mount_errno;
+ int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
+ int error_count = 0;
+ int mret = -1;
+ int mount_errno = 0;
+ int attempted_idx = -1;
if (!fstab) {
- return ret;
+ return -1;
}
for (i = 0; i < fstab->num_entries; i++) {
@@ -237,70 +350,92 @@
wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
}
- if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
- check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
- fstab->recs[i].mount_point);
- }
-
- if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
+ if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) &&
+ !device_is_debuggable()) {
if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
- ERROR("Could not set up verified partition, skipping!");
+ ERROR("Could not set up verified partition, skipping!\n");
continue;
}
}
+ int last_idx_inspected;
+ mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx);
+ i = last_idx_inspected;
+ mount_errno = errno;
- mret = __mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
- fstab->recs[i].fs_type, fstab->recs[i].flags,
- fstab->recs[i].fs_options);
-
+ /* Deal with encryptability. */
if (!mret) {
+ /* If this is encryptable, need to trigger encryption */
+ if ((fstab->recs[attempted_idx].fs_mgr_flags & MF_FORCECRYPT)) {
+ 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;
+ }
+ }
/* Success! Go get the next one */
continue;
}
- /* back up errno as partition_wipe clobbers the value */
- mount_errno = errno;
-
- /* mount(2) returned an error, check if it's encrypted and deal with it */
- if ((fstab->recs[i].fs_mgr_flags & MF_CRYPT) &&
- !partition_wiped(fstab->recs[i].blk_device)) {
- /* Need to mount a tmpfs at this mountpoint for now, and set
- * properties that vold will query later for decrypting
- */
- if (mount("tmpfs", fstab->recs[i].mount_point, "tmpfs",
- MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) {
- ERROR("Cannot mount tmpfs filesystem for encrypted fs at %s error: %s\n",
- fstab->recs[i].mount_point, strerror(errno));
- goto out;
+ /* mount(2) returned an error, check if it's encryptable and deal with it */
+ if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
+ fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) {
+ if(partition_wiped(fstab->recs[attempted_idx].blk_device)) {
+ ERROR("%s(): %s is wiped and %s %s is encryptable. Suggest recovery...\n", __func__,
+ fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+ fstab->recs[attempted_idx].fs_type);
+ encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY;
+ continue;
+ } else {
+ /* Need to mount a tmpfs at this mountpoint for now, and set
+ * properties that vold will query later for decrypting
+ */
+ ERROR("%s(): possibly an encryptable blkdev %s for mount %s type %s )\n", __func__,
+ fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+ fstab->recs[attempted_idx].fs_type);
+ if (fs_mgr_do_tmpfs_mount(fstab->recs[attempted_idx].mount_point) < 0) {
+ ++error_count;
+ continue;
+ }
}
- encrypted = 1;
+ encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
} else {
ERROR("Failed to mount an un-encryptable or wiped partition on"
- "%s at %s options: %s error: %s\n",
- fstab->recs[i].blk_device, fstab->recs[i].mount_point,
- fstab->recs[i].fs_options, strerror(mount_errno));
- goto out;
+ "%s at %s options: %s error: %s\n",
+ fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+ fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
+ ++error_count;
+ continue;
}
}
- if (encrypted) {
- ret = 1;
+ if (error_count) {
+ return -1;
} else {
- ret = 0;
+ return encryptable;
}
-
-out:
- return ret;
}
/* If tmp_mount_point is non-null, mount the filesystem there. This is for the
* tmp mount we do to check the user password
+ * If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
+ * in turn, and stop on 1st success, or no more match.
*/
int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
char *tmp_mount_point)
{
int i = 0;
- int ret = -1;
+ int ret = FS_MGR_DOMNT_FAILED;
+ int mount_errors = 0;
+ int first_mount_errno = 0;
char *m;
if (!fstab) {
@@ -332,9 +467,10 @@
fstab->recs[i].mount_point);
}
- if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
+ if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) &&
+ !device_is_debuggable()) {
if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
- ERROR("Could not set up verified partition, skipping!");
+ ERROR("Could not set up verified partition, skipping!\n");
continue;
}
}
@@ -345,19 +481,27 @@
} else {
m = fstab->recs[i].mount_point;
}
- if (__mount(n_blk_device, m, fstab->recs[i].fs_type,
- fstab->recs[i].flags, fstab->recs[i].fs_options)) {
- ERROR("Cannot mount filesystem on %s at %s options: %s error: %s\n",
- n_blk_device, m, fstab->recs[i].fs_options, strerror(errno));
- goto out;
+ if (__mount(n_blk_device, m, &fstab->recs[i])) {
+ if (!first_mount_errno) first_mount_errno = errno;
+ mount_errors++;
+ continue;
} else {
ret = 0;
goto out;
}
}
-
- /* We didn't find a match, say so and return an error */
- ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
+ if (mount_errors) {
+ ERROR("Cannot mount filesystem on %s at %s. error: %s\n",
+ n_blk_device, m, strerror(first_mount_errno));
+ if (first_mount_errno == EBUSY) {
+ ret = FS_MGR_DOMNT_BUSY;
+ } else {
+ ret = FS_MGR_DOMNT_FAILED;
+ }
+ } else {
+ /* We didn't find a match, say so and return an error */
+ ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
+ }
out:
return ret;
@@ -437,7 +581,7 @@
zram_fp = fopen(ZRAM_CONF_DEV, "r+");
if (zram_fp == NULL) {
- ERROR("Unable to open zram conf device " ZRAM_CONF_DEV);
+ ERROR("Unable to open zram conf device %s\n", ZRAM_CONF_DEV);
ret = -1;
continue;
}
@@ -504,7 +648,7 @@
if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
continue;
}
- if (!(fstab->recs[i].fs_mgr_flags & MF_CRYPT)) {
+ if (!(fstab->recs[i].fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT))) {
continue;
}
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index f86fc6a..3f84179 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -59,6 +59,7 @@
{ "wait", MF_WAIT },
{ "check", MF_CHECK },
{ "encryptable=",MF_CRYPT },
+ { "forceencrypt=",MF_FORCECRYPT },
{ "nonremovable",MF_NONREMOVABLE },
{ "voldmanaged=",MF_VOLDMANAGED},
{ "length=", MF_LENGTH },
@@ -106,6 +107,11 @@
* location of the keys. Get it and return it.
*/
flag_vals->key_loc = strdup(strchr(p, '=') + 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.
+ */
+ flag_vals->key_loc = strdup(strchr(p, '=') + 1);
} else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
/* The length flag is followed by an = and the
* size of the partition. Get it and return it.
@@ -361,25 +367,47 @@
return 0;
}
-struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
+/*
+ * Returns the 1st matching fstab_rec that follows the start_rec.
+ * start_rec is the result of a previous search or NULL.
+ */
+struct fstab_rec *fs_mgr_get_entry_for_mount_point_after(struct fstab_rec *start_rec, struct fstab *fstab, const char *path)
{
int i;
-
if (!fstab) {
return NULL;
}
- for (i = 0; i < fstab->num_entries; i++) {
+ if (start_rec) {
+ for (i = 0; i < fstab->num_entries; i++) {
+ if (&fstab->recs[i] == start_rec) {
+ i++;
+ break;
+ }
+ }
+ } else {
+ i = 0;
+ }
+ for (; i < fstab->num_entries; i++) {
int len = strlen(fstab->recs[i].mount_point);
if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
(path[len] == '\0' || path[len] == '/')) {
return &fstab->recs[i];
}
}
-
return NULL;
}
+/*
+ * Returns the 1st matching mount point.
+ * There might be more. To look for others, use fs_mgr_get_entry_for_mount_point_after()
+ * and give the fstab_rec from the previous search.
+ */
+struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
+{
+ return fs_mgr_get_entry_for_mount_point_after(NULL, fstab, path);
+}
+
int fs_mgr_is_voldmanaged(struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_VOLDMANAGED;
@@ -392,7 +420,7 @@
int fs_mgr_is_encryptable(struct fstab_rec *fstab)
{
- return fstab->fs_mgr_flags & MF_CRYPT;
+ return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT);
}
int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 59ffd78..34938fa 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -23,7 +23,7 @@
#define INFO(x...) KLOG_INFO("fs_mgr", x)
#define ERROR(x...) KLOG_ERROR("fs_mgr", x)
-#define CRYPTO_TMPFS_OPTIONS "size=128m,mode=0771,uid=1000,gid=1000"
+#define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000"
#define WAIT_TIMEOUT 20
@@ -72,12 +72,9 @@
#define MF_SWAPPRIO 0x80
#define MF_ZRAMSIZE 0x100
#define MF_VERIFY 0x200
-/*
- * There is no emulated sdcard daemon running on /data/media on this device,
- * so treat the physical SD card as the only external storage device,
- * a la the Nexus One.
- */
-#define MF_NOEMULATEDSD 0x400
+#define MF_FORCECRYPT 0x400
+#define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only
+ external storage */
#define DM_BUF_SIZE 4096
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index c9a2a9b..01f7844 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -30,6 +30,7 @@
#include <time.h>
#include <private/android_filesystem_config.h>
+#include <cutils/properties.h>
#include <logwrap/logwrap.h>
#include "mincrypt/rsa.h"
@@ -120,7 +121,9 @@
{
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 = open(blk_device, O_RDONLY);
if (data_device < 0) {
@@ -334,6 +337,26 @@
return -1;
}
+static int set_verified_property(char *name) {
+ int ret;
+ char *key;
+ ret = asprintf(&key, "partition.%s.verified", name);
+ if (ret < 0) {
+ ERROR("Error formatting verified property");
+ return ret;
+ }
+ ret = PROP_NAME_MAX - strlen(key);
+ if (ret < 0) {
+ ERROR("Verified property name is too long");
+ return -1;
+ }
+ ret = property_set(key, "1");
+ if (ret < 0)
+ ERROR("Error setting verified property %s: %d", key, ret);
+ free(key);
+ return ret;
+}
+
int fs_mgr_setup_verity(struct fstab_rec *fstab) {
int retval = -1;
@@ -350,6 +373,13 @@
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);
+ return retval;
+ }
+
// get the device mapper fd
int fd;
if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
@@ -369,6 +399,7 @@
goto out;
}
+ verity_table = verity_table_signature = NULL;
// read the verity block at the end of the block device
if (read_verity_metadata(fstab->blk_device,
&verity_table_signature,
@@ -402,7 +433,8 @@
goto out;
}
- retval = 0;
+ // set the property indicating that the partition is verified
+ retval = set_verified_property(mount_point);
out:
close(fd);
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 835cf64..0c7eb20 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -24,6 +24,11 @@
extern "C" {
#endif
+/*
+ * 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
+ * return the 1st one.
+ */
struct fstab {
int num_entries;
struct fstab_rec *recs;
@@ -48,7 +53,15 @@
struct fstab *fs_mgr_read_fstab(const char *fstab_path);
void fs_mgr_free_fstab(struct fstab *fstab);
+
+#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
int fs_mgr_mount_all(struct fstab *fstab);
+
+#define FS_MGR_DOMNT_FAILED -1
+#define FS_MGR_DOMNT_BUSY -2
int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
char *tmp_mount_point);
int fs_mgr_do_tmpfs_mount(char *n_name);
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 473d375..1d238b1 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -7,12 +7,15 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := healthd_board_default.cpp
LOCAL_MODULE := libhealthd.default
+LOCAL_CFLAGS := -Werror
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
healthd.cpp \
+ healthd_mode_android.cpp \
+ healthd_mode_charger.cpp \
BatteryMonitor.cpp \
BatteryPropertiesRegistrar.cpp
@@ -22,9 +25,57 @@
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
-LOCAL_STATIC_LIBRARIES := libbatteryservice libbinder libz libutils libstdc++ libcutils liblog libm libc
+LOCAL_CFLAGS := -D__STDC_LIMIT_MACROS -Werror
+
+ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
+LOCAL_CFLAGS += -DCHARGER_DISABLE_INIT_BLANK
+endif
+
+ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
+LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
+endif
+
+LOCAL_C_INCLUDES := bootable/recovery
+
+LOCAL_STATIC_LIBRARIES := libbatteryservice libbinder libminui libpng libz libutils libstdc++ libcutils liblog libm libc
+
+ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
+LOCAL_STATIC_LIBRARIES += libsuspend
+endif
+
LOCAL_HAL_STATIC_LIBRARIES := libhealthd
+# Symlink /charger to /sbin/healthd
+LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT) \
+ && ln -sf /sbin/healthd $(TARGET_ROOT_OUT)/charger
+
include $(BUILD_EXECUTABLE)
+
+define _add-charger-image
+include $$(CLEAR_VARS)
+LOCAL_MODULE := system_core_charger_$(notdir $(1))
+LOCAL_MODULE_STEM := $(notdir $(1))
+_img_modules += $$(LOCAL_MODULE)
+LOCAL_SRC_FILES := $1
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $$(TARGET_ROOT_OUT)/res/images/charger
+include $$(BUILD_PREBUILT)
+endef
+
+_img_modules :=
+_images :=
+$(foreach _img, $(call find-subdir-subdir-files, "images", "*.png"), \
+ $(eval $(call _add-charger-image,$(_img))))
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := charger_res_images
+LOCAL_MODULE_TAGS := optional
+LOCAL_REQUIRED_MODULES := $(_img_modules)
+include $(BUILD_PHONY_PACKAGE)
+
+_add-charger-image :=
+_img_modules :=
+
endif
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 688c7ff..06497c2 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -18,7 +18,6 @@
#include "healthd.h"
#include "BatteryMonitor.h"
-#include "BatteryPropertiesRegistrar.h"
#include <dirent.h>
#include <errno.h>
@@ -28,16 +27,21 @@
#include <unistd.h>
#include <batteryservice/BatteryService.h>
#include <cutils/klog.h>
+#include <cutils/properties.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#define POWER_SUPPLY_SUBSYSTEM "power_supply"
#define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
+#define FAKE_BATTERY_CAPACITY 42
+#define FAKE_BATTERY_TEMPERATURE 424
namespace android {
struct sysfsStringEnumMap {
- char* s;
+ const char* s;
int val;
};
@@ -170,7 +174,6 @@
}
bool BatteryMonitor::update(void) {
- struct BatteryProperties props;
bool logthis;
props.chargerAcOnline = false;
@@ -178,24 +181,20 @@
props.chargerWirelessOnline = false;
props.batteryStatus = BATTERY_STATUS_UNKNOWN;
props.batteryHealth = BATTERY_HEALTH_UNKNOWN;
- props.batteryCurrentNow = INT_MIN;
- props.batteryChargeCounter = INT_MIN;
if (!mHealthdConfig->batteryPresentPath.isEmpty())
props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
else
- props.batteryPresent = true;
+ props.batteryPresent = mBatteryDevicePresent;
- props.batteryLevel = getIntField(mHealthdConfig->batteryCapacityPath);
+ props.batteryLevel = mBatteryFixedCapacity ?
+ mBatteryFixedCapacity :
+ getIntField(mHealthdConfig->batteryCapacityPath);
props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
- if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
- props.batteryCurrentNow = getIntField(mHealthdConfig->batteryCurrentNowPath);
-
- if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
- props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);
-
- props.batteryTemperature = getIntField(mHealthdConfig->batteryTemperaturePath);
+ props.batteryTemperature = mBatteryFixedTemperature ?
+ mBatteryFixedTemperature :
+ getIntField(mHealthdConfig->batteryTemperaturePath);
const int SIZE = 128;
char buf[SIZE];
@@ -244,7 +243,9 @@
if (logthis) {
char dmesgline[256];
- snprintf(dmesgline, sizeof(dmesgline),
+
+ if (props.batteryPresent) {
+ snprintf(dmesgline, sizeof(dmesgline),
"battery l=%d v=%d t=%s%d.%d h=%d st=%d",
props.batteryLevel, props.batteryVoltage,
props.batteryTemperature < 0 ? "-" : "",
@@ -252,11 +253,16 @@
abs(props.batteryTemperature % 10), props.batteryHealth,
props.batteryStatus);
- if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
- char b[20];
+ if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+ int c = getIntField(mHealthdConfig->batteryCurrentNowPath);
+ char b[20];
- snprintf(b, sizeof(b), " c=%d", props.batteryCurrentNow / 1000);
- strlcat(dmesgline, b, sizeof(dmesgline));
+ snprintf(b, sizeof(b), " c=%d", c / 1000);
+ strlcat(dmesgline, b, sizeof(dmesgline));
+ }
+ } else {
+ snprintf(dmesgline, sizeof(dmesgline),
+ "battery none");
}
KLOG_INFO(LOG_TAG, "%s chg=%s%s%s\n", dmesgline,
@@ -265,15 +271,110 @@
props.chargerWirelessOnline ? "w" : "");
}
- if (mBatteryPropertiesRegistrar != NULL)
- mBatteryPropertiesRegistrar->notifyListeners(props);
-
+ healthd_mode_ops->battery_update(&props);
return props.chargerAcOnline | props.chargerUsbOnline |
props.chargerWirelessOnline;
}
-void BatteryMonitor::init(struct healthd_config *hc, bool nosvcmgr) {
+status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
+ status_t ret = BAD_VALUE;
+
+ val->valueInt64 = LONG_MIN;
+
+ switch(id) {
+ case BATTERY_PROP_CHARGE_COUNTER:
+ if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
+ val->valueInt64 =
+ getIntField(mHealthdConfig->batteryChargeCounterPath);
+ ret = NO_ERROR;
+ } else {
+ ret = NAME_NOT_FOUND;
+ }
+ break;
+
+ case BATTERY_PROP_CURRENT_NOW:
+ if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+ val->valueInt64 =
+ getIntField(mHealthdConfig->batteryCurrentNowPath);
+ ret = NO_ERROR;
+ } else {
+ ret = NAME_NOT_FOUND;
+ }
+ break;
+
+ case BATTERY_PROP_CURRENT_AVG:
+ if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
+ val->valueInt64 =
+ getIntField(mHealthdConfig->batteryCurrentAvgPath);
+ ret = NO_ERROR;
+ } else {
+ ret = NAME_NOT_FOUND;
+ }
+ break;
+
+ case BATTERY_PROP_CAPACITY:
+ if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
+ val->valueInt64 =
+ getIntField(mHealthdConfig->batteryCapacityPath);
+ ret = NO_ERROR;
+ } else {
+ ret = NAME_NOT_FOUND;
+ }
+ break;
+
+ case BATTERY_PROP_ENERGY_COUNTER:
+ if (mHealthdConfig->energyCounter) {
+ ret = mHealthdConfig->energyCounter(&val->valueInt64);
+ } else {
+ ret = NAME_NOT_FOUND;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+void BatteryMonitor::dumpState(int fd) {
+ int v;
+ char vs[128];
+
+ snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d\n",
+ props.chargerAcOnline, props.chargerUsbOnline,
+ props.chargerWirelessOnline);
+ write(fd, vs, strlen(vs));
+ snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
+ props.batteryStatus, props.batteryHealth, props.batteryPresent);
+ write(fd, vs, strlen(vs));
+ snprintf(vs, sizeof(vs), "level: %d voltage: %d temp: %d\n",
+ props.batteryLevel, props.batteryVoltage,
+ props.batteryTemperature);
+ write(fd, vs, strlen(vs));
+
+ if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+ v = getIntField(mHealthdConfig->batteryCurrentNowPath);
+ snprintf(vs, sizeof(vs), "current now: %d\n", v);
+ write(fd, vs, strlen(vs));
+ }
+
+ if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
+ v = getIntField(mHealthdConfig->batteryCurrentAvgPath);
+ snprintf(vs, sizeof(vs), "current avg: %d\n", v);
+ write(fd, vs, strlen(vs));
+ }
+
+ if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
+ v = getIntField(mHealthdConfig->batteryChargeCounterPath);
+ snprintf(vs, sizeof(vs), "charge counter: %d\n", v);
+ write(fd, vs, strlen(vs));
+ }
+}
+
+void BatteryMonitor::init(struct healthd_config *hc) {
String8 path;
+ char pval[PROPERTY_VALUE_MAX];
mHealthdConfig = hc;
DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);
@@ -288,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);
@@ -303,6 +403,8 @@
break;
case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
+ mBatteryDevicePresent = true;
+
if (mHealthdConfig->batteryStatusPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
@@ -358,6 +460,14 @@
mHealthdConfig->batteryCurrentNowPath = path;
}
+ if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
+ path.clear();
+ path.appendFormat("%s/%s/current_avg",
+ POWER_SUPPLY_SYSFS_PATH, name);
+ if (access(path, R_OK) == 0)
+ mHealthdConfig->batteryCurrentAvgPath = path;
+ }
+
if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/charge_counter",
@@ -400,24 +510,31 @@
if (!mChargerNames.size())
KLOG_ERROR(LOG_TAG, "No charger supplies found\n");
- if (mHealthdConfig->batteryStatusPath.isEmpty())
- KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
- if (mHealthdConfig->batteryHealthPath.isEmpty())
- KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
- if (mHealthdConfig->batteryPresentPath.isEmpty())
- KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
- if (mHealthdConfig->batteryCapacityPath.isEmpty())
- KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
- if (mHealthdConfig->batteryVoltagePath.isEmpty())
- KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
- if (mHealthdConfig->batteryTemperaturePath.isEmpty())
- KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
- if (mHealthdConfig->batteryTechnologyPath.isEmpty())
- KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
+ if (!mBatteryDevicePresent) {
+ KLOG_INFO(LOG_TAG, "No battery devices found\n");
+ hc->periodic_chores_interval_fast = -1;
+ hc->periodic_chores_interval_slow = -1;
+ } else {
+ if (mHealthdConfig->batteryStatusPath.isEmpty())
+ KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
+ if (mHealthdConfig->batteryHealthPath.isEmpty())
+ KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
+ if (mHealthdConfig->batteryPresentPath.isEmpty())
+ KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
+ if (mHealthdConfig->batteryCapacityPath.isEmpty())
+ KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
+ if (mHealthdConfig->batteryVoltagePath.isEmpty())
+ KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
+ if (mHealthdConfig->batteryTemperaturePath.isEmpty())
+ KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
+ if (mHealthdConfig->batteryTechnologyPath.isEmpty())
+ KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
+ }
- if (nosvcmgr == false) {
- mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(this);
- mBatteryPropertiesRegistrar->publish();
+ if (property_get("ro.boot.fake_battery", pval, NULL) > 0
+ && strtol(pval, NULL, 10) != 0) {
+ mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY;
+ mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
}
}
diff --git a/healthd/BatteryMonitor.h b/healthd/BatteryMonitor.h
index ba291af..3425f27 100644
--- a/healthd/BatteryMonitor.h
+++ b/healthd/BatteryMonitor.h
@@ -17,17 +17,15 @@
#ifndef HEALTHD_BATTERYMONITOR_H
#define HEALTHD_BATTERYMONITOR_H
+#include <batteryservice/BatteryService.h>
#include <binder/IInterface.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include "healthd.h"
-#include "BatteryPropertiesRegistrar.h"
namespace android {
-class BatteryPropertiesRegistrar;
-
class BatteryMonitor {
public:
@@ -39,14 +37,18 @@
ANDROID_POWER_SUPPLY_TYPE_BATTERY
};
- void init(struct healthd_config *hc, bool nosvcmgr);
+ void init(struct healthd_config *hc);
bool update(void);
+ status_t getProperty(int id, struct BatteryProperty *val);
+ void dumpState(int fd);
private:
struct healthd_config *mHealthdConfig;
Vector<String8> mChargerNames;
-
- sp<BatteryPropertiesRegistrar> mBatteryPropertiesRegistrar;
+ bool mBatteryDevicePresent;
+ int mBatteryFixedCapacity;
+ int mBatteryFixedTemperature;
+ struct BatteryProperties props;
int getBatteryStatus(const char* status);
int getBatteryHealth(const char* status);
diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp
index 6a33ad8..09667a1 100644
--- a/healthd/BatteryPropertiesRegistrar.cpp
+++ b/healthd/BatteryPropertiesRegistrar.cpp
@@ -18,19 +18,20 @@
#include <batteryservice/BatteryService.h>
#include <batteryservice/IBatteryPropertiesListener.h>
#include <batteryservice/IBatteryPropertiesRegistrar.h>
+#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+#include <private/android_filesystem_config.h>
#include <utils/Errors.h>
#include <utils/Mutex.h>
#include <utils/String16.h>
+#include "healthd.h"
+
namespace android {
-BatteryPropertiesRegistrar::BatteryPropertiesRegistrar(BatteryMonitor* monitor) {
- mBatteryMonitor = monitor;
-}
-
void BatteryPropertiesRegistrar::publish() {
- defaultServiceManager()->addService(String16("batterypropreg"), this);
+ defaultServiceManager()->addService(String16("batteryproperties"), this);
}
void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) {
@@ -42,36 +43,57 @@
void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesListener>& listener) {
{
+ if (listener == NULL)
+ return;
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);
}
- mBatteryMonitor->update();
+ healthd_battery_update();
}
void BatteryPropertiesRegistrar::unregisterListener(const sp<IBatteryPropertiesListener>& listener) {
+ if (listener == NULL)
+ 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;
}
}
}
+status_t BatteryPropertiesRegistrar::getProperty(int id, struct BatteryProperty *val) {
+ return healthd_get_property(id, val);
+}
+
+status_t BatteryPropertiesRegistrar::dump(int fd, const Vector<String16>& /*args*/) {
+ IPCThreadState* self = IPCThreadState::self();
+ const int pid = self->getCallingPid();
+ const int uid = self->getCallingUid();
+ if ((uid != AID_SHELL) &&
+ !PermissionCache::checkPermission(
+ String16("android.permission.DUMP"), pid, uid))
+ return PERMISSION_DENIED;
+
+ healthd_dump_battery_state(fd);
+ return OK;
+}
+
void BatteryPropertiesRegistrar::binderDied(const wp<IBinder>& who) {
Mutex::Autolock _l(mRegistrationLock);
for (size_t i = 0; i < mListeners.size(); i++) {
- if (mListeners[i]->asBinder() == who) {
+ if (IInterface::asBinder(mListeners[i]) == who) {
mListeners.removeAt(i);
break;
}
diff --git a/healthd/BatteryPropertiesRegistrar.h b/healthd/BatteryPropertiesRegistrar.h
index 793ddad..8853874 100644
--- a/healthd/BatteryPropertiesRegistrar.h
+++ b/healthd/BatteryPropertiesRegistrar.h
@@ -17,10 +17,9 @@
#ifndef HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
#define HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
-#include "BatteryMonitor.h"
-
#include <binder/IBinder.h>
#include <utils/Mutex.h>
+#include <utils/String16.h>
#include <utils/Vector.h>
#include <batteryservice/BatteryService.h>
#include <batteryservice/IBatteryPropertiesListener.h>
@@ -28,22 +27,20 @@
namespace android {
-class BatteryMonitor;
-
class BatteryPropertiesRegistrar : public BnBatteryPropertiesRegistrar,
public IBinder::DeathRecipient {
public:
- BatteryPropertiesRegistrar(BatteryMonitor* monitor);
void publish();
void notifyListeners(struct BatteryProperties props);
private:
- BatteryMonitor* mBatteryMonitor;
Mutex mRegistrationLock;
Vector<sp<IBatteryPropertiesListener> > mListeners;
void registerListener(const sp<IBatteryPropertiesListener>& listener);
void unregisterListener(const sp<IBatteryPropertiesListener>& listener);
+ status_t getProperty(int id, struct BatteryProperty *val);
+ status_t dump(int fd, const Vector<String16>& args);
void binderDied(const wp<IBinder>& who);
};
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index 9b84c3e..b34583d 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -21,16 +21,17 @@
#include "BatteryMonitor.h"
#include <errno.h>
+#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include <batteryservice/BatteryService.h>
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
#include <cutils/klog.h>
#include <cutils/uevent.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
+#include <utils/Errors.h>
using namespace android;
@@ -49,16 +50,20 @@
.batteryTemperaturePath = String8(String8::kEmptyString),
.batteryTechnologyPath = String8(String8::kEmptyString),
.batteryCurrentNowPath = String8(String8::kEmptyString),
+ .batteryCurrentAvgPath = String8(String8::kEmptyString),
.batteryChargeCounterPath = String8(String8::kEmptyString),
+ .energyCounter = NULL,
};
+static int eventct;
+static int epollfd;
+
#define POWER_SUPPLY_SUBSYSTEM "power_supply"
-// epoll events: uevent, wakealarm, binder
-#define MAX_EPOLL_EVENTS 3
+// epoll_create() parameter is actually unused
+#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;
@@ -67,7 +72,80 @@
static BatteryMonitor* gBatteryMonitor;
-static bool nosvcmgr;
+struct healthd_mode_ops *healthd_mode_ops;
+
+// Android mode
+
+extern void healthd_mode_android_init(struct healthd_config *config);
+extern int healthd_mode_android_preparetowait(void);
+extern void healthd_mode_android_battery_update(
+ struct android::BatteryProperties *props);
+
+// Charger mode
+
+extern void healthd_mode_charger_init(struct healthd_config *config);
+extern int healthd_mode_charger_preparetowait(void);
+extern void healthd_mode_charger_heartbeat(void);
+extern void healthd_mode_charger_battery_update(
+ struct android::BatteryProperties *props);
+
+// NOPs for modes that need no special action
+
+static void healthd_mode_nop_init(struct healthd_config *config);
+static int healthd_mode_nop_preparetowait(void);
+static void healthd_mode_nop_heartbeat(void);
+static void healthd_mode_nop_battery_update(
+ struct android::BatteryProperties *props);
+
+static struct healthd_mode_ops android_ops = {
+ .init = healthd_mode_android_init,
+ .preparetowait = healthd_mode_android_preparetowait,
+ .heartbeat = healthd_mode_nop_heartbeat,
+ .battery_update = healthd_mode_android_battery_update,
+};
+
+static struct healthd_mode_ops charger_ops = {
+ .init = healthd_mode_charger_init,
+ .preparetowait = healthd_mode_charger_preparetowait,
+ .heartbeat = healthd_mode_charger_heartbeat,
+ .battery_update = healthd_mode_charger_battery_update,
+};
+
+static struct healthd_mode_ops recovery_ops = {
+ .init = healthd_mode_nop_init,
+ .preparetowait = healthd_mode_nop_preparetowait,
+ .heartbeat = healthd_mode_nop_heartbeat,
+ .battery_update = healthd_mode_nop_battery_update,
+};
+
+static void healthd_mode_nop_init(struct healthd_config* /*config*/) {
+}
+
+static int healthd_mode_nop_preparetowait(void) {
+ return -1;
+}
+
+static void healthd_mode_nop_heartbeat(void) {
+}
+
+static void healthd_mode_nop_battery_update(
+ struct android::BatteryProperties* /*props*/) {
+}
+
+int healthd_register_event(int fd, void (*handler)(uint32_t)) {
+ struct epoll_event ev;
+
+ ev.events = EPOLLIN | EPOLLWAKEUP;
+ ev.data.ptr = (void *)handler;
+ if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+ KLOG_ERROR(LOG_TAG,
+ "epoll_ctl failed; errno=%d\n", errno);
+ return -1;
+ }
+
+ eventct++;
+ return 0;
+}
static void wakealarm_set_interval(int interval) {
struct itimerspec itval;
@@ -89,7 +167,11 @@
KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
}
-static void battery_update(void) {
+status_t healthd_get_property(int id, struct BatteryProperty *val) {
+ return gBatteryMonitor->getProperty(id, val);
+}
+
+void healthd_battery_update(void) {
// Fast wake interval when on charger (watch for overheat);
// slow wake interval when on battery (watch for drained battery).
@@ -113,21 +195,17 @@
-1 : healthd_config.periodic_chores_interval_fast * 1000;
}
+void healthd_dump_battery_state(int fd) {
+ gBatteryMonitor->dumpState(fd);
+ fsync(fd);
+}
+
static void periodic_chores() {
- battery_update();
+ healthd_battery_update();
}
-static void uevent_init(void) {
- uevent_fd = uevent_open_socket(64*1024, true);
-
- if (uevent_fd >= 0)
- fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
- else
- KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
-}
-
-#define UEVENT_MSG_LEN 1024
-static void uevent_event(void) {
+#define UEVENT_MSG_LEN 2048
+static void uevent_event(uint32_t /*epevents*/) {
char msg[UEVENT_MSG_LEN+2];
char *cp;
int n;
@@ -144,7 +222,7 @@
while (*cp) {
if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
- battery_update();
+ healthd_battery_update();
break;
}
@@ -154,6 +232,31 @@
}
}
+static void uevent_init(void) {
+ uevent_fd = uevent_open_socket(64*1024, true);
+
+ if (uevent_fd < 0) {
+ KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+ return;
+ }
+
+ fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
+ if (healthd_register_event(uevent_fd, uevent_event))
+ KLOG_ERROR(LOG_TAG,
+ "register for uevent events failed\n");
+}
+
+static void wakealarm_event(uint32_t /*epevents*/) {
+ unsigned long long wakeups;
+
+ if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
+ KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
+ return;
+ }
+
+ periodic_chores();
+}
+
static void wakealarm_init(void) {
wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
if (wakealarm_fd == -1) {
@@ -161,82 +264,24 @@
return;
}
+ if (healthd_register_event(wakealarm_fd, wakealarm_event))
+ KLOG_ERROR(LOG_TAG,
+ "Registration of wakealarm event failed\n");
+
wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
}
-static void wakealarm_event(void) {
- unsigned long long wakeups;
-
- if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
- KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm_fd failed\n");
- return;
- }
-
- periodic_chores();
-}
-
-static void binder_init(void) {
- ProcessState::self()->setThreadPoolMaxThreadCount(0);
- IPCThreadState::self()->disableBackgroundScheduling(true);
- IPCThreadState::self()->setupPolling(&binder_fd);
-}
-
-static void binder_event(void) {
- IPCThreadState::self()->handlePolledCommands();
-}
-
static void healthd_mainloop(void) {
- struct epoll_event ev;
- int epollfd;
- int maxevents = 0;
-
- epollfd = epoll_create(MAX_EPOLL_EVENTS);
- if (epollfd == -1) {
- KLOG_ERROR(LOG_TAG,
- "healthd_mainloop: epoll_create failed; errno=%d\n",
- errno);
- return;
- }
-
- if (uevent_fd >= 0) {
- ev.events = EPOLLIN | EPOLLWAKEUP;
- ev.data.ptr = (void *)uevent_event;
- if (epoll_ctl(epollfd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1)
- KLOG_ERROR(LOG_TAG,
- "healthd_mainloop: epoll_ctl for uevent_fd failed; errno=%d\n",
- errno);
- else
- maxevents++;
- }
-
- if (wakealarm_fd >= 0) {
- ev.events = EPOLLIN | EPOLLWAKEUP;
- ev.data.ptr = (void *)wakealarm_event;
- if (epoll_ctl(epollfd, EPOLL_CTL_ADD, wakealarm_fd, &ev) == -1)
- KLOG_ERROR(LOG_TAG,
- "healthd_mainloop: epoll_ctl for wakealarm_fd failed; errno=%d\n",
- errno);
- else
- maxevents++;
- }
-
- if (binder_fd >= 0) {
- ev.events = EPOLLIN | EPOLLWAKEUP;
- ev.data.ptr= (void *)binder_event;
- if (epoll_ctl(epollfd, EPOLL_CTL_ADD, binder_fd, &ev) == -1)
- KLOG_ERROR(LOG_TAG,
- "healthd_mainloop: epoll_ctl for binder_fd failed; errno=%d\n",
- errno);
- else
- maxevents++;
- }
-
while (1) {
- struct epoll_event events[maxevents];
+ struct epoll_event events[eventct];
int nevents;
+ int timeout = awake_poll_interval;
+ int mode_timeout;
- IPCThreadState::self()->flushCommands();
- nevents = epoll_wait(epollfd, events, maxevents, awake_poll_interval);
+ mode_timeout = healthd_mode_ops->preparetowait();
+ if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
+ timeout = mode_timeout;
+ nevents = epoll_wait(epollfd, events, eventct, timeout);
if (nevents == -1) {
if (errno == EINTR)
@@ -247,39 +292,70 @@
for (int n = 0; n < nevents; ++n) {
if (events[n].data.ptr)
- (*(void (*)())events[n].data.ptr)();
+ (*(void (*)(int))events[n].data.ptr)(events[n].events);
}
if (!nevents)
periodic_chores();
+
+ healthd_mode_ops->heartbeat();
}
return;
}
-int main(int argc, char **argv) {
- int ch;
-
- klog_set_level(KLOG_LEVEL);
-
- while ((ch = getopt(argc, argv, "n")) != -1) {
- switch (ch) {
- case 'n':
- nosvcmgr = true;
- break;
- case '?':
- default:
- KLOG_WARNING(LOG_TAG, "Unrecognized healthd option: %c\n", ch);
- }
+static int healthd_init() {
+ epollfd = epoll_create(MAX_EPOLL_EVENTS);
+ if (epollfd == -1) {
+ KLOG_ERROR(LOG_TAG,
+ "epoll_create failed; errno=%d\n",
+ errno);
+ return -1;
}
+ healthd_mode_ops->init(&healthd_config);
healthd_board_init(&healthd_config);
wakealarm_init();
uevent_init();
- binder_init();
gBatteryMonitor = new BatteryMonitor();
- gBatteryMonitor->init(&healthd_config, nosvcmgr);
+ gBatteryMonitor->init(&healthd_config);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ int ch;
+ int ret;
+
+ klog_set_level(KLOG_LEVEL);
+ healthd_mode_ops = &android_ops;
+
+ if (!strcmp(basename(argv[0]), "charger")) {
+ healthd_mode_ops = &charger_ops;
+ } else {
+ while ((ch = getopt(argc, argv, "cr")) != -1) {
+ switch (ch) {
+ case 'c':
+ healthd_mode_ops = &charger_ops;
+ break;
+ case 'r':
+ healthd_mode_ops = &recovery_ops;
+ break;
+ case '?':
+ default:
+ KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n",
+ optopt);
+ exit(1);
+ }
+ }
+ }
+
+ ret = healthd_init();
+ if (ret) {
+ KLOG_ERROR("Initialization failed, exiting\n");
+ exit(2);
+ }
healthd_mainloop();
- return 0;
+ KLOG_ERROR("Main loop terminated, exiting\n");
+ return 3;
}
diff --git a/healthd/healthd.h b/healthd/healthd.h
index 5374fb1..972e728 100644
--- a/healthd/healthd.h
+++ b/healthd/healthd.h
@@ -18,6 +18,8 @@
#define _HEALTHD_H_
#include <batteryservice/BatteryService.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
#include <utils/String8.h>
// periodic_chores_interval_fast, periodic_chores_interval_slow: intervals at
@@ -61,9 +63,37 @@
android::String8 batteryTemperaturePath;
android::String8 batteryTechnologyPath;
android::String8 batteryCurrentNowPath;
+ android::String8 batteryCurrentAvgPath;
android::String8 batteryChargeCounterPath;
+
+ int (*energyCounter)(int64_t *);
};
+// Global helper functions
+
+int healthd_register_event(int fd, void (*handler)(uint32_t));
+void healthd_battery_update();
+android::status_t healthd_get_property(int id,
+ struct android::BatteryProperty *val);
+void healthd_dump_battery_state(int fd);
+
+struct healthd_mode_ops {
+ void (*init)(struct healthd_config *config);
+ int (*preparetowait)(void);
+ void (*heartbeat)(void);
+ void (*battery_update)(struct android::BatteryProperties *props);
+};
+
+extern struct healthd_mode_ops *healthd_mode_ops;
+
+// Charger mode
+
+void healthd_mode_charger_init(struct healthd_config *config);
+int healthd_mode_charger_preparetowait(void);
+void healthd_mode_charger_heartbeat(void);
+void healthd_mode_charger_battery_update(
+ struct android::BatteryProperties *props);
+
// The following are implemented in libhealthd_board to handle board-specific
// behavior.
//
diff --git a/healthd/healthd_mode_android.cpp b/healthd/healthd_mode_android.cpp
new file mode 100644
index 0000000..fd153a2
--- /dev/null
+++ b/healthd/healthd_mode_android.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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 LOG_TAG "healthd-android"
+
+#include "healthd.h"
+#include "BatteryPropertiesRegistrar.h"
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <cutils/klog.h>
+#include <sys/epoll.h>
+
+using namespace android;
+
+static int gBinderFd;
+static sp<BatteryPropertiesRegistrar> gBatteryPropertiesRegistrar;
+
+void healthd_mode_android_battery_update(
+ struct android::BatteryProperties *props) {
+ if (gBatteryPropertiesRegistrar != NULL)
+ gBatteryPropertiesRegistrar->notifyListeners(*props);
+
+ return;
+}
+
+int healthd_mode_android_preparetowait(void) {
+ IPCThreadState::self()->flushCommands();
+ return -1;
+}
+
+static void binder_event(uint32_t /*epevents*/) {
+ IPCThreadState::self()->handlePolledCommands();
+}
+
+void healthd_mode_android_init(struct healthd_config* /*config*/) {
+ ProcessState::self()->setThreadPoolMaxThreadCount(0);
+ IPCThreadState::self()->disableBackgroundScheduling(true);
+ IPCThreadState::self()->setupPolling(&gBinderFd);
+
+ if (gBinderFd >= 0) {
+ if (healthd_register_event(gBinderFd, binder_event))
+ KLOG_ERROR(LOG_TAG,
+ "Register for binder events failed\n");
+ }
+
+ gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
+ gBatteryPropertiesRegistrar->publish();
+}
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
new file mode 100644
index 0000000..291cb6c
--- /dev/null
+++ b/healthd/healthd_mode_charger.cpp
@@ -0,0 +1,714 @@
+/*
+ * Copyright (C) 2011-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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <linux/input.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <linux/netlink.h>
+
+#include <batteryservice/BatteryService.h>
+#include <cutils/android_reboot.h>
+#include <cutils/klog.h>
+#include <cutils/misc.h>
+#include <cutils/uevent.h>
+#include <cutils/properties.h>
+
+#ifdef CHARGER_ENABLE_SUSPEND
+#include <suspend/autosuspend.h>
+#endif
+
+#include "minui/minui.h"
+
+#include "healthd.h"
+
+char *locale;
+
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+#define MSEC_PER_SEC (1000LL)
+#define NSEC_PER_MSEC (1000000LL)
+
+#define BATTERY_UNKNOWN_TIME (2 * MSEC_PER_SEC)
+#define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC)
+#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
+
+#define BATTERY_FULL_THRESH 95
+#define SCREEN_ON_BATTERY_THRESH 0
+
+#define LAST_KMSG_PATH "/proc/last_kmsg"
+#define LAST_KMSG_PSTORE_PATH "/sys/fs/pstore/console-ramoops"
+#define LAST_KMSG_MAX_SZ (32 * 1024)
+
+#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
+#define LOGI(x...) do { KLOG_INFO("charger", x); } while (0)
+#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
+
+struct key_state {
+ bool pending;
+ bool down;
+ int64_t timestamp;
+};
+
+struct frame {
+ int disp_time;
+ int min_capacity;
+ bool level_only;
+
+ gr_surface surface;
+};
+
+struct animation {
+ bool run;
+
+ struct frame *frames;
+ int cur_frame;
+ int num_frames;
+
+ int cur_cycle;
+ int num_cycles;
+
+ /* current capacity being animated */
+ int capacity;
+};
+
+struct charger {
+ bool have_battery_state;
+ bool charger_connected;
+ int capacity;
+ int64_t next_screen_transition;
+ int64_t next_key_check;
+ int64_t next_pwr_check;
+
+ struct key_state keys[KEY_MAX + 1];
+
+ struct animation *batt_anim;
+ gr_surface surf_unknown;
+};
+
+static struct frame batt_anim_frames[] = {
+ {
+ .disp_time = 750,
+ .min_capacity = 0,
+ .level_only = false,
+ .surface = NULL,
+ },
+ {
+ .disp_time = 750,
+ .min_capacity = 20,
+ .level_only = false,
+ .surface = NULL,
+ },
+ {
+ .disp_time = 750,
+ .min_capacity = 40,
+ .level_only = false,
+ .surface = NULL,
+ },
+ {
+ .disp_time = 750,
+ .min_capacity = 60,
+ .level_only = false,
+ .surface = NULL,
+ },
+ {
+ .disp_time = 750,
+ .min_capacity = 80,
+ .level_only = true,
+ .surface = NULL,
+ },
+ {
+ .disp_time = 750,
+ .min_capacity = BATTERY_FULL_THRESH,
+ .level_only = false,
+ .surface = NULL,
+ },
+};
+
+static struct animation battery_animation = {
+ .run = false,
+ .frames = batt_anim_frames,
+ .cur_frame = 0,
+ .num_frames = ARRAY_SIZE(batt_anim_frames),
+ .cur_cycle = 0,
+ .num_cycles = 3,
+ .capacity = 0,
+};
+
+static struct charger charger_state;
+
+static int char_width;
+static int char_height;
+static bool minui_inited;
+
+/* current time in milliseconds */
+static int64_t curr_time_ms(void)
+{
+ struct timespec tm;
+ clock_gettime(CLOCK_MONOTONIC, &tm);
+ return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
+}
+
+static void clear_screen(void)
+{
+ gr_color(0, 0, 0, 255);
+ gr_clear();
+}
+
+#define MAX_KLOG_WRITE_BUF_SZ 256
+
+static void dump_last_kmsg(void)
+{
+ char *buf;
+ char *ptr;
+ unsigned sz = 0;
+ int len;
+
+ LOGI("\n");
+ LOGI("*************** LAST KMSG ***************\n");
+ LOGI("\n");
+ buf = (char *)load_file(LAST_KMSG_PSTORE_PATH, &sz);
+
+ if (!buf || !sz) {
+ buf = (char *)load_file(LAST_KMSG_PATH, &sz);
+ if (!buf || !sz) {
+ LOGI("last_kmsg not found. Cold reset?\n");
+ goto out;
+ }
+ }
+
+ len = min(sz, LAST_KMSG_MAX_SZ);
+ ptr = buf + (sz - len);
+
+ while (len > 0) {
+ int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
+ char yoink;
+ char *nl;
+
+ nl = (char *)memrchr(ptr, '\n', cnt - 1);
+ if (nl)
+ cnt = nl - ptr + 1;
+
+ yoink = ptr[cnt];
+ ptr[cnt] = '\0';
+ klog_write(6, "<6>%s", ptr);
+ ptr[cnt] = yoink;
+
+ len -= cnt;
+ ptr += cnt;
+ }
+
+ free(buf);
+
+out:
+ LOGI("\n");
+ LOGI("************* END LAST KMSG *************\n");
+ LOGI("\n");
+}
+
+static int get_battery_capacity()
+{
+ return charger_state.capacity;
+}
+
+#ifdef CHARGER_ENABLE_SUSPEND
+static int request_suspend(bool enable)
+{
+ if (enable)
+ return autosuspend_enable();
+ else
+ return autosuspend_disable();
+}
+#else
+static int request_suspend(bool /*enable*/)
+{
+ return 0;
+}
+#endif
+
+static int draw_text(const char *str, int x, int y)
+{
+ int str_len_px = gr_measure(str);
+
+ if (x < 0)
+ x = (gr_fb_width() - str_len_px) / 2;
+ if (y < 0)
+ y = (gr_fb_height() - char_height) / 2;
+ gr_text(x, y, str, 0);
+
+ return y + char_height;
+}
+
+static void android_green(void)
+{
+ gr_color(0xa4, 0xc6, 0x39, 255);
+}
+
+/* returns the last y-offset of where the surface ends */
+static int draw_surface_centered(struct charger* /*charger*/, gr_surface surface)
+{
+ int w;
+ int h;
+ int x;
+ int y;
+
+ w = gr_get_width(surface);
+ h = gr_get_height(surface);
+ x = (gr_fb_width() - w) / 2 ;
+ y = (gr_fb_height() - h) / 2 ;
+
+ LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
+ gr_blit(surface, 0, 0, w, h, x, y);
+ return y + h;
+}
+
+static void draw_unknown(struct charger *charger)
+{
+ int y;
+ if (charger->surf_unknown) {
+ draw_surface_centered(charger, charger->surf_unknown);
+ } else {
+ android_green();
+ y = draw_text("Charging!", -1, -1);
+ draw_text("?\?/100", -1, y + 25);
+ }
+}
+
+static void draw_battery(struct charger *charger)
+{
+ struct animation *batt_anim = charger->batt_anim;
+ struct frame *frame = &batt_anim->frames[batt_anim->cur_frame];
+
+ if (batt_anim->num_frames != 0) {
+ draw_surface_centered(charger, frame->surface);
+ LOGV("drawing frame #%d min_cap=%d time=%d\n",
+ batt_anim->cur_frame, frame->min_capacity,
+ frame->disp_time);
+ }
+}
+
+static void redraw_screen(struct charger *charger)
+{
+ struct animation *batt_anim = charger->batt_anim;
+
+ clear_screen();
+
+ /* try to display *something* */
+ if (batt_anim->capacity < 0 || batt_anim->num_frames == 0)
+ draw_unknown(charger);
+ else
+ draw_battery(charger);
+ gr_flip();
+}
+
+static void kick_animation(struct animation *anim)
+{
+ anim->run = true;
+}
+
+static void reset_animation(struct animation *anim)
+{
+ anim->cur_cycle = 0;
+ anim->cur_frame = 0;
+ anim->run = false;
+}
+
+static void update_screen_state(struct charger *charger, int64_t now)
+{
+ struct animation *batt_anim = charger->batt_anim;
+ int disp_time;
+
+ if (!batt_anim->run || now < charger->next_screen_transition)
+ return;
+
+ if (!minui_inited) {
+ int batt_cap = get_battery_capacity();
+
+ if (batt_cap < SCREEN_ON_BATTERY_THRESH) {
+ LOGV("[%" PRId64 "] level %d, leave screen off\n", now, batt_cap);
+ batt_anim->run = false;
+ charger->next_screen_transition = -1;
+ if (charger->charger_connected)
+ request_suspend(true);
+ return;
+ }
+
+ gr_init();
+ gr_font_size(&char_width, &char_height);
+
+#ifndef CHARGER_DISABLE_INIT_BLANK
+ gr_fb_blank(true);
+#endif
+ minui_inited = true;
+ }
+
+ /* animation is over, blank screen and leave */
+ if (batt_anim->cur_cycle == batt_anim->num_cycles) {
+ reset_animation(batt_anim);
+ charger->next_screen_transition = -1;
+ gr_fb_blank(true);
+ LOGV("[%" PRId64 "] animation done\n", now);
+ if (charger->charger_connected)
+ request_suspend(true);
+ return;
+ }
+
+ disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time;
+
+ /* animation starting, set up the animation */
+ if (batt_anim->cur_frame == 0) {
+ int batt_cap;
+
+ LOGV("[%" PRId64 "] animation starting\n", now);
+ batt_cap = get_battery_capacity();
+ if (batt_cap >= 0 && batt_anim->num_frames != 0) {
+ int i;
+
+ /* find first frame given current capacity */
+ for (i = 1; i < batt_anim->num_frames; i++) {
+ if (batt_cap < batt_anim->frames[i].min_capacity)
+ break;
+ }
+ batt_anim->cur_frame = i - 1;
+
+ /* show the first frame for twice as long */
+ disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2;
+ }
+
+ batt_anim->capacity = batt_cap;
+ }
+
+ /* unblank the screen on first cycle */
+ if (batt_anim->cur_cycle == 0)
+ gr_fb_blank(false);
+
+ /* draw the new frame (@ cur_frame) */
+ redraw_screen(charger);
+
+ /* if we don't have anim frames, we only have one image, so just bump
+ * the cycle counter and exit
+ */
+ if (batt_anim->num_frames == 0 || batt_anim->capacity < 0) {
+ LOGV("[%" PRId64 "] animation missing or unknown battery status\n", now);
+ charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;
+ batt_anim->cur_cycle++;
+ return;
+ }
+
+ /* schedule next screen transition */
+ charger->next_screen_transition = now + disp_time;
+
+ /* advance frame cntr to the next valid frame only if we are charging
+ * if necessary, advance cycle cntr, and reset frame cntr
+ */
+ if (charger->charger_connected) {
+ batt_anim->cur_frame++;
+
+ /* if the frame is used for level-only, that is only show it when it's
+ * the current level, skip it during the animation.
+ */
+ while (batt_anim->cur_frame < batt_anim->num_frames &&
+ batt_anim->frames[batt_anim->cur_frame].level_only)
+ batt_anim->cur_frame++;
+ if (batt_anim->cur_frame >= batt_anim->num_frames) {
+ batt_anim->cur_cycle++;
+ batt_anim->cur_frame = 0;
+
+ /* don't reset the cycle counter, since we use that as a signal
+ * in a test above to check if animation is over
+ */
+ }
+ } else {
+ /* Stop animating if we're not charging.
+ * If we stop it immediately instead of going through this loop, then
+ * the animation would stop somewhere in the middle.
+ */
+ batt_anim->cur_frame = 0;
+ batt_anim->cur_cycle++;
+ }
+}
+
+static int set_key_callback(int code, int value, void *data)
+{
+ struct charger *charger = (struct charger *)data;
+ int64_t now = curr_time_ms();
+ int down = !!value;
+
+ if (code > KEY_MAX)
+ return -1;
+
+ /* ignore events that don't modify our state */
+ if (charger->keys[code].down == down)
+ return 0;
+
+ /* only record the down even timestamp, as the amount
+ * of time the key spent not being pressed is not useful */
+ if (down)
+ charger->keys[code].timestamp = now;
+ charger->keys[code].down = down;
+ charger->keys[code].pending = true;
+ if (down) {
+ LOGV("[%" PRId64 "] key[%d] down\n", now, code);
+ } else {
+ int64_t duration = now - charger->keys[code].timestamp;
+ int64_t secs = duration / 1000;
+ int64_t msecs = duration - secs * 1000;
+ LOGV("[%" PRId64 "] key[%d] up (was down for %" PRId64 ".%" PRId64 "sec)\n",
+ now, code, secs, msecs);
+ }
+
+ return 0;
+}
+
+static void update_input_state(struct charger *charger,
+ struct input_event *ev)
+{
+ if (ev->type != EV_KEY)
+ return;
+ set_key_callback(ev->code, ev->value, charger);
+}
+
+static void set_next_key_check(struct charger *charger,
+ struct key_state *key,
+ int64_t timeout)
+{
+ int64_t then = key->timestamp + timeout;
+
+ if (charger->next_key_check == -1 || then < charger->next_key_check)
+ charger->next_key_check = then;
+}
+
+static void process_key(struct charger *charger, int code, int64_t now)
+{
+ struct key_state *key = &charger->keys[code];
+
+ if (code == KEY_POWER) {
+ if (key->down) {
+ int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
+ if (now >= reboot_timeout) {
+ /* We do not currently support booting from charger mode on
+ all devices. Check the property and continue booting or reboot
+ accordingly. */
+ if (property_get_bool("ro.enable_boot_charger_mode", false)) {
+ LOGI("[%" PRId64 "] booting from charger mode\n", now);
+ property_set("sys.boot_from_charger_mode", "1");
+ } else {
+ LOGI("[%" PRId64 "] rebooting\n", now);
+ android_reboot(ANDROID_RB_RESTART, 0, 0);
+ }
+ } else {
+ /* if the key is pressed but timeout hasn't expired,
+ * make sure we wake up at the right-ish time to check
+ */
+ set_next_key_check(charger, key, POWER_ON_KEY_TIME);
+ }
+ } else {
+ /* if the power key got released, force screen state cycle */
+ if (key->pending) {
+ request_suspend(false);
+ kick_animation(charger->batt_anim);
+ }
+ }
+ }
+
+ key->pending = false;
+}
+
+static void handle_input_state(struct charger *charger, int64_t now)
+{
+ process_key(charger, KEY_POWER, now);
+
+ if (charger->next_key_check != -1 && now > charger->next_key_check)
+ charger->next_key_check = -1;
+}
+
+static void handle_power_supply_state(struct charger *charger, int64_t now)
+{
+ if (!charger->have_battery_state)
+ return;
+
+ if (!charger->charger_connected) {
+ request_suspend(false);
+ if (charger->next_pwr_check == -1) {
+ charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
+ LOGI("[%" PRId64 "] device unplugged: shutting down in %" PRId64 " (@ %" PRId64 ")\n",
+ now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
+ } else if (now >= charger->next_pwr_check) {
+ LOGI("[%" PRId64 "] shutting down\n", now);
+ android_reboot(ANDROID_RB_POWEROFF, 0, 0);
+ } else {
+ /* otherwise we already have a shutdown timer scheduled */
+ }
+ } else {
+ /* online supply present, reset shutdown timer if set */
+ if (charger->next_pwr_check != -1) {
+ LOGI("[%" PRId64 "] device plugged in: shutdown cancelled\n", now);
+ kick_animation(charger->batt_anim);
+ }
+ charger->next_pwr_check = -1;
+ }
+}
+
+void healthd_mode_charger_heartbeat()
+{
+ struct charger *charger = &charger_state;
+ int64_t now = curr_time_ms();
+
+ handle_input_state(charger, now);
+ handle_power_supply_state(charger, now);
+
+ /* do screen update last in case any of the above want to start
+ * screen transitions (animations, etc)
+ */
+ update_screen_state(charger, now);
+}
+
+void healthd_mode_charger_battery_update(
+ struct android::BatteryProperties *props)
+{
+ struct charger *charger = &charger_state;
+
+ charger->charger_connected =
+ props->chargerAcOnline || props->chargerUsbOnline ||
+ props->chargerWirelessOnline;
+ charger->capacity = props->batteryLevel;
+
+ if (!charger->have_battery_state) {
+ charger->have_battery_state = true;
+ charger->next_screen_transition = curr_time_ms() - 1;
+ reset_animation(charger->batt_anim);
+ kick_animation(charger->batt_anim);
+ }
+}
+
+int healthd_mode_charger_preparetowait(void)
+{
+ struct charger *charger = &charger_state;
+ int64_t now = curr_time_ms();
+ int64_t next_event = INT64_MAX;
+ int64_t timeout;
+
+ LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n", now,
+ charger->next_screen_transition, charger->next_key_check,
+ charger->next_pwr_check);
+
+ if (charger->next_screen_transition != -1)
+ next_event = charger->next_screen_transition;
+ if (charger->next_key_check != -1 && charger->next_key_check < next_event)
+ next_event = charger->next_key_check;
+ if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
+ next_event = charger->next_pwr_check;
+
+ if (next_event != -1 && next_event != INT64_MAX)
+ timeout = max(0, next_event - now);
+ else
+ timeout = -1;
+
+ return (int)timeout;
+}
+
+static int input_callback(int fd, unsigned int epevents, void *data)
+{
+ struct charger *charger = (struct charger *)data;
+ struct input_event ev;
+ int ret;
+
+ ret = ev_get_input(fd, epevents, &ev);
+ if (ret)
+ return -1;
+ update_input_state(charger, &ev);
+ return 0;
+}
+
+static void charger_event_handler(uint32_t /*epevents*/)
+{
+ int ret;
+
+ ret = ev_wait(-1);
+ if (!ret)
+ ev_dispatch();
+}
+
+void healthd_mode_charger_init(struct healthd_config* /*config*/)
+{
+ int ret;
+ struct charger *charger = &charger_state;
+ int i;
+ int epollfd;
+
+ dump_last_kmsg();
+
+ LOGI("--------------- STARTING CHARGER MODE ---------------\n");
+
+ ret = ev_init(input_callback, charger);
+ if (!ret) {
+ epollfd = ev_get_epollfd();
+ healthd_register_event(epollfd, charger_event_handler);
+ }
+
+ ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
+ if (ret < 0) {
+ LOGE("Cannot load battery_fail image\n");
+ charger->surf_unknown = NULL;
+ }
+
+ charger->batt_anim = &battery_animation;
+
+ gr_surface* scale_frames;
+ int scale_count;
+ ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames);
+ if (ret < 0) {
+ LOGE("Cannot load battery_scale image\n");
+ charger->batt_anim->num_frames = 0;
+ charger->batt_anim->num_cycles = 1;
+ } else if (scale_count != charger->batt_anim->num_frames) {
+ LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
+ scale_count, charger->batt_anim->num_frames);
+ charger->batt_anim->num_frames = 0;
+ charger->batt_anim->num_cycles = 1;
+ } else {
+ for (i = 0; i < charger->batt_anim->num_frames; i++) {
+ charger->batt_anim->frames[i].surface = scale_frames[i];
+ }
+ }
+
+ ev_sync_key_state(set_key_callback, charger);
+
+ charger->next_screen_transition = -1;
+ charger->next_key_check = -1;
+ charger->next_pwr_check = -1;
+}
diff --git a/charger/images/battery_fail.png b/healthd/images/battery_fail.png
similarity index 100%
rename from charger/images/battery_fail.png
rename to healthd/images/battery_fail.png
Binary files differ
diff --git a/charger/images/battery_scale.png b/healthd/images/battery_scale.png
similarity index 100%
rename from charger/images/battery_scale.png
rename to healthd/images/battery_scale.png
Binary files differ
diff --git a/include/android/log.h b/include/android/log.h
index f5b1900..1c171b7 100644
--- a/include/android/log.h
+++ b/include/android/log.h
@@ -98,8 +98,16 @@
*/
int __android_log_print(int prio, const char *tag, const char *fmt, ...)
#if defined(__GNUC__)
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+ __attribute__ ((format(gnu_printf, 3, 4)))
+#else
__attribute__ ((format(printf, 3, 4)))
#endif
+#else
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+#endif
;
/*
@@ -117,8 +125,16 @@
const char *fmt, ...)
#if defined(__GNUC__)
__attribute__ ((noreturn))
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+ __attribute__ ((format(gnu_printf, 3, 4)))
+#else
__attribute__ ((format(printf, 3, 4)))
#endif
+#else
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+#endif
;
#ifdef __cplusplus
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
index 13083bd..4ed23a8 100644
--- a/include/backtrace/BacktraceMap.h
+++ b/include/backtrace/BacktraceMap.h
@@ -18,6 +18,7 @@
#define _BACKTRACE_BACKTRACE_MAP_H
#include <stdint.h>
+#include <sys/types.h>
#ifdef USE_MINGW
// MINGW does not define these constants.
#define PROT_NONE 0
@@ -40,7 +41,10 @@
class BacktraceMap {
public:
- static BacktraceMap* Create(pid_t pid);
+ // If uncached is true, then parse the current process map as of the call.
+ // Passing a map created with uncached set to true to Backtrace::Create()
+ // is unsupported.
+ static BacktraceMap* Create(pid_t pid, bool uncached = false);
virtual ~BacktraceMap();
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 172a0cd..0000000
--- a/include/cutils/atomic-arm.h
+++ /dev/null
@@ -1,176 +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 void android_memory_store_barrier()
-{
-#if ANDROID_SMP == 0
- android_compiler_barrier();
-#else
- __asm__ __volatile__ ("dmb st" : : : "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 4562ad0..0000000
--- a/include/cutils/atomic-arm64.h
+++ /dev/null
@@ -1,227 +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");
-}
-
-#if ANDROID_SMP == 0
-extern ANDROID_ATOMIC_INLINE
-void android_memory_barrier(void)
-{
- android_compiler_barrier();
-}
-extern ANDROID_ATOMIC_INLINE
-void android_memory_store_barrier(void)
-{
- android_compiler_barrier();
-}
-#else
-extern ANDROID_ATOMIC_INLINE
-void android_memory_barrier(void)
-{
- __asm__ __volatile__ ("dmb ish" : : : "memory");
-}
-extern ANDROID_ATOMIC_INLINE
-void android_memory_store_barrier(void)
-{
- __asm__ __volatile__ ("dmb ishst" : : : "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
-int64_t android_atomic_acquire_load64(volatile const int64_t *ptr)
-{
- int64_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
-int64_t android_atomic_release_load64(volatile const int64_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_acquire_store64(int64_t value, volatile int64_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
-void android_atomic_release_store64(int64_t value, volatile int64_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
-int64_t android_atomic_cas64(int64_t old_value, int64_t new_value,
- volatile int64_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
-int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value,
- volatile int64_t *ptr)
-{
- int status = android_atomic_cas64(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
-int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value,
- volatile int64_t *ptr)
-{
- android_memory_barrier();
- return android_atomic_cas64(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 4f90ef1..0000000
--- a/include/cutils/atomic-inline.h
+++ /dev/null
@@ -1,76 +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(__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
-
-#if ANDROID_SMP == 0
-#define ANDROID_MEMBAR_STORE android_compiler_barrier
-#else
-#define ANDROID_MEMBAR_STORE android_memory_store_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 f9d3e25..0000000
--- a/include/cutils/atomic-mips.h
+++ /dev/null
@@ -1,199 +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();
-}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
-{
- android_compiler_barrier();
-}
-#else
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
-{
- __asm__ __volatile__ ("sync" : : : "memory");
-}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_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_swap(int32_t new_value, volatile int32_t *ptr)
-{
- int32_t prev, status;
- do {
- __asm__ __volatile__ (
- " move %[status], %[new_value]\n"
- " ll %[prev], (%[ptr])\n"
- " sc %[status], (%[ptr])\n"
- : [prev] "=&r" (prev), [status] "=&r" (status)
- : [ptr] "r" (ptr), [new_value] "r" (new_value)
- );
- } while (__builtin_expect(status == 0, 0));
- android_memory_barrier();
- return prev;
-}
-
-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 9480f57..0000000
--- a/include/cutils/atomic-x86.h
+++ /dev/null
@@ -1,153 +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();
-}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
-{
- android_compiler_barrier();
-}
-#else
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
-{
- __asm__ __volatile__ ("mfence" : : : "memory");
-}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
-{
- android_compiler_barrier();
-}
-#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 5b5c203..0000000
--- a/include/cutils/atomic-x86_64.h
+++ /dev/null
@@ -1,226 +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");
-}
-
-#if ANDROID_SMP == 0
-extern ANDROID_ATOMIC_INLINE
-void android_memory_barrier(void)
-{
- android_compiler_barrier();
-}
-extern ANDROID_ATOMIC_INLINE
-void android_memory_store_barrier(void)
-{
- android_compiler_barrier();
-}
-#else
-extern ANDROID_ATOMIC_INLINE
-void android_memory_barrier(void)
-{
- __asm__ __volatile__ ("mfence" : : : "memory");
-}
-extern ANDROID_ATOMIC_INLINE
-void android_memory_store_barrier(void)
-{
- android_compiler_barrier();
-}
-#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
-int64_t android_atomic_acquire_load64(volatile const int64_t *ptr)
-{
- int64_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
-int64_t android_atomic_release_load64(volatile const int64_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_acquire_store64(int64_t value, volatile int64_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
-void android_atomic_release_store64(int64_t value, volatile int64_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
-int64_t android_atomic_cas64(int64_t old_value, int64_t new_value,
- volatile int64_t *ptr)
-{
- int64_t prev;
- __asm__ __volatile__ ("lock; cmpxchgq %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
-int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value,
- volatile int64_t *ptr)
-{
- /* Loads are not reordered with other loads. */
- return android_atomic_cas64(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
-int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value,
- volatile int64_t *ptr)
-{
- /* Stores are not reordered with other stores. */
- return android_atomic_cas64(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 1787e34..ded972a 100644
--- a/include/cutils/atomic.h
+++ b/include/cutils/atomic.h
@@ -19,14 +19,27 @@
#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
/*
- * A handful of basic atomic operations. The appropriate pthread
- * functions should be used instead of these whenever possible.
+ * A handful of basic atomic operations.
+ * THESE ARE HERE FOR LEGACY REASONS ONLY. AVOID.
+ *
+ * PREFERRED ALTERNATIVES:
+ * - Use C++/C/pthread locks/mutexes whenever there is not a
+ * convincing reason to do otherwise. Note that very clever and
+ * complicated, but correct, lock-free code is often slower than
+ * using locks, especially where nontrivial data structures
+ * are involved.
+ * - C11 stdatomic.h.
+ * - Where supported, C++11 std::atomic<T> .
+ *
+ * PLEASE STOP READING HERE UNLESS YOU ARE TRYING TO UNDERSTAND
+ * OR UPDATE OLD CODE.
*
* The "acquire" and "release" terms can be defined intuitively in terms
* of the placement of memory barriers in a simple lock implementation:
@@ -65,39 +78,102 @@
* 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.
*
- * 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.
+ * Note that the notion of a "release" ordering for a load 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 leading
+ * atomic_thread_fence (typically with memory_order_acquire,
+ * not memory_order_release!) instead. If you do not understand
+ * 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.
*/
-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);
+}
-#if defined (__LP64__)
-int64_t android_atomic_acquire_load64(volatile const int64_t* addr);
-int64_t android_atomic_release_load64(volatile const int64_t* addr);
-#endif
+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.
*
- * 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.
+ * 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.
*/
-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. */
+}
-#if defined (__LP64__)
-void android_atomic_acquire_store64(int64_t value, volatile int64_t* addr);
-void android_atomic_release_store64(int64_t value, volatile int64_t* addr);
-#endif
+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.
@@ -111,17 +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);
-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_acquire,
+ memory_order_acquire));
+}
-#if defined (__LP64__)
-int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value,
- volatile int64_t *ptr);
-int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value,
- volatile int64_t *ptr);
-#endif
+ANDROID_ATOMIC_INLINE
+int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue,
+ 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
@@ -131,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/bitops.h b/include/cutils/bitops.h
index c26dc54..045830d 100644
--- a/include/cutils/bitops.h
+++ b/include/cutils/bitops.h
@@ -59,7 +59,7 @@
static inline int bitmask_ffz(unsigned int *bitmask, int num_bits)
{
int bit, result;
- unsigned int i;
+ size_t i;
for (i = 0; i < BITS_TO_WORDS(num_bits); i++) {
bit = ffs(~bitmask[i]);
@@ -77,7 +77,7 @@
static inline int bitmask_weight(unsigned int *bitmask, int num_bits)
{
- int i;
+ size_t i;
int weight = 0;
for (i = 0; i < BITS_TO_WORDS(num_bits); i++)
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h
index ae6bfc4..4bcc8e6 100644
--- a/include/cutils/debugger.h
+++ b/include/cutils/debugger.h
@@ -23,10 +23,13 @@
extern "C" {
#endif
-#if __LP64__
-#define DEBUGGER_SOCKET_NAME "android:debuggerd64"
+#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 "android:debuggerd"
+#define DEBUGGER_SOCKET_NAME DEBUGGER32_SOCKET_NAME
#endif
typedef enum {
@@ -45,6 +48,16 @@
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.
diff --git a/include/cutils/fs.h b/include/cutils/fs.h
index d1d4cf2..70f0b92 100644
--- a/include/cutils/fs.h
+++ b/include/cutils/fs.h
@@ -18,6 +18,7 @@
#define __CUTILS_FS_H
#include <sys/types.h>
+#include <unistd.h>
/*
* TEMP_FAILURE_RETRY is defined by some, but not all, versions of
diff --git a/include/cutils/jstring.h b/include/cutils/jstring.h
index ee0018f..a342608 100644
--- a/include/cutils/jstring.h
+++ b/include/cutils/jstring.h
@@ -24,7 +24,10 @@
extern "C" {
#endif
-typedef uint16_t char16_t;
+#if __STDC_VERSION__ < 201112L && __cplusplus < 201103L
+ typedef uint16_t char16_t;
+#endif
+ // otherwise char16_t is a keyword with the right semantics
extern char * strndup16to8 (const char16_t* s, size_t n);
extern size_t strnlen16to8 (const char16_t* s, size_t n);
diff --git a/include/cutils/klog.h b/include/cutils/klog.h
index 3635e89..d5ae6d7 100644
--- a/include/cutils/klog.h
+++ b/include/cutils/klog.h
@@ -25,7 +25,7 @@
void klog_init(void);
int klog_get_level(void);
void klog_set_level(int level);
-void klog_close(void);
+/* 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);
diff --git a/include/cutils/list.h b/include/cutils/list.h
index 945729a..4ba2cfd 100644
--- a/include/cutils/list.h
+++ b/include/cutils/list.h
@@ -44,10 +44,10 @@
#define list_for_each_reverse(node, list) \
for (node = (list)->prev; node != (list); node = node->prev)
-#define list_for_each_safe(node, next, list) \
- for (node = (list)->next, next = node->next; \
+#define list_for_each_safe(node, n, list) \
+ for (node = (list)->next, n = node->next; \
node != (list); \
- node = next, next = node->next)
+ node = n, n = node->next)
static inline void list_init(struct listnode *node)
{
@@ -63,6 +63,14 @@
head->prev = item;
}
+static inline void list_add_head(struct listnode *head, struct listnode *item)
+{
+ item->next = head->next;
+ item->prev = head;
+ head->next->prev = item;
+ head->next = item;
+}
+
static inline void list_remove(struct listnode *item)
{
item->next->prev = item->prev;
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/properties.h b/include/cutils/properties.h
index 2c70165..798db8b 100644
--- a/include/cutils/properties.h
+++ b/include/cutils/properties.h
@@ -20,6 +20,7 @@
#include <sys/cdefs.h>
#include <stddef.h>
#include <sys/system_properties.h>
+#include <stdint.h>
#ifdef __cplusplus
extern "C" {
@@ -44,6 +45,64 @@
*/
int property_get(const char *key, char *value, const char *default_value);
+/* property_get_bool: returns the value of key coerced into a
+** boolean. If the property is not set, then the default value is returned.
+**
+* The following is considered to be true (1):
+** "1", "true", "y", "yes", "on"
+**
+** The following is considered to be false (0):
+** "0", "false", "n", "no", "off"
+**
+** The conversion is whitespace-sensitive (e.g. " off" will not be false).
+**
+** If no property with this key is set (or the key is NULL) or the boolean
+** conversion fails, the default value is returned.
+**/
+int8_t property_get_bool(const char *key, int8_t default_value);
+
+/* property_get_int64: returns the value of key truncated and coerced into a
+** int64_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+** -- 0 prefix is octal
+** -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int64_t property_get_int64(const char *key, int64_t default_value);
+
+/* property_get_int32: returns the value of key truncated and coerced into an
+** int32_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+** -- 0 prefix is octal
+** -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int32_t property_get_int32(const char *key, int32_t default_value);
+
/* property_set: returns 0 on success, < 0 on failure
*/
int property_set(const char *key, const char *value);
diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h
index 19cae0c..daf43ec 100644
--- a/include/cutils/sockets.h
+++ b/include/cutils/sockets.h
@@ -86,6 +86,8 @@
extern int socket_loopback_client(int port, int type);
extern int socket_network_client(const char *host, int port, int type);
+extern int socket_network_client_timeout(const char *host, int port, int type,
+ int timeout);
extern int socket_loopback_server(int port, int type);
extern int socket_local_server(const char *name, int namespaceId, int type);
extern int socket_local_server_bind(int s, const char *name, int namespaceId);
diff --git a/include/cutils/str_parms.h b/include/cutils/str_parms.h
index 247c996..66f3637 100644
--- a/include/cutils/str_parms.h
+++ b/include/cutils/str_parms.h
@@ -34,6 +34,12 @@
int str_parms_add_float(struct str_parms *str_parms, const char *key,
float value);
+// Returns non-zero if the str_parms contains the specified key.
+int str_parms_has_key(struct str_parms *str_parms, const char *key);
+
+// Gets value associated with the specified key (if present), placing it in the buffer
+// pointed to by the out_val parameter. Returns the length of the returned string value.
+// If 'key' isn't in the parms, then return -ENOENT (-2) and leave 'out_val' untouched.
int str_parms_get_str(struct str_parms *str_parms, const char *key,
char *out_val, int len);
int str_parms_get_int(struct str_parms *str_parms, const char *key,
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index dbd5e25..59ff6c1 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -20,16 +20,13 @@
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
+#include <stdio.h>
#include <sys/cdefs.h>
#include <sys/types.h>
#include <unistd.h>
-#include <cutils/compiler.h>
-#ifdef ANDROID_SMP
-#include <cutils/atomic-inline.h>
-#else
#include <cutils/atomic.h>
-#endif
+#include <cutils/compiler.h>
__BEGIN_DECLS
@@ -68,7 +65,9 @@
#define ATRACE_TAG_RESOURCES (1<<13)
#define ATRACE_TAG_DALVIK (1<<14)
#define ATRACE_TAG_RS (1<<15)
-#define ATRACE_TAG_LAST ATRACE_TAG_RS
+#define ATRACE_TAG_BIONIC (1<<16)
+#define ATRACE_TAG_POWER (1<<17)
+#define ATRACE_TAG_LAST ATRACE_TAG_POWER
// Reserved for initialization.
#define ATRACE_TAG_NOT_READY (1LL<<63)
@@ -83,13 +82,6 @@
#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.
* This function should not be explicitly called, the first call to any normal
@@ -181,11 +173,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);
}
}
@@ -215,12 +204,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);
}
}
@@ -229,20 +214,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.
@@ -251,12 +230,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);
}
}
@@ -268,12 +243,8 @@
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);
}
}
diff --git a/include/cutils/tztime.h b/include/cutils/tztime.h
deleted file mode 100644
index dbdbd60..0000000
--- a/include/cutils/tztime.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef _CUTILS_TZTIME_H
-#define _CUTILS_TZTIME_H
-
-// TODO: fix both callers to just include <bionic_time.h> themselves.
-#include <bionic_time.h>
-
-#endif /* __CUTILS_TZTIME_H */
-
diff --git a/include/log/log.h b/include/log/log.h
index 5b76c1a..ace12d6 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -491,7 +491,7 @@
#endif
#ifndef LOG_EVENT_STRING
#define LOG_EVENT_STRING(_tag, _value) \
- ((void) 0) /* not implemented -- must combine len with string */
+ (void) __android_log_bswrite(_tag, _value);
#endif
/* TODO: something for LIST */
diff --git a/include/log/log_read.h b/include/log/log_read.h
index 54d71a4..946711a 100644
--- a/include/log/log_read.h
+++ b/include/log/log_read.h
@@ -67,7 +67,8 @@
// timespec
bool operator== (const timespec &T) const
{
- return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
+ return (tv_sec == static_cast<uint32_t>(T.tv_sec))
+ && (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
}
bool operator!= (const timespec &T) const
{
@@ -75,8 +76,9 @@
}
bool operator< (const timespec &T) const
{
- return (tv_sec < T.tv_sec)
- || ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
+ return (tv_sec < static_cast<uint32_t>(T.tv_sec))
+ || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+ && (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
}
bool operator>= (const timespec &T) const
{
@@ -84,8 +86,9 @@
}
bool operator> (const timespec &T) const
{
- return (tv_sec > T.tv_sec)
- || ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
+ return (tv_sec > static_cast<uint32_t>(T.tv_sec))
+ || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+ && (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
}
bool operator<= (const timespec &T) const
{
diff --git a/include/log/logd.h b/include/log/logd.h
index 379c373..2e6f220 100644
--- a/include/log/logd.h
+++ b/include/log/logd.h
@@ -41,6 +41,7 @@
int __android_log_bwrite(int32_t tag, const void *payload, size_t len);
int __android_log_btwrite(int32_t tag, char type, const void *payload,
size_t len);
+int __android_log_bswrite(int32_t tag, const char *payload);
#ifdef __cplusplus
}
diff --git a/include/log/logger.h b/include/log/logger.h
index ed39c4f..53be1d3 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -62,9 +62,8 @@
/*
* The maximum size of the log entry payload that can be
- * written to the kernel logger driver. An attempt to write
- * more than this amount to /dev/log/* will result in a
- * truncated log entry.
+ * written to the logger. An attempt to write more than
+ * this amount will result in a truncated log entry.
*/
#define LOGGER_ENTRY_MAX_PAYLOAD 4076
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/nativebridge/native_bridge.h b/include/nativebridge/native_bridge.h
new file mode 100644
index 0000000..523dc49
--- /dev/null
+++ b/include/nativebridge/native_bridge.h
@@ -0,0 +1,168 @@
+/*
+ * 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 NATIVE_BRIDGE_H_
+#define NATIVE_BRIDGE_H_
+
+#include "jni.h"
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace android {
+
+struct NativeBridgeRuntimeCallbacks;
+struct NativeBridgeRuntimeValues;
+
+// Open the native bridge, if any. Should be called by Runtime::Init(). A null library filename
+// signals that we do not want to load a native bridge.
+bool LoadNativeBridge(const char* native_bridge_library_filename,
+ const NativeBridgeRuntimeCallbacks* runtime_callbacks);
+
+// Quick check whether a native bridge will be needed. This is based off of the instruction set
+// of the process.
+bool NeedsNativeBridge(const char* instruction_set);
+
+// Do the early initialization part of the native bridge, if necessary. This should be done under
+// high privileges.
+bool PreInitializeNativeBridge(const char* app_data_dir, const char* instruction_set);
+
+// Initialize the native bridge, if any. Should be called by Runtime::DidForkFromZygote. The JNIEnv*
+// will be used to modify the app environment for the bridge.
+bool InitializeNativeBridge(JNIEnv* env, const char* instruction_set);
+
+// Unload the native bridge, if any. Should be called by Runtime::DidForkFromZygote.
+void UnloadNativeBridge();
+
+// Check whether a native bridge is available (opened or initialized). Requires a prior call to
+// LoadNativeBridge.
+bool NativeBridgeAvailable();
+
+// Check whether a native bridge is available (initialized). Requires a prior call to
+// LoadNativeBridge & InitializeNativeBridge.
+bool NativeBridgeInitialized();
+
+// Load a shared library that is supported by the native bridge.
+void* NativeBridgeLoadLibrary(const char* libpath, int flag);
+
+// Get a native bridge trampoline for specified native method.
+void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty, uint32_t len);
+
+// True if native library is valid and is for an ABI that is supported by native bridge.
+bool NativeBridgeIsSupported(const char* libpath);
+
+// Returns whether we have seen a native bridge error. This could happen because the library
+// was not found, rejected, could not be initialized and so on.
+//
+// This functionality is mainly for testing.
+bool NativeBridgeError();
+
+// Returns whether a given string is acceptable as a native bridge library filename.
+//
+// This functionality is exposed mainly for testing.
+bool NativeBridgeNameAcceptable(const char* native_bridge_library_filename);
+
+// Native bridge interfaces to runtime.
+struct NativeBridgeCallbacks {
+ // Version number of the interface.
+ uint32_t version;
+
+ // Initialize native bridge. Native bridge's internal implementation must ensure MT safety and
+ // that the native bridge is initialized only once. Thus it is OK to call this interface for an
+ // already initialized native bridge.
+ //
+ // Parameters:
+ // runtime_cbs [IN] the pointer to NativeBridgeRuntimeCallbacks.
+ // Returns:
+ // true iff initialization was successful.
+ bool (*initialize)(const NativeBridgeRuntimeCallbacks* runtime_cbs, const char* private_dir,
+ const char* instruction_set);
+
+ // Load a shared library that is supported by the native bridge.
+ //
+ // Parameters:
+ // libpath [IN] path to the shared library
+ // flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
+ // Returns:
+ // The opaque handle of the shared library if sucessful, otherwise NULL
+ void* (*loadLibrary)(const char* libpath, int flag);
+
+ // Get a native bridge trampoline for specified native method. The trampoline has same
+ // sigature as the native method.
+ //
+ // Parameters:
+ // handle [IN] the handle returned from loadLibrary
+ // shorty [IN] short descriptor of native method
+ // len [IN] length of shorty
+ // Returns:
+ // address of trampoline if successful, otherwise NULL
+ void* (*getTrampoline)(void* handle, const char* name, const char* shorty, uint32_t len);
+
+ // Check whether native library is valid and is for an ABI that is supported by native bridge.
+ //
+ // Parameters:
+ // libpath [IN] path to the shared library
+ // Returns:
+ // TRUE if library is supported by native bridge, FALSE otherwise
+ bool (*isSupported)(const char* libpath);
+
+ // Provide environment values required by the app running with native bridge according to the
+ // instruction set.
+ //
+ // Parameters:
+ // instruction_set [IN] the instruction set of the app
+ // Returns:
+ // NULL if not supported by native bridge.
+ // Otherwise, return all environment values to be set after fork.
+ const struct NativeBridgeRuntimeValues* (*getAppEnv)(const char* instruction_set);
+};
+
+// Runtime interfaces to native bridge.
+struct NativeBridgeRuntimeCallbacks {
+ // Get shorty of a Java method. The shorty is supposed to be persistent in memory.
+ //
+ // Parameters:
+ // env [IN] pointer to JNIenv.
+ // mid [IN] Java methodID.
+ // Returns:
+ // short descriptor for method.
+ const char* (*getMethodShorty)(JNIEnv* env, jmethodID mid);
+
+ // Get number of native methods for specified class.
+ //
+ // Parameters:
+ // env [IN] pointer to JNIenv.
+ // clazz [IN] Java class object.
+ // Returns:
+ // number of native methods.
+ uint32_t (*getNativeMethodCount)(JNIEnv* env, jclass clazz);
+
+ // Get at most 'method_count' native methods for specified class 'clazz'. Results are outputed
+ // via 'methods' [OUT]. The signature pointer in JNINativeMethod is reused as the method shorty.
+ //
+ // Parameters:
+ // env [IN] pointer to JNIenv.
+ // clazz [IN] Java class object.
+ // methods [OUT] array of method with the name, shorty, and fnPtr.
+ // method_count [IN] max number of elements in methods.
+ // Returns:
+ // number of method it actually wrote to methods.
+ uint32_t (*getNativeMethods)(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
+ uint32_t method_count);
+};
+
+}; // namespace android
+
+#endif // NATIVE_BRIDGE_H_
diff --git a/include/netd_client/FwmarkCommands.h b/include/netd_client/FwmarkCommands.h
deleted file mode 100644
index 0d22f02..0000000
--- a/include/netd_client/FwmarkCommands.h
+++ /dev/null
@@ -1,29 +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.
- */
-
-#ifndef NETD_CLIENT_FWMARK_COMMANDS_H
-#define NETD_CLIENT_FWMARK_COMMANDS_H
-
-#include <stdint.h>
-
-// Commands sent from clients to the fwmark server to mark sockets (i.e., set their SO_MARK).
-const uint8_t FWMARK_COMMAND_ON_CREATE = 0;
-const uint8_t FWMARK_COMMAND_ON_CONNECT = 1;
-const uint8_t FWMARK_COMMAND_ON_ACCEPT = 2;
-const uint8_t FWMARK_COMMAND_SELECT_NETWORK = 3;
-const uint8_t FWMARK_COMMAND_PROTECT_FROM_VPN = 4;
-
-#endif // NETD_CLIENT_FWMARK_COMMANDS_H
diff --git a/include/netutils/ifc.h b/include/netutils/ifc.h
index 1f5421d..3b27234 100644
--- a/include/netutils/ifc.h
+++ b/include/netutils/ifc.h
@@ -36,6 +36,7 @@
#define RESET_IPV4_ADDRESSES 0x01
#define RESET_IPV6_ADDRESSES 0x02
+#define RESET_IGNORE_INTERFACE_ADDRESS 0x04
#define RESET_ALL_ADDRESSES (RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES)
extern int ifc_reset_connections(const char *ifname, const int reset_mask);
@@ -49,19 +50,8 @@
extern int ifc_set_hwaddr(const char *name, const void *ptr);
extern int ifc_clear_addresses(const char *name);
-/* This function is deprecated. Use ifc_add_route instead. */
-extern int ifc_add_host_route(const char *name, in_addr_t addr);
-extern int ifc_remove_host_routes(const char *name);
-extern int ifc_get_default_route(const char *ifname);
-/* This function is deprecated. Use ifc_add_route instead */
-extern int ifc_set_default_route(const char *ifname, in_addr_t gateway);
-/* This function is deprecated. Use ifc_add_route instead */
extern int ifc_create_default_route(const char *name, in_addr_t addr);
extern int ifc_remove_default_route(const char *ifname);
-extern int ifc_add_route(const char *name, const char *addr, int prefix_length,
- const char *gw);
-extern int ifc_remove_route(const char *ifname, const char *dst,
- int prefix_length, const char *gw);
extern int ifc_get_info(const char *name, in_addr_t *addr, int *prefixLength,
unsigned *flags);
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index d662107..5efe2e1 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -77,11 +77,17 @@
#define AID_SDCARD_AV 1034 /* external storage audio/video access */
#define AID_SDCARD_ALL 1035 /* access all users external storage */
#define AID_LOGD 1036 /* log daemon */
+#define AID_SHARED_RELRO 1037 /* creator of shared GNU RELRO files */
#define AID_SHELL 2000 /* adb and debug shell user */
#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 */
@@ -93,6 +99,7 @@
#define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */
#define AID_NET_BT_STACK 3008 /* bluetooth: access config files */
+#define AID_EVERYBODY 9997 /* shared between all apps in the same profile */
#define AID_MISC 9998 /* access to misc storage */
#define AID_NOBODY 9999
@@ -153,6 +160,7 @@
{ "sdcard_av", AID_SDCARD_AV, },
{ "sdcard_all", AID_SDCARD_ALL, },
{ "logd", AID_LOGD, },
+ { "shared_relro", AID_SHARED_RELRO, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
@@ -167,6 +175,7 @@
{ "net_bw_acct", AID_NET_BW_ACCT, },
{ "net_bt_stack", AID_NET_BT_STACK, },
+ { "everybody", AID_EVERYBODY, },
{ "misc", AID_MISC, },
{ "nobody", AID_NOBODY, },
};
@@ -192,12 +201,13 @@
{ 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_SYSTEM, AID_SYSTEM, 0, "data/dalvik-cache" },
+ { 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" },
@@ -222,7 +232,6 @@
{ 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/*" },
@@ -239,7 +248,7 @@
/* the following five files are INTENTIONALLY set-uid, but they
* are NOT included on user builds. */
- { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/su" },
+ { 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" },
@@ -249,6 +258,8 @@
/* 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/*" },
@@ -258,7 +269,6 @@
{ 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, "charger*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" },
{ 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" },
{ 00644, AID_ROOT, AID_ROOT, 0, 0 },
diff --git a/include/private/pixelflinger/ggl_fixed.h b/include/private/pixelflinger/ggl_fixed.h
index d0493f3..787f620 100644
--- a/include/private/pixelflinger/ggl_fixed.h
+++ b/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/include/system/audio.h b/include/system/audio.h
index f36befb..9a25cfb 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -20,6 +20,7 @@
#include <stdbool.h>
#include <stdint.h>
+#include <stdio.h>
#include <sys/cdefs.h>
#include <sys/types.h>
@@ -34,11 +35,17 @@
/* device address used to refer to the standard remote submix */
#define AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS "0"
+/* AudioFlinger and AudioPolicy services use I/O handles to identify audio sources and sinks */
typedef int audio_io_handle_t;
+#define AUDIO_IO_HANDLE_NONE 0
/* Audio stream types */
typedef enum {
+ /* These values must kept in sync with
+ * frameworks/base/media/java/android/media/AudioSystem.java
+ */
AUDIO_STREAM_DEFAULT = -1,
+ AUDIO_STREAM_MIN = 0,
AUDIO_STREAM_VOICE_CALL = 0,
AUDIO_STREAM_SYSTEM = 1,
AUDIO_STREAM_RING = 2,
@@ -46,7 +53,9 @@
AUDIO_STREAM_ALARM = 4,
AUDIO_STREAM_NOTIFICATION = 5,
AUDIO_STREAM_BLUETOOTH_SCO = 6,
- AUDIO_STREAM_ENFORCED_AUDIBLE = 7, /* Sounds that cannot be muted by user and must be routed to speaker */
+ AUDIO_STREAM_ENFORCED_AUDIBLE = 7, /* Sounds that cannot be muted by user
+ * and must be routed to speaker
+ */
AUDIO_STREAM_DTMF = 8,
AUDIO_STREAM_TTS = 9,
@@ -55,7 +64,61 @@
} audio_stream_type_t;
/* Do not change these values without updating their counterparts
- * in media/java/android/media/MediaRecorder.java!
+ * in frameworks/base/media/java/android/media/AudioAttributes.java
+ */
+typedef enum {
+ AUDIO_CONTENT_TYPE_UNKNOWN = 0,
+ AUDIO_CONTENT_TYPE_SPEECH = 1,
+ AUDIO_CONTENT_TYPE_MUSIC = 2,
+ AUDIO_CONTENT_TYPE_MOVIE = 3,
+ AUDIO_CONTENT_TYPE_SONIFICATION = 4,
+
+ AUDIO_CONTENT_TYPE_CNT,
+ AUDIO_CONTENT_TYPE_MAX = AUDIO_CONTENT_TYPE_CNT - 1,
+} audio_content_type_t;
+
+/* Do not change these values without updating their counterparts
+ * in frameworks/base/media/java/android/media/AudioAttributes.java
+ */
+typedef enum {
+ AUDIO_USAGE_UNKNOWN = 0,
+ AUDIO_USAGE_MEDIA = 1,
+ AUDIO_USAGE_VOICE_COMMUNICATION = 2,
+ AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING = 3,
+ AUDIO_USAGE_ALARM = 4,
+ AUDIO_USAGE_NOTIFICATION = 5,
+ AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE = 6,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9,
+ AUDIO_USAGE_NOTIFICATION_EVENT = 10,
+ AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY = 11,
+ AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12,
+ AUDIO_USAGE_ASSISTANCE_SONIFICATION = 13,
+ AUDIO_USAGE_GAME = 14,
+
+ AUDIO_USAGE_CNT,
+ AUDIO_USAGE_MAX = AUDIO_USAGE_CNT - 1,
+} audio_usage_t;
+
+typedef uint32_t audio_flags_mask_t;
+
+/* Do not change these values without updating their counterparts
+ * in frameworks/base/media/java/android/media/AudioAttributes.java
+ */
+enum {
+ AUDIO_FLAG_AUDIBILITY_ENFORCED = 0x1,
+ AUDIO_FLAG_SECURE = 0x2,
+ AUDIO_FLAG_SCO = 0x4,
+ AUDIO_FLAG_BEACON = 0x8,
+ AUDIO_FLAG_HW_AV_SYNC = 0x10,
+ AUDIO_FLAG_HW_HOTWORD = 0x20,
+};
+
+/* Do not change these values without updating their counterparts
+ * in frameworks/base/media/java/android/media/MediaRecorder.java,
+ * frameworks/av/services/audiopolicy/AudioPolicyService.cpp,
+ * and system/media/audio_effects/include/audio_effects/audio_effects_conf.h!
*/
typedef enum {
AUDIO_SOURCE_DEFAULT = 0,
@@ -79,6 +142,16 @@
at the audio HAL. */
} audio_source_t;
+/* Audio attributes */
+#define AUDIO_ATTRIBUTES_TAGS_MAX_SIZE 256
+typedef struct {
+ audio_content_type_t content_type;
+ audio_usage_t usage;
+ audio_source_t source;
+ audio_flags_mask_t flags;
+ char tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; /* UTF8 */
+} audio_attributes_t;
+
/* special audio session values
* (XXX: should this be living in the audio effects land?)
*/
@@ -93,18 +166,35 @@
* (value must be 0)
*/
AUDIO_SESSION_OUTPUT_MIX = 0,
+
+ /* application does not specify an explicit session ID to be used,
+ * and requests a new session ID to be allocated
+ * TODO use unique values for AUDIO_SESSION_OUTPUT_MIX and AUDIO_SESSION_ALLOCATE,
+ * after all uses have been updated from 0 to the appropriate symbol, and have been tested.
+ */
+ AUDIO_SESSION_ALLOCATE = 0,
} audio_session_t;
+/* a unique ID allocated by AudioFlinger for use as a audio_io_handle_t or audio_session_t */
+typedef int audio_unique_id_t;
+
+#define AUDIO_UNIQUE_ID_ALLOCATE AUDIO_SESSION_ALLOCATE
+
/* Audio sub formats (see enum audio_format). */
/* PCM sub formats */
typedef enum {
+ /* All of these are in native byte order */
AUDIO_FORMAT_PCM_SUB_16_BIT = 0x1, /* DO NOT CHANGE - PCM signed 16 bits */
AUDIO_FORMAT_PCM_SUB_8_BIT = 0x2, /* DO NOT CHANGE - PCM unsigned 8 bits */
AUDIO_FORMAT_PCM_SUB_32_BIT = 0x3, /* PCM signed .31 fixed point */
AUDIO_FORMAT_PCM_SUB_8_24_BIT = 0x4, /* PCM signed 7.24 fixed point */
+ AUDIO_FORMAT_PCM_SUB_FLOAT = 0x5, /* PCM single-precision floating point */
+ AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED = 0x6, /* PCM signed .23 fixed point packed in 3 bytes */
} audio_format_pcm_sub_fmt_t;
+/* The audio_format_*_sub_fmt_t declarations are not currently used */
+
/* MP3 sub format field definition : can use 11 LSBs in the same way as MP3
* frame header to specify bit rate, stereo mode, version...
*/
@@ -121,7 +211,16 @@
/* AAC sub format field definition: specify profile or bitrate for recording... */
typedef enum {
- AUDIO_FORMAT_AAC_SUB_NONE = 0x0,
+ AUDIO_FORMAT_AAC_SUB_MAIN = 0x1,
+ AUDIO_FORMAT_AAC_SUB_LC = 0x2,
+ AUDIO_FORMAT_AAC_SUB_SSR = 0x4,
+ AUDIO_FORMAT_AAC_SUB_LTP = 0x8,
+ AUDIO_FORMAT_AAC_SUB_HE_V1 = 0x10,
+ AUDIO_FORMAT_AAC_SUB_SCALABLE = 0x20,
+ AUDIO_FORMAT_AAC_SUB_ERLC = 0x40,
+ AUDIO_FORMAT_AAC_SUB_LD = 0x80,
+ AUDIO_FORMAT_AAC_SUB_HE_V2 = 0x100,
+ AUDIO_FORMAT_AAC_SUB_ELD = 0x200,
} audio_format_aac_sub_fmt_t;
/* VORBIS sub format field definition: specify quality for recording... */
@@ -129,7 +228,7 @@
AUDIO_FORMAT_VORBIS_SUB_NONE = 0x0,
} audio_format_vorbis_sub_fmt_t;
-/* Audio format consists in a main format field (upper 8 bits) and a sub format
+/* Audio format consists of a main format field (upper 8 bits) and a sub format
* field (lower 24 bits).
*
* The main format indicates the main codec type. The sub format field
@@ -146,24 +245,65 @@
AUDIO_FORMAT_AMR_NB = 0x02000000UL,
AUDIO_FORMAT_AMR_WB = 0x03000000UL,
AUDIO_FORMAT_AAC = 0x04000000UL,
- AUDIO_FORMAT_HE_AAC_V1 = 0x05000000UL,
- AUDIO_FORMAT_HE_AAC_V2 = 0x06000000UL,
+ AUDIO_FORMAT_HE_AAC_V1 = 0x05000000UL, /* Deprecated, Use AUDIO_FORMAT_AAC_HE_V1*/
+ AUDIO_FORMAT_HE_AAC_V2 = 0x06000000UL, /* Deprecated, Use AUDIO_FORMAT_AAC_HE_V2*/
AUDIO_FORMAT_VORBIS = 0x07000000UL,
+ AUDIO_FORMAT_OPUS = 0x08000000UL,
+ AUDIO_FORMAT_AC3 = 0x09000000UL,
+ AUDIO_FORMAT_E_AC3 = 0x0A000000UL,
AUDIO_FORMAT_MAIN_MASK = 0xFF000000UL,
AUDIO_FORMAT_SUB_MASK = 0x00FFFFFFUL,
/* Aliases */
+ /* note != AudioFormat.ENCODING_PCM_16BIT */
AUDIO_FORMAT_PCM_16_BIT = (AUDIO_FORMAT_PCM |
AUDIO_FORMAT_PCM_SUB_16_BIT),
+ /* note != AudioFormat.ENCODING_PCM_8BIT */
AUDIO_FORMAT_PCM_8_BIT = (AUDIO_FORMAT_PCM |
AUDIO_FORMAT_PCM_SUB_8_BIT),
AUDIO_FORMAT_PCM_32_BIT = (AUDIO_FORMAT_PCM |
AUDIO_FORMAT_PCM_SUB_32_BIT),
AUDIO_FORMAT_PCM_8_24_BIT = (AUDIO_FORMAT_PCM |
AUDIO_FORMAT_PCM_SUB_8_24_BIT),
+ AUDIO_FORMAT_PCM_FLOAT = (AUDIO_FORMAT_PCM |
+ AUDIO_FORMAT_PCM_SUB_FLOAT),
+ AUDIO_FORMAT_PCM_24_BIT_PACKED = (AUDIO_FORMAT_PCM |
+ AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED),
+ AUDIO_FORMAT_AAC_MAIN = (AUDIO_FORMAT_AAC |
+ AUDIO_FORMAT_AAC_SUB_MAIN),
+ AUDIO_FORMAT_AAC_LC = (AUDIO_FORMAT_AAC |
+ AUDIO_FORMAT_AAC_SUB_LC),
+ AUDIO_FORMAT_AAC_SSR = (AUDIO_FORMAT_AAC |
+ AUDIO_FORMAT_AAC_SUB_SSR),
+ AUDIO_FORMAT_AAC_LTP = (AUDIO_FORMAT_AAC |
+ AUDIO_FORMAT_AAC_SUB_LTP),
+ AUDIO_FORMAT_AAC_HE_V1 = (AUDIO_FORMAT_AAC |
+ AUDIO_FORMAT_AAC_SUB_HE_V1),
+ AUDIO_FORMAT_AAC_SCALABLE = (AUDIO_FORMAT_AAC |
+ AUDIO_FORMAT_AAC_SUB_SCALABLE),
+ AUDIO_FORMAT_AAC_ERLC = (AUDIO_FORMAT_AAC |
+ AUDIO_FORMAT_AAC_SUB_ERLC),
+ AUDIO_FORMAT_AAC_LD = (AUDIO_FORMAT_AAC |
+ AUDIO_FORMAT_AAC_SUB_LD),
+ AUDIO_FORMAT_AAC_HE_V2 = (AUDIO_FORMAT_AAC |
+ AUDIO_FORMAT_AAC_SUB_HE_V2),
+ AUDIO_FORMAT_AAC_ELD = (AUDIO_FORMAT_AAC |
+ AUDIO_FORMAT_AAC_SUB_ELD),
} audio_format_t;
+/* For the channel mask for position assignment representation */
enum {
+
+/* These can be a complete audio_channel_mask_t. */
+
+ AUDIO_CHANNEL_NONE = 0x0,
+ AUDIO_CHANNEL_INVALID = 0xC0000000,
+
+/* These can be the bits portion of an audio_channel_mask_t
+ * with representation AUDIO_CHANNEL_REPRESENTATION_POSITION.
+ * Using these bits as a complete audio_channel_mask_t is deprecated.
+ */
+
/* output channels */
AUDIO_CHANNEL_OUT_FRONT_LEFT = 0x1,
AUDIO_CHANNEL_OUT_FRONT_RIGHT = 0x2,
@@ -184,6 +324,8 @@
AUDIO_CHANNEL_OUT_TOP_BACK_CENTER = 0x10000,
AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000,
+/* TODO: should these be considered complete channel masks, or only bits? */
+
AUDIO_CHANNEL_OUT_MONO = AUDIO_CHANNEL_OUT_FRONT_LEFT,
AUDIO_CHANNEL_OUT_STEREO = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
AUDIO_CHANNEL_OUT_FRONT_RIGHT),
@@ -191,16 +333,26 @@
AUDIO_CHANNEL_OUT_FRONT_RIGHT |
AUDIO_CHANNEL_OUT_BACK_LEFT |
AUDIO_CHANNEL_OUT_BACK_RIGHT),
- AUDIO_CHANNEL_OUT_SURROUND = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
+ AUDIO_CHANNEL_OUT_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD,
+ /* like AUDIO_CHANNEL_OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */
+ AUDIO_CHANNEL_OUT_QUAD_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
AUDIO_CHANNEL_OUT_FRONT_RIGHT |
- AUDIO_CHANNEL_OUT_FRONT_CENTER |
- AUDIO_CHANNEL_OUT_BACK_CENTER),
+ AUDIO_CHANNEL_OUT_SIDE_LEFT |
+ AUDIO_CHANNEL_OUT_SIDE_RIGHT),
AUDIO_CHANNEL_OUT_5POINT1 = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
AUDIO_CHANNEL_OUT_FRONT_RIGHT |
AUDIO_CHANNEL_OUT_FRONT_CENTER |
AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
AUDIO_CHANNEL_OUT_BACK_LEFT |
AUDIO_CHANNEL_OUT_BACK_RIGHT),
+ AUDIO_CHANNEL_OUT_5POINT1_BACK = AUDIO_CHANNEL_OUT_5POINT1,
+ /* like AUDIO_CHANNEL_OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */
+ AUDIO_CHANNEL_OUT_5POINT1_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
+ AUDIO_CHANNEL_OUT_FRONT_RIGHT |
+ AUDIO_CHANNEL_OUT_FRONT_CENTER |
+ AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
+ AUDIO_CHANNEL_OUT_SIDE_LEFT |
+ AUDIO_CHANNEL_OUT_SIDE_RIGHT),
// matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND definition for 7.1
AUDIO_CHANNEL_OUT_7POINT1 = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
AUDIO_CHANNEL_OUT_FRONT_RIGHT |
@@ -229,6 +381,8 @@
AUDIO_CHANNEL_OUT_TOP_BACK_CENTER|
AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT),
+/* These are bits only, not complete values */
+
/* input channels */
AUDIO_CHANNEL_IN_LEFT = 0x4,
AUDIO_CHANNEL_IN_RIGHT = 0x8,
@@ -245,6 +399,8 @@
AUDIO_CHANNEL_IN_VOICE_UPLINK = 0x4000,
AUDIO_CHANNEL_IN_VOICE_DNLINK = 0x8000,
+/* TODO: should these be considered complete channel masks, or only bits, or deprecated? */
+
AUDIO_CHANNEL_IN_MONO = AUDIO_CHANNEL_IN_FRONT,
AUDIO_CHANNEL_IN_STEREO = (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT),
AUDIO_CHANNEL_IN_FRONT_BACK = (AUDIO_CHANNEL_IN_FRONT | AUDIO_CHANNEL_IN_BACK),
@@ -264,8 +420,111 @@
AUDIO_CHANNEL_IN_VOICE_DNLINK),
};
+/* A channel mask per se only defines the presence or absence of a channel, not the order.
+ * But see AUDIO_INTERLEAVE_* below for the platform convention of order.
+ *
+ * audio_channel_mask_t is an opaque type and its internal layout should not
+ * be assumed as it may change in the future.
+ * Instead, always use the functions declared in this header to examine.
+ *
+ * These are the current representations:
+ *
+ * AUDIO_CHANNEL_REPRESENTATION_POSITION
+ * is a channel mask representation for position assignment.
+ * Each low-order bit corresponds to the spatial position of a transducer (output),
+ * or interpretation of channel (input).
+ * The user of a channel mask needs to know the context of whether it is for output or input.
+ * The constants AUDIO_CHANNEL_OUT_* or AUDIO_CHANNEL_IN_* apply to the bits portion.
+ * It is not permitted for no bits to be set.
+ *
+ * AUDIO_CHANNEL_REPRESENTATION_INDEX
+ * is a channel mask representation for index assignment.
+ * Each low-order bit corresponds to a selected channel.
+ * There is no platform interpretation of the various bits.
+ * There is no concept of output or input.
+ * It is not permitted for no bits to be set.
+ *
+ * All other representations are reserved for future use.
+ *
+ * Warning: current representation distinguishes between input and output, but this will not the be
+ * case in future revisions of the platform. Wherever there is an ambiguity between input and output
+ * that is currently resolved by checking the channel mask, the implementer should look for ways to
+ * fix it with additional information outside of the mask.
+ */
typedef uint32_t audio_channel_mask_t;
+/* Maximum number of channels for all representations */
+#define AUDIO_CHANNEL_COUNT_MAX 30
+
+/* log(2) of maximum number of representations, not part of public API */
+#define AUDIO_CHANNEL_REPRESENTATION_LOG2 2
+
+/* Representations */
+typedef enum {
+ AUDIO_CHANNEL_REPRESENTATION_POSITION = 0, // must be zero for compatibility
+ // 1 is reserved for future use
+ AUDIO_CHANNEL_REPRESENTATION_INDEX = 2,
+ // 3 is reserved for future use
+} audio_channel_representation_t;
+
+/* The return value is undefined if the channel mask is invalid. */
+static inline uint32_t audio_channel_mask_get_bits(audio_channel_mask_t channel)
+{
+ return channel & ((1 << AUDIO_CHANNEL_COUNT_MAX) - 1);
+}
+
+/* The return value is undefined if the channel mask is invalid. */
+static inline audio_channel_representation_t audio_channel_mask_get_representation(
+ audio_channel_mask_t channel)
+{
+ // The right shift should be sufficient, but also "and" for safety in case mask is not 32 bits
+ return (audio_channel_representation_t)
+ ((channel >> AUDIO_CHANNEL_COUNT_MAX) & ((1 << AUDIO_CHANNEL_REPRESENTATION_LOG2) - 1));
+}
+
+/* Returns true if the channel mask is valid,
+ * or returns false for AUDIO_CHANNEL_NONE, AUDIO_CHANNEL_INVALID, and other invalid values.
+ * This function is unable to determine whether a channel mask for position assignment
+ * is invalid because an output mask has an invalid output bit set,
+ * or because an input mask has an invalid input bit set.
+ * All other APIs that take a channel mask assume that it is valid.
+ */
+static inline bool audio_channel_mask_is_valid(audio_channel_mask_t channel)
+{
+ uint32_t bits = audio_channel_mask_get_bits(channel);
+ audio_channel_representation_t representation = audio_channel_mask_get_representation(channel);
+ switch (representation) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ break;
+ default:
+ bits = 0;
+ break;
+ }
+ return bits != 0;
+}
+
+/* Not part of public API */
+static inline audio_channel_mask_t audio_channel_mask_from_representation_and_bits(
+ audio_channel_representation_t representation, uint32_t bits)
+{
+ return (audio_channel_mask_t) ((representation << AUDIO_CHANNEL_COUNT_MAX) | bits);
+}
+
+/* Expresses the convention when stereo audio samples are stored interleaved
+ * in an array. This should improve readability by allowing code to use
+ * symbolic indices instead of hard-coded [0] and [1].
+ *
+ * For multi-channel beyond stereo, the platform convention is that channels
+ * are interleaved in order from least significant channel mask bit
+ * to most significant channel mask bit, with unused bits skipped.
+ * Any exceptions to this convention will be noted at the appropriate API.
+ */
+enum {
+ AUDIO_INTERLEAVE_LEFT = 0,
+ AUDIO_INTERLEAVE_RIGHT = 1,
+};
+
typedef enum {
AUDIO_MODE_INVALID = -2,
AUDIO_MODE_CURRENT = -1,
@@ -278,7 +537,9 @@
AUDIO_MODE_MAX = AUDIO_MODE_CNT - 1,
} audio_mode_t;
+/* This enum is deprecated */
typedef enum {
+ AUDIO_IN_ACOUSTICS_NONE = 0,
AUDIO_IN_ACOUSTICS_AGC_ENABLE = 0x0001,
AUDIO_IN_ACOUSTICS_AGC_DISABLE = 0,
AUDIO_IN_ACOUSTICS_NS_ENABLE = 0x0002,
@@ -304,11 +565,29 @@
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400,
+ AUDIO_DEVICE_OUT_HDMI = AUDIO_DEVICE_OUT_AUX_DIGITAL,
+ /* uses an analog connection (multiplexed over the USB connector pins for instance) */
AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800,
AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000,
+ /* USB accessory mode: your Android device is a USB device and the dock is a USB host */
AUDIO_DEVICE_OUT_USB_ACCESSORY = 0x2000,
+ /* USB host mode: your Android device is a USB host and the dock is a USB device */
AUDIO_DEVICE_OUT_USB_DEVICE = 0x4000,
AUDIO_DEVICE_OUT_REMOTE_SUBMIX = 0x8000,
+ /* Telephony voice TX path */
+ AUDIO_DEVICE_OUT_TELEPHONY_TX = 0x10000,
+ /* Analog jack with line impedance detected */
+ AUDIO_DEVICE_OUT_LINE = 0x20000,
+ /* HDMI Audio Return Channel */
+ AUDIO_DEVICE_OUT_HDMI_ARC = 0x40000,
+ /* S/PDIF out */
+ AUDIO_DEVICE_OUT_SPDIF = 0x80000,
+ /* FM transmitter out */
+ AUDIO_DEVICE_OUT_FM = 0x100000,
+ /* Line out for av devices */
+ AUDIO_DEVICE_OUT_AUX_LINE = 0x200000,
+ /* limited-output speaker device for acoustic safety */
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE = 0x400000,
AUDIO_DEVICE_OUT_DEFAULT = AUDIO_DEVICE_BIT_DEFAULT,
AUDIO_DEVICE_OUT_ALL = (AUDIO_DEVICE_OUT_EARPIECE |
AUDIO_DEVICE_OUT_SPEAKER |
@@ -320,12 +599,19 @@
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
- AUDIO_DEVICE_OUT_AUX_DIGITAL |
+ AUDIO_DEVICE_OUT_HDMI |
AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
AUDIO_DEVICE_OUT_USB_ACCESSORY |
AUDIO_DEVICE_OUT_USB_DEVICE |
AUDIO_DEVICE_OUT_REMOTE_SUBMIX |
+ AUDIO_DEVICE_OUT_TELEPHONY_TX |
+ AUDIO_DEVICE_OUT_LINE |
+ AUDIO_DEVICE_OUT_HDMI_ARC |
+ AUDIO_DEVICE_OUT_SPDIF |
+ AUDIO_DEVICE_OUT_FM |
+ AUDIO_DEVICE_OUT_AUX_LINE |
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE |
AUDIO_DEVICE_OUT_DEFAULT),
AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
@@ -343,13 +629,26 @@
AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = AUDIO_DEVICE_BIT_IN | 0x8,
AUDIO_DEVICE_IN_WIRED_HEADSET = AUDIO_DEVICE_BIT_IN | 0x10,
AUDIO_DEVICE_IN_AUX_DIGITAL = AUDIO_DEVICE_BIT_IN | 0x20,
+ AUDIO_DEVICE_IN_HDMI = AUDIO_DEVICE_IN_AUX_DIGITAL,
+ /* Telephony voice RX path */
AUDIO_DEVICE_IN_VOICE_CALL = AUDIO_DEVICE_BIT_IN | 0x40,
+ AUDIO_DEVICE_IN_TELEPHONY_RX = AUDIO_DEVICE_IN_VOICE_CALL,
AUDIO_DEVICE_IN_BACK_MIC = AUDIO_DEVICE_BIT_IN | 0x80,
AUDIO_DEVICE_IN_REMOTE_SUBMIX = AUDIO_DEVICE_BIT_IN | 0x100,
AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x200,
AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x400,
AUDIO_DEVICE_IN_USB_ACCESSORY = AUDIO_DEVICE_BIT_IN | 0x800,
AUDIO_DEVICE_IN_USB_DEVICE = AUDIO_DEVICE_BIT_IN | 0x1000,
+ /* FM tuner input */
+ AUDIO_DEVICE_IN_FM_TUNER = AUDIO_DEVICE_BIT_IN | 0x2000,
+ /* TV tuner input */
+ AUDIO_DEVICE_IN_TV_TUNER = AUDIO_DEVICE_BIT_IN | 0x4000,
+ /* Analog jack with line impedance detected */
+ AUDIO_DEVICE_IN_LINE = AUDIO_DEVICE_BIT_IN | 0x8000,
+ /* S/PDIF in */
+ AUDIO_DEVICE_IN_SPDIF = AUDIO_DEVICE_BIT_IN | 0x10000,
+ AUDIO_DEVICE_IN_BLUETOOTH_A2DP = AUDIO_DEVICE_BIT_IN | 0x20000,
+ AUDIO_DEVICE_IN_LOOPBACK = AUDIO_DEVICE_BIT_IN | 0x40000,
AUDIO_DEVICE_IN_DEFAULT = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT,
AUDIO_DEVICE_IN_ALL = (AUDIO_DEVICE_IN_COMMUNICATION |
@@ -357,16 +656,24 @@
AUDIO_DEVICE_IN_BUILTIN_MIC |
AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET |
AUDIO_DEVICE_IN_WIRED_HEADSET |
- AUDIO_DEVICE_IN_AUX_DIGITAL |
- AUDIO_DEVICE_IN_VOICE_CALL |
+ AUDIO_DEVICE_IN_HDMI |
+ AUDIO_DEVICE_IN_TELEPHONY_RX |
AUDIO_DEVICE_IN_BACK_MIC |
AUDIO_DEVICE_IN_REMOTE_SUBMIX |
AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET |
AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET |
AUDIO_DEVICE_IN_USB_ACCESSORY |
AUDIO_DEVICE_IN_USB_DEVICE |
+ AUDIO_DEVICE_IN_FM_TUNER |
+ AUDIO_DEVICE_IN_TV_TUNER |
+ AUDIO_DEVICE_IN_LINE |
+ AUDIO_DEVICE_IN_SPDIF |
+ AUDIO_DEVICE_IN_BLUETOOTH_A2DP |
+ AUDIO_DEVICE_IN_LOOPBACK |
AUDIO_DEVICE_IN_DEFAULT),
AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
+ AUDIO_DEVICE_IN_ALL_USB = (AUDIO_DEVICE_IN_USB_ACCESSORY |
+ AUDIO_DEVICE_IN_USB_DEVICE),
};
typedef uint32_t audio_devices_t;
@@ -394,7 +701,8 @@
AUDIO_OUTPUT_FLAG_DEEP_BUFFER = 0x8, // use deep audio buffers
AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD = 0x10, // offload playback of compressed
// streams to hardware codec
- AUDIO_OUTPUT_FLAG_NON_BLOCKING = 0x20 // use non-blocking write
+ AUDIO_OUTPUT_FLAG_NON_BLOCKING = 0x20, // use non-blocking write
+ AUDIO_OUTPUT_FLAG_HW_AV_SYNC = 0x40 // output uses a hardware A/V synchronization source
} audio_output_flags_t;
/* The audio input flags are analogous to audio output flags.
@@ -403,8 +711,9 @@
* attributes corresponding to the specified flags.
*/
typedef enum {
- AUDIO_INPUT_FLAG_NONE = 0x0, // no attributes
- AUDIO_INPUT_FLAG_FAST = 0x1, // prefer an input that supports "fast tracks"
+ AUDIO_INPUT_FLAG_NONE = 0x0, // no attributes
+ AUDIO_INPUT_FLAG_FAST = 0x1, // prefer an input that supports "fast tracks"
+ AUDIO_INPUT_FLAG_HW_HOTWORD = 0x2, // prefer an input that captures from hw hotword source
} audio_input_flags_t;
/* Additional information about compressed streams offloaded to
@@ -434,8 +743,274 @@
static const audio_offload_info_t AUDIO_INFO_INITIALIZER = {
version: AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
size: sizeof(audio_offload_info_t),
+ sample_rate: 0,
+ channel_mask: 0,
+ format: AUDIO_FORMAT_DEFAULT,
+ stream_type: AUDIO_STREAM_VOICE_CALL,
+ bit_rate: 0,
+ duration_us: 0,
+ has_video: false,
+ is_streaming: false
};
+/* common audio stream configuration parameters
+ * You should memset() the entire structure to zero before use to
+ * ensure forward compatibility
+ */
+struct audio_config {
+ uint32_t sample_rate;
+ audio_channel_mask_t channel_mask;
+ audio_format_t format;
+ audio_offload_info_t offload_info;
+ size_t frame_count;
+};
+typedef struct audio_config audio_config_t;
+
+static const audio_config_t AUDIO_CONFIG_INITIALIZER = {
+ sample_rate: 0,
+ channel_mask: AUDIO_CHANNEL_NONE,
+ format: AUDIO_FORMAT_DEFAULT,
+ offload_info: {
+ version: AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
+ size: sizeof(audio_offload_info_t),
+ sample_rate: 0,
+ channel_mask: 0,
+ format: AUDIO_FORMAT_DEFAULT,
+ stream_type: AUDIO_STREAM_VOICE_CALL,
+ bit_rate: 0,
+ duration_us: 0,
+ has_video: false,
+ is_streaming: false
+ },
+ frame_count: 0,
+};
+
+
+/* audio hw module handle functions or structures referencing a module */
+typedef int audio_module_handle_t;
+
+/******************************
+ * Volume control
+ *****************************/
+
+/* If the audio hardware supports gain control on some audio paths,
+ * the platform can expose them in the audio_policy.conf file. The audio HAL
+ * will then implement gain control functions that will use the following data
+ * structures. */
+
+/* Type of gain control exposed by an audio port */
+#define AUDIO_GAIN_MODE_JOINT 0x1 /* supports joint channel gain control */
+#define AUDIO_GAIN_MODE_CHANNELS 0x2 /* supports separate channel gain control */
+#define AUDIO_GAIN_MODE_RAMP 0x4 /* supports gain ramps */
+
+typedef uint32_t audio_gain_mode_t;
+
+
+/* An audio_gain struct is a representation of a gain stage.
+ * A gain stage is always attached to an audio port. */
+struct audio_gain {
+ audio_gain_mode_t mode; /* e.g. AUDIO_GAIN_MODE_JOINT */
+ audio_channel_mask_t channel_mask; /* channels which gain an be controlled.
+ N/A if AUDIO_GAIN_MODE_CHANNELS is not supported */
+ int min_value; /* minimum gain value in millibels */
+ int max_value; /* maximum gain value in millibels */
+ int default_value; /* default gain value in millibels */
+ unsigned int step_value; /* gain step in millibels */
+ unsigned int min_ramp_ms; /* minimum ramp duration in ms */
+ unsigned int max_ramp_ms; /* maximum ramp duration in ms */
+};
+
+/* The gain configuration structure is used to get or set the gain values of a
+ * given port */
+struct audio_gain_config {
+ int index; /* index of the corresponding audio_gain in the
+ audio_port gains[] table */
+ audio_gain_mode_t mode; /* mode requested for this command */
+ audio_channel_mask_t channel_mask; /* channels which gain value follows.
+ N/A in joint mode */
+ int values[sizeof(audio_channel_mask_t) * 8]; /* gain values in millibels
+ for each channel ordered from LSb to MSb in
+ channel mask. The number of values is 1 in joint
+ mode or popcount(channel_mask) */
+ unsigned int ramp_duration_ms; /* ramp duration in ms */
+};
+
+/******************************
+ * Routing control
+ *****************************/
+
+/* Types defined here are used to describe an audio source or sink at internal
+ * framework interfaces (audio policy, patch panel) or at the audio HAL.
+ * Sink and sources are grouped in a concept of “audio port” representing an
+ * audio end point at the edge of the system managed by the module exposing
+ * the interface. */
+
+/* Audio port role: either source or sink */
+typedef enum {
+ AUDIO_PORT_ROLE_NONE,
+ AUDIO_PORT_ROLE_SOURCE,
+ AUDIO_PORT_ROLE_SINK,
+} audio_port_role_t;
+
+/* Audio port type indicates if it is a session (e.g AudioTrack),
+ * a mix (e.g PlaybackThread output) or a physical device
+ * (e.g AUDIO_DEVICE_OUT_SPEAKER) */
+typedef enum {
+ AUDIO_PORT_TYPE_NONE,
+ AUDIO_PORT_TYPE_DEVICE,
+ AUDIO_PORT_TYPE_MIX,
+ AUDIO_PORT_TYPE_SESSION,
+} audio_port_type_t;
+
+/* Each port has a unique ID or handle allocated by policy manager */
+typedef int audio_port_handle_t;
+#define AUDIO_PORT_HANDLE_NONE 0
+
+
+/* maximum audio device address length */
+#define AUDIO_DEVICE_MAX_ADDRESS_LEN 32
+
+/* extension for audio port configuration structure when the audio port is a
+ * hardware device */
+struct audio_port_config_device_ext {
+ audio_module_handle_t hw_module; /* module the device is attached to */
+ audio_devices_t type; /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
+ char address[AUDIO_DEVICE_MAX_ADDRESS_LEN]; /* device address. "" if N/A */
+};
+
+/* extension for audio port configuration structure when the audio port is a
+ * sub mix */
+struct audio_port_config_mix_ext {
+ audio_module_handle_t hw_module; /* module the stream is attached to */
+ audio_io_handle_t handle; /* I/O handle of the input/output stream */
+ union {
+ //TODO: change use case for output streams: use strategy and mixer attributes
+ audio_stream_type_t stream;
+ audio_source_t source;
+ } usecase;
+};
+
+/* extension for audio port configuration structure when the audio port is an
+ * audio session */
+struct audio_port_config_session_ext {
+ audio_session_t session; /* audio session */
+};
+
+/* Flags indicating which fields are to be considered in struct audio_port_config */
+#define AUDIO_PORT_CONFIG_SAMPLE_RATE 0x1
+#define AUDIO_PORT_CONFIG_CHANNEL_MASK 0x2
+#define AUDIO_PORT_CONFIG_FORMAT 0x4
+#define AUDIO_PORT_CONFIG_GAIN 0x8
+#define AUDIO_PORT_CONFIG_ALL (AUDIO_PORT_CONFIG_SAMPLE_RATE | \
+ AUDIO_PORT_CONFIG_CHANNEL_MASK | \
+ AUDIO_PORT_CONFIG_FORMAT | \
+ AUDIO_PORT_CONFIG_GAIN)
+
+/* audio port configuration structure used to specify a particular configuration of
+ * an audio port */
+struct audio_port_config {
+ audio_port_handle_t id; /* port unique ID */
+ audio_port_role_t role; /* sink or source */
+ audio_port_type_t type; /* device, mix ... */
+ unsigned int config_mask; /* e.g AUDIO_PORT_CONFIG_ALL */
+ unsigned int sample_rate; /* sampling rate in Hz */
+ audio_channel_mask_t channel_mask; /* channel mask if applicable */
+ audio_format_t format; /* format if applicable */
+ struct audio_gain_config gain; /* gain to apply if applicable */
+ union {
+ struct audio_port_config_device_ext device; /* device specific info */
+ struct audio_port_config_mix_ext mix; /* mix specific info */
+ struct audio_port_config_session_ext session; /* session specific info */
+ } ext;
+};
+
+
+/* max number of sampling rates in audio port */
+#define AUDIO_PORT_MAX_SAMPLING_RATES 16
+/* max number of channel masks in audio port */
+#define AUDIO_PORT_MAX_CHANNEL_MASKS 16
+/* max number of audio formats in audio port */
+#define AUDIO_PORT_MAX_FORMATS 16
+/* max number of gain controls in audio port */
+#define AUDIO_PORT_MAX_GAINS 16
+
+/* extension for audio port structure when the audio port is a hardware device */
+struct audio_port_device_ext {
+ audio_module_handle_t hw_module; /* module the device is attached to */
+ audio_devices_t type; /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
+ char address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+};
+
+/* Latency class of the audio mix */
+typedef enum {
+ AUDIO_LATENCY_LOW,
+ AUDIO_LATENCY_NORMAL,
+} audio_mix_latency_class_t;
+
+/* extension for audio port structure when the audio port is a sub mix */
+struct audio_port_mix_ext {
+ audio_module_handle_t hw_module; /* module the stream is attached to */
+ audio_io_handle_t handle; /* I/O handle of the input.output stream */
+ audio_mix_latency_class_t latency_class; /* latency class */
+ // other attributes: routing strategies
+};
+
+/* extension for audio port structure when the audio port is an audio session */
+struct audio_port_session_ext {
+ audio_session_t session; /* audio session */
+};
+
+
+struct audio_port {
+ audio_port_handle_t id; /* port unique ID */
+ audio_port_role_t role; /* sink or source */
+ audio_port_type_t type; /* device, mix ... */
+ unsigned int num_sample_rates; /* number of sampling rates in following array */
+ unsigned int sample_rates[AUDIO_PORT_MAX_SAMPLING_RATES];
+ unsigned int num_channel_masks; /* number of channel masks in following array */
+ audio_channel_mask_t channel_masks[AUDIO_PORT_MAX_CHANNEL_MASKS];
+ unsigned int num_formats; /* number of formats in following array */
+ audio_format_t formats[AUDIO_PORT_MAX_FORMATS];
+ unsigned int num_gains; /* number of gains in following array */
+ struct audio_gain gains[AUDIO_PORT_MAX_GAINS];
+ struct audio_port_config active_config; /* current audio port configuration */
+ union {
+ struct audio_port_device_ext device;
+ struct audio_port_mix_ext mix;
+ struct audio_port_session_ext session;
+ } ext;
+};
+
+/* An audio patch represents a connection between one or more source ports and
+ * one or more sink ports. Patches are connected and disconnected by audio policy manager or by
+ * applications via framework APIs.
+ * Each patch is identified by a handle at the interface used to create that patch. For instance,
+ * when a patch is created by the audio HAL, the HAL allocates and returns a handle.
+ * This handle is unique to a given audio HAL hardware module.
+ * But the same patch receives another system wide unique handle allocated by the framework.
+ * This unique handle is used for all transactions inside the framework.
+ */
+typedef int audio_patch_handle_t;
+#define AUDIO_PATCH_HANDLE_NONE 0
+
+#define AUDIO_PATCH_PORTS_MAX 16
+
+struct audio_patch {
+ audio_patch_handle_t id; /* patch unique ID */
+ unsigned int num_sources; /* number of sources in following array */
+ struct audio_port_config sources[AUDIO_PATCH_PORTS_MAX];
+ unsigned int num_sinks; /* number of sinks in following array */
+ struct audio_port_config sinks[AUDIO_PATCH_PORTS_MAX];
+};
+
+
+
+/* a HW synchronization source returned by the audio HAL */
+typedef uint32_t audio_hw_sync_t;
+
+/* an invalid HW synchronization source indicating an error */
+#define AUDIO_HW_SYNC_INVALID 0
+
static inline bool audio_is_output_device(audio_devices_t device)
{
if (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
@@ -460,8 +1035,17 @@
return (device & AUDIO_DEVICE_BIT_IN) == 0;
}
+static inline bool audio_is_a2dp_in_device(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if ((popcount(device) == 1) && (device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP))
+ return true;
+ }
+ return false;
+}
-static inline bool audio_is_a2dp_device(audio_devices_t device)
+static inline bool audio_is_a2dp_out_device(audio_devices_t device)
{
if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_A2DP))
return true;
@@ -469,6 +1053,12 @@
return false;
}
+// Deprecated - use audio_is_a2dp_out_device() instead
+static inline bool audio_is_a2dp_device(audio_devices_t device)
+{
+ return audio_is_a2dp_out_device(device);
+}
+
static inline bool audio_is_bluetooth_sco_device(audio_devices_t device)
{
if ((device & AUDIO_DEVICE_BIT_IN) == 0) {
@@ -483,12 +1073,25 @@
return false;
}
+static inline bool audio_is_usb_out_device(audio_devices_t device)
+{
+ return ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_USB));
+}
+
+static inline bool audio_is_usb_in_device(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if (popcount(device) == 1 && (device & AUDIO_DEVICE_IN_ALL_USB) != 0)
+ return true;
+ }
+ return false;
+}
+
+/* OBSOLETE - use audio_is_usb_out_device() instead. */
static inline bool audio_is_usb_device(audio_devices_t device)
{
- if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_USB))
- return true;
- else
- return false;
+ return audio_is_usb_out_device(device);
}
static inline bool audio_is_remote_submix_device(audio_devices_t device)
@@ -500,75 +1103,200 @@
return false;
}
+/* Returns true if:
+ * representation is valid, and
+ * there is at least one channel bit set which _could_ correspond to an input channel, and
+ * there are no channel bits set which could _not_ correspond to an input channel.
+ * Otherwise returns false.
+ */
static inline bool audio_is_input_channel(audio_channel_mask_t channel)
{
- if ((channel & ~AUDIO_CHANNEL_IN_ALL) == 0)
- return channel != 0;
- else
+ uint32_t bits = audio_channel_mask_get_bits(channel);
+ switch (audio_channel_mask_get_representation(channel)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ if (bits & ~AUDIO_CHANNEL_IN_ALL) {
+ bits = 0;
+ }
+ // fall through
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ return bits != 0;
+ default:
return false;
+ }
}
+/* Returns true if:
+ * representation is valid, and
+ * there is at least one channel bit set which _could_ correspond to an output channel, and
+ * there are no channel bits set which could _not_ correspond to an output channel.
+ * Otherwise returns false.
+ */
static inline bool audio_is_output_channel(audio_channel_mask_t channel)
{
- if ((channel & ~AUDIO_CHANNEL_OUT_ALL) == 0)
- return channel != 0;
- else
+ uint32_t bits = audio_channel_mask_get_bits(channel);
+ switch (audio_channel_mask_get_representation(channel)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ if (bits & ~AUDIO_CHANNEL_OUT_ALL) {
+ bits = 0;
+ }
+ // fall through
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ return bits != 0;
+ default:
return false;
+ }
}
-/* Derive an output channel mask from a channel count.
+/* Returns the number of channels from an input channel mask,
+ * used in the context of audio input or recording.
+ * If a channel bit is set which could _not_ correspond to an input channel,
+ * it is excluded from the count.
+ * Returns zero if the representation is invalid.
+ */
+static inline uint32_t audio_channel_count_from_in_mask(audio_channel_mask_t channel)
+{
+ uint32_t bits = audio_channel_mask_get_bits(channel);
+ switch (audio_channel_mask_get_representation(channel)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ // TODO: We can now merge with from_out_mask and remove anding
+ bits &= AUDIO_CHANNEL_IN_ALL;
+ // fall through
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ return popcount(bits);
+ default:
+ return 0;
+ }
+}
+
+/* Returns the number of channels from an output channel mask,
+ * used in the context of audio output or playback.
+ * If a channel bit is set which could _not_ correspond to an output channel,
+ * it is excluded from the count.
+ * Returns zero if the representation is invalid.
+ */
+static inline uint32_t audio_channel_count_from_out_mask(audio_channel_mask_t channel)
+{
+ uint32_t bits = audio_channel_mask_get_bits(channel);
+ switch (audio_channel_mask_get_representation(channel)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ // TODO: We can now merge with from_in_mask and remove anding
+ bits &= AUDIO_CHANNEL_OUT_ALL;
+ // fall through
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ return popcount(bits);
+ default:
+ return 0;
+ }
+}
+
+/* Derive an output channel mask for position assignment from a channel count.
* This is to be used when the content channel mask is unknown. The 1, 2, 4, 5, 6, 7 and 8 channel
* cases are mapped to the standard game/home-theater layouts, but note that 4 is mapped to quad,
* and not stereo + FC + mono surround. A channel count of 3 is arbitrarily mapped to stereo + FC
* for continuity with stereo.
- * Returns the matching channel mask, or 0 if the number of channels exceeds that of the
- * configurations for which a default channel mask is defined.
+ * Returns the matching channel mask,
+ * or AUDIO_CHANNEL_NONE if the channel count is zero,
+ * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the
+ * configurations for which a default output channel mask is defined.
*/
static inline audio_channel_mask_t audio_channel_out_mask_from_count(uint32_t channel_count)
{
- switch(channel_count) {
+ uint32_t bits;
+ switch (channel_count) {
+ case 0:
+ return AUDIO_CHANNEL_NONE;
case 1:
- return AUDIO_CHANNEL_OUT_MONO;
+ bits = AUDIO_CHANNEL_OUT_MONO;
+ break;
case 2:
- return AUDIO_CHANNEL_OUT_STEREO;
+ bits = AUDIO_CHANNEL_OUT_STEREO;
+ break;
case 3:
- return (AUDIO_CHANNEL_OUT_STEREO | AUDIO_CHANNEL_OUT_FRONT_CENTER);
+ bits = AUDIO_CHANNEL_OUT_STEREO | AUDIO_CHANNEL_OUT_FRONT_CENTER;
+ break;
case 4: // 4.0
- return AUDIO_CHANNEL_OUT_QUAD;
+ bits = AUDIO_CHANNEL_OUT_QUAD;
+ break;
case 5: // 5.0
- return (AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER);
+ bits = AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER;
+ break;
case 6: // 5.1
- return AUDIO_CHANNEL_OUT_5POINT1;
+ bits = AUDIO_CHANNEL_OUT_5POINT1;
+ break;
case 7: // 6.1
- return (AUDIO_CHANNEL_OUT_5POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER);
+ bits = AUDIO_CHANNEL_OUT_5POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER;
+ break;
case 8:
- return AUDIO_CHANNEL_OUT_7POINT1;
+ bits = AUDIO_CHANNEL_OUT_7POINT1;
+ break;
default:
- return 0;
+ return AUDIO_CHANNEL_INVALID;
}
+ return audio_channel_mask_from_representation_and_bits(
+ AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
}
-/* Similar to above, but for input. Currently handles only mono and stereo. */
+/* Derive an input channel mask for position assignment from a channel count.
+ * Currently handles only mono and stereo.
+ * Returns the matching channel mask,
+ * or AUDIO_CHANNEL_NONE if the channel count is zero,
+ * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the
+ * configurations for which a default input channel mask is defined.
+ */
static inline audio_channel_mask_t audio_channel_in_mask_from_count(uint32_t channel_count)
{
+ uint32_t bits;
switch (channel_count) {
+ case 0:
+ return AUDIO_CHANNEL_NONE;
case 1:
- return AUDIO_CHANNEL_IN_MONO;
+ bits = AUDIO_CHANNEL_IN_MONO;
+ break;
case 2:
- return AUDIO_CHANNEL_IN_STEREO;
+ bits = AUDIO_CHANNEL_IN_STEREO;
+ break;
default:
- return 0;
+ return AUDIO_CHANNEL_INVALID;
}
+ return audio_channel_mask_from_representation_and_bits(
+ AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
+}
+
+/* Derive a channel mask for index assignment from a channel count.
+ * Returns the matching channel mask,
+ * or AUDIO_CHANNEL_NONE if the channel count is zero,
+ * or AUDIO_CHANNEL_INVALID if the channel count exceeds AUDIO_CHANNEL_COUNT_MAX.
+ */
+static inline audio_channel_mask_t audio_channel_mask_for_index_assignment_from_count(
+ uint32_t channel_count)
+{
+ if (channel_count == 0) {
+ return AUDIO_CHANNEL_NONE;
+ }
+ if (channel_count > AUDIO_CHANNEL_COUNT_MAX) {
+ return AUDIO_CHANNEL_INVALID;
+ }
+ uint32_t bits = (1 << channel_count) - 1;
+ return audio_channel_mask_from_representation_and_bits(
+ AUDIO_CHANNEL_REPRESENTATION_INDEX, bits);
}
static inline bool audio_is_valid_format(audio_format_t format)
{
switch (format & AUDIO_FORMAT_MAIN_MASK) {
case AUDIO_FORMAT_PCM:
- if (format != AUDIO_FORMAT_PCM_16_BIT &&
- format != AUDIO_FORMAT_PCM_8_BIT) {
+ switch (format) {
+ case AUDIO_FORMAT_PCM_16_BIT:
+ case AUDIO_FORMAT_PCM_8_BIT:
+ case AUDIO_FORMAT_PCM_32_BIT:
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ case AUDIO_FORMAT_PCM_FLOAT:
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ return true;
+ default:
return false;
}
+ /* not reached */
case AUDIO_FORMAT_MP3:
case AUDIO_FORMAT_AMR_NB:
case AUDIO_FORMAT_AMR_WB:
@@ -576,6 +1304,9 @@
case AUDIO_FORMAT_HE_AAC_V1:
case AUDIO_FORMAT_HE_AAC_V2:
case AUDIO_FORMAT_VORBIS:
+ case AUDIO_FORMAT_OPUS:
+ case AUDIO_FORMAT_AC3:
+ case AUDIO_FORMAT_E_AC3:
return true;
default:
return false;
@@ -596,18 +1327,41 @@
case AUDIO_FORMAT_PCM_8_24_BIT:
size = sizeof(int32_t);
break;
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ size = sizeof(uint8_t) * 3;
+ break;
case AUDIO_FORMAT_PCM_16_BIT:
size = sizeof(int16_t);
break;
case AUDIO_FORMAT_PCM_8_BIT:
size = sizeof(uint8_t);
break;
+ case AUDIO_FORMAT_PCM_FLOAT:
+ size = sizeof(float);
+ break;
default:
break;
}
return size;
}
+/* converts device address to string sent to audio HAL via set_parameters */
+static char *audio_device_address_to_parameter(audio_devices_t device, const char *address)
+{
+ const size_t kSize = AUDIO_DEVICE_MAX_ADDRESS_LEN + sizeof("a2dp_sink_address=");
+ char param[kSize];
+
+ if (device & AUDIO_DEVICE_OUT_ALL_A2DP)
+ snprintf(param, kSize, "%s=%s", "a2dp_sink_address", address);
+ else if (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
+ snprintf(param, kSize, "%s=%s", "mix", address);
+ else
+ snprintf(param, kSize, "%s", address);
+
+ return strdup(param);
+}
+
+
__END_DECLS
#endif // ANDROID_AUDIO_CORE_H
diff --git a/include/system/audio_policy.h b/include/system/audio_policy.h
index a6554de..2881104 100644
--- a/include/system/audio_policy.h
+++ b/include/system/audio_policy.h
@@ -44,6 +44,7 @@
AUDIO_POLICY_FORCE_DIGITAL_DOCK,
AUDIO_POLICY_FORCE_NO_BT_A2DP, /* A2DP sink is not preferred to speaker or wired HS */
AUDIO_POLICY_FORCE_SYSTEM_ENFORCED,
+ AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED,
AUDIO_POLICY_FORCE_CFG_CNT,
AUDIO_POLICY_FORCE_CFG_MAX = AUDIO_POLICY_FORCE_CFG_CNT - 1,
@@ -58,6 +59,7 @@
AUDIO_POLICY_FORCE_FOR_RECORD,
AUDIO_POLICY_FORCE_FOR_DOCK,
AUDIO_POLICY_FORCE_FOR_SYSTEM,
+ AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO,
AUDIO_POLICY_FORCE_USE_CNT,
AUDIO_POLICY_FORCE_USE_MAX = AUDIO_POLICY_FORCE_USE_CNT - 1,
diff --git a/include/system/graphics.h b/include/system/graphics.h
index be86ae4..c3fca97 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -165,24 +165,104 @@
/*
* Android RAW sensor format:
*
- * This format is exposed outside of the HAL to applications.
+ * This format is exposed outside of the camera HAL to applications.
*
- * RAW_SENSOR is a single-channel 16-bit format, typically representing raw
- * Bayer-pattern images from an image sensor, with minimal processing.
+ * RAW_SENSOR is a single-channel, 16-bit, little endian format, typically
+ * representing raw Bayer-pattern images from an image sensor, with minimal
+ * processing.
*
* The exact pixel layout of the data in the buffer is sensor-dependent, and
* needs to be queried from the camera device.
*
* Generally, not all 16 bits are used; more common values are 10 or 12
- * bits. All parameters to interpret the raw data (black and white points,
+ * bits. If not all bits are used, the lower-order bits are filled first.
+ * All parameters to interpret the raw data (black and white points,
* color space, etc) must be queried from the camera device.
*
* This format assumes
* - an even width
* - an even height
- * - a horizontal stride multiple of 16 pixels (32 bytes).
+ * - a horizontal stride multiple of 16 pixels
+ * - a vertical stride equal to the height
+ * - strides are specified in pixels, not in bytes
+ *
+ * size = stride * height * 2
+ *
+ * This format must be accepted by the gralloc module when used with the
+ * following usage flags:
+ * - GRALLOC_USAGE_HW_CAMERA_*
+ * - GRALLOC_USAGE_SW_*
+ * - GRALLOC_USAGE_RENDERSCRIPT
*/
- HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20,
+ HAL_PIXEL_FORMAT_RAW16 = 0x20,
+ HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20, // TODO(rubenbrunk): Remove RAW_SENSOR.
+
+ /*
+ * Android RAW10 format:
+ *
+ * This format is exposed outside of the camera HAL to applications.
+ *
+ * RAW10 is a single-channel, 10-bit per pixel, densely packed in each row,
+ * unprocessed format, usually representing raw Bayer-pattern images coming from
+ * an image sensor.
+ *
+ * In an image buffer with this format, starting from the first pixel of each
+ * row, each 4 consecutive pixels are packed into 5 bytes (40 bits). Each one
+ * of the first 4 bytes contains the top 8 bits of each pixel, The fifth byte
+ * contains the 2 least significant bits of the 4 pixels, the exact layout data
+ * for each 4 consecutive pixels is illustrated below (Pi[j] stands for the jth
+ * bit of the ith pixel):
+ *
+ * bit 7 bit 0
+ * =====|=====|=====|=====|=====|=====|=====|=====|
+ * Byte 0: |P0[9]|P0[8]|P0[7]|P0[6]|P0[5]|P0[4]|P0[3]|P0[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 1: |P1[9]|P1[8]|P1[7]|P1[6]|P1[5]|P1[4]|P1[3]|P1[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 2: |P2[9]|P2[8]|P2[7]|P2[6]|P2[5]|P2[4]|P2[3]|P2[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 3: |P3[9]|P3[8]|P3[7]|P3[6]|P3[5]|P3[4]|P3[3]|P3[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 4: |P3[1]|P3[0]|P2[1]|P2[0]|P1[1]|P1[0]|P0[1]|P0[0]|
+ * ===============================================
+ *
+ * This format assumes
+ * - a width multiple of 4 pixels
+ * - an even height
+ * - a vertical stride equal to the height
+ * - strides are specified in bytes, not in pixels
+ *
+ * size = stride * height
+ *
+ * When stride is equal to width * (10 / 8), there will be no padding bytes at
+ * the end of each row, the entire image data is densely packed. When stride is
+ * larger than width * (10 / 8), padding bytes will be present at the end of each
+ * row (including the last row).
+ *
+ * This format must be accepted by the gralloc module when used with the
+ * following usage flags:
+ * - GRALLOC_USAGE_HW_CAMERA_*
+ * - GRALLOC_USAGE_SW_*
+ * - GRALLOC_USAGE_RENDERSCRIPT
+ */
+ HAL_PIXEL_FORMAT_RAW10 = 0x25,
+
+ /*
+ * Android opaque RAW format:
+ *
+ * This format is exposed outside of the camera HAL to applications.
+ *
+ * RAW_OPAQUE is a format for unprocessed raw image buffers coming from an
+ * image sensor. The actual structure of buffers of this format is
+ * implementation-dependent.
+ *
+ * This format must be accepted by the gralloc module when used with the
+ * following usage flags:
+ * - GRALLOC_USAGE_HW_CAMERA_*
+ * - GRALLOC_USAGE_SW_*
+ * - GRALLOC_USAGE_RENDERSCRIPT
+ */
+ HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24,
/*
* Android binary blob graphics buffer format:
@@ -297,6 +377,136 @@
HAL_TRANSFORM_RESERVED = 0x08,
};
+/**
+ * Colorspace 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).
+ */
+
+enum {
+ /*
+ * Arbitrary colorspace with manually defined characteristics.
+ * Colorspace definition must be communicated separately.
+ *
+ * This is used when specifying primaries, transfer characteristics,
+ * etc. separately.
+ *
+ * A typical use case is in video encoding parameters (e.g. for H.264),
+ * where a colorspace can have separately defined primaries, transfer
+ * characteristics, etc.
+ */
+ HAL_COLORSPACE_ARBITRARY = 0x1,
+
+ /*
+ * YCbCr 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).
+ */
+
+ /*
+ * JPEG File Interchange Format (JFIF)
+ *
+ * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
+ *
+ * Transfer characteristic curve:
+ * E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
+ * E = 4.500 L, 0.018 > L >= 0
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ *
+ * Primaries: x y
+ * green 0.290 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ */
+ HAL_COLORSPACE_JFIF = 0x101,
+
+ /*
+ * ITU-R Recommendation 601 (BT.601) - 625-line
+ *
+ * Standard-definition television, 625 Lines (PAL)
+ *
+ * For 8-bit-depth formats:
+ * Luma (Y) samples should range from 16 to 235, inclusive
+ * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+ *
+ * For 10-bit-depth formats:
+ * Luma (Y) samples should range from 64 to 940, inclusive
+ * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+ *
+ * Transfer characteristic curve:
+ * E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
+ * E = 4.500 L, 0.018 > L >= 0
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ *
+ * Primaries: x y
+ * green 0.290 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ */
+ HAL_COLORSPACE_BT601_625 = 0x102,
+
+ /*
+ * ITU-R Recommendation 601 (BT.601) - 525-line
+ *
+ * Standard-definition television, 525 Lines (NTSC)
+ *
+ * For 8-bit-depth formats:
+ * Luma (Y) samples should range from 16 to 235, inclusive
+ * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+ *
+ * For 10-bit-depth formats:
+ * Luma (Y) samples should range from 64 to 940, inclusive
+ * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+ *
+ * Transfer characteristic curve:
+ * E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
+ * E = 4.500 L, 0.018 > L >= 0
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ *
+ * Primaries: x y
+ * green 0.310 0.595
+ * blue 0.155 0.070
+ * red 0.630 0.340
+ * white (D65) 0.3127 0.3290
+ */
+ HAL_COLORSPACE_BT601_525 = 0x103,
+
+ /*
+ * ITU-R Recommendation 709 (BT.709)
+ *
+ * High-definition television
+ *
+ * For 8-bit-depth formats:
+ * Luma (Y) samples should range from 16 to 235, inclusive
+ * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+ *
+ * For 10-bit-depth formats:
+ * Luma (Y) samples should range from 64 to 940, inclusive
+ * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+ *
+ * Primaries: x y
+ * green 0.300 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ */
+ HAL_COLORSPACE_BT709 = 0x104,
+};
+
#ifdef __cplusplus
}
#endif
diff --git a/include/system/sound_trigger.h b/include/system/sound_trigger.h
new file mode 100644
index 0000000..773e4f7
--- /dev/null
+++ b/include/system/sound_trigger.h
@@ -0,0 +1,223 @@
+/*
+ * 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 ANDROID_SOUND_TRIGGER_H
+#define ANDROID_SOUND_TRIGGER_H
+
+#include <stdbool.h>
+#include <system/audio.h>
+
+#define SOUND_TRIGGER_MAX_STRING_LEN 64 /* max length of strings in properties or
+ descriptor structs */
+#define SOUND_TRIGGER_MAX_LOCALE_LEN 6 /* max length of locale string. e.g en_US */
+#define SOUND_TRIGGER_MAX_USERS 10 /* max number of concurrent users */
+#define SOUND_TRIGGER_MAX_PHRASES 10 /* max number of concurrent phrases */
+
+typedef enum {
+ SOUND_TRIGGER_STATE_NO_INIT = -1, /* The sound trigger service is not initialized */
+ SOUND_TRIGGER_STATE_ENABLED = 0, /* The sound trigger service is enabled */
+ SOUND_TRIGGER_STATE_DISABLED = 1 /* The sound trigger service is disabled */
+} sound_trigger_service_state_t;
+
+#define RECOGNITION_MODE_VOICE_TRIGGER 0x1 /* simple voice trigger */
+#define RECOGNITION_MODE_USER_IDENTIFICATION 0x2 /* trigger only if one user in model identified */
+#define RECOGNITION_MODE_USER_AUTHENTICATION 0x4 /* trigger only if one user in mode
+ authenticated */
+#define RECOGNITION_STATUS_SUCCESS 0
+#define RECOGNITION_STATUS_ABORT 1
+#define RECOGNITION_STATUS_FAILURE 2
+
+#define SOUND_MODEL_STATUS_UPDATED 0
+
+typedef enum {
+ SOUND_MODEL_TYPE_UNKNOWN = -1, /* use for unspecified sound model type */
+ SOUND_MODEL_TYPE_KEYPHRASE = 0 /* use for key phrase sound models */
+} sound_trigger_sound_model_type_t;
+
+typedef struct sound_trigger_uuid_s {
+ unsigned int timeLow;
+ unsigned short timeMid;
+ unsigned short timeHiAndVersion;
+ unsigned short clockSeq;
+ unsigned char node[6];
+} sound_trigger_uuid_t;
+
+/*
+ * sound trigger implementation descriptor read by the framework via get_properties().
+ * Used by SoundTrigger service to report to applications and manage concurrency and policy.
+ */
+struct sound_trigger_properties {
+ char implementor[SOUND_TRIGGER_MAX_STRING_LEN]; /* implementor name */
+ char description[SOUND_TRIGGER_MAX_STRING_LEN]; /* implementation description */
+ unsigned int version; /* implementation version */
+ sound_trigger_uuid_t uuid; /* unique implementation ID.
+ Must change with version each version */
+ unsigned int max_sound_models; /* maximum number of concurrent sound models
+ loaded */
+ unsigned int max_key_phrases; /* maximum number of key phrases */
+ unsigned int max_users; /* maximum number of concurrent users detected */
+ unsigned int recognition_modes; /* all supported modes.
+ e.g RECOGNITION_MODE_VOICE_TRIGGER */
+ bool capture_transition; /* supports seamless transition from detection
+ to capture */
+ unsigned int max_buffer_ms; /* maximum buffering capacity in ms if
+ capture_transition is true*/
+ bool concurrent_capture; /* supports capture by other use cases while
+ detection is active */
+ bool trigger_in_event; /* returns the trigger capture in event */
+ unsigned int power_consumption_mw; /* Rated power consumption when detection is active
+ with TDB silence/sound/speech ratio */
+};
+
+typedef int sound_trigger_module_handle_t;
+
+struct sound_trigger_module_descriptor {
+ sound_trigger_module_handle_t handle;
+ struct sound_trigger_properties properties;
+};
+
+typedef int sound_model_handle_t;
+
+/*
+ * Generic sound model descriptor. This struct is the header of a larger block passed to
+ * load_sound_model() and containing the binary data of the sound model.
+ * Proprietary representation of users in binary data must match information indicated
+ * by users field
+ */
+struct sound_trigger_sound_model {
+ sound_trigger_sound_model_type_t type; /* model type. e.g. SOUND_MODEL_TYPE_KEYPHRASE */
+ sound_trigger_uuid_t uuid; /* unique sound model ID. */
+ sound_trigger_uuid_t vendor_uuid; /* unique vendor ID. Identifies the engine the
+ sound model was build for */
+ unsigned int data_size; /* size of opaque model data */
+ unsigned int data_offset; /* offset of opaque data start from head of struct
+ (e.g sizeof struct sound_trigger_sound_model) */
+};
+
+/* key phrase descriptor */
+struct sound_trigger_phrase {
+ unsigned int id; /* keyphrase ID */
+ unsigned int recognition_mode; /* recognition modes supported by this key phrase */
+ unsigned int num_users; /* number of users in the key phrase */
+ unsigned int users[SOUND_TRIGGER_MAX_USERS]; /* users ids: (not uid_t but sound trigger
+ specific IDs */
+ char locale[SOUND_TRIGGER_MAX_LOCALE_LEN]; /* locale - JAVA Locale style (e.g. en_US) */
+ char text[SOUND_TRIGGER_MAX_STRING_LEN]; /* phrase text in UTF-8 format. */
+};
+
+/*
+ * Specialized sound model for key phrase detection.
+ * Proprietary representation of key phrases in binary data must match information indicated
+ * by phrases field
+ */
+struct sound_trigger_phrase_sound_model {
+ struct sound_trigger_sound_model common;
+ unsigned int num_phrases; /* number of key phrases in model */
+ struct sound_trigger_phrase phrases[SOUND_TRIGGER_MAX_PHRASES];
+};
+
+
+/*
+ * Generic recognition event sent via recognition callback
+ */
+struct sound_trigger_recognition_event {
+ int status; /* recognition status e.g.
+ RECOGNITION_STATUS_SUCCESS */
+ sound_trigger_sound_model_type_t type; /* event type, same as sound model type.
+ e.g. SOUND_MODEL_TYPE_KEYPHRASE */
+ sound_model_handle_t model; /* loaded sound model that triggered the
+ event */
+ bool capture_available; /* it is possible to capture audio from this
+ utterance buffered by the
+ implementation */
+ int capture_session; /* audio session ID. framework use */
+ int capture_delay_ms; /* delay in ms between end of model
+ detection and start of audio available
+ for capture. A negative value is possible
+ (e.g. if key phrase is also available for
+ capture */
+ int capture_preamble_ms; /* duration in ms of audio captured
+ before the start of the trigger.
+ 0 if none. */
+ bool trigger_in_data; /* the opaque data is the capture of
+ the trigger sound */
+ audio_config_t audio_config; /* audio format of either the trigger in
+ event data or to use for capture of the
+ rest of the utterance */
+ unsigned int data_size; /* size of opaque event data */
+ unsigned int data_offset; /* offset of opaque data start from start of
+ this struct (e.g sizeof struct
+ sound_trigger_phrase_recognition_event) */
+};
+
+/*
+ * Confidence level for each user in struct sound_trigger_phrase_recognition_extra
+ */
+struct sound_trigger_confidence_level {
+ unsigned int user_id; /* user ID */
+ unsigned int level; /* confidence level in percent (0 - 100).
+ - min level for recognition configuration
+ - detected level for recognition event */
+};
+
+/*
+ * Specialized recognition event for key phrase detection
+ */
+struct sound_trigger_phrase_recognition_extra {
+ unsigned int id; /* keyphrase ID */
+ unsigned int recognition_modes; /* recognition modes used for this keyphrase */
+ unsigned int confidence_level; /* confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER */
+ unsigned int num_levels; /* number of user confidence levels */
+ struct sound_trigger_confidence_level levels[SOUND_TRIGGER_MAX_USERS];
+};
+
+struct sound_trigger_phrase_recognition_event {
+ struct sound_trigger_recognition_event common;
+ unsigned int num_phrases;
+ struct sound_trigger_phrase_recognition_extra phrase_extras[SOUND_TRIGGER_MAX_PHRASES];
+};
+
+/*
+ * configuration for sound trigger capture session passed to start_recognition()
+ */
+struct sound_trigger_recognition_config {
+ audio_io_handle_t capture_handle; /* IO handle that will be used for capture.
+ N/A if capture_requested is false */
+ audio_devices_t capture_device; /* input device requested for detection capture */
+ bool capture_requested; /* capture and buffer audio for this recognition
+ instance */
+ unsigned int num_phrases; /* number of key phrases recognition extras */
+ struct sound_trigger_phrase_recognition_extra phrases[SOUND_TRIGGER_MAX_PHRASES];
+ /* configuration for each key phrase */
+ unsigned int data_size; /* size of opaque capture configuration data */
+ unsigned int data_offset; /* offset of opaque data start from start of this struct
+ (e.g sizeof struct sound_trigger_recognition_config) */
+};
+
+/*
+ * Event sent via load sound model callback
+ */
+struct sound_trigger_model_event {
+ int status; /* sound model status e.g. SOUND_MODEL_STATUS_UPDATED */
+ sound_model_handle_t model; /* loaded sound model that triggered the event */
+ unsigned int data_size; /* size of event data if any. Size of updated sound model if
+ status is SOUND_MODEL_STATUS_UPDATED */
+ unsigned int data_offset; /* offset of data start from start of this struct
+ (e.g sizeof struct sound_trigger_model_event) */
+};
+
+
+#endif // ANDROID_SOUND_TRIGGER_H
diff --git a/include/system/window.h b/include/system/window.h
index 588f9c6..bf93b79 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -26,6 +26,13 @@
#include <system/graphics.h>
#include <unistd.h>
+#ifndef __UNUSED
+#define __UNUSED __attribute__((__unused__))
+#endif
+#ifndef __deprecated
+#define __deprecated __attribute__((__deprecated__))
+#endif
+
__BEGIN_DECLS
/*****************************************************************************/
@@ -89,10 +96,10 @@
// Implement the methods that sp<ANativeWindowBuffer> expects so that it
// can be used to automatically refcount ANativeWindowBuffer's.
- void incStrong(const void* id) const {
+ void incStrong(const void* /*id*/) const {
common.incRef(const_cast<android_native_base_t*>(&common));
}
- void decStrong(const void* id) const {
+ void decStrong(const void* /*id*/) const {
common.decRef(const_cast<android_native_base_t*>(&common));
}
#endif
@@ -235,7 +242,26 @@
* The consumer gralloc usage bits currently set by the consumer.
* The values are defined in hardware/libhardware/include/gralloc.h.
*/
- NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10
+ NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10,
+
+ /**
+ * Transformation that will by applied to buffers by the hwcomposer.
+ * This must not be set or checked by producer endpoints, and will
+ * disable the transform hint set in SurfaceFlinger (see
+ * NATIVE_WINDOW_TRANSFORM_HINT).
+ *
+ * INTENDED USE:
+ * Temporary - Please do not use this. This is intended only to be used
+ * by the camera's LEGACY mode.
+ *
+ * In situations where a SurfaceFlinger client wishes to set a transform
+ * that is not visible to the producer, and will always be applied in the
+ * hardware composer, the client can set this flag with
+ * native_window_set_buffers_sticky_transform. This can be used to rotate
+ * and flip buffers consumed by hardware composer without actually changing
+ * the aspect ratio of the buffers produced.
+ */
+ NATIVE_WINDOW_STICKY_TRANSFORM = 11,
};
/* Valid operations for the (*perform)() hook.
@@ -266,6 +292,8 @@
NATIVE_WINDOW_API_DISCONNECT = 14, /* private */
NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* private */
+ NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */
+ NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
};
/* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@@ -352,10 +380,10 @@
/* Implement the methods that sp<ANativeWindow> expects so that it
can be used to automatically refcount ANativeWindow's. */
- void incStrong(const void* id) const {
+ void incStrong(const void* /*id*/) const {
common.incRef(const_cast<android_native_base_t*>(&common));
}
- void decStrong(const void* id) const {
+ void decStrong(const void* /*id*/) const {
common.decRef(const_cast<android_native_base_t*>(&common));
}
#endif
@@ -582,7 +610,7 @@
* android_native_window_t is deprecated.
*/
typedef struct ANativeWindow ANativeWindow;
-typedef struct ANativeWindow android_native_window_t;
+typedef struct ANativeWindow android_native_window_t __deprecated;
/*
* native_window_set_usage(..., usage)
@@ -603,13 +631,19 @@
/* deprecated. Always returns 0. Don't call. */
static inline int native_window_connect(
- struct ANativeWindow* window, int api) {
+ struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
+
+static inline int native_window_connect(
+ struct ANativeWindow* window __UNUSED, int api __UNUSED) {
return 0;
}
/* deprecated. Always returns 0. Don't call. */
static inline int native_window_disconnect(
- struct ANativeWindow* window, int api) {
+ struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
+
+static inline int native_window_disconnect(
+ struct ANativeWindow* window __UNUSED, int api __UNUSED) {
return 0;
}
@@ -664,6 +698,10 @@
*/
static inline int native_window_set_active_rect(
struct ANativeWindow* window,
+ android_native_rect_t const * active_rect) __deprecated;
+
+static inline int native_window_set_active_rect(
+ struct ANativeWindow* window,
android_native_rect_t const * active_rect)
{
return native_window_set_post_transform_crop(window, active_rect);
@@ -691,6 +729,10 @@
*/
static inline int native_window_set_buffers_geometry(
struct ANativeWindow* window,
+ int w, int h, int format) __deprecated;
+
+static inline int native_window_set_buffers_geometry(
+ struct ANativeWindow* window,
int w, int h, int format)
{
return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
@@ -770,6 +812,23 @@
}
/*
+ * native_window_set_buffers_sticky_transform(..., int transform)
+ * All buffers queued after this call will be displayed transformed according
+ * to the transform parameter specified applied on top of the regular buffer
+ * transform. Setting this transform will disable the transform hint.
+ *
+ * Temporary - This is only intended to be used by the LEGACY camera mode, do
+ * not use this for anything else.
+ */
+static inline int native_window_set_buffers_sticky_transform(
+ struct ANativeWindow* window,
+ int transform)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM,
+ transform);
+}
+
+/*
* native_window_set_buffers_timestamp(..., int64_t timestamp)
* All buffers queued after this call will be associated with the timestamp
* parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO
@@ -835,6 +894,17 @@
return anw->dequeueBuffer_DEPRECATED(anw, anb);
}
+/*
+ * native_window_set_sideband_stream(..., native_handle_t*)
+ * Attach a sideband buffer stream to a native window.
+ */
+static inline int native_window_set_sideband_stream(
+ struct ANativeWindow* window,
+ native_handle_t* sidebandHandle)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_SIDEBAND_STREAM,
+ sidebandHandle);
+}
__END_DECLS
diff --git a/include/sysutils/NetlinkEvent.h b/include/sysutils/NetlinkEvent.h
index c0a9418..c345cdb 100644
--- a/include/sysutils/NetlinkEvent.h
+++ b/include/sysutils/NetlinkEvent.h
@@ -37,6 +37,8 @@
const static int NlActionAddressUpdated;
const static int NlActionAddressRemoved;
const static int NlActionRdnss;
+ const static int NlActionRouteUpdated;
+ const static int NlActionRouteRemoved;
NetlinkEvent();
virtual ~NetlinkEvent();
@@ -52,8 +54,11 @@
protected:
bool parseBinaryNetlinkMessage(char *buffer, int size);
bool parseAsciiNetlinkMessage(char *buffer, int size);
- bool parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr, int rtasize);
- bool parseNdUserOptMessage(struct nduseroptmsg *msg, int optsize);
+ bool parseIfInfoMessage(const struct nlmsghdr *nh);
+ bool parseIfAddrMessage(const struct nlmsghdr *nh);
+ bool parseUlogPacketMessage(const struct nlmsghdr *nh);
+ bool parseRtMessage(const struct nlmsghdr *nh);
+ bool parseNdUserOptMessage(const struct nlmsghdr *nh);
};
#endif
diff --git a/include/usbhost/usbhost.h b/include/usbhost/usbhost.h
index 1d67c12..d26e931 100644
--- a/include/usbhost/usbhost.h
+++ b/include/usbhost/usbhost.h
@@ -189,6 +189,13 @@
int usb_device_connect_kernel_driver(struct usb_device *device,
unsigned int interface, int connect);
+/* Sets the current configuration for the device to the specified configuration */
+int usb_device_set_configuration(struct usb_device *device, int configuration);
+
+/* Sets the specified interface of a USB device */
+int usb_device_set_interface(struct usb_device *device, unsigned int interface,
+ unsigned int alt_setting);
+
/* Sends a control message to the specified device on endpoint zero */
int usb_device_control_transfer(struct usb_device *device,
int requestType,
diff --git a/include/utils/AndroidThreads.h b/include/utils/AndroidThreads.h
index 4eee14d..3c640b6 100644
--- a/include/utils/AndroidThreads.h
+++ b/include/utils/AndroidThreads.h
@@ -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/BitSet.h b/include/utils/BitSet.h
index 19c03d1..8c61293 100644
--- a/include/utils/BitSet.h
+++ b/include/utils/BitSet.h
@@ -30,73 +30,103 @@
struct BitSet32 {
uint32_t value;
- inline BitSet32() : value(0) { }
+ inline BitSet32() : value(0UL) { }
explicit inline BitSet32(uint32_t value) : value(value) { }
// Gets the value associated with a particular bit index.
- static inline uint32_t valueForBit(uint32_t n) { return 0x80000000 >> n; }
+ static inline uint32_t valueForBit(uint32_t n) { return 0x80000000UL >> n; }
// Clears the bit set.
- inline void clear() { value = 0; }
+ inline void clear() { clear(value); }
+
+ static inline void clear(uint32_t& value) { value = 0UL; }
// Returns the number of marked bits in the set.
- inline uint32_t count() const { return __builtin_popcount(value); }
+ inline uint32_t count() const { return count(value); }
+
+ static inline uint32_t count(uint32_t value) { return __builtin_popcountl(value); }
// Returns true if the bit set does not contain any marked bits.
- inline bool isEmpty() const { return ! value; }
+ inline bool isEmpty() const { return isEmpty(value); }
+
+ static inline bool isEmpty(uint32_t value) { return ! value; }
// Returns true if the bit set does not contain any unmarked bits.
- inline bool isFull() const { return value == 0xffffffff; }
+ inline bool isFull() const { return isFull(value); }
+
+ static inline bool isFull(uint32_t value) { return value == 0xffffffffUL; }
// Returns true if the specified bit is marked.
- inline bool hasBit(uint32_t n) const { return value & valueForBit(n); }
+ inline bool hasBit(uint32_t n) const { return hasBit(value, n); }
+
+ static inline bool hasBit(uint32_t value, uint32_t n) { return value & valueForBit(n); }
// Marks the specified bit.
- inline void markBit(uint32_t n) { value |= valueForBit(n); }
+ inline void markBit(uint32_t n) { markBit(value, n); }
+
+ static inline void markBit (uint32_t& value, uint32_t n) { value |= valueForBit(n); }
// Clears the specified bit.
- inline void clearBit(uint32_t n) { value &= ~ valueForBit(n); }
+ inline void clearBit(uint32_t n) { clearBit(value, n); }
+
+ static inline void clearBit(uint32_t& value, uint32_t n) { value &= ~ valueForBit(n); }
// Finds the first marked bit in the set.
// Result is undefined if all bits are unmarked.
- inline uint32_t firstMarkedBit() const { return __builtin_clz(value); }
+ inline uint32_t firstMarkedBit() const { return firstMarkedBit(value); }
+
+ static uint32_t firstMarkedBit(uint32_t value) { return clz_checked(value); }
// Finds the first unmarked bit in the set.
// Result is undefined if all bits are marked.
- inline uint32_t firstUnmarkedBit() const { return __builtin_clz(~ value); }
+ inline uint32_t firstUnmarkedBit() const { return firstUnmarkedBit(value); }
+
+ static inline uint32_t firstUnmarkedBit(uint32_t value) { return clz_checked(~ value); }
// Finds the last marked bit in the set.
// Result is undefined if all bits are unmarked.
- inline uint32_t lastMarkedBit() const { return 31 - __builtin_ctz(value); }
+ inline uint32_t lastMarkedBit() const { return lastMarkedBit(value); }
+
+ static inline uint32_t lastMarkedBit(uint32_t value) { return 31 - ctz_checked(value); }
// Finds the first marked bit in the set and clears it. Returns the bit index.
// Result is undefined if all bits are unmarked.
- inline uint32_t clearFirstMarkedBit() {
- uint32_t n = firstMarkedBit();
- clearBit(n);
+ inline uint32_t clearFirstMarkedBit() { return clearFirstMarkedBit(value); }
+
+ static inline uint32_t clearFirstMarkedBit(uint32_t& value) {
+ uint32_t n = firstMarkedBit(value);
+ clearBit(value, n);
return n;
}
// Finds the first unmarked bit in the set and marks it. Returns the bit index.
// Result is undefined if all bits are marked.
- inline uint32_t markFirstUnmarkedBit() {
- uint32_t n = firstUnmarkedBit();
- markBit(n);
+ inline uint32_t markFirstUnmarkedBit() { return markFirstUnmarkedBit(value); }
+
+ static inline uint32_t markFirstUnmarkedBit(uint32_t& value) {
+ uint32_t n = firstUnmarkedBit(value);
+ markBit(value, n);
return n;
}
// Finds the last marked bit in the set and clears it. Returns the bit index.
// Result is undefined if all bits are unmarked.
- inline uint32_t clearLastMarkedBit() {
- uint32_t n = lastMarkedBit();
- clearBit(n);
+ inline uint32_t clearLastMarkedBit() { return clearLastMarkedBit(value); }
+
+ static inline uint32_t clearLastMarkedBit(uint32_t& value) {
+ uint32_t n = lastMarkedBit(value);
+ clearBit(value, n);
return n;
}
// Gets the index of the specified bit in the set, which is the number of
// marked bits that appear before the specified bit.
inline uint32_t getIndexOfBit(uint32_t n) const {
- return __builtin_popcount(value & ~(0xffffffffUL >> n));
+ return getIndexOfBit(value, n);
+ }
+
+ static inline uint32_t getIndexOfBit(uint32_t value, uint32_t n) {
+ return __builtin_popcountl(value & ~(0xffffffffUL >> n));
}
inline bool operator== (const BitSet32& other) const { return value == other.value; }
@@ -115,10 +145,150 @@
value |= other.value;
return *this;
}
+
+private:
+ // We use these helpers as the signature of __builtin_c{l,t}z has "unsigned int" for the
+ // input, which is only guaranteed to be 16b, not 32. The compiler should optimize this away.
+ static inline uint32_t clz_checked(uint32_t value) {
+ if (sizeof(unsigned int) == sizeof(uint32_t)) {
+ return __builtin_clz(value);
+ } else {
+ return __builtin_clzl(value);
+ }
+ }
+
+ static inline uint32_t ctz_checked(uint32_t value) {
+ if (sizeof(unsigned int) == sizeof(uint32_t)) {
+ return __builtin_ctz(value);
+ } else {
+ return __builtin_ctzl(value);
+ }
+ }
};
ANDROID_BASIC_TYPES_TRAITS(BitSet32)
+// A simple set of 64 bits that can be individually marked or cleared.
+struct BitSet64 {
+ uint64_t value;
+
+ inline BitSet64() : value(0ULL) { }
+ explicit inline BitSet64(uint64_t value) : value(value) { }
+
+ // Gets the value associated with a particular bit index.
+ static inline uint64_t valueForBit(uint32_t n) { return 0x8000000000000000ULL >> n; }
+
+ // Clears the bit set.
+ inline void clear() { clear(value); }
+
+ static inline void clear(uint64_t& value) { value = 0ULL; }
+
+ // Returns the number of marked bits in the set.
+ inline uint32_t count() const { return count(value); }
+
+ static inline uint32_t count(uint64_t value) { return __builtin_popcountll(value); }
+
+ // Returns true if the bit set does not contain any marked bits.
+ inline bool isEmpty() const { return isEmpty(value); }
+
+ static inline bool isEmpty(uint64_t value) { return ! value; }
+
+ // Returns true if the bit set does not contain any unmarked bits.
+ inline bool isFull() const { return isFull(value); }
+
+ static inline bool isFull(uint64_t value) { return value == 0xffffffffffffffffULL; }
+
+ // Returns true if the specified bit is marked.
+ inline bool hasBit(uint32_t n) const { return hasBit(value, n); }
+
+ static inline bool hasBit(uint64_t value, uint32_t n) { return value & valueForBit(n); }
+
+ // Marks the specified bit.
+ inline void markBit(uint32_t n) { markBit(value, n); }
+
+ static inline void markBit(uint64_t& value, uint32_t n) { value |= valueForBit(n); }
+
+ // Clears the specified bit.
+ inline void clearBit(uint32_t n) { clearBit(value, n); }
+
+ static inline void clearBit(uint64_t& value, uint32_t n) { value &= ~ valueForBit(n); }
+
+ // Finds the first marked bit in the set.
+ // Result is undefined if all bits are unmarked.
+ inline uint32_t firstMarkedBit() const { return firstMarkedBit(value); }
+
+ static inline uint32_t firstMarkedBit(uint64_t value) { return __builtin_clzll(value); }
+
+ // Finds the first unmarked bit in the set.
+ // Result is undefined if all bits are marked.
+ inline uint32_t firstUnmarkedBit() const { return firstUnmarkedBit(value); }
+
+ static inline uint32_t firstUnmarkedBit(uint64_t value) { return __builtin_clzll(~ value); }
+
+ // Finds the last marked bit in the set.
+ // Result is undefined if all bits are unmarked.
+ inline uint32_t lastMarkedBit() const { return lastMarkedBit(value); }
+
+ static inline uint32_t lastMarkedBit(uint64_t value) { return 63 - __builtin_ctzll(value); }
+
+ // Finds the first marked bit in the set and clears it. Returns the bit index.
+ // Result is undefined if all bits are unmarked.
+ inline uint32_t clearFirstMarkedBit() { return clearFirstMarkedBit(value); }
+
+ static inline uint32_t clearFirstMarkedBit(uint64_t& value) {
+ uint64_t n = firstMarkedBit(value);
+ clearBit(value, n);
+ return n;
+ }
+
+ // Finds the first unmarked bit in the set and marks it. Returns the bit index.
+ // Result is undefined if all bits are marked.
+ inline uint32_t markFirstUnmarkedBit() { return markFirstUnmarkedBit(value); }
+
+ static inline uint32_t markFirstUnmarkedBit(uint64_t& value) {
+ uint64_t n = firstUnmarkedBit(value);
+ markBit(value, n);
+ return n;
+ }
+
+ // Finds the last marked bit in the set and clears it. Returns the bit index.
+ // Result is undefined if all bits are unmarked.
+ inline uint32_t clearLastMarkedBit() { return clearLastMarkedBit(value); }
+
+ static inline uint32_t clearLastMarkedBit(uint64_t& value) {
+ uint64_t n = lastMarkedBit(value);
+ clearBit(value, n);
+ return n;
+ }
+
+ // Gets the index of the specified bit in the set, which is the number of
+ // marked bits that appear before the specified bit.
+ inline uint32_t getIndexOfBit(uint32_t n) const { return getIndexOfBit(value, n); }
+
+ static inline uint32_t getIndexOfBit(uint64_t value, uint32_t n) {
+ return __builtin_popcountll(value & ~(0xffffffffffffffffULL >> n));
+ }
+
+ inline bool operator== (const BitSet64& other) const { return value == other.value; }
+ inline bool operator!= (const BitSet64& other) const { return value != other.value; }
+ inline BitSet64 operator& (const BitSet64& other) const {
+ return BitSet64(value & other.value);
+ }
+ inline BitSet64& operator&= (const BitSet64& other) {
+ value &= other.value;
+ return *this;
+ }
+ inline BitSet64 operator| (const BitSet64& other) const {
+ return BitSet64(value | other.value);
+ }
+ inline BitSet64& operator|= (const BitSet64& other) {
+ value |= other.value;
+ return *this;
+ }
+};
+
+ANDROID_BASIC_TYPES_TRAITS(BitSet64)
+
} // namespace android
#endif // UTILS_BITSET_H
diff --git a/include/utils/Compat.h b/include/utils/Compat.h
index fb7748e..0df40a1 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,13 +29,11 @@
return lseek(fd, offset, whence);
}
-#ifdef HAVE_PREAD
static inline ssize_t pread64(int fd, void* buf, size_t nbytes, off64_t offset) {
return pread(fd, buf, nbytes, offset);
}
-#endif
-#endif /* !HAVE_OFF64_T */
+#endif /* __APPLE__ */
#if HAVE_PRINTF_ZD
# define ZD "%zd"
@@ -48,6 +44,17 @@
#endif
/*
+ * 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 CONSTEXPR
+#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.
diff --git a/include/utils/Condition.h b/include/utils/Condition.h
index e63ba7e..1c99d1a 100644
--- a/include/utils/Condition.h
+++ b/include/utils/Condition.h
@@ -60,7 +60,7 @@
status_t wait(Mutex& mutex);
// same with relative timeout
status_t waitRelative(Mutex& mutex, nsecs_t reltime);
- // Signal the condition variable, allowing one thread to continue.
+ // Signal the condition variable, allowing exactly one thread to continue.
void signal();
// Signal the condition variable, allowing one or all threads to continue.
void signal(WakeUpType type) {
@@ -132,6 +132,17 @@
#endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
}
inline void Condition::signal() {
+ /*
+ * POSIX says pthread_cond_signal wakes up "one or more" waiting threads.
+ * However bionic follows the glibc guarantee which wakes up "exactly one"
+ * waiting thread.
+ *
+ * man 3 pthread_cond_signal
+ * pthread_cond_signal restarts one of the threads that are waiting on
+ * the condition variable cond. If no threads are waiting on cond,
+ * nothing happens. If several threads are waiting on cond, exactly one
+ * is restarted, but it is not specified which.
+ */
pthread_cond_signal(&mCond);
}
inline void Condition::broadcast() {
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..6c0aa52 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
@@ -123,7 +127,7 @@
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/Functor.h b/include/utils/Functor.h
index e24ded4..09ea614 100644
--- a/include/utils/Functor.h
+++ b/include/utils/Functor.h
@@ -25,7 +25,7 @@
public:
Functor() {}
virtual ~Functor() {}
- virtual status_t operator ()(int what, void* data) { return NO_ERROR; }
+ virtual status_t operator ()(int /*what*/, void* /*data*/) { return NO_ERROR; }
};
}; // namespace android
diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h
index 053bfaf..cd9d7f9 100644
--- a/include/utils/LruCache.h
+++ b/include/utils/LruCache.h
@@ -17,8 +17,8 @@
#ifndef ANDROID_UTILS_LRU_CACHE_H
#define ANDROID_UTILS_LRU_CACHE_H
+#include <UniquePtr.h>
#include <utils/BasicHashtable.h>
-#include <utils/UniquePtr.h>
namespace android {
@@ -48,6 +48,7 @@
bool remove(const TKey& key);
bool removeOldest();
void clear();
+ const TValue& peekOldestValue();
class Iterator {
public:
@@ -56,7 +57,7 @@
bool next() {
mIndex = mCache.mTable->next(mIndex);
- return mIndex != -1;
+ return (ssize_t)mIndex != -1;
}
size_t index() const {
@@ -103,9 +104,13 @@
// Implementation is here, because it's fully templated
template <typename TKey, typename TValue>
-LruCache<TKey, TValue>::LruCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity),
- mNullValue(NULL), mTable(new BasicHashtable<TKey, Entry>), mYoungest(NULL), mOldest(NULL),
- mListener(NULL) {
+LruCache<TKey, TValue>::LruCache(uint32_t maxCapacity)
+ : mTable(new BasicHashtable<TKey, Entry>)
+ , mListener(NULL)
+ , mOldest(NULL)
+ , mYoungest(NULL)
+ , mMaxCapacity(maxCapacity)
+ , mNullValue(NULL) {
};
template<typename K, typename V>
@@ -180,6 +185,14 @@
}
template <typename TKey, typename TValue>
+const TValue& LruCache<TKey, TValue>::peekOldestValue() {
+ if (mOldest) {
+ return mOldest->value;
+ }
+ return mNullValue;
+}
+
+template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::clear() {
if (mListener) {
for (Entry* p = mOldest; p != NULL; p = p->child) {
diff --git a/include/utils/NativeHandle.h b/include/utils/NativeHandle.h
new file mode 100644
index 0000000..b825168
--- /dev/null
+++ b/include/utils/NativeHandle.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_NATIVE_HANDLE_H
+#define ANDROID_NATIVE_HANDLE_H
+
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+
+typedef struct native_handle native_handle_t;
+
+namespace android {
+
+class NativeHandle: public LightRefBase<NativeHandle> {
+public:
+ // Create a refcounted wrapper around a native_handle_t, and declare
+ // whether the wrapper owns the handle (so that it should clean up the
+ // handle upon destruction) or not.
+ // If handle is NULL, no NativeHandle will be created.
+ static sp<NativeHandle> create(native_handle_t* handle, bool ownsHandle);
+
+ const native_handle_t* handle() const {
+ return mHandle;
+ }
+
+private:
+ // for access to the destructor
+ friend class LightRefBase<NativeHandle>;
+
+ NativeHandle(native_handle_t* handle, bool ownsHandle);
+ virtual ~NativeHandle();
+
+ native_handle_t* mHandle;
+ bool mOwnsHandle;
+
+ // non-copyable
+ NativeHandle(const NativeHandle&);
+ NativeHandle& operator=(const NativeHandle&);
+};
+
+} // namespace android
+
+#endif // ANDROID_NATIVE_HANDLE_H
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index cbfe13a..eac6a78 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -203,6 +203,13 @@
mutable volatile int32_t mCount;
};
+// This is a wrapper around LightRefBase that simply enforces a virtual
+// destructor to eliminate the template requirement of LightRefBase
+class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> {
+public:
+ virtual ~VirtualLightRefBase() {}
+};
+
// ---------------------------------------------------------------------------
template <typename T>
@@ -484,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>));
@@ -503,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/String8.h b/include/utils/String8.h
index ef59470..ecfcf10 100644
--- a/include/utils/String8.h
+++ b/include/utils/String8.h
@@ -130,11 +130,19 @@
// start, or -1 if not found
ssize_t find(const char* other, size_t start = 0) const;
+ // return true if this string contains the specified substring
+ inline bool contains(const char* other) const;
+
+ // removes all occurrence of the specified substring
+ // returns true if any were found and removed
+ bool removeAll(const char* other);
+
void toLower();
void toLower(size_t start, size_t numChars);
void toUpper();
void toUpper(size_t start, size_t numChars);
+
/*
* These methods operate on the string as if it were a path name.
*/
@@ -280,6 +288,11 @@
return SharedBuffer::bufferFromData(mString);
}
+inline bool String8::contains(const char* other) const
+{
+ return find(other) >= 0;
+}
+
inline String8& String8::operator=(const String8& other)
{
setTo(other);
diff --git a/include/utils/Thread.h b/include/utils/Thread.h
index df30611..c867e95 100644
--- a/include/utils/Thread.h
+++ b/include/utils/Thread.h
@@ -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/Unicode.h b/include/utils/Unicode.h
index 5b98de2..aaf951b 100644
--- a/include/utils/Unicode.h
+++ b/include/utils/Unicode.h
@@ -24,8 +24,8 @@
// Definitions exist in C++11
#if defined __cplusplus && __cplusplus < 201103L
-typedef uint32_t char32_t;
-typedef uint16_t char16_t;
+typedef unsigned int char32_t;
+typedef unsigned short char16_t;
#endif
// Standard string functions on char16_t strings.
diff --git a/include/utils/UniquePtr.h b/include/utils/UniquePtr.h
deleted file mode 100644
index bc62fe6..0000000
--- a/include/utils/UniquePtr.h
+++ /dev/null
@@ -1,239 +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.
- */
-
-/* === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE ===
- *
- * THIS IS A COPY OF libcore/include/UniquePtr.h AND AS SUCH THAT IS THE
- * CANONICAL SOURCE OF THIS FILE. PLEASE KEEP THEM IN SYNC.
- *
- * === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE ===
- */
-
-#ifndef UNIQUE_PTR_H_included
-#define UNIQUE_PTR_H_included
-
-#include <cstdlib> // For NULL.
-
-// Default deleter for pointer types.
-template <typename T>
-struct DefaultDelete {
- enum { type_must_be_complete = sizeof(T) };
- DefaultDelete() {}
- void operator()(T* p) const {
- delete p;
- }
-};
-
-// Default deleter for array types.
-template <typename T>
-struct DefaultDelete<T[]> {
- enum { type_must_be_complete = sizeof(T) };
- void operator()(T* p) const {
- delete[] p;
- }
-};
-
-// A smart pointer that deletes the given pointer on destruction.
-// Equivalent to C++0x's std::unique_ptr (a combination of boost::scoped_ptr
-// and boost::scoped_array).
-// Named to be in keeping with Android style but also to avoid
-// collision with any other implementation, until we can switch over
-// to unique_ptr.
-// Use thus:
-// UniquePtr<C> c(new C);
-template <typename T, typename D = DefaultDelete<T> >
-class UniquePtr {
-public:
- // Construct a new UniquePtr, taking ownership of the given raw pointer.
- explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) {
- }
-
- ~UniquePtr() {
- reset();
- }
-
- // Accessors.
- T& operator*() const { return *mPtr; }
- T* operator->() const { return mPtr; }
- T* get() const { return mPtr; }
-
- // Returns the raw pointer and hands over ownership to the caller.
- // The pointer will not be deleted by UniquePtr.
- T* release() __attribute__((warn_unused_result)) {
- T* result = mPtr;
- mPtr = NULL;
- return result;
- }
-
- // Takes ownership of the given raw pointer.
- // If this smart pointer previously owned a different raw pointer, that
- // raw pointer will be freed.
- void reset(T* ptr = NULL) {
- if (ptr != mPtr) {
- D()(mPtr);
- mPtr = ptr;
- }
- }
-
-private:
- // The raw pointer.
- T* mPtr;
-
- // Comparing unique pointers is probably a mistake, since they're unique.
- template <typename T2> bool operator==(const UniquePtr<T2>& p) const;
- template <typename T2> bool operator!=(const UniquePtr<T2>& p) const;
-
- // Disallow copy and assignment.
- UniquePtr(const UniquePtr&);
- void operator=(const UniquePtr&);
-};
-
-// Partial specialization for array types. Like std::unique_ptr, this removes
-// operator* and operator-> but adds operator[].
-template <typename T, typename D>
-class UniquePtr<T[], D> {
-public:
- explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) {
- }
-
- ~UniquePtr() {
- reset();
- }
-
- T& operator[](size_t i) const {
- return mPtr[i];
- }
- T* get() const { return mPtr; }
-
- T* release() __attribute__((warn_unused_result)) {
- T* result = mPtr;
- mPtr = NULL;
- return result;
- }
-
- void reset(T* ptr = NULL) {
- if (ptr != mPtr) {
- D()(mPtr);
- mPtr = ptr;
- }
- }
-
-private:
- T* mPtr;
-
- // Disallow copy and assignment.
- UniquePtr(const UniquePtr&);
- void operator=(const UniquePtr&);
-};
-
-#if UNIQUE_PTR_TESTS
-
-// Run these tests with:
-// g++ -g -DUNIQUE_PTR_TESTS -x c++ UniquePtr.h && ./a.out
-
-#include <stdio.h>
-
-static void assert(bool b) {
- if (!b) {
- fprintf(stderr, "FAIL\n");
- abort();
- }
- fprintf(stderr, "OK\n");
-}
-static int cCount = 0;
-struct C {
- C() { ++cCount; }
- ~C() { --cCount; }
-};
-static bool freed = false;
-struct Freer {
- void operator()(int* p) {
- assert(*p == 123);
- free(p);
- freed = true;
- }
-};
-
-int main(int argc, char* argv[]) {
- //
- // UniquePtr<T> tests...
- //
-
- // Can we free a single object?
- {
- UniquePtr<C> c(new C);
- assert(cCount == 1);
- }
- assert(cCount == 0);
- // Does release work?
- C* rawC;
- {
- UniquePtr<C> c(new C);
- assert(cCount == 1);
- rawC = c.release();
- }
- assert(cCount == 1);
- delete rawC;
- // Does reset work?
- {
- UniquePtr<C> c(new C);
- assert(cCount == 1);
- c.reset(new C);
- assert(cCount == 1);
- }
- assert(cCount == 0);
-
- //
- // UniquePtr<T[]> tests...
- //
-
- // Can we free an array?
- {
- UniquePtr<C[]> cs(new C[4]);
- assert(cCount == 4);
- }
- assert(cCount == 0);
- // Does release work?
- {
- UniquePtr<C[]> c(new C[4]);
- assert(cCount == 4);
- rawC = c.release();
- }
- assert(cCount == 4);
- delete[] rawC;
- // Does reset work?
- {
- UniquePtr<C[]> c(new C[4]);
- assert(cCount == 4);
- c.reset(new C[2]);
- assert(cCount == 2);
- }
- assert(cCount == 0);
-
- //
- // Custom deleter tests...
- //
- assert(!freed);
- {
- UniquePtr<int, Freer> i(reinterpret_cast<int*>(malloc(sizeof(int))));
- *i = 123;
- }
- assert(freed);
- return 0;
-}
-#endif
-
-#endif // UNIQUE_PTR_H_included
diff --git a/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h
index 1877494..7da6e84 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)) {}
};
/*
@@ -124,24 +133,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 +161,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/init/Android.mk b/init/Android.mk
index 15a23be..8cda879 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -25,7 +25,7 @@
endif
ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1
+LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_DISABLE_SELINUX=1
endif
# Enable ueventd logging
@@ -33,6 +33,10 @@
LOCAL_MODULE:= init
+# Currently, init doesn't start when built with clang.
+# Needs further investigation.
+LOCAL_CLANG := false
+
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
@@ -47,25 +51,9 @@
libmincrypt \
libext4_utils_static
-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
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)
diff --git a/init/bootchart.c b/init/bootchart.c
index f72fcaa..a514261 100644
--- a/init/bootchart.c
+++ b/init/bootchart.c
@@ -119,6 +119,18 @@
}
}
+static long long
+get_uptime_jiffies()
+{
+ char buff[64];
+ long long jiffies = 0;
+
+ if (proc_read("/proc/uptime", buff, sizeof(buff)) > 0)
+ jiffies = 100LL*strtod(buff,NULL);
+
+ return jiffies;
+}
+
static void
log_header(void)
{
@@ -185,22 +197,11 @@
do_log_uptime(FileBuff log)
{
char buff[65];
- int fd, ret, len;
+ int 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);
- }
- }
+ snprintf(buff,sizeof(buff),"%lld\n",get_uptime_jiffies());
+ len = strlen(buff);
+ file_buff_write(log, buff, len);
}
static void
@@ -376,3 +377,9 @@
file_buff_done(log_procs);
acct(NULL);
}
+
+/* called to get time (in ms) used by bootchart */
+long long bootchart_gettime( void )
+{
+ return 10LL*get_uptime_jiffies();
+}
diff --git a/init/bootchart.h b/init/bootchart.h
index 39d2d4f..ed65e8a 100644
--- a/init/bootchart.h
+++ b/init/bootchart.h
@@ -26,6 +26,7 @@
extern int bootchart_init(void);
extern int bootchart_step(void);
extern void bootchart_finish(void);
+extern long long bootchart_gettime(void);
# define BOOTCHART_POLLING_MS 200 /* polling period in ms */
# define BOOTCHART_DEFAULT_TIME_SEC (2*60) /* default polling time in seconds */
diff --git a/init/builtins.c b/init/builtins.c
index d9f7bbe..5d2a517 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -48,7 +48,7 @@
#include <private/android_filesystem_config.h>
-void add_environment(const char *name, const char *value);
+int add_environment(const char *name, const char *value);
extern int init_module(void *, unsigned long, const char *);
@@ -261,8 +261,7 @@
int do_export(int nargs, char **args)
{
- add_environment(args[1], args[2]);
- return 0;
+ return add_environment(args[1], args[2]);
}
int do_hostname(int nargs, char **args)
@@ -434,6 +433,7 @@
sprintf(tmp, "/dev/block/loop%d", n);
loop = open(tmp, mode);
if (loop < 0) {
+ close(fd);
return -1;
}
@@ -474,13 +474,33 @@
}
+static int wipe_data_via_recovery()
+{
+ mkdir("/cache/recovery", 0700);
+ int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC, 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);
+ close(fd);
+ } else {
+ ERROR("could not open /cache/recovery/command\n");
+ return -1;
+ }
+ android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+ while (1) { pause(); } // never reached
+}
+
+
+/*
+ * This function might request a reboot, in which case it will
+ * not return.
+ */
int do_mount_all(int nargs, char **args)
{
pid_t pid;
int ret = -1;
int child_ret = -1;
int status;
- const char *prop;
struct fstab *fstab;
if (nargs != 2) {
@@ -496,7 +516,12 @@
pid = fork();
if (pid > 0) {
/* Parent. Wait for the child to return */
- waitpid(pid, &status, 0);
+ 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);
+ }
+
if (WIFEXITED(status)) {
ret = WEXITSTATUS(status);
} else {
@@ -511,23 +536,32 @@
if (child_ret == -1) {
ERROR("fs_mgr_mount_all returned an error\n");
}
- exit(child_ret);
+ _exit(child_ret);
} else {
/* fork failed, return an error */
return -1;
}
- /* ret is 1 if the device is encrypted, 0 if not, and -1 on error */
- if (ret == 1) {
+ if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
+ property_set("vold.decrypt", "trigger_encryption");
+ } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
property_set("ro.crypto.state", "encrypted");
- property_set("vold.decrypt", "1");
- } else if (ret == 0) {
+ property_set("vold.decrypt", "trigger_default_encryption");
+ } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
property_set("ro.crypto.state", "unencrypted");
/* If fs_mgr determined this is an unencrypted device, then trigger
* that action.
*/
action_for_each_trigger("nonencrypted", action_add_queue_tail);
+ } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
+ /* Setup a wipe via recovery, and reboot into recovery */
+ 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 > 0) {
+ ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
}
+ /* else ... < 0: error */
return ret;
}
@@ -862,11 +896,24 @@
}
int do_loglevel(int nargs, char **args) {
- if (nargs == 2) {
- klog_set_level(atoi(args[1]));
- return 0;
+ int log_level;
+ char log_level_str[PROP_VALUE_MAX] = "";
+ if (nargs != 2) {
+ ERROR("loglevel: missing argument\n");
+ return -EINVAL;
}
- return -1;
+
+ if (expand_props(log_level_str, args[1], sizeof(log_level_str))) {
+ ERROR("loglevel: cannot expand '%s'\n", args[1]);
+ return -EINVAL;
+ }
+ log_level = atoi(log_level_str);
+ if (log_level < KLOG_ERROR_LEVEL || log_level > KLOG_DEBUG_LEVEL) {
+ ERROR("loglevel: invalid log level'%d'\n", log_level);
+ return -EINVAL;
+ }
+ klog_set_level(log_level);
+ return 0;
}
int do_load_persist_props(int nargs, char **args) {
@@ -877,6 +924,14 @@
return -1;
}
+int do_load_all_props(int nargs, char **args) {
+ if (nargs == 1) {
+ load_all_props();
+ return 0;
+ }
+ return -1;
+}
+
int do_wait(int nargs, char **args)
{
if (nargs == 2) {
diff --git a/init/devices.c b/init/devices.c
index 5d7ad3b..dde43df 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -15,6 +15,7 @@
*/
#include <errno.h>
+#include <fnmatch.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -77,6 +78,7 @@
unsigned int uid;
unsigned int gid;
unsigned short prefix;
+ unsigned short wildcard;
};
struct perm_node {
@@ -97,7 +99,8 @@
int add_dev_perms(const char *name, const char *attr,
mode_t perm, unsigned int uid, unsigned int gid,
- unsigned short prefix) {
+ unsigned short prefix,
+ unsigned short wildcard) {
struct perm_node *node = calloc(1, sizeof(*node));
if (!node)
return -ENOMEM;
@@ -116,6 +119,7 @@
node->dp.uid = uid;
node->dp.gid = gid;
node->dp.prefix = prefix;
+ node->dp.wildcard = wildcard;
if (attr)
list_add_tail(&sys_perms, &node->plist);
@@ -130,42 +134,63 @@
char buf[512];
struct listnode *node;
struct perms_ *dp;
- char *secontext;
- /* upaths omit the "/sys" that paths in this list
- * contain, so we add 4 when comparing...
- */
+ /* upaths omit the "/sys" that paths in this list
+ * contain, so we add 4 when comparing...
+ */
list_for_each(node, &sys_perms) {
dp = &(node_to_item(node, struct perm_node, plist))->dp;
if (dp->prefix) {
if (strncmp(upath, dp->name + 4, strlen(dp->name + 4)))
continue;
+ } else if (dp->wildcard) {
+ if (fnmatch(dp->name + 4, upath, FNM_PATHNAME) != 0)
+ continue;
} else {
if (strcmp(upath, dp->name + 4))
continue;
}
if ((strlen(upath) + strlen(dp->attr) + 6) > sizeof(buf))
- return;
+ break;
sprintf(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);
- if (sehandle) {
- secontext = NULL;
- selabel_lookup(sehandle, &secontext, buf, 0);
- if (secontext) {
- setfilecon(buf, secontext);
- freecon(secontext);
- }
- }
+ }
+
+ // Now fixup SELinux file labels
+ int len = snprintf(buf, sizeof(buf), "/sys%s", upath);
+ if ((len < 0) || ((size_t) len >= sizeof(buf))) {
+ // Overflow
+ return;
+ }
+ if (access(buf, F_OK) == 0) {
+ INFO("restorecon_recursive: %s\n", buf);
+ restorecon_recursive(buf);
}
}
-static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid)
+static bool perm_path_matches(const char *path, struct perms_ *dp)
{
- mode_t perm;
+ if (dp->prefix) {
+ if (strncmp(path, dp->name, strlen(dp->name)) == 0)
+ return true;
+ } else if (dp->wildcard) {
+ if (fnmatch(dp->name, path, FNM_PATHNAME) == 0)
+ return true;
+ } else {
+ if (strcmp(path, dp->name) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+static mode_t get_device_perm(const char *path, const char **links,
+ unsigned *uid, unsigned *gid)
+{
struct listnode *node;
struct perm_node *perm_node;
struct perms_ *dp;
@@ -174,19 +199,30 @@
* override ueventd.rc
*/
list_for_each_reverse(node, &dev_perms) {
+ bool match = false;
+
perm_node = node_to_item(node, struct perm_node, plist);
dp = &perm_node->dp;
- if (dp->prefix) {
- if (strncmp(path, dp->name, strlen(dp->name)))
- continue;
+ if (perm_path_matches(path, dp)) {
+ match = true;
} else {
- if (strcmp(path, dp->name))
- continue;
+ if (links) {
+ int i;
+ for (i = 0; links[i]; i++) {
+ if (perm_path_matches(links[i], dp)) {
+ match = true;
+ break;
+ }
+ }
+ }
}
- *uid = dp->uid;
- *gid = dp->gid;
- return dp->perm;
+
+ if (match) {
+ *uid = dp->uid;
+ *gid = dp->gid;
+ return dp->perm;
+ }
}
/* Default if nothing found. */
*uid = 0;
@@ -196,7 +232,8 @@
static void make_device(const char *path,
const char *upath UNUSED,
- int block, int major, int minor)
+ int block, int major, int minor,
+ const char **links)
{
unsigned uid;
unsigned gid;
@@ -204,10 +241,10 @@
dev_t dev;
char *secontext = NULL;
- mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
+ mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
if (sehandle) {
- selabel_lookup(sehandle, &secontext, path, mode);
+ selabel_lookup_best_match(sehandle, &secontext, path, links, mode);
setfscreatecon(secontext);
}
@@ -298,6 +335,37 @@
}
}
+/* Given a path that may start with a PCI device, populate the supplied buffer
+ * with the PCI domain/bus number and the peripheral ID and return 0.
+ * If it doesn't start with a PCI device, or there is some error, return -1 */
+static int find_pci_device_prefix(const char *path, char *buf, ssize_t buf_sz)
+{
+ const char *start, *end;
+
+ if (strncmp(path, "/devices/pci", 12))
+ return -1;
+
+ /* Beginning of the prefix is the initial "pci" after "/devices/" */
+ start = path + 9;
+
+ /* End of the prefix is two path '/' later, capturing the domain/bus number
+ * and the peripheral ID. Example: pci0000:00/0000:00:1f.2 */
+ end = strchr(start, '/');
+ if (!end)
+ return -1;
+ end = strchr(end + 1, '/');
+ if (!end)
+ return -1;
+
+ /* Make sure we have enough room for the string plus null terminator */
+ if (end - start + 1 > buf_sz)
+ return -1;
+
+ strncpy(buf, start, end - start);
+ buf[end - start] = '\0';
+ return 0;
+}
+
#if LOG_UEVENTS
static inline suseconds_t get_usecs(void)
@@ -389,7 +457,7 @@
/* skip "/devices/platform/<driver>" */
parent = strchr(uevent->path + pdev->path_len, '/');
- if (!*parent)
+ if (!parent)
goto err;
if (!strncmp(parent, "/usb", 4)) {
@@ -422,34 +490,36 @@
return NULL;
}
-static char **parse_platform_block_device(struct uevent *uevent)
+static char **get_block_device_symlinks(struct uevent *uevent)
{
const char *device;
struct platform_node *pdev;
char *slash;
- int width;
+ const char *type;
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)
+ if (pdev) {
+ device = pdev->name;
+ type = "platform";
+ } else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) {
+ device = buf;
+ type = "pci";
+ } else {
return NULL;
- device = pdev->name;
+ }
char **links = malloc(sizeof(char *) * 4);
if (!links)
return NULL;
memset(links, 0, sizeof(char *) * 4);
- INFO("found platform device %s\n", device);
+ INFO("found %s device %s\n", type, device);
- snprintf(link_path, sizeof(link_path), "/dev/block/platform/%s", device);
+ snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
if (uevent->partition_name) {
p = strdup(uevent->partition_name);
@@ -485,7 +555,7 @@
int i;
if(!strcmp(action, "add")) {
- make_device(devpath, path, block, major, minor);
+ make_device(devpath, path, block, major, minor, (const char **)links);
if (links) {
for (i = 0; links[i]; i++)
make_link(devpath, links[i]);
@@ -556,7 +626,7 @@
make_dir(base, 0755);
if (!strncmp(uevent->path, "/devices/", 9))
- links = parse_platform_block_device(uevent);
+ links = get_block_device_symlinks(uevent);
handle_device(uevent->action, devpath, uevent->path, 1,
uevent->major, uevent->minor, links);
@@ -850,7 +920,6 @@
static void handle_firmware_event(struct uevent *uevent)
{
pid_t pid;
- int ret;
if(strcmp(uevent->subsystem, "firmware"))
return;
@@ -862,11 +931,13 @@
pid = fork();
if (!pid) {
process_firmware_event(uevent);
- exit(EXIT_SUCCESS);
+ _exit(EXIT_SUCCESS);
+ } else if (pid < 0) {
+ log_event_print("could not fork to process firmware event: %s\n", strerror(errno));
}
}
-#define UEVENT_MSG_LEN 1024
+#define UEVENT_MSG_LEN 2048
void handle_device_fd()
{
char msg[UEVENT_MSG_LEN+2];
@@ -967,15 +1038,18 @@
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
fcntl(device_fd, F_SETFL, O_NONBLOCK);
- if (stat(coldboot_done, &info) < 0) {
+ 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);
+ fd = open(COLDBOOT_DONE, O_WRONLY|O_CREAT, 0000);
close(fd);
log_event_print("coldboot %ld uS\n", ((long) (t1 - t0)));
+ // t0 & t1 are unused if the log isn't doing anything.
+ (void)t0;
+ (void)t1;
} else {
log_event_print("skipping coldboot, already done\n");
}
diff --git a/init/devices.h b/init/devices.h
index a84fa58..5d0fe88 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -23,6 +23,7 @@
extern void device_init(void);
extern int add_dev_perms(const char *name, const char *attr,
mode_t perm, unsigned int uid,
- unsigned int gid, unsigned short prefix);
+ unsigned int gid, unsigned short prefix,
+ unsigned short wildcard);
int get_device_fd();
#endif /* _INIT_DEVICES_H */
diff --git a/init/init.c b/init/init.c
index 1538aa6..2b82937 100644
--- a/init/init.c
+++ b/init/init.c
@@ -65,6 +65,7 @@
#if BOOTCHART
static int bootchart_count;
+static long long bootchart_time = 0;
#endif
static char console[32];
@@ -75,7 +76,6 @@
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)
{
@@ -96,11 +96,24 @@
/* add_environment - add "key=value" to the current environment */
int add_environment(const char *key, const char *val)
{
- int n;
+ size_t n;
+ size_t key_len = strlen(key);
- for (n = 0; n < 31; n++) {
- if (!ENV[n]) {
- size_t len = strlen(key) + strlen(val) + 2;
+ /* The last environment entry is reserved to terminate the list */
+ for (n = 0; n < (ARRAY_SIZE(ENV) - 1); n++) {
+
+ /* Delete any existing entry for this key */
+ if (ENV[n] != NULL) {
+ size_t entry_key_len = strcspn(ENV[n], "=");
+ if ((entry_key_len == key_len) && (strncmp(ENV[n], key, entry_key_len) == 0)) {
+ free((char*)ENV[n]);
+ ENV[n] = NULL;
+ }
+ }
+
+ /* 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);
ENV[n] = entry;
@@ -108,7 +121,9 @@
}
}
- return 1;
+ ERROR("No env. room to store: '%s':'%s'\n", key, val);
+
+ return -1;
}
static void zap_stdio(void)
@@ -154,7 +169,6 @@
struct stat s;
pid_t pid;
int needs_console;
- int n;
char *scon = NULL;
int rc;
@@ -528,7 +542,8 @@
void execute_one_command(void)
{
- int ret;
+ int ret, i;
+ char cmd_str[256] = "";
if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
cur_action = action_remove_queue_head();
@@ -545,16 +560,26 @@
return;
ret = cur_command->func(cur_command->nargs, cur_command->args);
- INFO("command '%s' r=%d\n", cur_command->args[0], ret);
+ if (klog_get_level() >= KLOG_INFO_LEVEL) {
+ for (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);
+ }
}
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);
+ 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);
+ ERROR("Timed out waiting for %s\n", COLDBOOT_DONE);
return ret;
}
@@ -791,27 +816,21 @@
* 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();
- return 0;
-}
-
-static int check_startup_action(int nargs, char **args)
-{
- /* make sure we actually have all the pieces we need */
- if ((get_property_set_fd() < 0) ||
- (get_signal_fd() < 0)) {
- ERROR("init startup failure\n");
+ if (get_signal_fd() < 0) {
+ ERROR("signal_init() failed\n");
exit(1);
}
-
- /* signal that we hit this point */
- unlink("/dev/.booting");
-
return 0;
}
@@ -841,24 +860,21 @@
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 i = 0;
- struct selabel_handle* sehandle = NULL;
- while ((sehandle == NULL) && seopts_prop[i].value) {
- sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP, &seopts_prop[i], 1);
- i++;
- }
-
+ 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[i - 1].value);
+ INFO("SELinux: Loaded property contexts from %s\n", seopts_prop[policy_index].value);
return sehandle;
}
@@ -871,6 +887,7 @@
static bool selinux_is_disabled(void)
{
+#ifdef ALLOW_DISABLE_SELINUX
char tmp[PROP_VALUE_MAX];
if (access("/sys/fs/selinux", F_OK) != 0) {
@@ -884,12 +901,14 @@
/* 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) {
@@ -906,6 +925,7 @@
ERROR("SELinux: Unknown value of ro.boot.selinux. Got: \"%s\". Assuming enforcing.\n", tmp);
}
+#endif
return true;
}
@@ -937,7 +957,7 @@
return 0;
}
-static int log_callback(int type, const char *fmt, ...)
+int log_callback(int type, const char *fmt, ...)
{
int level;
va_list ap;
@@ -981,9 +1001,6 @@
{
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;
@@ -1050,8 +1067,7 @@
is_charger = !strcmp(bootmode, "charger");
INFO("property init\n");
- if (!is_charger)
- property_load_boot_defaults();
+ property_load_boot_defaults();
INFO("reading config file\n");
init_parse_config_file("/init.rc");
@@ -1066,31 +1082,21 @@
/* execute all the boot actions to get us started */
action_for_each_trigger("init", action_add_queue_tail);
- /* skip mounting filesystems in charger mode */
- if (!is_charger) {
- action_for_each_trigger("early-fs", action_add_queue_tail);
- action_for_each_trigger("fs", action_add_queue_tail);
- action_for_each_trigger("post-fs", action_add_queue_tail);
- action_for_each_trigger("post-fs-data", 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
*/
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");
- queue_builtin_action(check_startup_action, "check_startup");
+ /* Don't mount filesystems or start core system services if in charger mode. */
if (is_charger) {
action_for_each_trigger("charger", action_add_queue_tail);
} else {
- action_for_each_trigger("early-boot", action_add_queue_tail);
- action_for_each_trigger("boot", action_add_queue_tail);
+ 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");
@@ -1137,11 +1143,29 @@
#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;
+ long long current_time;
+ int elapsed_time, remaining_time;
+
+ current_time = bootchart_gettime();
+ elapsed_time = current_time - bootchart_time;
+
+ if (elapsed_time >= BOOTCHART_POLLING_MS) {
+ /* count missed samples */
+ while (elapsed_time >= BOOTCHART_POLLING_MS) {
+ elapsed_time -= BOOTCHART_POLLING_MS;
+ bootchart_count--;
+ }
+ /* count may be negative, take a sample anyway */
+ bootchart_time = current_time;
+ if (bootchart_step() < 0 || bootchart_count <= 0) {
+ bootchart_finish();
+ bootchart_count = 0;
+ }
+ }
+ if (bootchart_count > 0) {
+ remaining_time = BOOTCHART_POLLING_MS - elapsed_time;
+ if (timeout < 0 || timeout > remaining_time)
+ timeout = remaining_time;
}
}
#endif
diff --git a/init/init.h b/init/init.h
index c241912..a7615a3 100644
--- a/init/init.h
+++ b/init/init.h
@@ -29,10 +29,14 @@
struct listnode clist;
int (*func)(int nargs, char **args);
+
+ int line;
+ const char *filename;
+
int nargs;
char *args[1];
};
-
+
struct action {
/* node in list of all actions */
struct listnode alist;
@@ -43,7 +47,7 @@
unsigned hash;
const char *name;
-
+
struct listnode commands;
struct command *current;
};
diff --git a/init/init_parser.c b/init/init_parser.c
index 02e5bdc..2b4db8e 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -33,9 +33,6 @@
#include <cutils/iosched_policy.h>
#include <cutils/list.h>
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
static list_declare(service_list);
static list_declare(action_list);
static list_declare(action_queue);
@@ -120,6 +117,7 @@
case 'l':
if (!strcmp(s, "oglevel")) return K_loglevel;
if (!strcmp(s, "oad_persist_props")) return K_load_persist_props;
+ if (!strcmp(s, "oad_all_props")) return K_load_all_props;
break;
case 'm':
if (!strcmp(s, "kdir")) return K_mkdir;
@@ -189,19 +187,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 $.
@@ -583,6 +576,7 @@
cmd = calloc(1, sizeof(*cmd));
cmd->func = func;
cmd->args[0] = name;
+ cmd->nargs = 1;
list_add_tail(&act->commands, &cmd->clist);
list_add_tail(&action_list, &act->alist);
@@ -760,7 +754,7 @@
break;
case K_setenv: { /* name value */
struct svcenvinfo *ei;
- if (nargs < 2) {
+ if (nargs < 3) {
parse_error(state, "setenv option requires name and value arguments\n");
break;
}
@@ -848,7 +842,6 @@
{
struct command *cmd;
struct action *act = state->context;
- int (*func)(int nargs, char **args);
int kw, n;
if (nargs == 0) {
@@ -869,6 +862,8 @@
}
cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
cmd->func = kw_func(kw);
+ cmd->line = state->line;
+ cmd->filename = state->filename;
cmd->nargs = nargs;
memcpy(cmd->args, args, sizeof(char*) * nargs);
list_add_tail(&act->commands, &cmd->clist);
diff --git a/init/keywords.h b/init/keywords.h
index 6625330..2d97e5b 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -39,6 +39,7 @@
int do_chmod(int nargs, char **args);
int do_loglevel(int nargs, char **args);
int do_load_persist_props(int nargs, char **args);
+int do_load_all_props(int nargs, char **args);
int do_wait(int nargs, char **args);
#define __MAKE_KEYWORD_ENUM__
#define KEYWORD(symbol, flags, nargs, func) K_##symbol,
@@ -101,6 +102,7 @@
KEYWORD(chmod, COMMAND, 2, do_chmod)
KEYWORD(loglevel, COMMAND, 1, do_loglevel)
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)
#ifdef __MAKE_KEYWORD_ENUM__
KEYWORD_COUNT,
diff --git a/init/log.h b/init/log.h
index 0ba770f..e9cb65a 100644
--- a/init/log.h
+++ b/init/log.h
@@ -23,4 +23,6 @@
#define NOTICE(x...) KLOG_NOTICE("init", x)
#define INFO(x...) KLOG_INFO("init", x)
+extern int log_callback(int type, const char *fmt, ...);
+
#endif
diff --git a/init/property_service.c b/init/property_service.c
index 4bcf883..1f98e13 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -24,6 +24,7 @@
#include <dirent.h>
#include <limits.h>
#include <errno.h>
+#include <sys/poll.h>
#include <cutils/misc.h>
#include <cutils/sockets.h>
@@ -38,7 +39,6 @@
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/mman.h>
-#include <sys/atomics.h>
#include <private/android_filesystem_config.h>
#include <selinux/selinux.h>
@@ -56,64 +56,6 @@
static int property_set_fd = -1;
-/* White list of permissions for setting property services. */
-struct {
- const char *prefix;
- unsigned int uid;
- unsigned int gid;
-} property_perms[] = {
- { "net.rmnet0.", AID_RADIO, 0 },
- { "net.gprs.", AID_RADIO, 0 },
- { "net.ppp", AID_RADIO, 0 },
- { "net.qmi", AID_RADIO, 0 },
- { "net.lte", AID_RADIO, 0 },
- { "net.cdma", AID_RADIO, 0 },
- { "ril.", AID_RADIO, 0 },
- { "gsm.", AID_RADIO, 0 },
- { "persist.radio", AID_RADIO, 0 },
- { "net.dns", AID_RADIO, 0 },
- { "sys.usb.config", AID_RADIO, 0 },
- { "net.", AID_SYSTEM, 0 },
- { "dev.", AID_SYSTEM, 0 },
- { "runtime.", AID_SYSTEM, 0 },
- { "hw.", AID_SYSTEM, 0 },
- { "sys.", AID_SYSTEM, 0 },
- { "sys.powerctl", AID_SHELL, 0 },
- { "service.", AID_SYSTEM, 0 },
- { "wlan.", AID_SYSTEM, 0 },
- { "gps.", AID_GPS, 0 },
- { "bluetooth.", AID_BLUETOOTH, 0 },
- { "dhcp.", AID_SYSTEM, 0 },
- { "dhcp.", AID_DHCP, 0 },
- { "debug.", AID_SYSTEM, 0 },
- { "debug.", AID_SHELL, 0 },
- { "log.", AID_SHELL, 0 },
- { "service.adb.root", AID_SHELL, 0 },
- { "service.adb.tcp.port", AID_SHELL, 0 },
- { "persist.logd.size",AID_SYSTEM, 0 },
- { "persist.sys.", AID_SYSTEM, 0 },
- { "persist.service.", AID_SYSTEM, 0 },
- { "persist.security.", AID_SYSTEM, 0 },
- { "persist.gps.", AID_GPS, 0 },
- { "persist.service.bdroid.", AID_BLUETOOTH, 0 },
- { "selinux." , AID_SYSTEM, 0 },
- { NULL, 0, 0 }
-};
-
-/*
- * White list of UID that are allowed to start/stop services.
- * Currently there are no user apps that require.
- */
-struct {
- const char *service;
- unsigned int uid;
- unsigned int gid;
-} control_perms[] = {
- { "dumpstate",AID_SHELL, AID_LOG },
- { "ril-daemon",AID_RADIO, AID_RADIO },
- {NULL, 0, 0 }
-};
-
typedef struct {
size_t size;
int fd;
@@ -121,7 +63,6 @@
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;
@@ -195,61 +136,15 @@
}
/*
- * Checks permissions for starting/stoping system services.
- * AID_SYSTEM and AID_ROOT are always allowed.
- *
- * Returns 1 if uid allowed, 0 otherwise.
- */
-static int check_control_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx) {
-
- int i;
- if (uid == AID_SYSTEM || uid == AID_ROOT)
- return check_control_mac_perms(name, sctx);
-
- /* Search the ACL */
- for (i = 0; control_perms[i].service; i++) {
- if (strcmp(control_perms[i].service, name) == 0) {
- if ((uid && control_perms[i].uid == uid) ||
- (gid && control_perms[i].gid == gid)) {
- return check_control_mac_perms(name, sctx);
- }
- }
- }
- return 0;
-}
-
-/*
* Checks permissions for setting system properties.
* Returns 1 if uid allowed, 0 otherwise.
*/
-static int check_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx)
+static int check_perms(const char *name, char *sctx)
{
- int i;
- unsigned int app_id;
-
if(!strncmp(name, "ro.", 3))
name +=3;
- if (uid == 0)
- return check_mac_perms(name, sctx);
-
- app_id = multiuser_get_app_id(uid);
- if (app_id == AID_BLUETOOTH) {
- uid = app_id;
- }
-
- for (i = 0; property_perms[i].prefix; i++) {
- if (strncmp(property_perms[i].prefix, name,
- strlen(property_perms[i].prefix)) == 0) {
- if ((uid && property_perms[i].uid == uid) ||
- (gid && property_perms[i].gid == gid)) {
-
- return check_mac_perms(name, sctx);
- }
- }
- }
-
- return 0;
+ return check_mac_perms(name, sctx);
}
int __property_get(const char *name, char *value)
@@ -283,7 +178,6 @@
static bool is_legal_property_name(const char* name, size_t namelen)
{
size_t i;
- bool previous_was_dot = false;
if (namelen >= PROP_NAME_MAX) return false;
if (namelen < 1) return false;
if (name[0] == '.') return false;
@@ -293,11 +187,10 @@
/* Don't allow ".." to appear in a property name */
for (i = 0; i < namelen; i++) {
if (name[i] == '.') {
- if (previous_was_dot == true) return false;
- previous_was_dot = true;
+ // i=0 is guaranteed to never have a dot. See above.
+ if (name[i-1] == '.') return false;
continue;
}
- previous_was_dot = false;
if (name[i] == '_' || name[i] == '-') continue;
if (name[i] >= 'a' && name[i] <= 'z') continue;
if (name[i] >= 'A' && name[i] <= 'Z') continue;
@@ -364,12 +257,14 @@
prop_msg msg;
int s;
int r;
- int res;
struct ucred cr;
struct sockaddr_un addr;
socklen_t addr_size = sizeof(addr);
socklen_t cr_size = sizeof(cr);
char * source_ctx = NULL;
+ struct pollfd ufds[1];
+ const int timeout_ms = 2 * 1000; /* Default 2 sec timeout for caller to send property. */
+ int nr;
if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
return;
@@ -382,7 +277,21 @@
return;
}
- r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));
+ ufds[0].fd = s;
+ ufds[0].events = POLLIN;
+ ufds[0].revents = 0;
+ nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));
+ if (nr == 0) {
+ ERROR("sys_prop: timeout waiting for uid=%d to send property message.\n", cr.uid);
+ 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));
+ 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);
@@ -407,14 +316,14 @@
// Keep the old close-socket-early behavior when handling
// ctl.* properties.
close(s);
- if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) {
+ if (check_control_mac_perms(msg.value, source_ctx)) {
handle_control_message((char*) msg.name + 4, (char*) msg.value);
} else {
ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
}
} else {
- if (check_perms(msg.name, cr.uid, cr.gid, source_ctx)) {
+ if (check_perms(msg.name, source_ctx)) {
property_set((char*) msg.name, (char*) msg.value);
} else {
ERROR("sys_prop: permission denied uid:%d name:%s\n",
@@ -534,10 +443,8 @@
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) {
@@ -622,18 +529,22 @@
load_persistent_properties();
}
-void start_property_service(void)
+void load_all_props(void)
{
- int fd;
-
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_FACTORY, "ro.*");
load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
+}
+
+void start_property_service(void)
+{
+ int fd;
fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);
if(fd < 0) return;
diff --git a/init/property_service.h b/init/property_service.h
index 46cbd8f..730495e 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -24,6 +24,7 @@
extern void property_init(void);
extern void property_load_boot_defaults(void);
extern void load_persist_props(void);
+extern void load_all_props(void);
extern void start_property_service(void);
void get_property_workspace(int *fd, int *sz);
extern int __property_get(const char *name, char *value);
diff --git a/init/readme.txt b/init/readme.txt
index 613a9e9..750d953 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -123,15 +123,6 @@
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.
-
-service-exited-<name>
- Triggers of this form occur when the specified service exits.
-
-
Commands
--------
@@ -211,8 +202,6 @@
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.
@@ -257,9 +246,9 @@
or the timeout has been reached. If timeout is not specified it
currently defaults to five seconds.
-write <path> <string> [ <string> ]*
- Open the file at <path> and write one or more strings
- to it with write(2)
+write <path> <string>
+ Open the file at <path> and write a string to it with write(2)
+ without appending.
Properties
@@ -327,12 +316,6 @@
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
diff --git a/init/ueventd.c b/init/ueventd.c
index 662196d..833e4fd 100644
--- a/init/ueventd.c
+++ b/init/ueventd.c
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
+#include <selinux/selinux.h>
#include <private/android_filesystem_config.h>
@@ -76,6 +77,10 @@
}
#endif
+ union selinux_callback cb;
+ cb.func_log = log_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
@@ -122,6 +127,7 @@
uid_t uid;
gid_t gid;
int prefix = 0;
+ int wildcard = 0;
char *endptr;
int ret;
char *tmp = 0;
@@ -154,9 +160,13 @@
name = tmp;
} else {
int len = strlen(name);
- if (name[len - 1] == '*') {
+ char *wildcard_chr = strchr(name, '*');
+ if ((name[len - 1] == '*') &&
+ (wildcard_chr == (name + len - 1))) {
prefix = 1;
name[len - 1] = '\0';
+ } else if (wildcard_chr) {
+ wildcard = 1;
}
}
@@ -183,6 +193,6 @@
}
gid = ret;
- add_dev_perms(name, attr, perm, uid, gid, prefix);
+ add_dev_perms(name, attr, perm, uid, gid, prefix, wildcard);
free(tmp);
}
diff --git a/init/util.c b/init/util.c
index 0f69e1c..e1a3ee3 100644
--- a/init/util.c
+++ b/init/util.c
@@ -329,9 +329,9 @@
if (!s)
return;
- for (; *s; s++) {
+ while (*s) {
s += strspn(s, accept);
- if (*s) *s = '_';
+ if (*s) *s++ = '_';
}
}
diff --git a/init/util.h b/init/util.h
index 04b8129..4cfe99d 100644
--- a/init/util.h
+++ b/init/util.h
@@ -22,7 +22,7 @@
#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,
diff --git a/libbacktrace/Android.build.mk b/libbacktrace/Android.build.mk
index 3c80cc2..7e1cd53 100644
--- a/libbacktrace/Android.build.mk
+++ b/libbacktrace/Android.build.mk
@@ -18,6 +18,7 @@
LOCAL_MODULE := $(module)
LOCAL_MODULE_TAGS := $(module_tag)
+LOCAL_MULTILIB := $($(module)_multilib)
LOCAL_ADDITIONAL_DEPENDENCIES := \
$(LOCAL_PATH)/Android.mk \
@@ -60,14 +61,16 @@
$($(module)_ldlibs_$(build_type)) \
ifeq ($(build_type),target)
- include external/stlport/libstlport.mk
-
include $(BUILD_$(build_target))
endif
ifeq ($(build_type),host)
# Only build if host builds are supported.
ifeq ($(build_host),true)
+ LOCAL_CFLAGS += -Wno-extern-c-compat
+ ifneq ($($(module)_libc++),)
+ include external/libcxx/libcxx.mk
+ endif
include $(BUILD_HOST_$(build_target))
endif
endif
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index fa79221..f2f71f9 100755
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -64,12 +64,17 @@
libbacktrace_static_libraries_host := \
libcutils \
+libbacktrace_ldlibs_host := \
+ -lpthread \
+ -lrt \
+
module := libbacktrace
module_tag := optional
build_type := target
build_target := SHARED_LIBRARY
include $(LOCAL_PATH)/Android.build.mk
build_type := host
+libbacktrace_multilib := both
include $(LOCAL_PATH)/Android.build.mk
#-------------------------------------------------------------------------
@@ -140,6 +145,8 @@
LOCAL_SRC_FILES := \
BacktraceMap.cpp \
+LOCAL_MULTILIB := both
+
include $(BUILD_HOST_SHARED_LIBRARY)
endif # HOST_OS-darwin
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 0056f4b..f38e484 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -137,7 +137,7 @@
#if defined(__APPLE__)
// Corkscrew and libunwind don't compile on the mac, so create a generic
// map object.
-BacktraceMap* BacktraceMap::Create(pid_t pid) {
+BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) {
BacktraceMap* map = new BacktraceMap(pid);
if (!map->Build()) {
delete map;
diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp
index 018d51f..439cc3b 100644
--- a/libbacktrace/BacktraceThread.cpp
+++ b/libbacktrace/BacktraceThread.cpp
@@ -17,14 +17,15 @@
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
-#include <linux/futex.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>
@@ -32,10 +33,6 @@
#include "BacktraceThread.h"
#include "thread_utils.h"
-static inline int futex(volatile int* uaddr, int op, int val, const struct timespec* ts, volatile int* uaddr2, int val3) {
- return syscall(__NR_futex, uaddr, op, val, ts, uaddr2, val3);
-}
-
//-------------------------------------------------------------------------
// ThreadEntry implementation.
//-------------------------------------------------------------------------
@@ -45,7 +42,14 @@
// 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), futex_(0), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), next_(ThreadEntry::list_), prev_(NULL) {
+ : 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;
@@ -99,22 +103,41 @@
next_ = NULL;
prev_ = NULL;
+
+ pthread_cond_destroy(&wait_cond_);
}
void ThreadEntry::Wait(int value) {
timespec ts;
- ts.tv_sec = 10;
- ts.tv_nsec = 0;
- errno = 0;
- futex(&futex_, FUTEX_WAIT, value, &ts, NULL, 0);
- if (errno != 0 && errno != EWOULDBLOCK) {
- BACK_LOGW("futex wait failed, futex = %d: %s", futex_, strerror(errno));
+ 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() {
- futex_++;
- futex(&futex_, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
+ 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));
}
//-------------------------------------------------------------------------
@@ -129,14 +152,14 @@
return;
}
- entry->CopyUcontext(reinterpret_cast<ucontext_t*>(sigcontext));
+ 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(1);
+ entry->Wait(2);
ThreadEntry::Remove(entry);
}
@@ -188,7 +211,7 @@
}
// Wait for the thread to get the ucontext.
- entry->Wait(0);
+ entry->Wait(1);
// After the thread has received the signal, allow other unwinders to
// continue.
diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h
index a75a807..99a8638 100644
--- a/libbacktrace/BacktraceThread.h
+++ b/libbacktrace/BacktraceThread.h
@@ -40,18 +40,18 @@
static void Remove(ThreadEntry* entry);
- inline void CopyUcontext(ucontext_t* ucontext) {
- memcpy(&ucontext_, ucontext, sizeof(ucontext_));
- }
-
void Wake();
void Wait(int);
+ void CopyUcontextFromSigcontext(void*);
+
inline void Lock() {
pthread_mutex_lock(&mutex_);
- // Reset the futex value in case of multiple unwinds of the same thread.
- futex_ = 0;
+
+ // Always reset the wait value since this could be the first or nth
+ // time this entry is locked.
+ wait_value_ = 0;
}
inline void Unlock() {
@@ -68,9 +68,11 @@
pid_t pid_;
pid_t tid_;
- int futex_;
int ref_count_;
pthread_mutex_t mutex_;
+ pthread_mutex_t wait_mutex_;
+ pthread_cond_t wait_cond_;
+ int wait_value_;
ThreadEntry* next_;
ThreadEntry* prev_;
ucontext_t ucontext_;
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index 1615518..387d768 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -15,6 +15,7 @@
*/
#include <pthread.h>
+#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
@@ -129,9 +130,13 @@
//-------------------------------------------------------------------------
// BacktraceMap create function.
//-------------------------------------------------------------------------
-BacktraceMap* BacktraceMap::Create(pid_t pid) {
+BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) {
BacktraceMap* map;
- if (pid == getpid()) {
+
+ if (uncached) {
+ // Force use of the base class to parse the maps when this call is made.
+ map = new BacktraceMap(pid);
+ } else if (pid == getpid()) {
map = new UnwindMapLocal();
} else {
map = new UnwindMap(pid);
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index ed6b211..8002ed6 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -51,7 +51,7 @@
#define NS_PER_SEC 1000000000ULL
// Number of simultaneous dumping operations to perform.
-#define NUM_THREADS 20
+#define NUM_THREADS 40
// Number of simultaneous threads running in our forked process.
#define NUM_PTRACE_THREADS 5
@@ -486,6 +486,13 @@
struct sigaction new_action;
ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &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
+ cur_action.sa_flags &= ~SA_RESTORER;
+ new_action.sa_flags &= ~SA_RESTORER;
+#endif
EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
}
@@ -583,7 +590,7 @@
// Wait for tids to be set.
for (std::vector<thread_t>::iterator it = runners.begin(); it != runners.end(); ++it) {
- ASSERT_TRUE(WaitForNonZero(&it->state, 10));
+ ASSERT_TRUE(WaitForNonZero(&it->state, 30));
}
// Start all of the dumpers at once, they will spin until they are signalled
@@ -602,7 +609,7 @@
android_atomic_acquire_store(1, &dump_now);
for (size_t i = 0; i < NUM_THREADS; i++) {
- ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 10));
+ ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 30));
// Tell the runner thread to exit its infinite loop.
android_atomic_acquire_store(0, &runners[i].state);
@@ -625,7 +632,7 @@
ASSERT_TRUE(pthread_create(&runner.threadId, &attr, ThreadMaxRun, &runner) == 0);
// Wait for tids to be set.
- ASSERT_TRUE(WaitForNonZero(&runner.state, 10));
+ ASSERT_TRUE(WaitForNonZero(&runner.state, 30));
// Start all of the dumpers at once, they will spin until they are signalled
// to begin their dump run.
@@ -645,7 +652,7 @@
android_atomic_acquire_store(1, &dump_now);
for (size_t i = 0; i < NUM_THREADS; i++) {
- ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 100));
+ ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 30));
ASSERT_TRUE(dumpers[i].backtrace != NULL);
VerifyMaxDump(dumpers[i].backtrace);
diff --git a/libbacktrace/map_info.c b/libbacktrace/map_info.c
new file mode 100644
index 0000000..073b24a
--- /dev/null
+++ b/libbacktrace/map_info.c
@@ -0,0 +1,173 @@
+/*
+ * 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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <log/log.h>
+#include <sys/time.h>
+
+#include <backtrace/backtrace.h>
+
+#if defined(__APPLE__)
+
+// Mac OS vmmap(1) output:
+// __TEXT 0009f000-000a1000 [ 8K 8K] r-x/rwx SM=COW /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
+// 012345678901234567890123456789012345678901234567890123456789
+// 0 1 2 3 4 5
+static backtrace_map_info_t* parse_vmmap_line(const char* line) {
+ unsigned long int start;
+ unsigned long int end;
+ char permissions[4];
+ int name_pos;
+ if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c %n",
+ &start, &end, permissions, &name_pos) != 3) {
+ return NULL;
+ }
+
+ const char* name = line + name_pos;
+ size_t name_len = strlen(name);
+
+ backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len);
+ if (mi != NULL) {
+ mi->start = start;
+ mi->end = end;
+ mi->is_readable = permissions[0] == 'r';
+ mi->is_writable = permissions[1] == 'w';
+ mi->is_executable = permissions[2] == 'x';
+ memcpy(mi->name, name, name_len);
+ mi->name[name_len - 1] = '\0';
+ ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
+ "is_readable=%d, is_writable=%d is_executable=%d, name=%s",
+ mi->start, mi->end,
+ mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
+ }
+ return mi;
+}
+
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid) {
+ char cmd[1024];
+ if (pid < 0) {
+ pid = getpid();
+ }
+ snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid);
+ FILE* fp = popen(cmd, "r");
+ if (fp == NULL) {
+ return NULL;
+ }
+
+ char line[1024];
+ backtrace_map_info_t* milist = NULL;
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ backtrace_map_info_t* mi = parse_vmmap_line(line);
+ if (mi != NULL) {
+ mi->next = milist;
+ milist = mi;
+ }
+ }
+ pclose(fp);
+ return milist;
+}
+
+#else
+
+// Linux /proc/<pid>/maps lines:
+// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so\n
+// 012345678901234567890123456789012345678901234567890123456789
+// 0 1 2 3 4 5
+static backtrace_map_info_t* parse_maps_line(const char* line)
+{
+ unsigned long int start;
+ unsigned long int end;
+ char permissions[5];
+ int name_pos;
+ if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d%n", &start, &end,
+ permissions, &name_pos) != 3) {
+ return NULL;
+ }
+
+ while (isspace(line[name_pos])) {
+ name_pos += 1;
+ }
+ const char* name = line + name_pos;
+ size_t name_len = strlen(name);
+ if (name_len && name[name_len - 1] == '\n') {
+ name_len -= 1;
+ }
+
+ backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len + 1);
+ if (mi) {
+ mi->start = start;
+ mi->end = end;
+ mi->is_readable = strlen(permissions) == 4 && permissions[0] == 'r';
+ mi->is_writable = strlen(permissions) == 4 && permissions[1] == 'w';
+ mi->is_executable = strlen(permissions) == 4 && permissions[2] == 'x';
+ memcpy(mi->name, name, name_len);
+ mi->name[name_len] = '\0';
+ ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
+ "is_readable=%d, is_writable=%d, is_executable=%d, name=%s",
+ mi->start, mi->end,
+ mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
+ }
+ return mi;
+}
+
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid) {
+ char path[PATH_MAX];
+ char line[1024];
+ FILE* fp;
+ backtrace_map_info_t* milist = NULL;
+
+ if (tid < 0) {
+ tid = getpid();
+ }
+ snprintf(path, PATH_MAX, "/proc/%d/maps", tid);
+ fp = fopen(path, "r");
+ if (fp) {
+ while(fgets(line, sizeof(line), fp)) {
+ backtrace_map_info_t* mi = parse_maps_line(line);
+ if (mi) {
+ mi->next = milist;
+ milist = mi;
+ }
+ }
+ fclose(fp);
+ }
+ return milist;
+}
+
+#endif
+
+void backtrace_destroy_map_info_list(backtrace_map_info_t* milist) {
+ while (milist) {
+ backtrace_map_info_t* next = milist->next;
+ free(milist);
+ milist = next;
+ }
+}
+
+const backtrace_map_info_t* backtrace_find_map_info(
+ const backtrace_map_info_t* milist, uintptr_t addr) {
+ const backtrace_map_info_t* mi = milist;
+ while (mi && !(addr >= mi->start && addr < mi->end)) {
+ mi = mi->next;
+ }
+ return mi;
+}
diff --git a/libctest/Android.mk b/libctest/Android.mk
deleted file mode 100644
index 815fabb..0000000
--- a/libctest/Android.mk
+++ /dev/null
@@ -1,7 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libctest
-LOCAL_SRC_FILES := ctest.c
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/libctest/NOTICE b/libctest/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/libctest/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/libctest/ctest.c b/libctest/ctest.c
deleted file mode 100644
index ee6331f..0000000
--- a/libctest/ctest.c
+++ /dev/null
@@ -1,161 +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 <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <ctest/ctest.h>
-
-#define MAX_TESTS 255
-
-/** Semi-random number used to identify assertion errors. */
-#define ASSERTION_ERROR 42
-
-typedef void TestCase();
-
-/** A suite of tests. */
-typedef struct {
- int size;
- const char* testNames[MAX_TESTS];
- TestCase* tests[MAX_TESTS];
- int currentTest;
- FILE* out;
-} TestSuite;
-
-/** Gets the test suite. Creates it if necessary. */
-static TestSuite* getTestSuite() {
- static TestSuite* suite = NULL;
-
- if (suite != NULL) {
- return suite;
- }
-
- suite = calloc(1, sizeof(TestSuite));
- assert(suite != NULL);
-
- suite->out = tmpfile();
- assert(suite->out != NULL);
-
- return suite;
-}
-
-void addNamedTest(const char* name, TestCase* test) {
- TestSuite* testSuite = getTestSuite();
- assert(testSuite->size <= MAX_TESTS);
-
- int index = testSuite->size;
- testSuite->testNames[index] = name;
- testSuite->tests[index] = test;
-
- testSuite->size++;
-}
-
-/** Prints failures to stderr. */
-static void printFailures(int failures) {
- TestSuite* suite = getTestSuite();
-
- fprintf(stderr, "FAILURE! %d of %d tests failed. Failures:\n",
- failures, suite->size);
-
- // Copy test output to stdout.
- rewind(suite->out);
- char buffer[512];
- size_t read;
- while ((read = fread(buffer, sizeof(char), 512, suite->out)) > 0) {
- // TODO: Make sure we actually wrote 'read' bytes.
- fwrite(buffer, sizeof(char), read, stderr);
- }
-}
-
-/** Runs a single test case. */
-static int runCurrentTest() {
- TestSuite* suite = getTestSuite();
-
- pid_t pid = fork();
- if (pid == 0) {
- // Child process. Runs test case.
- suite->tests[suite->currentTest]();
-
- // Exit successfully.
- exit(0);
- } else if (pid < 0) {
- fprintf(stderr, "Fork failed.");
- exit(1);
- } else {
- // Parent process. Wait for child.
- int status;
- waitpid(pid, &status, 0);
-
- if (!WIFEXITED(status)) {
- return -1;
- }
-
- return WEXITSTATUS(status);
- }
-}
-
-void runTests() {
- TestSuite* suite = getTestSuite();
-
- int failures = 0;
- for (suite->currentTest = 0; suite->currentTest < suite->size;
- suite->currentTest++) {
- // Flush stdout before forking.
- fflush(stdout);
-
- int result = runCurrentTest();
-
- if (result != 0) {
- printf("X");
-
- failures++;
-
- // Handle errors other than assertions.
- if (result != ASSERTION_ERROR) {
- // TODO: Report file name.
- fprintf(suite->out, "Process failed: [%s] status: %d\n",
- suite->testNames[suite->currentTest], result);
- fflush(suite->out);
- }
- } else {
- printf(".");
- }
- }
-
- printf("\n");
-
- if (failures > 0) {
- printFailures(failures);
- } else {
- printf("SUCCESS! %d tests ran successfully.\n", suite->size);
- }
-}
-
-void assertTrueWithSource(int value, const char* file, int line, char* message) {
- if (!value) {
- TestSuite* suite = getTestSuite();
-
- fprintf(suite->out, "Assertion failed: [%s:%d] %s: %s\n", file, line,
- suite->testNames[suite->currentTest], message);
- fflush(suite->out);
-
- // Exit the process for this test case.
- exit(ASSERTION_ERROR);
- }
-}
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 945ebdd..7202704 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -16,24 +16,10 @@
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 \
- socket_inaddr_any_server.c \
- socket_local_client.c \
- socket_local_server.c \
- socket_loopback_client.c \
- socket_loopback_server.c \
- socket_network_client.c \
- sockets.c \
config_utils.c \
cpu_info.c \
load_file.c \
@@ -47,9 +33,6 @@
iosched_policy.c \
str_parms.c \
-commonHostSources := \
- ashmem-host.c
-
# 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
@@ -67,7 +50,18 @@
ifneq ($(WINDOWS_HOST_ONLY),1)
commonSources += \
fs.c \
- multiuser.c
+ multiuser.c \
+ socket_inaddr_any_server.c \
+ socket_local_client.c \
+ socket_local_server.c \
+ socket_loopback_client.c \
+ socket_loopback_server.c \
+ socket_network_client.c \
+ sockets.c \
+
+ commonHostSources += \
+ ashmem-host.c
+
endif
@@ -76,25 +70,14 @@
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)
-# Static library for host, 64-bit
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := lib64cutils
-LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c
-LOCAL_STATIC_LIBRARIES := lib64log
-LOCAL_CFLAGS += $(hostSmpFlag) -m64
-ifneq ($(HOST_OS),windows)
-LOCAL_CFLAGS += -Werror
-endif
-include $(BUILD_HOST_STATIC_LIBRARY)
-
# Tests for host
# ========================================================
include $(CLEAR_VARS)
@@ -106,6 +89,7 @@
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)
@@ -119,30 +103,51 @@
ashmem-dev.c \
debugger.c \
klog.c \
+ memory.c \
partition_utils.c \
properties.c \
qtaguid.c \
trace.c \
- uevent.c
+ uevent.c \
-ifeq ($(TARGET_ARCH),arm)
- LOCAL_SRC_FILES += arch-arm/memset32.S
-else # !arm
- ifeq ($(TARGET_ARCH),x86)
- LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32
- LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c
- else # !x86
- ifeq ($(TARGET_ARCH),mips)
- LOCAL_SRC_FILES += arch-mips/android_memset.c
- else # !mips
- LOCAL_SRC_FILES += memory.c
- endif # !mips
- endif # !x86
-endif # !arm
+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 \
+
+ifndef ARCH_MIPS_REV6
+LOCAL_SRC_FILES_mips += \
+ arch-mips/android_memset.c \
+
+LOCAL_CFLAGS_mips += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+endif
+
+# TODO: switch mips64 back to using 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.S \
+ arch-x86_64/android_memset32.S \
+
+LOCAL_CFLAGS_arm += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_arm64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+#LOCAL_CFLAGS_mips64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_x86 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_x86_64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
LOCAL_C_INCLUDES := $(libcutils_c_includes)
LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS += $(targetSmpFlag) -Werror
+LOCAL_CFLAGS += -Werror -std=gnu90
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -151,8 +156,9 @@
# 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)
@@ -161,6 +167,7 @@
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 b7895fa..5d98295 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -57,7 +57,7 @@
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")) {
+ if ((match == 6) && !strncmp(mount_dev, "/dev/block", 10) && strstr(mount_opts, "rw,")) {
found_rw_fs = 1;
break;
}
diff --git a/libcutils/arch-arm/memset32.S b/libcutils/arch-arm/memset32.S
index 4697265..6efab9f 100644
--- a/libcutils/arch-arm/memset32.S
+++ b/libcutils/arch-arm/memset32.S
@@ -51,8 +51,10 @@
android_memset32:
.fnstart
- .save {lr}
+ .cfi_startproc
str lr, [sp, #-4]!
+ .cfi_def_cfa_offset 4
+ .cfi_rel_offset lr, 0
/* align the destination to a cache-line */
mov r12, r1
@@ -89,5 +91,8 @@
strmih lr, [r0], #2
ldr lr, [sp], #4
+ .cfi_def_cfa_offset 0
+ .cfi_restore lr
bx lr
+ .cfi_endproc
.fnend
diff --git a/libcutils/arch-arm64/android_memset.S b/libcutils/arch-arm64/android_memset.S
new file mode 100644
index 0000000..9a83a68
--- /dev/null
+++ b/libcutils/arch-arm64/android_memset.S
@@ -0,0 +1,211 @@
+/* Copyright (c) 2012, Linaro Limited
+ 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 the Linaro 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
+ HOLDER 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.
+*/
+
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64
+ * Unaligned accesses
+ *
+ */
+
+/* By default we assume that the DC instruction can be used to zero
+ data blocks more efficiently. In some circumstances this might be
+ unsafe, for example in an asymmetric multiprocessor environment with
+ different DC clear lengths (neither the upper nor lower lengths are
+ safe to use). */
+
+#define dst x0
+#define count x2
+#define tmp1 x3
+#define tmp1w w3
+#define tmp2 x4
+#define tmp2w w4
+#define zva_len_x x5
+#define zva_len w5
+#define zva_bits_x x6
+
+#define A_l x1
+#define A_lw w1
+#define tmp3w w9
+
+#define ENTRY(f) \
+ .text; \
+ .globl f; \
+ .align 0; \
+ .type f, %function; \
+ f: \
+ .cfi_startproc \
+
+#define END(f) \
+ .cfi_endproc; \
+ .size f, .-f; \
+
+ENTRY(android_memset16)
+ ands A_lw, A_lw, #0xffff
+ b.eq .Lzero_mem
+ orr A_lw, A_lw, A_lw, lsl #16
+ b .Lexpand_to_64
+END(android_memset16)
+
+ENTRY(android_memset32)
+ cmp A_lw, #0
+ b.eq .Lzero_mem
+.Lexpand_to_64:
+ orr A_l, A_l, A_l, lsl #32
+.Ltail_maybe_long:
+ cmp count, #64
+ b.ge .Lnot_short
+.Ltail_maybe_tiny:
+ cmp count, #15
+ b.le .Ltail15tiny
+.Ltail63:
+ ands tmp1, count, #0x30
+ b.eq .Ltail15
+ add dst, dst, tmp1
+ cmp tmp1w, #0x20
+ b.eq 1f
+ b.lt 2f
+ stp A_l, A_l, [dst, #-48]
+1:
+ stp A_l, A_l, [dst, #-32]
+2:
+ stp A_l, A_l, [dst, #-16]
+
+.Ltail15:
+ and count, count, #15
+ add dst, dst, count
+ stp A_l, A_l, [dst, #-16] /* Repeat some/all of last store. */
+ ret
+
+.Ltail15tiny:
+ /* Set up to 15 bytes. Does not assume earlier memory
+ being set. */
+ tbz count, #3, 1f
+ str A_l, [dst], #8
+1:
+ tbz count, #2, 1f
+ str A_lw, [dst], #4
+1:
+ tbz count, #1, 1f
+ strh A_lw, [dst], #2
+1:
+ ret
+
+ /* Critical loop. Start at a new cache line boundary. Assuming
+ * 64 bytes per line, this ensures the entire loop is in one line. */
+ .p2align 6
+.Lnot_short:
+ neg tmp2, dst
+ ands tmp2, tmp2, #15
+ b.eq 2f
+ /* Bring DST to 128-bit (16-byte) alignment. We know that there's
+ * more than that to set, so we simply store 16 bytes and advance by
+ * the amount required to reach alignment. */
+ sub count, count, tmp2
+ stp A_l, A_l, [dst]
+ add dst, dst, tmp2
+ /* There may be less than 63 bytes to go now. */
+ cmp count, #63
+ b.le .Ltail63
+2:
+ sub dst, dst, #16 /* Pre-bias. */
+ sub count, count, #64
+1:
+ stp A_l, A_l, [dst, #16]
+ stp A_l, A_l, [dst, #32]
+ stp A_l, A_l, [dst, #48]
+ stp A_l, A_l, [dst, #64]!
+ subs count, count, #64
+ b.ge 1b
+ tst count, #0x3f
+ add dst, dst, #16
+ b.ne .Ltail63
+ ret
+
+ /* For zeroing memory, check to see if we can use the ZVA feature to
+ * zero entire 'cache' lines. */
+.Lzero_mem:
+ mov A_l, #0
+ cmp count, #63
+ b.le .Ltail_maybe_tiny
+ neg tmp2, dst
+ ands tmp2, tmp2, #15
+ b.eq 1f
+ sub count, count, tmp2
+ stp A_l, A_l, [dst]
+ add dst, dst, tmp2
+ cmp count, #63
+ b.le .Ltail63
+1:
+ /* For zeroing small amounts of memory, it's not worth setting up
+ * the line-clear code. */
+ cmp count, #128
+ b.lt .Lnot_short
+ mrs tmp1, dczid_el0
+ tbnz tmp1, #4, .Lnot_short
+ mov tmp3w, #4
+ and zva_len, tmp1w, #15 /* Safety: other bits reserved. */
+ lsl zva_len, tmp3w, zva_len
+
+.Lzero_by_line:
+ /* Compute how far we need to go to become suitably aligned. We're
+ * already at quad-word alignment. */
+ cmp count, zva_len_x
+ b.lt .Lnot_short /* Not enough to reach alignment. */
+ sub zva_bits_x, zva_len_x, #1
+ neg tmp2, dst
+ ands tmp2, tmp2, zva_bits_x
+ b.eq 1f /* Already aligned. */
+ /* Not aligned, check that there's enough to copy after alignment. */
+ sub tmp1, count, tmp2
+ cmp tmp1, #64
+ ccmp tmp1, zva_len_x, #8, ge /* NZCV=0b1000 */
+ b.lt .Lnot_short
+ /* We know that there's at least 64 bytes to zero and that it's safe
+ * to overrun by 64 bytes. */
+ mov count, tmp1
+2:
+ stp A_l, A_l, [dst]
+ stp A_l, A_l, [dst, #16]
+ stp A_l, A_l, [dst, #32]
+ subs tmp2, tmp2, #64
+ stp A_l, A_l, [dst, #48]
+ add dst, dst, #64
+ b.ge 2b
+ /* We've overrun a bit, so adjust dst downwards. */
+ add dst, dst, tmp2
+1:
+ sub count, count, zva_len_x
+3:
+ dc zva, dst
+ add dst, dst, zva_len_x
+ subs count, count, zva_len_x
+ b.ge 3b
+ ands count, count, zva_bits_x
+ b.ne .Ltail_maybe_long
+ ret
+END(android_memset32)
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.S b/libcutils/arch-x86_64/android_memset16.S
new file mode 100644
index 0000000..cb6d4a3
--- /dev/null
+++ b/libcutils/arch-x86_64/android_memset16.S
@@ -0,0 +1,565 @@
+/*
+ * 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 "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 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 JMPTBL(I, B) I - B
+
+/* Branch to an entry in a jump table. TABLE is a jump table with
+ relative offsets. INDEX is a register contains the index into the
+ jump table. SCALE is the scale of INDEX. */
+#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \
+ lea TABLE(%rip), %r11; \
+ movslq (%r11, INDEX, SCALE), INDEX; \
+ lea (%r11, INDEX), INDEX; \
+ jmp *INDEX
+
+ .section .text.sse2,"ax",@progbits
+ ALIGN (4)
+ENTRY (MEMSET) // Address in rdi
+ shr $1, %rdx // Count in rdx
+ movzwl %si, %ecx
+ /* Fill the whole ECX with pattern. */
+ shl $16, %esi
+ or %esi, %ecx // Pattern in ecx
+
+ cmp $32, %rdx
+ jae L(32wordsormore)
+
+L(write_less32words):
+ lea (%rdi, %rdx, 2), %rdi
+ BRANCH_TO_JMPTBL_ENTRY (L(table_less32words), %rdx, 4)
+
+ .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 %ecx, -56(%rdi)
+ movl %ecx, -52(%rdi)
+L(write_24words):
+ movl %ecx, -48(%rdi)
+ movl %ecx, -44(%rdi)
+L(write_20words):
+ movl %ecx, -40(%rdi)
+ movl %ecx, -36(%rdi)
+L(write_16words):
+ movl %ecx, -32(%rdi)
+ movl %ecx, -28(%rdi)
+L(write_12words):
+ movl %ecx, -24(%rdi)
+ movl %ecx, -20(%rdi)
+L(write_8words):
+ movl %ecx, -16(%rdi)
+ movl %ecx, -12(%rdi)
+L(write_4words):
+ movl %ecx, -8(%rdi)
+ movl %ecx, -4(%rdi)
+L(write_0words):
+ ret
+
+ ALIGN (4)
+L(write_29words):
+ movl %ecx, -58(%rdi)
+ movl %ecx, -54(%rdi)
+L(write_25words):
+ movl %ecx, -50(%rdi)
+ movl %ecx, -46(%rdi)
+L(write_21words):
+ movl %ecx, -42(%rdi)
+ movl %ecx, -38(%rdi)
+L(write_17words):
+ movl %ecx, -34(%rdi)
+ movl %ecx, -30(%rdi)
+L(write_13words):
+ movl %ecx, -26(%rdi)
+ movl %ecx, -22(%rdi)
+L(write_9words):
+ movl %ecx, -18(%rdi)
+ movl %ecx, -14(%rdi)
+L(write_5words):
+ movl %ecx, -10(%rdi)
+ movl %ecx, -6(%rdi)
+L(write_1words):
+ mov %cx, -2(%rdi)
+ ret
+
+ ALIGN (4)
+L(write_30words):
+ movl %ecx, -60(%rdi)
+ movl %ecx, -56(%rdi)
+L(write_26words):
+ movl %ecx, -52(%rdi)
+ movl %ecx, -48(%rdi)
+L(write_22words):
+ movl %ecx, -44(%rdi)
+ movl %ecx, -40(%rdi)
+L(write_18words):
+ movl %ecx, -36(%rdi)
+ movl %ecx, -32(%rdi)
+L(write_14words):
+ movl %ecx, -28(%rdi)
+ movl %ecx, -24(%rdi)
+L(write_10words):
+ movl %ecx, -20(%rdi)
+ movl %ecx, -16(%rdi)
+L(write_6words):
+ movl %ecx, -12(%rdi)
+ movl %ecx, -8(%rdi)
+L(write_2words):
+ movl %ecx, -4(%rdi)
+ ret
+
+ ALIGN (4)
+L(write_31words):
+ movl %ecx, -62(%rdi)
+ movl %ecx, -58(%rdi)
+L(write_27words):
+ movl %ecx, -54(%rdi)
+ movl %ecx, -50(%rdi)
+L(write_23words):
+ movl %ecx, -46(%rdi)
+ movl %ecx, -42(%rdi)
+L(write_19words):
+ movl %ecx, -38(%rdi)
+ movl %ecx, -34(%rdi)
+L(write_15words):
+ movl %ecx, -30(%rdi)
+ movl %ecx, -26(%rdi)
+L(write_11words):
+ movl %ecx, -22(%rdi)
+ movl %ecx, -18(%rdi)
+L(write_7words):
+ movl %ecx, -14(%rdi)
+ movl %ecx, -10(%rdi)
+L(write_3words):
+ movl %ecx, -6(%rdi)
+ movw %cx, -2(%rdi)
+ ret
+
+ ALIGN (4)
+L(32wordsormore):
+ shl $1, %rdx
+ test $0x01, %edi
+ jz L(aligned2bytes)
+ mov %ecx, (%rdi)
+ mov %ecx, -4(%rdi, %rdx)
+ sub $2, %rdx
+ add $1, %rdi
+ rol $8, %ecx
+L(aligned2bytes):
+ /* Fill xmm0 with the pattern. */
+ movd %ecx, %xmm0
+ pshufd $0, %xmm0, %xmm0
+
+ testl $0xf, %edi
+ jz L(aligned_16)
+/* RDX > 32 and RDI is not 16 byte aligned. */
+ movdqu %xmm0, (%rdi)
+ mov %rdi, %rsi
+ and $-16, %rdi
+ add $16, %rdi
+ sub %rdi, %rsi
+ add %rsi, %rdx
+
+ ALIGN (4)
+L(aligned_16):
+ cmp $128, %rdx
+ jge L(128bytesormore)
+
+L(aligned_16_less128bytes):
+ add %rdx, %rdi
+ shr $1, %rdx
+ BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+ ALIGN (4)
+L(128bytesormore):
+ cmp $SHARED_CACHE_SIZE, %rdx
+ jg L(128bytesormore_nt)
+
+L(128bytesormore_normal):
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jl L(128bytesless_normal)
+
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jl L(128bytesless_normal)
+
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jl L(128bytesless_normal)
+
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jge L(128bytesormore_normal)
+
+L(128bytesless_normal):
+ add %rdx, %rdi
+ shr $1, %rdx
+ BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+ ALIGN (4)
+L(128bytesormore_nt):
+ sub $128, %rdx
+ movntdq %xmm0, (%rdi)
+ movntdq %xmm0, 0x10(%rdi)
+ movntdq %xmm0, 0x20(%rdi)
+ movntdq %xmm0, 0x30(%rdi)
+ movntdq %xmm0, 0x40(%rdi)
+ movntdq %xmm0, 0x50(%rdi)
+ movntdq %xmm0, 0x60(%rdi)
+ movntdq %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jge L(128bytesormore_nt)
+
+ sfence
+ add %rdx, %rdi
+ shr $1, %rdx
+ BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+ .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(%rdi)
+L(aligned_16_96bytes):
+ movdqa %xmm0, -96(%rdi)
+L(aligned_16_80bytes):
+ movdqa %xmm0, -80(%rdi)
+L(aligned_16_64bytes):
+ movdqa %xmm0, -64(%rdi)
+L(aligned_16_48bytes):
+ movdqa %xmm0, -48(%rdi)
+L(aligned_16_32bytes):
+ movdqa %xmm0, -32(%rdi)
+L(aligned_16_16bytes):
+ movdqa %xmm0, -16(%rdi)
+L(aligned_16_0bytes):
+ ret
+
+ ALIGN (4)
+L(aligned_16_114bytes):
+ movdqa %xmm0, -114(%rdi)
+L(aligned_16_98bytes):
+ movdqa %xmm0, -98(%rdi)
+L(aligned_16_82bytes):
+ movdqa %xmm0, -82(%rdi)
+L(aligned_16_66bytes):
+ movdqa %xmm0, -66(%rdi)
+L(aligned_16_50bytes):
+ movdqa %xmm0, -50(%rdi)
+L(aligned_16_34bytes):
+ movdqa %xmm0, -34(%rdi)
+L(aligned_16_18bytes):
+ movdqa %xmm0, -18(%rdi)
+L(aligned_16_2bytes):
+ movw %cx, -2(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_116bytes):
+ movdqa %xmm0, -116(%rdi)
+L(aligned_16_100bytes):
+ movdqa %xmm0, -100(%rdi)
+L(aligned_16_84bytes):
+ movdqa %xmm0, -84(%rdi)
+L(aligned_16_68bytes):
+ movdqa %xmm0, -68(%rdi)
+L(aligned_16_52bytes):
+ movdqa %xmm0, -52(%rdi)
+L(aligned_16_36bytes):
+ movdqa %xmm0, -36(%rdi)
+L(aligned_16_20bytes):
+ movdqa %xmm0, -20(%rdi)
+L(aligned_16_4bytes):
+ movl %ecx, -4(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_118bytes):
+ movdqa %xmm0, -118(%rdi)
+L(aligned_16_102bytes):
+ movdqa %xmm0, -102(%rdi)
+L(aligned_16_86bytes):
+ movdqa %xmm0, -86(%rdi)
+L(aligned_16_70bytes):
+ movdqa %xmm0, -70(%rdi)
+L(aligned_16_54bytes):
+ movdqa %xmm0, -54(%rdi)
+L(aligned_16_38bytes):
+ movdqa %xmm0, -38(%rdi)
+L(aligned_16_22bytes):
+ movdqa %xmm0, -22(%rdi)
+L(aligned_16_6bytes):
+ movl %ecx, -6(%rdi)
+ movw %cx, -2(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_120bytes):
+ movdqa %xmm0, -120(%rdi)
+L(aligned_16_104bytes):
+ movdqa %xmm0, -104(%rdi)
+L(aligned_16_88bytes):
+ movdqa %xmm0, -88(%rdi)
+L(aligned_16_72bytes):
+ movdqa %xmm0, -72(%rdi)
+L(aligned_16_56bytes):
+ movdqa %xmm0, -56(%rdi)
+L(aligned_16_40bytes):
+ movdqa %xmm0, -40(%rdi)
+L(aligned_16_24bytes):
+ movdqa %xmm0, -24(%rdi)
+L(aligned_16_8bytes):
+ movq %xmm0, -8(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_122bytes):
+ movdqa %xmm0, -122(%rdi)
+L(aligned_16_106bytes):
+ movdqa %xmm0, -106(%rdi)
+L(aligned_16_90bytes):
+ movdqa %xmm0, -90(%rdi)
+L(aligned_16_74bytes):
+ movdqa %xmm0, -74(%rdi)
+L(aligned_16_58bytes):
+ movdqa %xmm0, -58(%rdi)
+L(aligned_16_42bytes):
+ movdqa %xmm0, -42(%rdi)
+L(aligned_16_26bytes):
+ movdqa %xmm0, -26(%rdi)
+L(aligned_16_10bytes):
+ movq %xmm0, -10(%rdi)
+ movw %cx, -2(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_124bytes):
+ movdqa %xmm0, -124(%rdi)
+L(aligned_16_108bytes):
+ movdqa %xmm0, -108(%rdi)
+L(aligned_16_92bytes):
+ movdqa %xmm0, -92(%rdi)
+L(aligned_16_76bytes):
+ movdqa %xmm0, -76(%rdi)
+L(aligned_16_60bytes):
+ movdqa %xmm0, -60(%rdi)
+L(aligned_16_44bytes):
+ movdqa %xmm0, -44(%rdi)
+L(aligned_16_28bytes):
+ movdqa %xmm0, -28(%rdi)
+L(aligned_16_12bytes):
+ movq %xmm0, -12(%rdi)
+ movl %ecx, -4(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_126bytes):
+ movdqa %xmm0, -126(%rdi)
+L(aligned_16_110bytes):
+ movdqa %xmm0, -110(%rdi)
+L(aligned_16_94bytes):
+ movdqa %xmm0, -94(%rdi)
+L(aligned_16_78bytes):
+ movdqa %xmm0, -78(%rdi)
+L(aligned_16_62bytes):
+ movdqa %xmm0, -62(%rdi)
+L(aligned_16_46bytes):
+ movdqa %xmm0, -46(%rdi)
+L(aligned_16_30bytes):
+ movdqa %xmm0, -30(%rdi)
+L(aligned_16_14bytes):
+ movq %xmm0, -14(%rdi)
+ movl %ecx, -6(%rdi)
+ movw %cx, -2(%rdi)
+ ret
+
+END (MEMSET)
diff --git a/libcutils/arch-x86_64/android_memset32.S b/libcutils/arch-x86_64/android_memset32.S
new file mode 100644
index 0000000..1514aa2
--- /dev/null
+++ b/libcutils/arch-x86_64/android_memset32.S
@@ -0,0 +1,373 @@
+/*
+ * 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 "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 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 JMPTBL(I, B) I - B
+
+/* Branch to an entry in a jump table. TABLE is a jump table with
+ relative offsets. INDEX is a register contains the index into the
+ jump table. SCALE is the scale of INDEX. */
+#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \
+ lea TABLE(%rip), %r11; \
+ movslq (%r11, INDEX, SCALE), INDEX; \
+ lea (%r11, INDEX), INDEX; \
+ jmp *INDEX
+
+ .section .text.sse2,"ax",@progbits
+ ALIGN (4)
+ENTRY (MEMSET) // Address in rdi
+ shr $2, %rdx // Count in rdx
+ movl %esi, %ecx // Pattern in ecx
+
+ cmp $16, %rdx
+ jae L(16dbwordsormore)
+
+L(write_less16dbwords):
+ lea (%rdi, %rdx, 4), %rdi
+ BRANCH_TO_JMPTBL_ENTRY (L(table_less16dbwords), %rdx, 4)
+
+ .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 %ecx, -60(%rdi)
+L(write_14dbwords):
+ movl %ecx, -56(%rdi)
+L(write_13dbwords):
+ movl %ecx, -52(%rdi)
+L(write_12dbwords):
+ movl %ecx, -48(%rdi)
+L(write_11dbwords):
+ movl %ecx, -44(%rdi)
+L(write_10dbwords):
+ movl %ecx, -40(%rdi)
+L(write_9dbwords):
+ movl %ecx, -36(%rdi)
+L(write_8dbwords):
+ movl %ecx, -32(%rdi)
+L(write_7dbwords):
+ movl %ecx, -28(%rdi)
+L(write_6dbwords):
+ movl %ecx, -24(%rdi)
+L(write_5dbwords):
+ movl %ecx, -20(%rdi)
+L(write_4dbwords):
+ movl %ecx, -16(%rdi)
+L(write_3dbwords):
+ movl %ecx, -12(%rdi)
+L(write_2dbwords):
+ movl %ecx, -8(%rdi)
+L(write_1dbwords):
+ movl %ecx, -4(%rdi)
+L(write_0dbwords):
+ ret
+
+ ALIGN (4)
+L(16dbwordsormore):
+ test $3, %edi
+ jz L(aligned4bytes)
+ mov %ecx, (%rdi)
+ mov %ecx, -4(%rdi, %rdx, 4)
+ sub $1, %rdx
+ rol $24, %ecx
+ add $1, %rdi
+ test $3, %edi
+ jz L(aligned4bytes)
+ ror $8, %ecx
+ add $1, %rdi
+ test $3, %edi
+ jz L(aligned4bytes)
+ ror $8, %ecx
+ add $1, %rdi
+L(aligned4bytes):
+ shl $2, %rdx
+
+ /* Fill xmm0 with the pattern. */
+ movd %ecx, %xmm0
+ pshufd $0, %xmm0, %xmm0
+
+ testl $0xf, %edi
+ jz L(aligned_16)
+/* RDX > 32 and RDI is not 16 byte aligned. */
+ movdqu %xmm0, (%rdi)
+ mov %rdi, %rsi
+ and $-16, %rdi
+ add $16, %rdi
+ sub %rdi, %rsi
+ add %rsi, %rdx
+
+ ALIGN (4)
+L(aligned_16):
+ cmp $128, %rdx
+ jge L(128bytesormore)
+
+L(aligned_16_less128bytes):
+ add %rdx, %rdi
+ shr $2, %rdx
+ BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+ ALIGN (4)
+L(128bytesormore):
+ cmp $SHARED_CACHE_SIZE, %rdx
+ jg L(128bytesormore_nt)
+
+L(128bytesormore_normal):
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jl L(128bytesless_normal)
+
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jl L(128bytesless_normal)
+
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jl L(128bytesless_normal)
+
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jge L(128bytesormore_normal)
+
+L(128bytesless_normal):
+ add %rdx, %rdi
+ shr $2, %rdx
+ BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+ ALIGN (4)
+L(128bytesormore_nt):
+ sub $128, %rdx
+ movntdq %xmm0, (%rdi)
+ movntdq %xmm0, 0x10(%rdi)
+ movntdq %xmm0, 0x20(%rdi)
+ movntdq %xmm0, 0x30(%rdi)
+ movntdq %xmm0, 0x40(%rdi)
+ movntdq %xmm0, 0x50(%rdi)
+ movntdq %xmm0, 0x60(%rdi)
+ movntdq %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jge L(128bytesormore_nt)
+
+ sfence
+ add %rdx, %rdi
+ shr $2, %rdx
+ BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+ .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(%rdi)
+L(aligned_16_96bytes):
+ movdqa %xmm0, -96(%rdi)
+L(aligned_16_80bytes):
+ movdqa %xmm0, -80(%rdi)
+L(aligned_16_64bytes):
+ movdqa %xmm0, -64(%rdi)
+L(aligned_16_48bytes):
+ movdqa %xmm0, -48(%rdi)
+L(aligned_16_32bytes):
+ movdqa %xmm0, -32(%rdi)
+L(aligned_16_16bytes):
+ movdqa %xmm0, -16(%rdi)
+L(aligned_16_0bytes):
+ ret
+
+ ALIGN (4)
+L(aligned_16_116bytes):
+ movdqa %xmm0, -116(%rdi)
+L(aligned_16_100bytes):
+ movdqa %xmm0, -100(%rdi)
+L(aligned_16_84bytes):
+ movdqa %xmm0, -84(%rdi)
+L(aligned_16_68bytes):
+ movdqa %xmm0, -68(%rdi)
+L(aligned_16_52bytes):
+ movdqa %xmm0, -52(%rdi)
+L(aligned_16_36bytes):
+ movdqa %xmm0, -36(%rdi)
+L(aligned_16_20bytes):
+ movdqa %xmm0, -20(%rdi)
+L(aligned_16_4bytes):
+ movl %ecx, -4(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_120bytes):
+ movdqa %xmm0, -120(%rdi)
+L(aligned_16_104bytes):
+ movdqa %xmm0, -104(%rdi)
+L(aligned_16_88bytes):
+ movdqa %xmm0, -88(%rdi)
+L(aligned_16_72bytes):
+ movdqa %xmm0, -72(%rdi)
+L(aligned_16_56bytes):
+ movdqa %xmm0, -56(%rdi)
+L(aligned_16_40bytes):
+ movdqa %xmm0, -40(%rdi)
+L(aligned_16_24bytes):
+ movdqa %xmm0, -24(%rdi)
+L(aligned_16_8bytes):
+ movq %xmm0, -8(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_124bytes):
+ movdqa %xmm0, -124(%rdi)
+L(aligned_16_108bytes):
+ movdqa %xmm0, -108(%rdi)
+L(aligned_16_92bytes):
+ movdqa %xmm0, -92(%rdi)
+L(aligned_16_76bytes):
+ movdqa %xmm0, -76(%rdi)
+L(aligned_16_60bytes):
+ movdqa %xmm0, -60(%rdi)
+L(aligned_16_44bytes):
+ movdqa %xmm0, -44(%rdi)
+L(aligned_16_28bytes):
+ movdqa %xmm0, -28(%rdi)
+L(aligned_16_12bytes):
+ movq %xmm0, -12(%rdi)
+ movl %ecx, -4(%rdi)
+ ret
+
+END (MEMSET)
diff --git a/libnl_2/cache.c b/libcutils/arch-x86_64/cache.h
similarity index 62%
rename from libnl_2/cache.c
rename to libcutils/arch-x86_64/cache.h
index c21974d..f144309 100644
--- a/libnl_2/cache.c
+++ b/libcutils/arch-x86_64/cache.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * 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.
@@ -14,24 +14,9 @@
* limitations under the License.
*/
-/* NOTICE: This is a clean room re-implementation of libnl */
+/* Values are optimized for Silvermont */
+#define SHARED_CACHE_SIZE (1024*1024) /* Silvermont L2 Cache */
+#define DATA_CACHE_SIZE (24*1024) /* Silvermont L1 Data Cache */
-#include "netlink/cache.h"
-#include "netlink/object.h"
-
-void nl_cache_free(struct nl_cache *cache)
-{
-
-}
-
-void nl_cache_clear(struct nl_cache *cache)
-{
-
-}
-
-void nl_cache_remove(struct nl_object *obj)
-{
-
-}
-
-
+#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 7873964..4ac4f57 100644
--- a/libcutils/ashmem-host.c
+++ b/libcutils/ashmem-host.c
@@ -22,6 +22,8 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
+#include <pthread.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -36,83 +38,83 @@
#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;
+ 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)))]);
- srand(time(NULL) + pid);
-
-retry:
- /* 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)
- goto retry;
- return -1;
- }
-
- /* truncate the file to `len' bytes */
- if (ftruncate(fd, size) == -1)
- goto error;
-
- if (unlink(name) == -1)
- goto error;
-
- return fd;
-error:
- close(fd);
- return -1;
+ /* 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) {
+ return fd;
+ }
+ close(fd);
+ return -1;
}
int ashmem_set_prot_region(int fd __unused, int prot __unused)
{
- return 0;
+ return 0;
}
int ashmem_pin_region(int fd __unused, size_t offset __unused, size_t len __unused)
{
- return ASHMEM_NOT_PURGED;
+ return ASHMEM_NOT_PURGED;
}
int ashmem_unpin_region(int fd __unused, size_t offset __unused, size_t len __unused)
{
- return ASHMEM_IS_UNPINNED;
+ return ASHMEM_IS_UNPINNED;
}
int ashmem_get_size_region(int fd)
{
- struct stat buf;
- int result;
+ struct stat buf;
+ int result;
- result = fstat(fd, &buf);
- if (result == -1) {
- return -1;
- }
+ result = fstat(fd, &buf);
+ if (result == -1) {
+ return -1;
+ }
- // Check if this is an "ashmem" region.
- // TODO: This is very hacky, and can easily break. We need some reliable indicator.
- if (!(buf.st_nlink == 0 && S_ISREG(buf.st_mode))) {
- errno = ENOTTY;
- return -1;
- }
+ // Check if this is an "ashmem" region.
+ // TODO: This is very hacky, and can easily break. We need some reliable indicator.
+ if (!(buf.st_nlink == 0 && S_ISREG(buf.st_mode))) {
+ errno = ENOTTY;
+ return -1;
+ }
- return (int)buf.st_size; // TODO: care about overflow (> 2GB file)?
+ return (int)buf.st_size; // TODO: care about overflow (> 2GB file)?
}
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/debugger.c b/libcutils/debugger.c
index 056de5d..4035ee1 100644
--- a/libcutils/debugger.c
+++ b/libcutils/debugger.c
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#include <stdbool.h>
+#include <fcntl.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -21,70 +24,129 @@
#include <cutils/debugger.h>
#include <cutils/sockets.h>
-int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen) {
- int s = socket_local_client(DEBUGGER_SOCKET_NAME,
- ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
- if (s < 0) {
- return -1;
- }
+#if defined(__LP64__)
+#include <elf.h>
- debugger_msg_t msg;
- memset(&msg, 0, sizeof(msg));
+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) {
+ result = -1;
+ } else {
+ char ack;
+ if (TEMP_FAILURE_RETRY(read(sock_fd, &ack, 1)) != 1) {
+ result = -1;
+ }
+ }
+ return result;
+}
+
+static int make_dump_request(debugger_action_t action, pid_t tid) {
+ const char* socket_name;
+ debugger_msg_t msg;
+ size_t msg_len;
+ void* msg_ptr;
+
+#if defined(__LP64__)
+ debugger32_msg_t msg32;
+ if (is32bit(tid)) {
+ msg_len = sizeof(debugger32_msg_t);
+ memset(&msg32, 0, msg_len);
+ msg32.tid = tid;
+ msg32.action = action;
+ msg_ptr = &msg32;
+
+ socket_name = DEBUGGER32_SOCKET_NAME;
+ } else
+#endif
+ {
+ msg_len = sizeof(debugger_msg_t);
+ memset(&msg, 0, msg_len);
msg.tid = tid;
- msg.action = DEBUGGER_ACTION_DUMP_TOMBSTONE;
+ msg.action = action;
+ msg_ptr = &msg;
- int result = 0;
- if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
- result = -1;
- } else {
- char ack;
- if (TEMP_FAILURE_RETRY(read(s, &ack, 1)) != 1) {
- result = -1;
- } else {
- if (pathbuf && pathlen) {
- ssize_t n = TEMP_FAILURE_RETRY(read(s, pathbuf, pathlen - 1));
- if (n <= 0) {
- result = -1;
- } else {
- pathbuf[n] = '\0';
- }
- }
- }
- }
- TEMP_FAILURE_RETRY(close(s));
- return result;
+ socket_name = DEBUGGER_SOCKET_NAME;
+ }
+
+ int sock_fd = socket_local_client(socket_name, ANDROID_SOCKET_NAMESPACE_ABSTRACT,
+ SOCK_STREAM | SOCK_CLOEXEC);
+ if (sock_fd < 0) {
+ return -1;
+ }
+
+ if (send_request(sock_fd, msg_ptr, msg_len) < 0) {
+ TEMP_FAILURE_RETRY(close(sock_fd));
+ return -1;
+ }
+
+ return sock_fd;
}
int dump_backtrace_to_file(pid_t tid, int fd) {
- int s = socket_local_client(DEBUGGER_SOCKET_NAME,
- ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
- if (s < 0) {
- return -1;
- }
+ int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_BACKTRACE, tid);
+ if (sock_fd < 0) {
+ return -1;
+ }
- debugger_msg_t msg;
- memset(&msg, 0, sizeof(msg));
- msg.tid = tid;
- msg.action = DEBUGGER_ACTION_DUMP_BACKTRACE;
-
- int result = 0;
- if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
- result = -1;
- } else {
- char ack;
- if (TEMP_FAILURE_RETRY(read(s, &ack, 1)) != 1) {
- result = -1;
- } else {
- char buffer[4096];
- ssize_t n;
- while ((n = TEMP_FAILURE_RETRY(read(s, buffer, sizeof(buffer)))) > 0) {
- if (TEMP_FAILURE_RETRY(write(fd, buffer, n)) != n) {
- result = -1;
- break;
- }
- }
- }
+ /* Write the data read from the socket to the fd. */
+ int result = 0;
+ char buffer[1024];
+ ssize_t n;
+ while ((n = TEMP_FAILURE_RETRY(read(sock_fd, buffer, sizeof(buffer)))) > 0) {
+ if (TEMP_FAILURE_RETRY(write(fd, buffer, n)) != n) {
+ result = -1;
+ break;
}
- TEMP_FAILURE_RETRY(close(s));
- return result;
+ }
+ TEMP_FAILURE_RETRY(close(sock_fd));
+ return result;
+}
+
+int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen) {
+ int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_TOMBSTONE, tid);
+ if (sock_fd < 0) {
+ return -1;
+ }
+
+ /* Read the tombstone file name. */
+ char buffer[100]; /* This is larger than the largest tombstone path. */
+ int result = 0;
+ ssize_t n = TEMP_FAILURE_RETRY(read(sock_fd, buffer, sizeof(buffer) - 1));
+ if (n <= 0) {
+ result = -1;
+ } else {
+ if (pathbuf && pathlen) {
+ if (n >= (ssize_t) pathlen) {
+ n = pathlen - 1;
+ }
+ buffer[n] = '\0';
+ memcpy(pathbuf, buffer, n + 1);
+ }
+ }
+ TEMP_FAILURE_RETRY(close(sock_fd));
+ return result;
}
diff --git a/libcutils/dlmalloc_stubs.c b/libcutils/dlmalloc_stubs.c
index 6dca911..2db473d 100644
--- a/libcutils/dlmalloc_stubs.c
+++ b/libcutils/dlmalloc_stubs.c
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include "../../../bionic/libc/bionic/dlmalloc.h"
#include "log/log.h"
#define UNUSED __attribute__((__unused__))
diff --git a/libcutils/fs.c b/libcutils/fs.c
index 286a8eb..45c7add 100644
--- a/libcutils/fs.c
+++ b/libcutils/fs.c
@@ -212,7 +212,7 @@
/* Yay, segment is ready for us to step into */
int next_fd;
- if ((next_fd = openat(fd, segment, 0)) == -1) {
+ if ((next_fd = openat(fd, segment, O_NOFOLLOW | O_CLOEXEC)) == -1) {
ALOGE("Failed to openat(%s): %s", buf, strerror(errno));
res = -errno;
goto done_close;
diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c
index 67e101d..a6da9ca 100644
--- a/libcutils/iosched_policy.c
+++ b/libcutils/iosched_policy.c
@@ -21,31 +21,19 @@
#include <string.h>
#include <unistd.h>
-#ifdef HAVE_SCHED_H
-
#include <cutils/iosched_policy.h>
#ifdef HAVE_ANDROID_OS
-/* #include <linux/ioprio.h> */
-extern int ioprio_set(int which, int who, int ioprio);
-extern int ioprio_get(int which, int who);
+#include <linux/ioprio.h>
+#include <sys/syscall.h>
#define __android_unused
#else
#define __android_unused __attribute__((__unused__))
#endif
-enum {
- WHO_PROCESS = 1,
- WHO_PGRP,
- WHO_USER,
-};
-
-#define CLASS_SHIFT 13
-#define IOPRIO_NORM 4
-
int android_set_ioprio(int pid __android_unused, IoSchedClass clazz __android_unused, int ioprio __android_unused) {
#ifdef HAVE_ANDROID_OS
- if (ioprio_set(WHO_PROCESS, pid, ioprio | (clazz << CLASS_SHIFT))) {
+ if (syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, ioprio | (clazz << IOPRIO_CLASS_SHIFT))) {
return -1;
}
#endif
@@ -56,11 +44,11 @@
#ifdef HAVE_ANDROID_OS
int rc;
- if ((rc = ioprio_get(WHO_PROCESS, pid)) < 0) {
+ if ((rc = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, pid)) < 0) {
return -1;
}
- *clazz = (rc >> CLASS_SHIFT);
+ *clazz = (rc >> IOPRIO_CLASS_SHIFT);
*ioprio = (rc & 0xff);
#else
*clazz = IoSchedClass_NONE;
@@ -68,5 +56,3 @@
#endif
return 0;
}
-
-#endif /* HAVE_SCHED_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/properties.c b/libcutils/properties.c
index 28d8b2f..b283658 100644
--- a/libcutils/properties.c
+++ b/libcutils/properties.c
@@ -15,17 +15,95 @@
*/
#define LOG_TAG "properties"
+// #define LOG_NDEBUG 0
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include <unistd.h>
#include <cutils/sockets.h>
#include <errno.h>
#include <assert.h>
#include <cutils/properties.h>
+#include <stdbool.h>
+#include <inttypes.h>
#include "loghack.h"
+int8_t property_get_bool(const char *key, int8_t default_value) {
+ if (!key) {
+ return default_value;
+ }
+
+ int8_t result = default_value;
+ char buf[PROPERTY_VALUE_MAX] = {'\0',};
+
+ int len = property_get(key, buf, "");
+ if (len == 1) {
+ char ch = buf[0];
+ if (ch == '0' || ch == 'n') {
+ result = false;
+ } else if (ch == '1' || ch == 'y') {
+ result = true;
+ }
+ } else if (len > 1) {
+ if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
+ result = false;
+ } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+// Convert string property to int (default if fails); return default value if out of bounds
+static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound,
+ intmax_t default_value) {
+ if (!key) {
+ return default_value;
+ }
+
+ intmax_t result = default_value;
+ char buf[PROPERTY_VALUE_MAX] = {'\0',};
+ char *end = NULL;
+
+ int len = property_get(key, buf, "");
+ if (len > 0) {
+ int tmp = errno;
+ errno = 0;
+
+ // Infer base automatically
+ result = strtoimax(buf, &end, /*base*/0);
+ if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) {
+ // Over or underflow
+ result = default_value;
+ ALOGV("%s(%s,%" PRIdMAX ") - overflow", __FUNCTION__, key, default_value);
+ } else if (result < lower_bound || result > upper_bound) {
+ // Out of range of requested bounds
+ result = default_value;
+ ALOGV("%s(%s,%" PRIdMAX ") - out of range", __FUNCTION__, key, default_value);
+ } else if (end == buf) {
+ // Numeric conversion failed
+ result = default_value;
+ ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed",
+ __FUNCTION__, key, default_value);
+ }
+
+ errno = tmp;
+ }
+
+ return result;
+}
+
+int64_t property_get_int64(const char *key, int64_t default_value) {
+ return (int64_t)property_get_imax(key, INT64_MIN, INT64_MAX, default_value);
+}
+
+int32_t property_get_int32(const char *key, int32_t default_value) {
+ return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value);
+}
+
#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
@@ -44,10 +122,13 @@
if(len > 0) {
return len;
}
-
if(default_value) {
len = strlen(default_value);
- memcpy(value, default_value, len + 1);
+ if (len >= PROPERTY_VALUE_MAX) {
+ len = PROPERTY_VALUE_MAX - 1;
+ }
+ memcpy(value, default_value, len);
+ value[len] = '\0';
}
return len;
}
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 9f092d6..d3cedd4 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -39,21 +39,20 @@
#if defined(HAVE_ANDROID_OS) && defined(HAVE_SCHED_H) && defined(HAVE_PTHREADS)
-#include <sched.h>
#include <pthread.h>
-
-#ifndef SCHED_NORMAL
- #define SCHED_NORMAL 0
-#endif
-
-#ifndef SCHED_BATCH
- #define SCHED_BATCH 3
-#endif
+#include <sched.h>
+#include <sys/prctl.h>
#define POLICY_DEBUG 0
#define CAN_SET_SP_SYSTEM 0 // non-zero means to implement set_sched_policy(tid, SP_SYSTEM)
+// This prctl is only available in Android kernels.
+#define PR_SET_TIMERSLACK_PID 41
+
+// timer slack value in nS enforced when the thread moves to background
+#define TIMER_SLACK_BG 40000000
+
static pthread_once_t the_once = PTHREAD_ONCE_INIT;
static int __sys_supports_schedgroups = -1;
@@ -222,11 +221,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) {
@@ -261,11 +258,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);
@@ -325,6 +320,8 @@
¶m);
}
+ prctl(PR_SET_TIMERSLACK_PID, policy == SP_BACKGROUND ? TIMER_SLACK_BG : 0, tid);
+
return 0;
}
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 c52013d..e0031ba 100644
--- a/libcutils/socket_network_client.c
+++ b/libcutils/socket_network_client.c
@@ -15,18 +15,17 @@
*/
#include <errno.h>
+#include <fcntl.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#ifndef HAVE_WINSOCK
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
-#endif
#include <cutils/sockets.h>
@@ -36,27 +35,91 @@
*/
int socket_network_client(const char *host, int port, int type)
{
+ return socket_network_client_timeout(host, port, type, 0);
+}
+
+/* Connect to port on the IP interface. type is SOCK_STREAM or SOCK_DGRAM.
+ * timeout in seconds return is a file descriptor or -1 on error
+ */
+int socket_network_client_timeout(const char *host, int port, int type, int timeout)
+{
struct hostent *hp;
struct sockaddr_in addr;
int s;
+ int flags = 0, error = 0, ret = 0;
+ fd_set rset, wset;
+ socklen_t len = sizeof(error);
+ struct timeval ts;
+
+ ts.tv_sec = timeout;
+ ts.tv_usec = 0;
hp = gethostbyname(host);
- if(hp == 0) return -1;
-
+ if (hp == 0) return -1;
+
memset(&addr, 0, sizeof(addr));
addr.sin_family = hp->h_addrtype;
addr.sin_port = htons(port);
memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
s = socket(hp->h_addrtype, type, 0);
- if(s < 0) return -1;
+ if (s < 0) return -1;
- if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ if ((flags = fcntl(s, F_GETFL, 0)) < 0) {
+ close(s);
+ return -1;
+ }
+
+ if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
+ close(s);
+ return -1;
+ }
+
+ if ((ret = connect(s, (struct sockaddr *) &addr, sizeof(addr))) < 0) {
+ if (errno != EINPROGRESS) {
+ close(s);
+ return -1;
+ }
+ }
+
+ if (ret == 0)
+ goto done;
+
+ FD_ZERO(&rset);
+ FD_SET(s, &rset);
+ wset = rset;
+
+ if ((ret = select(s + 1, &rset, &wset, NULL, (timeout) ? &ts : NULL)) < 0) {
+ close(s);
+ return -1;
+ }
+ if (ret == 0) { // we had a timeout
+ errno = ETIMEDOUT;
+ close(s);
+ return -1;
+ }
+
+ if (FD_ISSET(s, &rset) || FD_ISSET(s, &wset)) {
+ if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
+ close(s);
+ return -1;
+ }
+ } else {
+ close(s);
+ return -1;
+ }
+
+ if (error) { // check if we had a socket error
+ errno = error;
+ close(s);
+ return -1;
+ }
+
+done:
+ if (fcntl(s, F_SETFL, flags) < 0) {
close(s);
return -1;
}
return s;
-
}
-
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
index 2e3ce9f..dfe8c4b 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.c
@@ -262,6 +262,10 @@
return ret;
}
+int str_parms_has_key(struct str_parms *str_parms, const char *key) {
+ return hashmapGet(str_parms->map, (void *)key) != NULL;
+}
+
int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val,
int len)
{
diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk
new file mode 100644
index 0000000..5a54698
--- /dev/null
+++ b/libcutils/tests/Android.mk
@@ -0,0 +1,52 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+test_src_files := \
+ MemsetTest.cpp \
+ PropertiesTest.cpp \
+
+include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_MODULE := libcutils_test
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ liblog \
+ libutils \
+
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_NATIVE_TEST)
+
+# The static libcutils tests cannot be built when using libc++ because there are
+# multiple symbol definition errors between libc++ and libgcc. b/18389856
+#include $(CLEAR_VARS)
+#LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+#LOCAL_MODULE := libcutils_test_static
+#LOCAL_FORCE_STATIC_EXECUTABLE := true
+#LOCAL_SRC_FILES := $(test_src_files)
+#LOCAL_STATIC_LIBRARIES := \
+# libc \
+# libcutils \
+# liblog \
+# libutils \
+
+#LOCAL_CXX_STL := stlport_static
+#LOCAL_MULTILIB := both
+#LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+#LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+#include $(BUILD_NATIVE_TEST)
diff --git a/libcutils/tests/MemsetTest.cpp b/libcutils/tests/MemsetTest.cpp
new file mode 100644
index 0000000..45efc51
--- /dev/null
+++ b/libcutils/tests/MemsetTest.cpp
@@ -0,0 +1,181 @@
+/*
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <cutils/memory.h>
+#include <gtest/gtest.h>
+
+#define FENCEPOST_LENGTH 8
+
+#define MAX_TEST_SIZE (64*1024)
+// Choose values that have no repeating byte values.
+#define MEMSET16_PATTERN 0xb139
+#define MEMSET32_PATTERN 0x48193a27
+
+enum test_e {
+ MEMSET16 = 0,
+ MEMSET32,
+};
+
+static int g_memset16_aligns[][2] = {
+ { 2, 0 },
+ { 4, 0 },
+ { 8, 0 },
+ { 16, 0 },
+ { 32, 0 },
+ { 64, 0 },
+ { 128, 0 },
+
+ { 4, 2 },
+
+ { 8, 2 },
+ { 8, 4 },
+ { 8, 6 },
+
+ { 128, 2 },
+ { 128, 4 },
+ { 128, 6 },
+ { 128, 8 },
+ { 128, 10 },
+ { 128, 12 },
+ { 128, 14 },
+ { 128, 16 },
+};
+
+static int g_memset32_aligns[][2] = {
+ { 4, 0 },
+ { 8, 0 },
+ { 16, 0 },
+ { 32, 0 },
+ { 64, 0 },
+ { 128, 0 },
+
+ { 8, 4 },
+
+ { 128, 4 },
+ { 128, 8 },
+ { 128, 12 },
+ { 128, 16 },
+};
+
+static size_t GetIncrement(size_t len, size_t min_incr) {
+ if (len >= 4096) {
+ return 1024;
+ } else if (len >= 1024) {
+ return 256;
+ }
+ return min_incr;
+}
+
+// Return a pointer into the current buffer with the specified alignment.
+static void *GetAlignedPtr(void *orig_ptr, int alignment, int or_mask) {
+ uint64_t ptr = reinterpret_cast<uint64_t>(orig_ptr);
+ if (alignment > 0) {
+ // When setting the alignment, set it to exactly the alignment chosen.
+ // The pointer returned will be guaranteed not to be aligned to anything
+ // more than that.
+ ptr += alignment - (ptr & (alignment - 1));
+ ptr |= alignment | or_mask;
+ }
+
+ return reinterpret_cast<void*>(ptr);
+}
+
+static void SetFencepost(uint8_t *buffer) {
+ for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
+ buffer[i] = 0xde;
+ buffer[i+1] = 0xad;
+ }
+}
+
+static void VerifyFencepost(uint8_t *buffer) {
+ for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
+ if (buffer[i] != 0xde || buffer[i+1] != 0xad) {
+ uint8_t expected_value;
+ if (buffer[i] == 0xde) {
+ i++;
+ expected_value = 0xad;
+ } else {
+ expected_value = 0xde;
+ }
+ ASSERT_EQ(expected_value, buffer[i]);
+ }
+ }
+}
+
+void RunMemsetTests(test_e test_type, uint32_t value, int align[][2], size_t num_aligns) {
+ size_t min_incr = 4;
+ if (test_type == MEMSET16) {
+ min_incr = 2;
+ value |= value << 16;
+ }
+ uint32_t* expected_buf = new uint32_t[MAX_TEST_SIZE/sizeof(uint32_t)];
+ for (size_t i = 0; i < MAX_TEST_SIZE/sizeof(uint32_t); i++) {
+ expected_buf[i] = value;
+ }
+
+ // Allocate one large buffer with lots of extra space so that we can
+ // guarantee that all possible alignments will fit.
+ uint8_t *buf = new uint8_t[3*MAX_TEST_SIZE];
+ uint8_t *buf_align;
+ for (size_t i = 0; i < num_aligns; i++) {
+ size_t incr = min_incr;
+ for (size_t len = incr; len <= MAX_TEST_SIZE; len += incr) {
+ incr = GetIncrement(len, min_incr);
+
+ buf_align = reinterpret_cast<uint8_t*>(GetAlignedPtr(
+ buf+FENCEPOST_LENGTH, align[i][0], align[i][1]));
+
+ SetFencepost(&buf_align[-FENCEPOST_LENGTH]);
+ SetFencepost(&buf_align[len]);
+
+ memset(buf_align, 0xff, len);
+ if (test_type == MEMSET16) {
+ android_memset16(reinterpret_cast<uint16_t*>(buf_align), value, len);
+ } else {
+ android_memset32(reinterpret_cast<uint32_t*>(buf_align), value, len);
+ }
+ ASSERT_EQ(0, memcmp(expected_buf, buf_align, len))
+ << "Failed size " << len << " align " << align[i][0] << " " << align[i][1] << "\n";
+
+ VerifyFencepost(&buf_align[-FENCEPOST_LENGTH]);
+ VerifyFencepost(&buf_align[len]);
+ }
+ }
+ delete expected_buf;
+ delete buf;
+}
+
+TEST(libcutils, android_memset16_non_zero) {
+ RunMemsetTests(MEMSET16, MEMSET16_PATTERN, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2]));
+}
+
+TEST(libcutils, android_memset16_zero) {
+ RunMemsetTests(MEMSET16, 0, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2]));
+}
+
+TEST(libcutils, android_memset32_non_zero) {
+ RunMemsetTests(MEMSET32, MEMSET32_PATTERN, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2]));
+}
+
+TEST(libcutils, android_memset32_zero) {
+ RunMemsetTests(MEMSET32, 0, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2]));
+}
diff --git a/libcutils/tests/PropertiesTest.cpp b/libcutils/tests/PropertiesTest.cpp
new file mode 100644
index 0000000..659821c
--- /dev/null
+++ b/libcutils/tests/PropertiesTest.cpp
@@ -0,0 +1,309 @@
+/*
+ * 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 LOG_TAG "Properties_test"
+#include <utils/Log.h>
+#include <gtest/gtest.h>
+
+#include <cutils/properties.h>
+#include <limits.h>
+#include <string>
+#include <sstream>
+#include <iostream>
+
+namespace android {
+
+#define STRINGIFY_INNER(x) #x
+#define STRINGIFY(x) STRINGIFY_INNER(x)
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+#define ASSERT_OK(x) ASSERT_EQ(0, (x))
+#define EXPECT_OK(x) EXPECT_EQ(0, (x))
+
+#define PROPERTY_TEST_KEY "libcutils.test.key"
+#define PROPERTY_TEST_VALUE_DEFAULT "<<<default_value>>>"
+
+template <typename T>
+static std::string HexString(T value) {
+ std::stringstream ss;
+ ss << "0x" << std::hex << std::uppercase << value;
+ return ss.str();
+}
+
+template <typename T>
+static ::testing::AssertionResult AssertEqualHex(const char *mExpr,
+ const char *nExpr,
+ T m,
+ T n) {
+ if (m == n) {
+ return ::testing::AssertionSuccess();
+ }
+
+ return ::testing::AssertionFailure()
+ << mExpr << " and " << nExpr << " (expected: " << HexString(m) <<
+ ", actual: " << HexString(n) << ") are not equal";
+}
+
+class PropertiesTest : public testing::Test {
+public:
+ PropertiesTest() : mValue() {}
+protected:
+ virtual void SetUp() {
+ EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
+ }
+
+ virtual void TearDown() {
+ EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
+ }
+
+ char mValue[PROPERTY_VALUE_MAX];
+
+ template <typename T>
+ static std::string ToString(T value) {
+ std::stringstream ss;
+ ss << value;
+
+ return ss.str();
+ }
+
+ // Return length of property read; value is written into mValue
+ int SetAndGetProperty(const char* value, const char* defaultValue = PROPERTY_TEST_VALUE_DEFAULT) {
+ EXPECT_OK(property_set(PROPERTY_TEST_KEY, value)) << "value: '" << value << "'";
+ return property_get(PROPERTY_TEST_KEY, mValue, defaultValue);
+ }
+
+ void ResetValue(unsigned char c = 0xFF) {
+ for (size_t i = 0; i < ARRAY_SIZE(mValue); ++i) {
+ mValue[i] = (char) c;
+ }
+ }
+};
+
+TEST_F(PropertiesTest, SetString) {
+
+ // Null key -> unsuccessful set
+ {
+ // Null key -> fails
+ EXPECT_GT(0, property_set(/*key*/NULL, PROPERTY_TEST_VALUE_DEFAULT));
+ }
+
+ // Null value -> returns default value
+ {
+ // Null value -> OK , and it clears the value
+ EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
+ ResetValue();
+
+ // Since the value is null, default value will be returned
+ int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+ EXPECT_EQ(strlen(PROPERTY_TEST_VALUE_DEFAULT), len);
+ EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue);
+ }
+
+ // Trivial case => get returns what was set
+ {
+ int len = SetAndGetProperty("hello_world");
+ EXPECT_EQ(strlen("hello_world"), len) << "hello_world key";
+ EXPECT_STREQ("hello_world", mValue);
+ ResetValue();
+ }
+
+ // Set to empty string => get returns default always
+ {
+ const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING";
+ int len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
+ EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key";
+ EXPECT_STREQ(EMPTY_STRING_DEFAULT, mValue);
+ ResetValue();
+ }
+
+ // Set to max length => get returns what was set
+ {
+ std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a');
+
+ int len = SetAndGetProperty(maxLengthString.c_str());
+ EXPECT_EQ(PROPERTY_VALUE_MAX-1, len) << "max length key";
+ EXPECT_STREQ(maxLengthString.c_str(), mValue);
+ ResetValue();
+ }
+
+ // Set to max length + 1 => set fails
+ {
+ const char* VALID_TEST_VALUE = "VALID_VALUE";
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, VALID_TEST_VALUE));
+
+ std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
+
+ // Expect that the value set fails since it's too long
+ EXPECT_GT(0, property_set(PROPERTY_TEST_KEY, oneLongerString.c_str()));
+ int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+
+ EXPECT_EQ(strlen(VALID_TEST_VALUE), len) << "set should've failed";
+ EXPECT_STREQ(VALID_TEST_VALUE, mValue);
+ ResetValue();
+ }
+}
+
+TEST_F(PropertiesTest, GetString) {
+
+ // Try to use a default value that's too long => set fails
+ {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+ std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a');
+ std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
+
+ // Expect that the value is truncated since it's too long (by 1)
+ int len = property_get(PROPERTY_TEST_KEY, mValue, oneLongerString.c_str());
+ EXPECT_EQ(PROPERTY_VALUE_MAX-1, len);
+ EXPECT_STREQ(maxLengthString.c_str(), mValue);
+ ResetValue();
+ }
+}
+
+TEST_F(PropertiesTest, GetBool) {
+ /**
+ * TRUE
+ */
+ const char *valuesTrue[] = { "1", "true", "y", "yes", "on", };
+ for (size_t i = 0; i < ARRAY_SIZE(valuesTrue); ++i) {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesTrue[i]));
+ bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
+ EXPECT_TRUE(val) << "Property should've been TRUE for value: '" << valuesTrue[i] << "'";
+ }
+
+ /**
+ * FALSE
+ */
+ const char *valuesFalse[] = { "0", "false", "n", "no", "off", };
+ for (size_t i = 0; i < ARRAY_SIZE(valuesFalse); ++i) {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesFalse[i]));
+ bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
+ EXPECT_FALSE(val) << "Property shoud've been FALSE For string value: '" << valuesFalse[i] << "'";
+ }
+
+ /**
+ * NEITHER
+ */
+ const char *valuesNeither[] = { "x0", "x1", "2", "-2", "True", "False", "garbage", "", " ",
+ "+1", " 1 ", " true", " true ", " y ", " yes", "yes ",
+ "+0", "-0", "00", " 00 ", " false", "false ",
+ };
+ for (size_t i = 0; i < ARRAY_SIZE(valuesNeither); ++i) {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesNeither[i]));
+
+ // The default value should always be used
+ bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
+ EXPECT_TRUE(val) << "Property should've been NEITHER (true) for string value: '" << valuesNeither[i] << "'";
+
+ val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
+ EXPECT_FALSE(val) << "Property should've been NEITHER (false) for string value: '" << valuesNeither[i] << "'";
+ }
+}
+
+TEST_F(PropertiesTest, GetInt64) {
+ const int64_t DEFAULT_VALUE = INT64_C(0xDEADBEEFBEEFDEAD);
+
+ const std::string longMaxString = ToString(INT64_MAX);
+ const std::string longStringOverflow = longMaxString + "0";
+
+ const std::string longMinString = ToString(INT64_MIN);
+ const std::string longStringUnderflow = longMinString + "0";
+
+ const char* setValues[] = {
+ // base 10
+ "1", "2", "12345", "-1", "-2", "-12345",
+ // base 16
+ "0xFF", "0x0FF", "0xC0FFEE",
+ // base 8
+ "0", "01234", "07",
+ // corner cases
+ " 2", "2 ", "+0", "-0", " +0 ", longMaxString.c_str(), longMinString.c_str(),
+ // failing cases
+ NULL, "", " ", " ", "hello", " true ", "y",
+ longStringOverflow.c_str(), longStringUnderflow.c_str(),
+ };
+
+ int64_t getValues[] = {
+ // base 10
+ 1, 2, 12345, -1, -2, -12345,
+ // base 16
+ 0xFF, 0x0FF, 0xC0FFEE,
+ // base 8
+ 0, 01234, 07,
+ // corner cases
+ 2, 2, 0, 0, 0, INT64_MAX, INT64_MIN,
+ // failing cases
+ DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE,
+ DEFAULT_VALUE, DEFAULT_VALUE,
+ };
+
+ ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues));
+
+ for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
+
+ int64_t val = property_get_int64(PROPERTY_TEST_KEY, DEFAULT_VALUE);
+ EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'";
+ }
+}
+
+TEST_F(PropertiesTest, GetInt32) {
+ const int32_t DEFAULT_VALUE = INT32_C(0xDEADBEEF);
+
+ const std::string intMaxString = ToString(INT32_MAX);
+ const std::string intStringOverflow = intMaxString + "0";
+
+ const std::string intMinString = ToString(INT32_MIN);
+ const std::string intStringUnderflow = intMinString + "0";
+
+ const char* setValues[] = {
+ // base 10
+ "1", "2", "12345", "-1", "-2", "-12345",
+ // base 16
+ "0xFF", "0x0FF", "0xC0FFEE", "0Xf00",
+ // base 8
+ "0", "01234", "07",
+ // corner cases
+ " 2", "2 ", "+0", "-0", " +0 ", intMaxString.c_str(), intMinString.c_str(),
+ // failing cases
+ NULL, "", " ", " ", "hello", " true ", "y",
+ intStringOverflow.c_str(), intStringUnderflow.c_str(),
+ };
+
+ int32_t getValues[] = {
+ // base 10
+ 1, 2, 12345, -1, -2, -12345,
+ // base 16
+ 0xFF, 0x0FF, 0xC0FFEE, 0Xf00,
+ // base 8
+ 0, 01234, 07,
+ // corner cases
+ 2, 2, 0, 0, 0, INT32_MAX, INT32_MIN,
+ // failing cases
+ DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE,
+ DEFAULT_VALUE, DEFAULT_VALUE,
+ };
+
+ ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues));
+
+ for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
+
+ int32_t val = property_get_int32(PROPERTY_TEST_KEY, DEFAULT_VALUE);
+ EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'";
+ }
+}
+
+} // namespace android
diff --git a/libcutils/trace.c b/libcutils/trace.c
index f57aac2..4396625 100644
--- a/libcutils/trace.c
+++ b/libcutils/trace.c
@@ -30,6 +30,13 @@
#define LOG_TAG "cutils-trace"
#include <log/log.h>
+/**
+ * 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
+
volatile int32_t atrace_is_ready = 0;
int atrace_marker_fd = -1;
uint64_t atrace_enabled_tags = ATRACE_TAG_NOT_READY;
@@ -183,3 +190,53 @@
{
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/libdiskconfig/Android.mk b/libdiskconfig/Android.mk
index b5d83fa..624e385 100644
--- a/libdiskconfig/Android.mk
+++ b/libdiskconfig/Android.mk
@@ -12,6 +12,7 @@
LOCAL_MODULE := libdiskconfig
LOCAL_MODULE_TAGS := optional
LOCAL_SYSTEM_SHARED_LIBRARIES := libcutils liblog libc
+LOCAL_CFLAGS := -Werror
include $(BUILD_SHARED_LIBRARY)
ifeq ($(HOST_OS),linux)
diff --git a/libdiskconfig/config_mbr.c b/libdiskconfig/config_mbr.c
index 7641b29..7b6ca1c 100644
--- a/libdiskconfig/config_mbr.c
+++ b/libdiskconfig/config_mbr.c
@@ -208,6 +208,26 @@
}
+static struct write_list *
+mk_mbr_sig()
+{
+ struct write_list *item;
+ if (!(item = alloc_wl(sizeof(uint16_t)))) {
+ ALOGE("Unable to allocate memory for MBR signature.");
+ return NULL;
+ }
+
+ {
+ /* DO NOT DEREFERENCE */
+ struct pc_boot_record *mbr = (void *)PC_MBR_DISK_OFFSET;
+ /* grab the offset in mbr where to write mbr signature. */
+ item->offset = (loff_t)((uintptr_t)((uint8_t *)(&mbr->mbr_sig)));
+ }
+
+ *((uint16_t*)item->data) = PC_BIOS_BOOT_SIG;
+ return item;
+}
+
struct write_list *
config_mbr(struct disk_info *dinfo)
{
@@ -276,6 +296,13 @@
wlist_add(&wr_list, temp_wr);
}
+ if ((temp_wr = mk_mbr_sig()))
+ wlist_add(&wr_list, temp_wr);
+ else {
+ ALOGE("Cannot set MBR signature");
+ goto fail;
+ }
+
return wr_list;
nospace:
diff --git a/libion/Android.mk b/libion/Android.mk
index e5d495b..6562cd3 100644
--- a/libion/Android.mk
+++ b/libion/Android.mk
@@ -1,4 +1,4 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := ion.c
@@ -7,6 +7,7 @@
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
+LOCAL_CFLAGS := -Werror
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
@@ -15,6 +16,7 @@
LOCAL_MODULE_TAGS := optional tests
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/libion/ion.c b/libion/ion.c
index 80bdc2a..a79525d 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -117,7 +117,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..abf527a 100644
--- a/libion/tests/Android.mk
+++ b/libion/tests/Android.mk
@@ -21,7 +21,6 @@
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 69ca416..a4e5f5e 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -58,6 +58,7 @@
LOCAL_MODULE := liblog
LOCAL_SRC_FILES := $(liblog_host_sources)
LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror
+LOCAL_MULTILIB := both
include $(BUILD_HOST_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -66,17 +67,10 @@
ifeq ($(strip $(HOST_OS)),linux)
LOCAL_LDLIBS := -lrt
endif
+LOCAL_MULTILIB := both
include $(BUILD_HOST_SHARED_LIBRARY)
-# Static library for host, 64-bit
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := lib64log
-LOCAL_SRC_FILES := $(liblog_host_sources)
-LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -m64 -Werror
-include $(BUILD_HOST_STATIC_LIBRARY)
-
# Shared and static library for target
# ========================================================
include $(CLEAR_VARS)
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index 136792d..117e154 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -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);
diff --git a/liblog/log_read.c b/liblog/log_read.c
index ca5a1a7..2f21a5d 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -72,7 +72,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 +87,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 +99,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/liblog/log_time.cpp b/liblog/log_time.cpp
index 755c2d9..209a9da 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);
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 121d84d..b2668ce 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -31,6 +31,10 @@
#include <time.h>
#include <unistd.h>
+#ifdef __BIONIC__
+#include <android/set_abort_message.h>
+#endif
+
#include <log/logd.h>
#include <log/logger.h>
#include <log/log_read.h>
@@ -54,7 +58,6 @@
#endif
#if FAKE_LOG_DEVICE
-#define WEAK __attribute__((weak))
static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
#else
static int logd_fd = -1;
@@ -107,7 +110,7 @@
close(i);
}
- i = socket(PF_UNIX, SOCK_DGRAM, 0);
+ i = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (i < 0) {
ret = -errno;
write_to_log = __write_to_log_null;
@@ -159,10 +162,14 @@
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 */
- if (getuid() == AID_LOGD) {
+ 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.
+ * ignore log messages we send to ourself (logd).
* Such log messages are often generated by libraries we depend on
* which use standard Android logging.
*/
@@ -193,6 +200,10 @@
* };
*/
+ 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();
@@ -200,11 +211,6 @@
newVec[0].iov_len = sizeof_log_id_t;
newVec[1].iov_base = (unsigned char *) &tid;
newVec[1].iov_len = sizeof(tid);
-
- clock_gettime(CLOCK_REALTIME, &ts);
- realtime_ts.tv_sec = ts.tv_sec;
- realtime_ts.tv_nsec = ts.tv_nsec;
-
newVec[2].iov_base = (unsigned char *) &realtime_ts;
newVec[2].iov_len = sizeof(log_time);
@@ -267,7 +273,7 @@
[LOG_ID_CRASH] = "crash"
};
-const WEAK char *android_log_id_to_name(log_id_t log_id)
+const char *android_log_id_to_name(log_id_t log_id)
{
if (log_id >= LOG_ID_MAX) {
log_id = LOG_ID_MAIN;
@@ -330,8 +336,7 @@
#if __BIONIC__
if (prio == ANDROID_LOG_FATAL) {
- extern void __android_set_abort_message(const char*);
- __android_set_abort_message(msg);
+ android_set_abort_message(msg);
}
#endif
@@ -470,3 +475,25 @@
return write_to_log(LOG_ID_EVENTS, vec, 3);
}
+
+/*
+ * Like __android_log_bwrite, but used for writing strings to the
+ * event log.
+ */
+int __android_log_bswrite(int32_t tag, const char *payload)
+{
+ struct iovec vec[4];
+ char type = EVENT_TYPE_STRING;
+ uint32_t len = strlen(payload);
+
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = &type;
+ vec[1].iov_len = sizeof(type);
+ vec[2].iov_base = &len;
+ vec[2].iov_len = sizeof(len);
+ vec[3].iov_base = (void*)payload;
+ vec[3].iov_len = len;
+
+ return write_to_log(LOG_ID_EVENTS, vec, 4);
+}
diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c
index 1d10748..ae621cb 100644
--- a/liblog/logd_write_kern.c
+++ b/liblog/logd_write_kern.c
@@ -28,6 +28,10 @@
#include <time.h>
#include <unistd.h>
+#ifdef __BIONIC__
+#include <android/set_abort_message.h>
+#endif
+
#include <log/log.h>
#include <log/logd.h>
#include <log/logger.h>
@@ -177,8 +181,7 @@
#if __BIONIC__
if (prio == ANDROID_LOG_FATAL) {
- extern void __android_set_abort_message(const char*);
- __android_set_abort_message(msg);
+ android_set_abort_message(msg);
}
#endif
@@ -317,3 +320,25 @@
return write_to_log(LOG_ID_EVENTS, vec, 3);
}
+
+/*
+ * Like __android_log_bwrite, but used for writing strings to the
+ * event log.
+ */
+int __android_log_bswrite(int32_t tag, const char *payload)
+{
+ struct iovec vec[4];
+ char type = EVENT_TYPE_STRING;
+ uint32_t len = strlen(payload);
+
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = &type;
+ vec[1].iov_len = sizeof(type);
+ vec[2].iov_base = &len;
+ vec[2].iov_len = sizeof(len);
+ vec[3].iov_base = (void*)payload;
+ vec[3].iov_len = len;
+
+ return write_to_log(LOG_ID_EVENTS, vec, 4);
+}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 08e830a..5987782 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(suffixLen));
/* the following code is tragically unreadable */
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index 255dc2e..172b186 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -43,10 +43,6 @@
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)
@@ -59,7 +55,8 @@
-g \
-Wall -Wextra \
-Werror \
- -fno-builtin
+ -fno-builtin \
+ -std=gnu++11
test_src_files := \
liblog_test.cpp
@@ -70,7 +67,7 @@
test_src_files += \
libc_test.cpp
-ifndef ($(TARGET_USES_LOGD),false)
+ifneq ($(TARGET_USES_LOGD),false)
test_c_flags += -DTARGET_USES_LOGD
endif
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 0abc375..9839729 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -99,7 +99,7 @@
pid_t pid = getpid();
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- (log_id_t)LOG_ID_MAIN, O_RDONLY | O_NDELAY, 1000, pid)));
+ (log_id_t)LOG_ID_CRASH, O_RDONLY | O_NDELAY, 1000, pid)));
char b[80];
struct timespec ts;
@@ -119,7 +119,7 @@
ASSERT_EQ(log_msg.entry.pid, pid);
- if ((int)log_msg.id() != LOG_ID_MAIN) {
+ if ((int)log_msg.id() != LOG_ID_CRASH) {
continue;
}
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index ec35e45..393e2cd 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -544,7 +544,7 @@
EXPECT_LE(LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag),
static_cast<size_t>(max_len));
- EXPECT_EQ(ret, max_len + sizeof(big_payload_tag));
+ EXPECT_EQ(ret, max_len + static_cast<ssize_t>(sizeof(big_payload_tag)));
}
TEST(liblog, dual_reader) {
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/libnativebridge/Android.mk b/libnativebridge/Android.mk
new file mode 100644
index 0000000..83169eb
--- /dev/null
+++ b/libnativebridge/Android.mk
@@ -0,0 +1,40 @@
+LOCAL_PATH:= $(call my-dir)
+
+NATIVE_BRIDGE_COMMON_SRC_FILES := \
+ native_bridge.cc
+
+# Shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_CLANG := true
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared library for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_CLANG := true
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+include $(LOCAL_PATH)/tests/Android.mk
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
new file mode 100644
index 0000000..eab2de0
--- /dev/null
+++ b/libnativebridge/native_bridge.cc
@@ -0,0 +1,488 @@
+/*
+ * 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 "nativebridge/native_bridge.h"
+
+#include <cstring>
+#include <cutils/log.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+
+namespace android {
+
+// Environment values required by the apps running with native bridge.
+struct NativeBridgeRuntimeValues {
+ const char* os_arch;
+ const char* cpu_abi;
+ const char* cpu_abi2;
+ const char* *supported_abis;
+ int32_t abi_count;
+};
+
+// The symbol name exposed by native-bridge with the type of NativeBridgeCallbacks.
+static constexpr const char* kNativeBridgeInterfaceSymbol = "NativeBridgeItf";
+
+enum class NativeBridgeState {
+ kNotSetup, // Initial state.
+ kOpened, // After successful dlopen.
+ kPreInitialized, // After successful pre-initialization.
+ kInitialized, // After successful initialization.
+ kClosed // Closed or errors.
+};
+
+static constexpr const char* kNotSetupString = "kNotSetup";
+static constexpr const char* kOpenedString = "kOpened";
+static constexpr const char* kPreInitializedString = "kPreInitialized";
+static constexpr const char* kInitializedString = "kInitialized";
+static constexpr const char* kClosedString = "kClosed";
+
+static const char* GetNativeBridgeStateString(NativeBridgeState state) {
+ switch (state) {
+ case NativeBridgeState::kNotSetup:
+ return kNotSetupString;
+
+ case NativeBridgeState::kOpened:
+ return kOpenedString;
+
+ case NativeBridgeState::kPreInitialized:
+ return kPreInitializedString;
+
+ case NativeBridgeState::kInitialized:
+ return kInitializedString;
+
+ case NativeBridgeState::kClosed:
+ return kClosedString;
+ }
+}
+
+// Current state of the native bridge.
+static NativeBridgeState state = NativeBridgeState::kNotSetup;
+
+// Whether we had an error at some point.
+static bool had_error = false;
+
+// Handle of the loaded library.
+static void* native_bridge_handle = nullptr;
+// Pointer to the callbacks. Available as soon as LoadNativeBridge succeeds, but only initialized
+// later.
+static NativeBridgeCallbacks* callbacks = nullptr;
+// Callbacks provided by the environment to the bridge. Passed to LoadNativeBridge.
+static const NativeBridgeRuntimeCallbacks* runtime_callbacks = nullptr;
+
+// The app's code cache directory.
+static char* app_code_cache_dir = nullptr;
+
+// Code cache directory (relative to the application private directory)
+// Ideally we'd like to call into framework to retrieve this name. However that's considered an
+// implementation detail and will require either hacks or consistent refactorings. We compromise
+// and hard code the directory name again here.
+static constexpr const char* kCodeCacheDir = "code_cache";
+
+static constexpr uint32_t kNativeBridgeCallbackVersion = 1;
+
+// Characters allowed in a native bridge filename. The first character must
+// be in [a-zA-Z] (expected 'l' for "libx"). The rest must be in [a-zA-Z0-9._-].
+static bool CharacterAllowed(char c, bool first) {
+ if (first) {
+ return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
+ } else {
+ return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') ||
+ (c == '.') || (c == '_') || (c == '-');
+ }
+}
+
+// We only allow simple names for the library. It is supposed to be a file in
+// /system/lib or /vendor/lib. Only allow a small range of characters, that is
+// names consisting of [a-zA-Z0-9._-] and starting with [a-zA-Z].
+bool NativeBridgeNameAcceptable(const char* nb_library_filename) {
+ const char* ptr = nb_library_filename;
+ if (*ptr == 0) {
+ // Emptry string. Allowed, means no native bridge.
+ return true;
+ } else {
+ // First character must be [a-zA-Z].
+ if (!CharacterAllowed(*ptr, true)) {
+ // Found an invalid fist character, don't accept.
+ ALOGE("Native bridge library %s has been rejected for first character %c", nb_library_filename, *ptr);
+ return false;
+ } else {
+ // For the rest, be more liberal.
+ ptr++;
+ while (*ptr != 0) {
+ if (!CharacterAllowed(*ptr, false)) {
+ // Found an invalid character, don't accept.
+ ALOGE("Native bridge library %s has been rejected for %c", nb_library_filename, *ptr);
+ return false;
+ }
+ ptr++;
+ }
+ }
+ return true;
+ }
+}
+
+static bool VersionCheck(NativeBridgeCallbacks* cb) {
+ return cb != nullptr && cb->version == kNativeBridgeCallbackVersion;
+}
+
+static void CloseNativeBridge(bool with_error) {
+ state = NativeBridgeState::kClosed;
+ had_error |= with_error;
+ delete[] app_code_cache_dir;
+ app_code_cache_dir = nullptr;
+}
+
+bool LoadNativeBridge(const char* nb_library_filename,
+ const NativeBridgeRuntimeCallbacks* runtime_cbs) {
+ // We expect only one place that calls LoadNativeBridge: Runtime::Init. At that point we are not
+ // multi-threaded, so we do not need locking here.
+
+ if (state != NativeBridgeState::kNotSetup) {
+ // Setup has been called before. Ignore this call.
+ if (nb_library_filename != nullptr) { // Avoids some log-spam for dalvikvm.
+ ALOGW("Called LoadNativeBridge for an already set up native bridge. State is %s.",
+ GetNativeBridgeStateString(state));
+ }
+ // Note: counts as an error, even though the bridge may be functional.
+ had_error = true;
+ return false;
+ }
+
+ if (nb_library_filename == nullptr || *nb_library_filename == 0) {
+ CloseNativeBridge(false);
+ return false;
+ } else {
+ if (!NativeBridgeNameAcceptable(nb_library_filename)) {
+ CloseNativeBridge(true);
+ } else {
+ // Try to open the library.
+ void* handle = dlopen(nb_library_filename, RTLD_LAZY);
+ if (handle != nullptr) {
+ callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
+ kNativeBridgeInterfaceSymbol));
+ if (callbacks != nullptr) {
+ if (VersionCheck(callbacks)) {
+ // Store the handle for later.
+ native_bridge_handle = handle;
+ } else {
+ callbacks = nullptr;
+ dlclose(handle);
+ ALOGW("Unsupported native bridge interface.");
+ }
+ } else {
+ dlclose(handle);
+ }
+ }
+
+ // Two failure conditions: could not find library (dlopen failed), or could not find native
+ // bridge interface (dlsym failed). Both are an error and close the native bridge.
+ if (callbacks == nullptr) {
+ CloseNativeBridge(true);
+ } else {
+ runtime_callbacks = runtime_cbs;
+ state = NativeBridgeState::kOpened;
+ }
+ }
+ return state == NativeBridgeState::kOpened;
+ }
+}
+
+#if defined(__arm__)
+static const char* kRuntimeISA = "arm";
+#elif defined(__aarch64__)
+static const char* kRuntimeISA = "arm64";
+#elif defined(__mips__)
+static const char* kRuntimeISA = "mips";
+#elif defined(__i386__)
+static const char* kRuntimeISA = "x86";
+#elif defined(__x86_64__)
+static const char* kRuntimeISA = "x86_64";
+#else
+static const char* kRuntimeISA = "unknown";
+#endif
+
+
+bool NeedsNativeBridge(const char* instruction_set) {
+ if (instruction_set == nullptr) {
+ ALOGE("Null instruction set in NeedsNativeBridge.");
+ return false;
+ }
+ return strncmp(instruction_set, kRuntimeISA, strlen(kRuntimeISA) + 1) != 0;
+}
+
+#ifdef __APPLE__
+template<typename T> void UNUSED(const T&) {}
+#endif
+
+bool PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruction_set) {
+ if (state != NativeBridgeState::kOpened) {
+ ALOGE("Invalid state: native bridge is expected to be opened.");
+ CloseNativeBridge(true);
+ return false;
+ }
+
+ if (app_data_dir_in == nullptr) {
+ ALOGE("Application private directory cannot be null.");
+ CloseNativeBridge(true);
+ return false;
+ }
+
+ // Create the path to the application code cache directory.
+ // The memory will be release after Initialization or when the native bridge is closed.
+ const size_t len = strlen(app_data_dir_in) + strlen(kCodeCacheDir) + 2; // '\0' + '/'
+ app_code_cache_dir = new char[len];
+ snprintf(app_code_cache_dir, len, "%s/%s", app_data_dir_in, kCodeCacheDir);
+
+ // Bind-mount /system/lib{,64}/<isa>/cpuinfo to /proc/cpuinfo.
+ // Failure is not fatal and will keep the native bridge in kPreInitialized.
+ state = NativeBridgeState::kPreInitialized;
+
+#ifndef __APPLE__
+ if (instruction_set == nullptr) {
+ return true;
+ }
+ size_t isa_len = strlen(instruction_set);
+ if (isa_len > 10) {
+ // 10 is a loose upper bound on the currently known instruction sets (a tight bound is 7 for
+ // x86_64 [including the trailing \0]). This is so we don't have to change here if there will
+ // be another instruction set in the future.
+ ALOGW("Instruction set %s is malformed, must be less than or equal to 10 characters.",
+ instruction_set);
+ return true;
+ }
+
+ // If the file does not exist, the mount command will fail,
+ // so we save the extra file existence check.
+ char cpuinfo_path[1024];
+
+#ifdef HAVE_ANDROID_OS
+ snprintf(cpuinfo_path, sizeof(cpuinfo_path), "/system/lib"
+#ifdef __LP64__
+ "64"
+#endif // __LP64__
+ "/%s/cpuinfo", instruction_set);
+#else // !HAVE_ANDROID_OS
+ // To be able to test on the host, we hardwire a relative path.
+ snprintf(cpuinfo_path, sizeof(cpuinfo_path), "./cpuinfo");
+#endif
+
+ // Bind-mount.
+ if (TEMP_FAILURE_RETRY(mount(cpuinfo_path, // Source.
+ "/proc/cpuinfo", // Target.
+ nullptr, // FS type.
+ MS_BIND, // Mount flags: bind mount.
+ nullptr)) == -1) { // "Data."
+ ALOGW("Failed to bind-mount %s as /proc/cpuinfo: %s", cpuinfo_path, strerror(errno));
+ }
+#else // __APPLE__
+ UNUSED(instruction_set);
+ ALOGW("Mac OS does not support bind-mounting. Host simulation of native bridge impossible.");
+#endif
+
+ return true;
+}
+
+static void SetCpuAbi(JNIEnv* env, jclass build_class, const char* field, const char* value) {
+ if (value != nullptr) {
+ jfieldID field_id = env->GetStaticFieldID(build_class, field, "Ljava/lang/String;");
+ if (field_id == nullptr) {
+ env->ExceptionClear();
+ ALOGW("Could not find %s field.", field);
+ return;
+ }
+
+ jstring str = env->NewStringUTF(value);
+ if (str == nullptr) {
+ env->ExceptionClear();
+ ALOGW("Could not create string %s.", value);
+ return;
+ }
+
+ env->SetStaticObjectField(build_class, field_id, str);
+ }
+}
+
+// Set up the environment for the bridged app.
+static void SetupEnvironment(NativeBridgeCallbacks* callbacks, JNIEnv* env, const char* isa) {
+ // Need a JNIEnv* to do anything.
+ if (env == nullptr) {
+ ALOGW("No JNIEnv* to set up app environment.");
+ return;
+ }
+
+ // Query the bridge for environment values.
+ const struct NativeBridgeRuntimeValues* env_values = callbacks->getAppEnv(isa);
+ if (env_values == nullptr) {
+ return;
+ }
+
+ // Keep the JNIEnv clean.
+ jint success = env->PushLocalFrame(16); // That should be small and large enough.
+ if (success < 0) {
+ // Out of memory, really borked.
+ ALOGW("Out of memory while setting up app environment.");
+ env->ExceptionClear();
+ return;
+ }
+
+ // Reset CPU_ABI & CPU_ABI2 to values required by the apps running with native bridge.
+ if (env_values->cpu_abi != nullptr || env_values->cpu_abi2 != nullptr ||
+ env_values->abi_count >= 0) {
+ jclass bclass_id = env->FindClass("android/os/Build");
+ if (bclass_id != nullptr) {
+ SetCpuAbi(env, bclass_id, "CPU_ABI", env_values->cpu_abi);
+ SetCpuAbi(env, bclass_id, "CPU_ABI2", env_values->cpu_abi2);
+ } else {
+ // For example in a host test environment.
+ env->ExceptionClear();
+ ALOGW("Could not find Build class.");
+ }
+ }
+
+ 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",
+ "(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.
+ env->CallStaticVoidMethod(sclass_id, set_prop_id, env->NewStringUTF("os.arch"),
+ env->NewStringUTF(env_values->os_arch));
+ } else {
+ env->ExceptionClear();
+ ALOGW("Could not find initUnchangeableSystemProperty method.");
+ }
+ } else {
+ env->ExceptionClear();
+ ALOGW("Could not find System class.");
+ }
+ }
+
+ // Make it pristine again.
+ env->PopLocalFrame(nullptr);
+}
+
+bool InitializeNativeBridge(JNIEnv* env, const char* instruction_set) {
+ // We expect only one place that calls InitializeNativeBridge: Runtime::DidForkFromZygote. At that
+ // point we are not multi-threaded, so we do not need locking here.
+
+ if (state == NativeBridgeState::kPreInitialized) {
+ // Check for code cache: if it doesn't exist try to create it.
+ struct stat st;
+ if (stat(app_code_cache_dir, &st) == -1) {
+ if (errno == ENOENT) {
+ if (mkdir(app_code_cache_dir, S_IRWXU | S_IRWXG | S_IXOTH) == -1) {
+ ALOGE("Cannot create code cache directory %s: %s.", app_code_cache_dir, strerror(errno));
+ CloseNativeBridge(true);
+ }
+ } else {
+ ALOGE("Cannot stat code cache directory %s: %s.", app_code_cache_dir, strerror(errno));
+ CloseNativeBridge(true);
+ }
+ } else if (!S_ISDIR(st.st_mode)) {
+ ALOGE("Code cache is not a directory %s.", app_code_cache_dir);
+ CloseNativeBridge(true);
+ }
+
+ // If we're still PreInitialized (dind't fail the code cache checks) try to initialize.
+ if (state == NativeBridgeState::kPreInitialized) {
+ if (callbacks->initialize(runtime_callbacks, app_code_cache_dir, instruction_set)) {
+ SetupEnvironment(callbacks, env, instruction_set);
+ state = NativeBridgeState::kInitialized;
+ // We no longer need the code cache path, release the memory.
+ delete[] app_code_cache_dir;
+ app_code_cache_dir = nullptr;
+ } else {
+ // Unload the library.
+ dlclose(native_bridge_handle);
+ CloseNativeBridge(true);
+ }
+ }
+ } else {
+ CloseNativeBridge(true);
+ }
+
+ return state == NativeBridgeState::kInitialized;
+}
+
+void UnloadNativeBridge() {
+ // We expect only one place that calls UnloadNativeBridge: Runtime::DidForkFromZygote. At that
+ // point we are not multi-threaded, so we do not need locking here.
+
+ switch(state) {
+ case NativeBridgeState::kOpened:
+ case NativeBridgeState::kPreInitialized:
+ case NativeBridgeState::kInitialized:
+ // Unload.
+ dlclose(native_bridge_handle);
+ CloseNativeBridge(false);
+ break;
+
+ case NativeBridgeState::kNotSetup:
+ // Not even set up. Error.
+ CloseNativeBridge(true);
+ break;
+
+ case NativeBridgeState::kClosed:
+ // Ignore.
+ break;
+ }
+}
+
+bool NativeBridgeError() {
+ return had_error;
+}
+
+bool NativeBridgeAvailable() {
+ return state == NativeBridgeState::kOpened
+ || state == NativeBridgeState::kPreInitialized
+ || state == NativeBridgeState::kInitialized;
+}
+
+bool NativeBridgeInitialized() {
+ // Calls of this are supposed to happen in a state where the native bridge is stable, i.e., after
+ // Runtime::DidForkFromZygote. In that case we do not need a lock.
+ return state == NativeBridgeState::kInitialized;
+}
+
+void* NativeBridgeLoadLibrary(const char* libpath, int flag) {
+ if (NativeBridgeInitialized()) {
+ return callbacks->loadLibrary(libpath, flag);
+ }
+ return nullptr;
+}
+
+void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty,
+ uint32_t len) {
+ if (NativeBridgeInitialized()) {
+ return callbacks->getTrampoline(handle, name, shorty, len);
+ }
+ return nullptr;
+}
+
+bool NativeBridgeIsSupported(const char* libpath) {
+ if (NativeBridgeInitialized()) {
+ return callbacks->isSupported(libpath);
+ }
+ return false;
+}
+
+}; // namespace android
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
new file mode 100644
index 0000000..f28c490
--- /dev/null
+++ b/libnativebridge/tests/Android.mk
@@ -0,0 +1,46 @@
+# Build the unit tests.
+LOCAL_PATH := $(call my-dir)
+
+include $(LOCAL_PATH)/Android.nativebridge-dummy.mk
+
+include $(CLEAR_VARS)
+
+# Build the unit tests.
+test_src_files := \
+ CodeCacheCreate_test.cpp \
+ CodeCacheExists_test.cpp \
+ CompleteFlow_test.cpp \
+ InvalidCharsNativeBridge_test.cpp \
+ NeedsNativeBridge_test.cpp \
+ PreInitializeNativeBridge_test.cpp \
+ PreInitializeNativeBridgeFail1_test.cpp \
+ PreInitializeNativeBridgeFail2_test.cpp \
+ ReSetupNativeBridge_test.cpp \
+ UnavailableNativeBridge_test.cpp \
+ ValidNameNativeBridge_test.cpp
+
+
+shared_libraries := \
+ liblog \
+ libnativebridge \
+ libnativebridge-dummy
+
+$(foreach file,$(test_src_files), \
+ $(eval include $(CLEAR_VARS)) \
+ $(eval LOCAL_CLANG := true) \
+ $(eval LOCAL_CPPFLAGS := -std=gnu++11) \
+ $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+ $(eval LOCAL_SRC_FILES := $(file)) \
+ $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+ $(eval include $(BUILD_NATIVE_TEST)) \
+)
+
+$(foreach file,$(test_src_files), \
+ $(eval include $(CLEAR_VARS)) \
+ $(eval LOCAL_CLANG := true) \
+ $(eval LOCAL_CPPFLAGS := -std=gnu++11) \
+ $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+ $(eval LOCAL_SRC_FILES := $(file)) \
+ $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+ $(eval include $(BUILD_HOST_NATIVE_TEST)) \
+)
diff --git a/libnativebridge/tests/Android.nativebridge-dummy.mk b/libnativebridge/tests/Android.nativebridge-dummy.mk
new file mode 100644
index 0000000..1caf50a
--- /dev/null
+++ b/libnativebridge/tests/Android.nativebridge-dummy.mk
@@ -0,0 +1,34 @@
+LOCAL_PATH:= $(call my-dir)
+
+NATIVE_BRIDGE_COMMON_SRC_FILES := \
+ DummyNativeBridge.cpp
+
+# Shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge-dummy
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared library for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge-dummy
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/libnativebridge/tests/CodeCacheCreate_test.cpp b/libnativebridge/tests/CodeCacheCreate_test.cpp
new file mode 100644
index 0000000..58270c4
--- /dev/null
+++ b/libnativebridge/tests/CodeCacheCreate_test.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+namespace android {
+
+// Tests that the bridge initialization creates the code_cache if it doesn't
+// exists.
+TEST_F(NativeBridgeTest, CodeCacheCreate) {
+ // Make sure that code_cache does not exists
+ struct stat st;
+ ASSERT_EQ(-1, stat(kCodeCache, &st));
+ ASSERT_EQ(ENOENT, errno);
+
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_FALSE(NativeBridgeError());
+
+ // Check that code_cache was created
+ ASSERT_EQ(0, stat(kCodeCache, &st));
+ ASSERT_TRUE(S_ISDIR(st.st_mode));
+
+ // Clean up
+ UnloadNativeBridge();
+ ASSERT_EQ(0, rmdir(kCodeCache));
+
+ ASSERT_FALSE(NativeBridgeError());
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/CodeCacheExists_test.cpp b/libnativebridge/tests/CodeCacheExists_test.cpp
new file mode 100644
index 0000000..8ba0158
--- /dev/null
+++ b/libnativebridge/tests/CodeCacheExists_test.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+namespace android {
+
+// Tests that the bridge is initialized without errors if the code_cache already
+// exists.
+TEST_F(NativeBridgeTest, CodeCacheExists) {
+ // Make sure that code_cache does not exists
+ struct stat st;
+ ASSERT_EQ(-1, stat(kCodeCache, &st));
+ ASSERT_EQ(ENOENT, errno);
+
+ // Create the code_cache
+ ASSERT_EQ(0, mkdir(kCodeCache, S_IRWXU | S_IRWXG | S_IXOTH));
+
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_FALSE(NativeBridgeError());
+
+ // Check that the code cache is still there
+ ASSERT_EQ(0, stat(kCodeCache, &st));
+ ASSERT_TRUE(S_ISDIR(st.st_mode));
+
+ // Clean up
+ UnloadNativeBridge();
+ ASSERT_EQ(0, rmdir(kCodeCache));
+
+ ASSERT_FALSE(NativeBridgeError());
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/CompleteFlow_test.cpp b/libnativebridge/tests/CompleteFlow_test.cpp
new file mode 100644
index 0000000..cf06d2c
--- /dev/null
+++ b/libnativebridge/tests/CompleteFlow_test.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+#include <unistd.h>
+
+namespace android {
+
+TEST_F(NativeBridgeTest, CompleteFlow) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ // Basic calls to check that nothing crashes
+ ASSERT_FALSE(NativeBridgeIsSupported(nullptr));
+ ASSERT_EQ(nullptr, NativeBridgeLoadLibrary(nullptr, 0));
+ ASSERT_EQ(nullptr, NativeBridgeGetTrampoline(nullptr, nullptr, nullptr, 0));
+
+ // Unload
+ UnloadNativeBridge();
+ ASSERT_FALSE(NativeBridgeAvailable());
+ ASSERT_FALSE(NativeBridgeError());
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/DummyNativeBridge.cpp b/libnativebridge/tests/DummyNativeBridge.cpp
new file mode 100644
index 0000000..b9894f6
--- /dev/null
+++ b/libnativebridge/tests/DummyNativeBridge.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+// A dummy implementation of the native-bridge interface.
+
+#include "nativebridge/native_bridge.h"
+
+// NativeBridgeCallbacks implementations
+extern "C" bool native_bridge_initialize(const android::NativeBridgeRuntimeCallbacks* /* art_cbs */,
+ const char* /* app_code_cache_dir */,
+ const char* /* isa */) {
+ return true;
+}
+
+extern "C" void* native_bridge_loadLibrary(const char* /* libpath */, int /* flag */) {
+ return nullptr;
+}
+
+extern "C" void* native_bridge_getTrampoline(void* /* handle */, const char* /* name */,
+ const char* /* shorty */, uint32_t /* len */) {
+ return nullptr;
+}
+
+extern "C" bool native_bridge_isSupported(const char* /* libpath */) {
+ return false;
+}
+
+extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge_getAppEnv(
+ const char* /* abi */) {
+ return nullptr;
+}
+
+android::NativeBridgeCallbacks NativeBridgeItf {
+ .version = 1,
+ .initialize = &native_bridge_initialize,
+ .loadLibrary = &native_bridge_loadLibrary,
+ .getTrampoline = &native_bridge_getTrampoline,
+ .isSupported = &native_bridge_isSupported,
+ .getAppEnv = &native_bridge_getAppEnv
+};
diff --git a/libnativebridge/tests/InvalidCharsNativeBridge_test.cpp b/libnativebridge/tests/InvalidCharsNativeBridge_test.cpp
new file mode 100644
index 0000000..8f7973d
--- /dev/null
+++ b/libnativebridge/tests/InvalidCharsNativeBridge_test.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+namespace android {
+
+static const char* kTestName = "../librandom$@-bridge_not.existing.so";
+
+TEST_F(NativeBridgeTest, InvalidChars) {
+ // Do one test actually calling setup.
+ EXPECT_EQ(false, NativeBridgeError());
+ LoadNativeBridge(kTestName, nullptr);
+ // This should lead to an error for invalid characters.
+ EXPECT_EQ(true, NativeBridgeError());
+
+ // Further tests need to use NativeBridgeNameAcceptable, as the error
+ // state can't be changed back.
+ EXPECT_EQ(false, NativeBridgeNameAcceptable("."));
+ EXPECT_EQ(false, NativeBridgeNameAcceptable(".."));
+ EXPECT_EQ(false, NativeBridgeNameAcceptable("_"));
+ EXPECT_EQ(false, NativeBridgeNameAcceptable("-"));
+ EXPECT_EQ(false, NativeBridgeNameAcceptable("lib@.so"));
+ EXPECT_EQ(false, NativeBridgeNameAcceptable("lib$.so"));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/NativeBridgeTest.h b/libnativebridge/tests/NativeBridgeTest.h
new file mode 100644
index 0000000..6a5c126
--- /dev/null
+++ b/libnativebridge/tests/NativeBridgeTest.h
@@ -0,0 +1,36 @@
+/*
+ * 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 NATIVE_BRIDGE_TEST_H_
+#define NATIVE_BRIDGE_TEST_H_
+
+#define LOG_TAG "NativeBridge_test"
+
+#include <nativebridge/native_bridge.h>
+#include <gtest/gtest.h>
+
+constexpr const char* kNativeBridgeLibrary = "libnativebridge-dummy.so";
+constexpr const char* kCodeCache = "./code_cache";
+
+namespace android {
+
+class NativeBridgeTest : public testing::Test {
+};
+
+}; // namespace android
+
+#endif // NATIVE_BRIDGE_H_
+
diff --git a/libnativebridge/tests/NeedsNativeBridge_test.cpp b/libnativebridge/tests/NeedsNativeBridge_test.cpp
new file mode 100644
index 0000000..e1c0876
--- /dev/null
+++ b/libnativebridge/tests/NeedsNativeBridge_test.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+namespace android {
+
+static const char* kISAs[] = { "arm", "arm64", "mips", "x86", "x86_64", "random", "64arm", "64_x86",
+ "64_x86_64", "", "reallylongstringabcd", nullptr };
+
+#if defined(__arm__)
+static const char* kRuntimeISA = "arm";
+#elif defined(__aarch64__)
+static const char* kRuntimeISA = "arm64";
+#elif defined(__mips__)
+static const char* kRuntimeISA = "mips";
+#elif defined(__i386__)
+static const char* kRuntimeISA = "x86";
+#elif defined(__x86_64__)
+static const char* kRuntimeISA = "x86_64";
+#else
+static const char* kRuntimeISA = "unknown";
+#endif
+
+TEST_F(NativeBridgeTest, NeedsNativeBridge) {
+ EXPECT_EQ(false, NeedsNativeBridge(kRuntimeISA));
+
+ const size_t kISACount = sizeof(kISAs)/sizeof(kISAs[0]);
+ for (size_t i = 0; i < kISACount; i++) {
+ EXPECT_EQ(kISAs[i] == nullptr ? false : strcmp(kISAs[i], kRuntimeISA) != 0,
+ NeedsNativeBridge(kISAs[i]));
+ }
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp b/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp
new file mode 100644
index 0000000..69c30a1
--- /dev/null
+++ b/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+#include <cstdio>
+#include <cstring>
+#include <cutils/log.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+namespace android {
+
+TEST_F(NativeBridgeTest, PreInitializeNativeBridgeFail1) {
+ // Needs a valid application directory.
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
+ ASSERT_FALSE(PreInitializeNativeBridge(nullptr, "isa"));
+ ASSERT_TRUE(NativeBridgeError());
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp b/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp
new file mode 100644
index 0000000..74e96e0
--- /dev/null
+++ b/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+#include <cstdio>
+#include <cstring>
+#include <cutils/log.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+namespace android {
+
+TEST_F(NativeBridgeTest, PreInitializeNativeBridgeFail2) {
+ // Needs LoadNativeBridge() first
+ ASSERT_FALSE(PreInitializeNativeBridge(nullptr, "isa"));
+ ASSERT_TRUE(NativeBridgeError());
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/PreInitializeNativeBridge_test.cpp b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
new file mode 100644
index 0000000..cec26ce
--- /dev/null
+++ b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+#include <cstdio>
+#include <cstring>
+#include <cutils/log.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+namespace android {
+
+static constexpr const char* kTestData = "PreInitializeNativeBridge test.";
+
+TEST_F(NativeBridgeTest, PreInitializeNativeBridge) {
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
+#ifndef __APPLE__ // Mac OS does not support bind-mount.
+#ifndef HAVE_ANDROID_OS // Cannot write into the hard-wired location.
+ // Try to create our mount namespace.
+ if (unshare(CLONE_NEWNS) != -1) {
+ // Create a dummy file.
+ FILE* cpuinfo = fopen("./cpuinfo", "w");
+ ASSERT_NE(nullptr, cpuinfo) << strerror(errno);
+ fprintf(cpuinfo, kTestData);
+ fclose(cpuinfo);
+
+ ASSERT_TRUE(PreInitializeNativeBridge("does not matter 1", "short 2"));
+
+ // Read /proc/cpuinfo
+ FILE* proc_cpuinfo = fopen("/proc/cpuinfo", "r");
+ ASSERT_NE(nullptr, proc_cpuinfo) << strerror(errno);
+ char buf[1024];
+ EXPECT_NE(nullptr, fgets(buf, sizeof(buf), proc_cpuinfo)) << "Error reading.";
+ fclose(proc_cpuinfo);
+
+ EXPECT_EQ(0, strcmp(buf, kTestData));
+
+ // Delete the file.
+ ASSERT_EQ(0, unlink("./cpuinfo")) << "Error unlinking temporary file.";
+ // Ending the test will tear down the mount namespace.
+ } else {
+ GTEST_LOG_(WARNING) << "Could not create mount namespace. Are you running this as root?";
+ }
+#endif
+#endif
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/ReSetupNativeBridge_test.cpp b/libnativebridge/tests/ReSetupNativeBridge_test.cpp
new file mode 100644
index 0000000..944e5d7
--- /dev/null
+++ b/libnativebridge/tests/ReSetupNativeBridge_test.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+namespace android {
+
+TEST_F(NativeBridgeTest, ReSetup) {
+ EXPECT_EQ(false, NativeBridgeError());
+ LoadNativeBridge("", nullptr);
+ EXPECT_EQ(false, NativeBridgeError());
+ LoadNativeBridge("", nullptr);
+ // This should lead to an error for trying to re-setup a native bridge.
+ EXPECT_EQ(true, NativeBridgeError());
+}
+
+} // namespace android
diff --git a/libnl_2/cache.c b/libnativebridge/tests/UnavailableNativeBridge_test.cpp
similarity index 61%
copy from libnl_2/cache.c
copy to libnativebridge/tests/UnavailableNativeBridge_test.cpp
index c21974d..ad374a5 100644
--- a/libnl_2/cache.c
+++ b/libnativebridge/tests/UnavailableNativeBridge_test.cpp
@@ -14,24 +14,16 @@
* limitations under the License.
*/
-/* NOTICE: This is a clean room re-implementation of libnl */
+#include "NativeBridgeTest.h"
-#include "netlink/cache.h"
-#include "netlink/object.h"
+namespace android {
-void nl_cache_free(struct nl_cache *cache)
-{
-
+TEST_F(NativeBridgeTest, NoNativeBridge) {
+ EXPECT_EQ(false, NativeBridgeAvailable());
+ // Try to initialize. This should fail as we are not set up.
+ EXPECT_EQ(false, InitializeNativeBridge(nullptr, nullptr));
+ EXPECT_EQ(true, NativeBridgeError());
+ EXPECT_EQ(false, NativeBridgeAvailable());
}
-void nl_cache_clear(struct nl_cache *cache)
-{
-
-}
-
-void nl_cache_remove(struct nl_object *obj)
-{
-
-}
-
-
+} // namespace android
diff --git a/libnativebridge/tests/ValidNameNativeBridge_test.cpp b/libnativebridge/tests/ValidNameNativeBridge_test.cpp
new file mode 100644
index 0000000..690be4a
--- /dev/null
+++ b/libnativebridge/tests/ValidNameNativeBridge_test.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 <NativeBridgeTest.h>
+
+namespace android {
+
+static const char* kTestName = "librandom-bridge_not.existing.so";
+
+TEST_F(NativeBridgeTest, ValidName) {
+ // Check that the name is acceptable.
+ EXPECT_EQ(true, NativeBridgeNameAcceptable(kTestName));
+
+ // Now check what happens on LoadNativeBridge.
+ EXPECT_EQ(false, NativeBridgeError());
+ LoadNativeBridge(kTestName, nullptr);
+ // This will lead to an error as the library doesn't exist.
+ EXPECT_EQ(true, NativeBridgeError());
+ EXPECT_EQ(false, NativeBridgeAvailable());
+}
+
+} // namespace android
diff --git a/libnetd_client/FwmarkClient.cpp b/libnetd_client/FwmarkClient.cpp
deleted file mode 100644
index e360b4e..0000000
--- a/libnetd_client/FwmarkClient.cpp
+++ /dev/null
@@ -1,96 +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 "FwmarkClient.h"
-
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-namespace {
-
-const sockaddr_un FWMARK_SERVER_PATH = {AF_UNIX, "/dev/socket/fwmarkd"};
-
-} // namespace
-
-bool FwmarkClient::shouldSetFwmark(int sockfd, const sockaddr* addr) {
- return sockfd >= 0 && addr && (addr->sa_family == AF_INET || addr->sa_family == AF_INET6) &&
- !getenv("ANDROID_NO_USE_FWMARK_CLIENT");
-}
-
-FwmarkClient::FwmarkClient() : mChannel(-1) {
-}
-
-FwmarkClient::~FwmarkClient() {
- if (mChannel >= 0) {
- // We don't care about errors while closing the channel, so restore any previous error.
- int error = errno;
- close(mChannel);
- errno = error;
- }
-}
-
-bool FwmarkClient::send(void* data, size_t len, int fd) {
- mChannel = socket(AF_UNIX, SOCK_STREAM, 0);
- if (mChannel == -1) {
- return false;
- }
-
- if (TEMP_FAILURE_RETRY(connect(mChannel, reinterpret_cast<const sockaddr*>(&FWMARK_SERVER_PATH),
- sizeof(FWMARK_SERVER_PATH))) == -1) {
- // If we are unable to connect to the fwmark server, assume there's no error. This protects
- // against future changes if the fwmark server goes away.
- errno = 0;
- return true;
- }
-
- iovec iov;
- iov.iov_base = data;
- iov.iov_len = len;
-
- msghdr message;
- memset(&message, 0, sizeof(message));
- message.msg_iov = &iov;
- message.msg_iovlen = 1;
-
- union {
- cmsghdr cmh;
- char cmsg[CMSG_SPACE(sizeof(fd))];
- } cmsgu;
-
- memset(cmsgu.cmsg, 0, sizeof(cmsgu.cmsg));
- message.msg_control = cmsgu.cmsg;
- message.msg_controllen = sizeof(cmsgu.cmsg);
-
- cmsghdr* const cmsgh = CMSG_FIRSTHDR(&message);
- cmsgh->cmsg_len = CMSG_LEN(sizeof(fd));
- cmsgh->cmsg_level = SOL_SOCKET;
- cmsgh->cmsg_type = SCM_RIGHTS;
- memcpy(CMSG_DATA(cmsgh), &fd, sizeof(fd));
-
- if (TEMP_FAILURE_RETRY(sendmsg(mChannel, &message, 0)) == -1) {
- return false;
- }
-
- int error = 0;
- if (TEMP_FAILURE_RETRY(recv(mChannel, &error, sizeof(error), 0)) == -1) {
- return false;
- }
-
- errno = error;
- return !error;
-}
diff --git a/libnetd_client/FwmarkClient.h b/libnetd_client/FwmarkClient.h
deleted file mode 100644
index 4cf0cc0..0000000
--- a/libnetd_client/FwmarkClient.h
+++ /dev/null
@@ -1,38 +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.
- */
-
-#ifndef NETD_CLIENT_FWMARK_CLIENT_H
-#define NETD_CLIENT_FWMARK_CLIENT_H
-
-#include <sys/socket.h>
-
-class FwmarkClient {
-public:
- // Returns true if |sockfd| should be sent to the fwmark server to have its SO_MARK set.
- static bool shouldSetFwmark(int sockfd, const sockaddr* addr);
-
- FwmarkClient();
- ~FwmarkClient();
-
- // Sends |data| to the fwmark server, along with |fd| as ancillary data using cmsg(3).
- // Returns true on success.
- bool send(void* data, size_t len, int fd);
-
-private:
- int mChannel;
-};
-
-#endif // NETD_CLIENT_INCLUDE_FWMARK_CLIENT_H
diff --git a/libnetd_client/NetdClient.cpp b/libnetd_client/NetdClient.cpp
deleted file mode 100644
index 8deea1e..0000000
--- a/libnetd_client/NetdClient.cpp
+++ /dev/null
@@ -1,84 +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 "FwmarkClient.h"
-#include "netd_client/FwmarkCommands.h"
-
-#include <sys/socket.h>
-#include <unistd.h>
-
-namespace {
-
-int closeFdAndRestoreErrno(int fd) {
- int error = errno;
- close(fd);
- errno = error;
- return -1;
-}
-
-typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
-typedef int (*AcceptFunctionType)(int, sockaddr*, socklen_t*);
-
-ConnectFunctionType libcConnect = 0;
-AcceptFunctionType libcAccept = 0;
-
-int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
- if (FwmarkClient::shouldSetFwmark(sockfd, addr)) {
- char data[] = {FWMARK_COMMAND_ON_CONNECT};
- if (!FwmarkClient().send(data, sizeof(data), sockfd)) {
- return -1;
- }
- }
- return libcConnect(sockfd, addr, addrlen);
-}
-
-int netdClientAccept(int sockfd, sockaddr* addr, socklen_t* addrlen) {
- int acceptedSocket = libcAccept(sockfd, addr, addrlen);
- if (acceptedSocket == -1) {
- return -1;
- }
- sockaddr socketAddress;
- if (!addr) {
- socklen_t socketAddressLen = sizeof(socketAddress);
- if (getsockname(acceptedSocket, &socketAddress, &socketAddressLen) == -1) {
- return closeFdAndRestoreErrno(acceptedSocket);
- }
- addr = &socketAddress;
- }
- if (FwmarkClient::shouldSetFwmark(acceptedSocket, addr)) {
- char data[] = {FWMARK_COMMAND_ON_ACCEPT};
- if (!FwmarkClient().send(data, sizeof(data), acceptedSocket)) {
- return closeFdAndRestoreErrno(acceptedSocket);
- }
- }
- return acceptedSocket;
-}
-
-} // namespace
-
-extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
- if (function && *function) {
- libcConnect = *function;
- *function = netdClientConnect;
- }
-}
-
-extern "C" void netdClientInitAccept(AcceptFunctionType* function) {
- if (function && *function) {
- libcAccept = *function;
- *function = netdClientAccept;
- }
-}
diff --git a/libnetutils/Android.mk b/libnetutils/Android.mk
index aba4621..1f61511 100644
--- a/libnetutils/Android.mk
+++ b/libnetutils/Android.mk
@@ -1,7 +1,7 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
+LOCAL_SRC_FILES := \
dhcpclient.c \
dhcpmsg.c \
dhcp_utils.c \
@@ -12,6 +12,8 @@
libcutils \
liblog
-LOCAL_MODULE:= libnetutils
+LOCAL_MODULE := libnetutils
+
+LOCAL_CFLAGS := -Werror
include $(BUILD_SHARED_LIBRARY)
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index e1df874..0f7c384 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -166,14 +166,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 +234,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 34500e7..700b02f 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));
@@ -282,16 +282,18 @@
ALOGD("chaddr = {%s}", buf);
for (n = 0; n < 64; n++) {
- if ((msg->sname[n] < ' ') || (msg->sname[n] > 127)) {
- if (msg->sname[n] == 0) break;
+ unsigned char x = msg->sname[n];
+ if ((x < ' ') || (x > 127)) {
+ if (x == 0) break;
msg->sname[n] = '.';
}
}
msg->sname[63] = 0;
for (n = 0; n < 128; n++) {
- if ((msg->file[n] < ' ') || (msg->file[n] > 127)) {
- if (msg->file[n] == 0) break;
+ unsigned char x = msg->file[n];
+ if ((x < ' ') || (x > 127)) {
+ if (x == 0) break;
msg->file[n] = '.';
}
}
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index 4d004f6..bfe7121 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -421,7 +421,6 @@
int ifc_set_hwaddr(const char *name, const void *ptr)
{
- int r;
struct ifreq ifr;
ifc_init_ifr(name, &ifr);
@@ -563,17 +562,7 @@
return ret;
}
-/* deprecated v4-only */
-int ifc_add_host_route(const char *name, in_addr_t dst)
-{
- struct in_addr in_dst, in_gw;
-
- in_dst.s_addr = dst;
- in_gw.s_addr = 0;
-
- return ifc_act_on_ipv4_route(SIOCADDRT, name, in_dst, 32, in_gw);
-}
-
+// Needed by code in hidden partner repositories / branches, so don't delete.
int ifc_enable(const char *ifname)
{
int result;
@@ -584,6 +573,7 @@
return result;
}
+// Needed by code in hidden partner repositories / branches, so don't delete.
int ifc_disable(const char *ifname)
{
unsigned addr, count;
@@ -608,14 +598,16 @@
{
#ifdef HAVE_ANDROID_OS
int result, success;
- in_addr_t myaddr;
+ in_addr_t myaddr = 0;
struct ifreq ifr;
struct in6_ifreq ifr6;
if (reset_mask & RESET_IPV4_ADDRESSES) {
/* IPv4. Clear connections on the IP address. */
ifc_init();
- ifc_get_info(ifname, &myaddr, NULL, NULL);
+ if (!(reset_mask & RESET_IGNORE_INTERFACE_ADDRESS)) {
+ ifc_get_info(ifname, &myaddr, NULL, NULL);
+ }
ifc_init_ifr(ifname, &ifr);
init_sockaddr_in(&ifr.ifr_addr, myaddr);
result = ioctl(ifc_ctl_sock, SIOCKILLADDR, &ifr);
@@ -648,118 +640,6 @@
}
/*
- * Remove the routes associated with the named interface.
- */
-int ifc_remove_host_routes(const char *name)
-{
- char ifname[64];
- in_addr_t dest, gway, mask;
- int flags, refcnt, use, metric, mtu, win, irtt;
- struct rtentry rt;
- FILE *fp;
- struct in_addr addr;
-
- fp = fopen("/proc/net/route", "r");
- if (fp == NULL)
- return -1;
- /* Skip the header line */
- if (fscanf(fp, "%*[^\n]\n") < 0) {
- fclose(fp);
- return -1;
- }
- ifc_init();
- for (;;) {
- int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
- ifname, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
- &mtu, &win, &irtt);
- if (nread != 11) {
- break;
- }
- if ((flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST)
- || strcmp(ifname, name) != 0) {
- continue;
- }
- memset(&rt, 0, sizeof(rt));
- rt.rt_dev = (void *)name;
- init_sockaddr_in(&rt.rt_dst, dest);
- init_sockaddr_in(&rt.rt_gateway, gway);
- init_sockaddr_in(&rt.rt_genmask, mask);
- addr.s_addr = dest;
- if (ioctl(ifc_ctl_sock, SIOCDELRT, &rt) < 0) {
- ALOGD("failed to remove route for %s to %s: %s",
- ifname, inet_ntoa(addr), strerror(errno));
- }
- }
- fclose(fp);
- ifc_close();
- return 0;
-}
-
-/*
- * Return the address of the default gateway
- *
- * TODO: factor out common code from this and remove_host_routes()
- * so that we only scan /proc/net/route in one place.
- *
- * DEPRECATED
- */
-int ifc_get_default_route(const char *ifname)
-{
- char name[64];
- in_addr_t dest, gway, mask;
- int flags, refcnt, use, metric, mtu, win, irtt;
- int result;
- FILE *fp;
-
- fp = fopen("/proc/net/route", "r");
- if (fp == NULL)
- return 0;
- /* Skip the header line */
- if (fscanf(fp, "%*[^\n]\n") < 0) {
- fclose(fp);
- return 0;
- }
- ifc_init();
- result = 0;
- for (;;) {
- int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
- name, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
- &mtu, &win, &irtt);
- if (nread != 11) {
- break;
- }
- if ((flags & (RTF_UP|RTF_GATEWAY)) == (RTF_UP|RTF_GATEWAY)
- && dest == 0
- && strcmp(ifname, name) == 0) {
- result = gway;
- break;
- }
- }
- fclose(fp);
- ifc_close();
- return result;
-}
-
-/*
- * Sets the specified gateway as the default route for the named interface.
- * DEPRECATED
- */
-int ifc_set_default_route(const char *ifname, in_addr_t gateway)
-{
- struct in_addr addr;
- int result;
-
- ifc_init();
- addr.s_addr = gateway;
- if ((result = ifc_create_default_route(ifname, gateway)) < 0) {
- ALOGD("failed to add %s as default route for %s: %s",
- inet_ntoa(addr), ifname, strerror(errno));
- }
- ifc_close();
- return result;
-}
-
-/*
* Removes the default route for the named interface.
*/
int ifc_remove_default_route(const char *ifname)
@@ -821,151 +701,3 @@
return 0;
}
-
-int ifc_act_on_ipv6_route(int action, const char *ifname, struct in6_addr dst, int prefix_length,
- struct in6_addr gw)
-{
- struct in6_rtmsg rtmsg;
- int result;
- int ifindex;
-
- memset(&rtmsg, 0, sizeof(rtmsg));
-
- ifindex = if_nametoindex(ifname);
- if (ifindex == 0) {
- printerr("if_nametoindex() failed: interface %s\n", ifname);
- return -ENXIO;
- }
-
- rtmsg.rtmsg_ifindex = ifindex;
- rtmsg.rtmsg_dst = dst;
- rtmsg.rtmsg_dst_len = prefix_length;
- rtmsg.rtmsg_flags = RTF_UP;
-
- if (prefix_length == 128) {
- rtmsg.rtmsg_flags |= RTF_HOST;
- }
-
- if (memcmp(&gw, &in6addr_any, sizeof(in6addr_any))) {
- rtmsg.rtmsg_flags |= RTF_GATEWAY;
- rtmsg.rtmsg_gateway = gw;
- }
-
- ifc_init6();
-
- if (ifc_ctl_sock6 < 0) {
- return -errno;
- }
-
- result = ioctl(ifc_ctl_sock6, action, &rtmsg);
- if (result < 0) {
- if (errno == EEXIST) {
- result = 0;
- } else {
- result = -errno;
- }
- }
- ifc_close6();
- return result;
-}
-
-int ifc_act_on_route(int action, const char *ifname, const char *dst, int prefix_length,
- const char *gw)
-{
- int ret = 0;
- struct sockaddr_in ipv4_dst, ipv4_gw;
- struct sockaddr_in6 ipv6_dst, ipv6_gw;
- struct addrinfo hints, *addr_ai, *gw_ai;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
- hints.ai_flags = AI_NUMERICHOST;
-
- ret = getaddrinfo(dst, NULL, &hints, &addr_ai);
-
- if (ret != 0) {
- printerr("getaddrinfo failed: invalid address %s\n", dst);
- return -EINVAL;
- }
-
- if (gw == NULL || (strlen(gw) == 0)) {
- if (addr_ai->ai_family == AF_INET6) {
- gw = "::";
- } else if (addr_ai->ai_family == AF_INET) {
- gw = "0.0.0.0";
- }
- }
-
- if (((addr_ai->ai_family == AF_INET6) && (prefix_length < 0 || prefix_length > 128)) ||
- ((addr_ai->ai_family == AF_INET) && (prefix_length < 0 || prefix_length > 32))) {
- printerr("ifc_add_route: invalid prefix length");
- freeaddrinfo(addr_ai);
- return -EINVAL;
- }
-
- ret = getaddrinfo(gw, NULL, &hints, &gw_ai);
- if (ret != 0) {
- printerr("getaddrinfo failed: invalid gateway %s\n", gw);
- freeaddrinfo(addr_ai);
- return -EINVAL;
- }
-
- if (addr_ai->ai_family != gw_ai->ai_family) {
- printerr("ifc_add_route: different address families: %s and %s\n", dst, gw);
- freeaddrinfo(addr_ai);
- freeaddrinfo(gw_ai);
- return -EINVAL;
- }
-
- if (addr_ai->ai_family == AF_INET6) {
- memcpy(&ipv6_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in6));
- memcpy(&ipv6_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in6));
- ret = ifc_act_on_ipv6_route(action, ifname, ipv6_dst.sin6_addr,
- prefix_length, ipv6_gw.sin6_addr);
- } else if (addr_ai->ai_family == AF_INET) {
- memcpy(&ipv4_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in));
- memcpy(&ipv4_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in));
- ret = ifc_act_on_ipv4_route(action, ifname, ipv4_dst.sin_addr,
- prefix_length, ipv4_gw.sin_addr);
- } else {
- printerr("ifc_add_route: getaddrinfo returned un supported address family %d\n",
- addr_ai->ai_family);
- ret = -EAFNOSUPPORT;
- }
-
- freeaddrinfo(addr_ai);
- freeaddrinfo(gw_ai);
- return ret;
-}
-
-/*
- * DEPRECATED
- */
-int ifc_add_ipv4_route(const char *ifname, struct in_addr dst, int prefix_length,
- struct in_addr gw)
-{
- int i =ifc_act_on_ipv4_route(SIOCADDRT, ifname, dst, prefix_length, gw);
- if (DBG) printerr("ifc_add_ipv4_route(%s, xx, %d, xx) = %d", ifname, prefix_length, i);
- return i;
-}
-
-/*
- * DEPRECATED
- */
-int ifc_add_ipv6_route(const char *ifname, struct in6_addr dst, int prefix_length,
- struct in6_addr gw)
-{
- return ifc_act_on_ipv6_route(SIOCADDRT, ifname, dst, prefix_length, gw);
-}
-
-int ifc_add_route(const char *ifname, const char *dst, int prefix_length, const char *gw)
-{
- int i = ifc_act_on_route(SIOCADDRT, ifname, dst, prefix_length, gw);
- if (DBG) printerr("ifc_add_route(%s, %s, %d, %s) = %d", ifname, dst, prefix_length, gw, i);
- return i;
-}
-
-int ifc_remove_route(const char *ifname, const char*dst, int prefix_length, const char *gw)
-{
- return ifc_act_on_route(SIOCDELRT, ifname, dst, prefix_length, gw);
-}
diff --git a/libnetutils/packet.c b/libnetutils/packet.c
index be4e0db..a878dd3 100644
--- a/libnetutils/packet.c
+++ b/libnetutils/packet.c
@@ -41,7 +41,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) {
@@ -230,6 +230,8 @@
packet.udp.check = 0;
sum = finish_sum(checksum(&packet, nread, 0));
packet.udp.check = temp;
+ if (!sum)
+ sum = finish_sum(sum);
if (temp != sum) {
ALOGW("UDP header checksum failure (0x%x should be 0x%x)", sum, temp);
return -1;
diff --git a/libnl_2/.gitignore b/libnl_2/.gitignore
deleted file mode 100644
index d4ca744..0000000
--- a/libnl_2/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-include/netlink/version.h.in
-cscope.*
diff --git a/libnl_2/Android.mk b/libnl_2/Android.mk
deleted file mode 100644
index 3721fc6..0000000
--- a/libnl_2/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-#######################################
-# * Netlink cache not implemented
-# * Library is not thread safe
-#######################################
-
-LOCAL_PATH := $(call my-dir)
-
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- attr.c \
- cache.c \
- genl/genl.c \
- genl/family.c \
- handlers.c \
- msg.c \
- netlink.c \
- object.c \
- socket.c \
- dbg.c
-
-LOCAL_C_INCLUDES += \
- external/libnl-headers
-
-# Static Library
-LOCAL_MODULE := libnl_2
-LOCAL_MODULE_TAGS := optional
-LOCAL_32_BIT_ONLY := true
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES :=
-LOCAL_WHOLE_STATIC_LIBRARIES:= libnl_2
-LOCAL_SHARED_LIBRARIES:= liblog
-LOCAL_MODULE := libnl_2
-LOCAL_MODULE_TAGS := optional
-LOCAL_32_BIT_ONLY := true
-include $(BUILD_SHARED_LIBRARY)
diff --git a/libnl_2/README b/libnl_2/README
deleted file mode 100644
index 14db6db..0000000
--- a/libnl_2/README
+++ /dev/null
@@ -1,88 +0,0 @@
-Netlink Protocol Library
-
-This library is a clean room re-implementation of libnl 2.0 and
-re-licensed under Apache 2.0. It was developed primarily to support
-wpa_supplicant. However, with additional development can be extended
-to support other netlink applications.
-
-Netlink Protocol Format (RFC3549)
-
-+-----------------+-+-------------------+-+
-|Netlink Message |P| Generic Netlink |P|
-| Header |A| Message Header |A|
-|(struct nlmsghdr)|D|(struct genlmsghdr)|D|
-+-----------------+-+-------------------+-+-------------+
-|len:4|type:2|flags:2|seq:4 pid:4|cmd:1|ver:1|reserved:2|
-+--------------------------------+----------------------+
-+-----------------+-+-----------------+-+-----------------+-+-----------------+-+---+
-|Netlink Attribute|P|Netlink Attribute|P|Netlink Attribute|P|Netlink Attribute|P|...|
-| #0 Header |A| #0 Payload |A| #1 Header |A| #1 Payload |A| |
-| (struct nlattr) |D| (void) |D| (struct nlattr) |D| (void) |D| |
-+-----------------+-+-----------------+-+-----------------+-+-----------------+-+---+
-|len:2(==4+payload)|type:2|payload|pad|
-+-------------------------+-------+---+
-
-NETLINK OVERVIEW
-
-* Each netlink message consists of a bitstream with a netlink header.
-* After this header a second header *can* be used specific to the netlink
- family in use. This library was tested using the generic netlink
- protocol defined by struct genlmsghdr to support nl80211.
-* After the header(s) netlink attributes can be appended to the message
- which hold can hold basic types such as unsigned integers and strings.
-* Attributes can also be nested. This is accomplished by calling "nla_nest_start"
- which creates an empty attribute with nest attributes as its payload. Then to
- close the nest, "nla_nest_end" is called.
-* All data structures in this implementation are byte-aligned (Currently 4 bytes).
-* Acknowledgements (ACKs) are sent as NLMSG_ERROR netlink message types (0x2) and
- have an error value of 0.
-
-KNOWN ISSUES
-
- GENERAL
- * Not tested for thread safety
-
- Android.mk
- * No dynamic library because of netlink cache not implemented and
- not tested for thread safety
-
- attr.c
- * nla_parse - does not use nla_policy argument
-
- cache.c
- * netlink cache not implemented and only supports one netlink family id
- which is stored in the nl_cache pointer instead of an actual cache
-
- netlink.c
- * nl_recvmsgs - does not support nl_cb_overwrite_recv()
- * nl_recv - sets/unsets asynchronous socket flag
-
-SOURCE FILES
-
-* Android.mk - Android makefile
-* README - This file
-* attr.c - Netlink attributes
-* cache.c - Netlink cache
-* genl/family.c - Generic netlink family id
-* genl/genl.c - Generic netlink
-* handlers.c - Netlink callbacks
-* msg.c - Netlink messages construction
-* netlink.c - Netlink socket communication
-* object.c - libnl object wrapper
-* socket.c - Netlink kernel socket utils
-
-IMPORTANT HEADER FILES - NOTE: These are based on the the origin GPL libnl headers
-
-* netlink-types.h - Contains many important structs for libnl
- to represent netlink objects
-* netlink/netlink-kernel.h - Netlink kernel headers and field constants.
-* netlink/msg.h - macros for iterating over netlink messages
-* netlink/attr.h - netlink attribute constants, iteration macros and setters
-
-REFERENCES
-
-* nl80211.h
-* netlink_types.h
-* $LINUX_KERNEL/net/wireless/nl80211.c
-* http://www.infradead.org/~tgr/libnl/doc-3.0/index.html
-* http://www.netfilter.org/projects/libmnl/doxygen/index.html
diff --git a/libnl_2/attr.c b/libnl_2/attr.c
deleted file mode 100644
index 2ef7590..0000000
--- a/libnl_2/attr.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * 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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <errno.h>
-#include "netlink/netlink.h"
-#include "netlink/msg.h"
-#include "netlink/attr.h"
-#include "netlink-types.h"
-
-/* Return payload of string attribute. */
-char *nla_get_string(struct nlattr *nla)
-{
- return (char *) nla_data(nla);
-}
-
-/* Return payload of 16 bit integer attribute. */
-uint16_t nla_get_u16(struct nlattr *nla)
-{
- return *((uint16_t *) nla_data(nla));
-}
-
-/* Return payload of 32 bit integer attribute. */
-uint32_t nla_get_u32(struct nlattr *nla)
-{
- return *((uint32_t *) nla_data(nla));
-}
-
-/* Return value of 8 bit integer attribute. */
-uint8_t nla_get_u8(struct nlattr *nla)
-{
- return *((uint8_t *) nla_data(nla));
-}
-
-/* Return payload of uint64_t attribute. */
-uint64_t nla_get_u64(struct nlattr *nla)
-{
- uint64_t tmp;
- nla_memcpy(&tmp, nla, sizeof(tmp));
- return tmp;
-}
-
-/* Head of payload */
-void *nla_data(const struct nlattr *nla)
-{
- return (void *) ((char *) nla + NLA_HDRLEN);
-}
-
-/* Return length of the payload . */
-int nla_len(const struct nlattr *nla)
-{
- return nla->nla_len - NLA_HDRLEN;
-}
-
-int nla_padlen(int payload)
-{
- return NLA_ALIGN(payload) - payload;
-}
-
-/* Start a new level of nested attributes. */
-struct nlattr *nla_nest_start(struct nl_msg *msg, int attrtype)
-{
- struct nlattr *start = (struct nlattr *)nlmsg_tail(msg->nm_nlh);
- int rc;
-
- rc = nla_put(msg, attrtype, 0, NULL);
- if (rc < 0)
- return NULL;
-
- return start;
-}
-
-/* Finalize nesting of attributes. */
-int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
-{
- /* Set attribute size */
- start->nla_len = (unsigned char *)nlmsg_tail(nlmsg_hdr(msg)) -
- (unsigned char *)start;
- return 0;
-}
-
-/* Return next attribute in a stream of attributes. */
-struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
-{
- struct nlattr *next_nla = NULL;
- if (nla->nla_len >= sizeof(struct nlattr) &&
- nla->nla_len <= *remaining){
- next_nla = (struct nlattr *) \
- ((char *) nla + NLA_ALIGN(nla->nla_len));
- *remaining = *remaining - NLA_ALIGN(nla->nla_len);
- }
-
- return next_nla;
-
-}
-
-/* Check if the attribute header and payload can be accessed safely. */
-int nla_ok(const struct nlattr *nla, int remaining)
-{
- return remaining > 0 &&
- nla->nla_len >= sizeof(struct nlattr) &&
- sizeof(struct nlattr) <= (unsigned int) remaining &&
- nla->nla_len <= remaining;
-}
-
-/* Create attribute index based on a stream of attributes. */
-/* NOTE: Policy not used ! */
-int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
- int len, struct nla_policy *policy)
-{
- struct nlattr *pos;
- int rem;
-
- /* First clear table */
- memset(tb, 0, (maxtype + 1) * sizeof(struct nlattr *));
-
- nla_for_each_attr(pos, head, len, rem) {
- int type = nla_type(pos);
-
- if ((type <= maxtype) && (type != 0))
- tb[type] = pos;
- }
-
- return 0;
-}
-
-
-/* Create attribute index based on nested attribute. */
-int nla_parse_nested(struct nlattr *tb[], int maxtype,
- struct nlattr *nla, struct nla_policy *policy)
-{
- return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
-}
-
-
-/* Add a unspecific attribute to netlink message. */
-int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
-{
- struct nlattr *nla;
-
- /* Reserve space and init nla header */
- nla = nla_reserve(msg, attrtype, datalen);
- if (nla) {
- memcpy(nla_data(nla), data, datalen);
- return 0;
- }
-
- return -EINVAL;
-}
-
-/* Add 8 bit integer attribute to netlink message. */
-int nla_put_u8(struct nl_msg *msg, int attrtype, uint8_t value)
-{
- return nla_put(msg, attrtype, sizeof(uint8_t), &value);
-}
-
-/* Add 16 bit integer attribute to netlink message. */
-int nla_put_u16(struct nl_msg *msg, int attrtype, uint16_t value)
-{
- return nla_put(msg, attrtype, sizeof(uint16_t), &value);
-}
-
-/* Add 32 bit integer attribute to netlink message. */
-int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value)
-{
- return nla_put(msg, attrtype, sizeof(uint32_t), &value);
-}
-
-/* Add 64 bit integer attribute to netlink message. */
-int nla_put_u64(struct nl_msg *msg, int attrtype, uint64_t value)
-{
- return nla_put(msg, attrtype, sizeof(uint64_t), &value);
-}
-
-/* Add nested attributes to netlink message. */
-/* Takes the attributes found in the nested message and appends them
- * to the message msg nested in a container of the type attrtype. The
- * nested message may not have a family specific header */
-int nla_put_nested(struct nl_msg *msg, int attrtype, struct nl_msg *nested)
-{
- int rc;
-
- rc = nla_put(msg, attrtype, nlmsg_attrlen(nlmsg_hdr(nested), 0),
- nlmsg_attrdata(nlmsg_hdr(nested), 0));
- return rc;
-
-}
-
-/* Return type of the attribute. */
-int nla_type(const struct nlattr *nla)
-{
- return (int)nla->nla_type & NLA_TYPE_MASK;
-}
-
-/* Reserves room for an attribute in specified netlink message and fills
- * in the attribute header (type,length). Return NULL if insufficient space */
-struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int data_len)
-{
-
- struct nlattr *nla;
- const unsigned int NEW_SIZE = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) +
- NLA_ALIGN(NLA_HDRLEN + data_len);
-
- /* Check enough space for attribute */
- if (NEW_SIZE > msg->nm_size)
- return NULL;
-
- nla = (struct nlattr *)nlmsg_tail(msg->nm_nlh);
- nla->nla_type = attrtype;
- nla->nla_len = NLA_HDRLEN + data_len;
- memset((unsigned char *)nla + nla->nla_len, 0, nla_padlen(data_len));
- msg->nm_nlh->nlmsg_len = NEW_SIZE;
- return nla;
-}
-
-/* Copy attribute payload to another memory area. */
-int nla_memcpy(void *dest, struct nlattr *src, int count)
-{
- if (!src || !dest)
- return 0;
- if (count > nla_len(src))
- count = nla_len(src);
- memcpy(dest, nla_data(src), count);
- return count;
-}
diff --git a/libnl_2/dbg.c b/libnl_2/dbg.c
deleted file mode 100644
index 9764de6..0000000
--- a/libnl_2/dbg.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "netlink/netlink.h"
-#include <android/log.h>
-
-void libnl_printf(int level, char *format, ...)
-{
- va_list ap;
-
- level = ANDROID_LOG_ERROR;
- va_start(ap, format);
- __android_log_vprint(level, "libnl_2", format, ap);
- va_end(ap);
-}
diff --git a/libnl_2/genl/family.c b/libnl_2/genl/family.c
deleted file mode 100644
index 1beee6e..0000000
--- a/libnl_2/genl/family.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include "netlink-types.h"
-
-static struct genl_family *genl_family_find_byname(const char *name)
-{
- return NULL;
-}
-
-/* Release reference and none outstanding */
-void genl_family_put(struct genl_family *family)
-{
- family->ce_refcnt--;
- if (family->ce_refcnt <= 0)
- free(family);
-}
-
-unsigned int genl_family_get_id(struct genl_family *family)
-{
- const int NO_FAMILY_ID = 0;
-
- if (!family)
- return NO_FAMILY_ID;
- else
- return family->gf_id;
-
-}
-
diff --git a/libnl_2/genl/genl.c b/libnl_2/genl/genl.c
deleted file mode 100644
index 1a39c6a..0000000
--- a/libnl_2/genl/genl.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * 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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <errno.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <netlink/genl/ctrl.h>
-#include <netlink/genl/family.h>
-#include "netlink-types.h"
-
-/* Get head of attribute data. */
-struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
-{
- return (struct nlattr *) \
- ((char *) gnlh + GENL_HDRLEN + NLMSG_ALIGN(hdrlen));
-
-}
-
-/* Get length of attribute data. */
-int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
-{
- struct nlattr *nla;
- struct nlmsghdr *nlh;
-
- nla = genlmsg_attrdata(gnlh, hdrlen);
- nlh = (struct nlmsghdr *) ((char *) gnlh - NLMSG_HDRLEN);
- return (char *) nlmsg_tail(nlh) - (char *) nla;
-}
-
-/* Add generic netlink header to netlink message. */
-void *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family,
- int hdrlen, int flags, uint8_t cmd, uint8_t version)
-{
- int new_size;
- struct nlmsghdr *nlh;
- struct timeval tv;
- struct genlmsghdr *gmh;
-
- /* Make sure nl_msg has enough space */
- new_size = NLMSG_HDRLEN + GENL_HDRLEN + hdrlen;
- if ((sizeof(struct nl_msg) + new_size) > msg->nm_size)
- goto fail;
-
- /* Fill in netlink header */
- nlh = msg->nm_nlh;
- nlh->nlmsg_len = new_size;
- nlh->nlmsg_type = family;
- nlh->nlmsg_pid = getpid();
- nlh->nlmsg_flags = flags | NLM_F_REQUEST | NLM_F_ACK;
-
- /* Get current time for sequence number */
- if (gettimeofday(&tv, NULL))
- nlh->nlmsg_seq = 1;
- else
- nlh->nlmsg_seq = (int) tv.tv_sec;
-
- /* Setup genlmsghdr in new message */
- gmh = (struct genlmsghdr *) ((char *)nlh + NLMSG_HDRLEN);
- gmh->cmd = (__u8) cmd;
- gmh->version = version;
-
- return gmh;
-fail:
- return NULL;
-
-}
-
-/* Socket has already been alloced to connect it to kernel? */
-int genl_connect(struct nl_sock *sk)
-{
- return nl_connect(sk, NETLINK_GENERIC);
-
-}
-
-int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
-{
- int rc = -1;
- int nl80211_genl_id = -1;
- char sendbuf[sizeof(struct nlmsghdr)+sizeof(struct genlmsghdr)];
- struct nlmsghdr nlmhdr;
- struct genlmsghdr gmhhdr;
- struct iovec sendmsg_iov;
- struct msghdr msg;
- int num_char;
- const int RECV_BUF_SIZE = getpagesize();
- char *recvbuf;
- struct iovec recvmsg_iov;
- int nl80211_flag = 0, nlm_f_multi = 0, nlmsg_done = 0;
- struct nlmsghdr *nlh;
-
- /* REQUEST GENERIC NETLINK FAMILY ID */
- /* Message buffer */
- nlmhdr.nlmsg_len = sizeof(sendbuf);
- nlmhdr.nlmsg_type = NETLINK_GENERIC;
- nlmhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
- nlmhdr.nlmsg_seq = sock->s_seq_next;
- nlmhdr.nlmsg_pid = sock->s_local.nl_pid;
-
- /* Generic netlink header */
- memset(&gmhhdr, 0, sizeof(gmhhdr));
- gmhhdr.cmd = CTRL_CMD_GETFAMILY;
- gmhhdr.version = CTRL_ATTR_FAMILY_ID;
-
- /* Combine netlink and generic netlink headers */
- memcpy(&sendbuf[0], &nlmhdr, sizeof(nlmhdr));
- memcpy(&sendbuf[0]+sizeof(nlmhdr), &gmhhdr, sizeof(gmhhdr));
-
- /* Create IO vector with Netlink message */
- sendmsg_iov.iov_base = &sendbuf;
- sendmsg_iov.iov_len = sizeof(sendbuf);
-
- /* Socket message */
- msg.msg_name = (void *) &sock->s_peer;
- msg.msg_namelen = sizeof(sock->s_peer);
- msg.msg_iov = &sendmsg_iov;
- msg.msg_iovlen = 1; /* Only sending one iov */
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_flags = 0;
-
- /* Send message and verify sent */
- num_char = sendmsg(sock->s_fd, &msg, 0);
- if (num_char == -1)
- return -errno;
-
- /* RECEIVE GENL CMD RESPONSE */
-
- /* Create receive iov buffer */
- recvbuf = (char *) malloc(RECV_BUF_SIZE);
-
- /* Attach to iov */
- recvmsg_iov.iov_base = recvbuf;
- recvmsg_iov.iov_len = RECV_BUF_SIZE;
-
- msg.msg_iov = &recvmsg_iov;
- msg.msg_iovlen = 1;
-
- /***************************************************************/
- /* Receive message. If multipart message, keep receiving until */
- /* message type is NLMSG_DONE */
- /***************************************************************/
-
- do {
-
- int recvmsg_len, nlmsg_rem;
-
- /* Receive message */
- memset(recvbuf, 0, RECV_BUF_SIZE);
- recvmsg_len = recvmsg(sock->s_fd, &msg, 0);
-
- /* Make sure receive successful */
- if (recvmsg_len < 0) {
- rc = -errno;
- goto error_recvbuf;
- }
-
- /* Parse nlmsghdr */
- nlmsg_for_each_msg(nlh, (struct nlmsghdr *) recvbuf, \
- recvmsg_len, nlmsg_rem) {
- struct nlattr *nla;
- int nla_rem;
-
- /* Check type */
- switch (nlh->nlmsg_type) {
- case NLMSG_DONE:
- goto return_genl_id;
- break;
- case NLMSG_ERROR:
-
- /* Should check nlmsgerr struct received */
- fprintf(stderr, "Receive message error\n");
- goto error_recvbuf;
- case NLMSG_OVERRUN:
- fprintf(stderr, "Receive data partly lost\n");
- goto error_recvbuf;
- case NLMSG_MIN_TYPE:
- case NLMSG_NOOP:
- break;
- default:
- break;
- }
-
-
-
- /* Check flags */
- if (nlh->nlmsg_flags & NLM_F_MULTI)
- nlm_f_multi = 1;
- else
- nlm_f_multi = 0;
-
- if (nlh->nlmsg_type & NLMSG_DONE)
- nlmsg_done = 1;
- else
- nlmsg_done = 0;
-
- /* Iteratve over attributes */
- nla_for_each_attr(nla,
- nlmsg_attrdata(nlh, GENL_HDRLEN),
- nlmsg_attrlen(nlh, GENL_HDRLEN),
- nla_rem){
-
- /* If this family is nl80211 */
- if (nla->nla_type == CTRL_ATTR_FAMILY_NAME &&
- !strcmp((char *)nla_data(nla),
- "nl80211"))
- nl80211_flag = 1;
-
- /* Save the family id */
- else if (nl80211_flag &&
- nla->nla_type == CTRL_ATTR_FAMILY_ID) {
- nl80211_genl_id =
- *((int *)nla_data(nla));
- nl80211_flag = 0;
- }
-
- }
-
- }
-
- } while (nlm_f_multi && !nlmsg_done);
-
-return_genl_id:
- /* Return family id as cache pointer */
- *result = (struct nl_cache *) nl80211_genl_id;
- rc = 0;
-error_recvbuf:
- free(recvbuf);
-error:
- return rc;
-}
-
-/* Checks the netlink cache to find family reference by name string */
-/* NOTE: Caller needs to call genl_family_put() when done with *
- * returned object */
-struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache, \
- const char *name)
-{
- struct genl_family *gf = (struct genl_family *) \
- malloc(sizeof(struct genl_family));
- if (!gf)
- goto fail;
- memset(gf, 0, sizeof(*gf));
-
- /* Add ref */
- gf->ce_refcnt++;
-
- /* Overriding cache pointer as family id for now */
- gf->gf_id = (uint16_t) ((uint32_t) cache);
- strncpy(gf->gf_name, name, GENL_NAMSIZ);
-
- return gf;
-fail:
- return NULL;
-
-}
-
-int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
-{
- struct nl_cache *cache = NULL;
- struct genl_family *gf = NULL;
- int id = -1;
-
- /* Hack to support wpa_supplicant */
- if (strcmp(name, "nlctrl") == 0)
- return NETLINK_GENERIC;
-
- if (strcmp(name, "nl80211") != 0) {
- fprintf(stderr, "%s is not supported\n", name);
- return id;
- }
-
- if (!genl_ctrl_alloc_cache(sk, &cache)) {
- gf = genl_ctrl_search_by_name(cache, name);
- if (gf)
- id = genl_family_get_id(gf);
- }
-
- if (gf)
- genl_family_put(gf);
- if (cache)
- nl_cache_free(cache);
-
- return id;
-}
diff --git a/libnl_2/handlers.c b/libnl_2/handlers.c
deleted file mode 100644
index 48dcab4..0000000
--- a/libnl_2/handlers.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <malloc.h>
-#include "netlink-types.h"
-#include "netlink/handlers.h"
-
-/* Allocate a new callback handle. */
-struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
-{
- struct nl_cb *cb;
-
- cb = (struct nl_cb *) malloc(sizeof(struct nl_cb));
- if (cb == NULL)
- goto fail;
- memset(cb, 0, sizeof(*cb));
-
- return nl_cb_get(cb);
-fail:
- return NULL;
-}
-
-/* Clone an existing callback handle */
-struct nl_cb *nl_cb_clone(struct nl_cb *orig)
-{
- struct nl_cb *new_cb;
-
- new_cb = nl_cb_alloc(NL_CB_DEFAULT);
- if (new_cb == NULL)
- goto fail;
-
- /* Copy original and set refcount to 1 */
- memcpy(new_cb, orig, sizeof(*orig));
- new_cb->cb_refcnt = 1;
-
- return new_cb;
-fail:
- return NULL;
-}
-
-/* Set up a callback. */
-int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind, \
- nl_recvmsg_msg_cb_t func, void *arg)
-{
- cb->cb_set[type] = func;
- cb->cb_args[type] = arg;
- return 0;
-}
-
-
-
-/* Set up an error callback. */
-int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind, \
- nl_recvmsg_err_cb_t func, void *arg)
-{
- cb->cb_err = func;
- cb->cb_err_arg = arg;
- return 0;
-
-}
-
-struct nl_cb *nl_cb_get(struct nl_cb *cb)
-{
- cb->cb_refcnt++;
- return cb;
-}
-
-void nl_cb_put(struct nl_cb *cb)
-{
- if (!cb)
- return;
- cb->cb_refcnt--;
- if (cb->cb_refcnt <= 0)
- free(cb);
-}
diff --git a/libnl_2/msg.c b/libnl_2/msg.c
deleted file mode 100644
index 1303e8a..0000000
--- a/libnl_2/msg.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <malloc.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include "netlink-types.h"
-
-/* Allocate a new netlink message with the default maximum payload size. */
-struct nl_msg *nlmsg_alloc(void)
-{
- /* Whole page will store nl_msg + nlmsghdr + genlmsghdr + payload */
- const int page_sz = getpagesize();
- struct nl_msg *nm;
- struct nlmsghdr *nlh;
-
- /* Netlink message */
- nm = (struct nl_msg *) malloc(page_sz);
- if (!nm)
- goto fail;
-
- /* Netlink message header pointer */
- nlh = (struct nlmsghdr *) ((char *) nm + sizeof(struct nl_msg));
-
- /* Initialize */
- memset(nm, 0, page_sz);
- nm->nm_size = page_sz;
-
- nm->nm_src.nl_family = AF_NETLINK;
- nm->nm_src.nl_pid = getpid();
-
- nm->nm_dst.nl_family = AF_NETLINK;
- nm->nm_dst.nl_pid = 0; /* Kernel */
-
- /* Initialize and add to netlink message */
- nlh->nlmsg_len = NLMSG_HDRLEN;
- nm->nm_nlh = nlh;
-
- /* Add to reference count and return nl_msg */
- nlmsg_get(nm);
- return nm;
-fail:
- return NULL;
-}
-
-/* Return pointer to message payload. */
-void *nlmsg_data(const struct nlmsghdr *nlh)
-{
- return (char *) nlh + NLMSG_HDRLEN;
-}
-
-/* Add reference count to nl_msg */
-void nlmsg_get(struct nl_msg *nm)
-{
- nm->nm_refcnt++;
-}
-
-/* Release a reference from an netlink message. */
-void nlmsg_free(struct nl_msg *nm)
-{
- if (nm) {
- nm->nm_refcnt--;
- if (nm->nm_refcnt <= 0)
- free(nm);
- }
-
-}
-
-/* Return actual netlink message. */
-struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
-{
- return n->nm_nlh;
-}
-
-/* Return head of attributes data / payload section */
-struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
-{
- unsigned char *data = nlmsg_data(nlh);
- return (struct nlattr *)(data + NLMSG_ALIGN(hdrlen));
-}
-
-/* Returns pointer to end of netlink message */
-void *nlmsg_tail(const struct nlmsghdr *nlh)
-{
- return (void *)((char *)nlh + NLMSG_ALIGN(nlh->nlmsg_len));
-}
-
-/* Next netlink message in message stream */
-struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
-{
- struct nlmsghdr *next_nlh = NULL;
- int len = nlmsg_len(nlh);
-
- len = NLMSG_ALIGN(len);
- if (*remaining > 0 &&
- len <= *remaining &&
- len >= (int) sizeof(struct nlmsghdr)) {
- next_nlh = (struct nlmsghdr *)((char *)nlh + len);
- *remaining -= len;
- }
-
- return next_nlh;
-}
-
-int nlmsg_datalen(const struct nlmsghdr *nlh)
-{
- return nlh->nlmsg_len - NLMSG_HDRLEN;
-}
-
-/* Length of attributes data */
-int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
-{
- return nlmsg_datalen(nlh) - NLMSG_ALIGN(hdrlen);
-}
-
-/* Length of netlink message */
-int nlmsg_len(const struct nlmsghdr *nlh)
-{
- return nlh->nlmsg_len;
-}
-
-/* Check if the netlink message fits into the remaining bytes */
-int nlmsg_ok(const struct nlmsghdr *nlh, int rem)
-{
- return rem >= (int)sizeof(struct nlmsghdr) &&
- rem >= nlmsg_len(nlh) &&
- nlmsg_len(nlh) >= (int) sizeof(struct nlmsghdr) &&
- nlmsg_len(nlh) <= (rem);
-}
-
-int nlmsg_padlen(int payload)
-{
- return NLMSG_ALIGN(payload) - payload;
-}
diff --git a/libnl_2/netlink.c b/libnl_2/netlink.c
deleted file mode 100644
index ee3d600..0000000
--- a/libnl_2/netlink.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * 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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include "netlink-types.h"
-
-#define NL_BUFFER_SZ (32768U)
-
-/* Checks message for completeness and sends it out */
-int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
-{
- struct nlmsghdr *nlh = msg->nm_nlh;
- struct timeval tv;
-
- if (!nlh) {
- int errsv = errno;
- fprintf(stderr, "Netlink message header is NULL!\n");
- return -errsv;
- }
-
- /* Complete the nl_msg header */
- if (gettimeofday(&tv, NULL))
- nlh->nlmsg_seq = 1;
- else
- nlh->nlmsg_seq = (int) tv.tv_sec;
- nlh->nlmsg_pid = sk->s_local.nl_pid;
- nlh->nlmsg_flags |= NLM_F_REQUEST | NLM_F_ACK;
-
- return nl_send(sk, msg);
-}
-
-/* Receives a netlink message, allocates a buffer in *buf and stores
- * the message content. The peer's netlink address is stored in
- * *nla. The caller is responsible for freeing the buffer allocated in
- * *buf if a positive value is returned. Interrupted system calls are
- * handled by repeating the read. The input buffer size is determined
- * by peeking before the actual read is done */
-int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, \
- unsigned char **buf, struct ucred **creds)
-{
- int rc = -1;
- int sk_flags;
- int RECV_BUF_SIZE = getpagesize();
- int errsv;
- struct iovec recvmsg_iov;
- struct msghdr msg;
-
- /* Allocate buffer */
- *buf = (unsigned char *) malloc(RECV_BUF_SIZE);
- if (!(*buf)) {
- rc = -ENOMEM;
- goto fail;
- }
-
- /* Prepare to receive message */
- recvmsg_iov.iov_base = *buf;
- recvmsg_iov.iov_len = RECV_BUF_SIZE;
-
- msg.msg_name = (void *) &sk->s_peer;
- msg.msg_namelen = sizeof(sk->s_peer);
- msg.msg_iov = &recvmsg_iov;
- msg.msg_iovlen = 1;
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_flags = 0;
-
- /* Make non blocking and then restore previous setting */
- sk_flags = fcntl(sk->s_fd, F_GETFL, 0);
- fcntl(sk->s_fd, F_SETFL, O_NONBLOCK);
- rc = recvmsg(sk->s_fd, &msg, 0);
- errsv = errno;
- fcntl(sk->s_fd, F_SETFL, sk_flags);
-
- if (rc < 0) {
- rc = -errsv;
- free(*buf);
- *buf = NULL;
- }
-
-fail:
- return rc;
-}
-
-/* Receive a set of messages from a netlink socket */
-/* NOTE: Does not currently support callback replacements!!! */
-int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
-{
- struct sockaddr_nl nla;
- struct ucred *creds;
-
- int rc, cb_rc = NL_OK, done = 0;
-
- do {
- unsigned char *buf;
- int i, rem, flags;
- struct nlmsghdr *nlh;
- struct nlmsgerr *nlme;
- struct nl_msg *msg;
-
- done = 0;
- rc = nl_recv(sk, &nla, &buf, &creds);
- if (rc < 0)
- break;
-
- nlmsg_for_each_msg(nlh, (struct nlmsghdr *) buf, rc, rem) {
-
- if (rc <= 0 || cb_rc == NL_STOP)
- break;
-
- /* Check for callbacks */
-
- msg = (struct nl_msg *) malloc(sizeof(struct nl_msg));
- memset(msg, 0, sizeof(*msg));
- msg->nm_nlh = nlh;
-
- /* Check netlink message type */
-
- switch (msg->nm_nlh->nlmsg_type) {
- case NLMSG_ERROR: /* Used for ACK too */
- /* Certainly we should be doing some
- * checking here to make sure this
- * message is intended for us */
- nlme = nlmsg_data(msg->nm_nlh);
- if (nlme->error == 0)
- msg->nm_nlh->nlmsg_flags |= NLM_F_ACK;
-
- rc = nlme->error;
- cb_rc = cb->cb_err(&nla, nlme, cb->cb_err_arg);
- nlme = NULL;
- break;
-
- case NLMSG_DONE:
- done = 1;
-
- case NLMSG_OVERRUN:
- case NLMSG_NOOP:
- default:
- break;
- };
-
- for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
-
- if (cb->cb_set[i]) {
- switch (i) {
- case NL_CB_VALID:
- if (rc > 0)
- cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
- break;
-
- case NL_CB_FINISH:
- if ((msg->nm_nlh->nlmsg_flags & NLM_F_MULTI) &&
- (msg->nm_nlh->nlmsg_type & NLMSG_DONE))
- cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
-
- break;
-
- case NL_CB_ACK:
- if (msg->nm_nlh->nlmsg_flags & NLM_F_ACK)
- cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
-
- break;
- default:
- break;
- }
- }
- }
-
- free(msg);
- if (done)
- break;
- }
- free(buf);
- buf = NULL;
-
- if (done)
- break;
- } while (rc > 0 && cb_rc != NL_STOP);
-
-success:
-fail:
- return rc;
-}
-
-/* Send raw data over netlink socket */
-int nl_send(struct nl_sock *sk, struct nl_msg *msg)
-{
- struct nlmsghdr *nlh = nlmsg_hdr(msg);
- struct iovec msg_iov;
-
- /* Create IO vector with Netlink message */
- msg_iov.iov_base = nlh;
- msg_iov.iov_len = nlh->nlmsg_len;
-
- return nl_send_iovec(sk, msg, &msg_iov, 1);
-}
-
-/* Send netlink message */
-int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg,
- struct iovec *iov, unsigned iovlen)
-{
- int rc;
-
- /* Socket message */
- struct msghdr mh = {
- .msg_name = (void *) &sk->s_peer,
- .msg_namelen = sizeof(sk->s_peer),
- .msg_iov = iov,
- .msg_iovlen = iovlen,
- .msg_control = NULL,
- .msg_controllen = 0,
- .msg_flags = 0
- };
-
- /* Send message and verify sent */
- rc = nl_sendmsg(sk, (struct nl_msg *) &mh, 0);
- if (rc < 0)
- fprintf(stderr, "Error sending netlink message: %d\n", errno);
- return rc;
-
-}
-
-/* Send netlink message with control over sendmsg() message header */
-int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
-{
- return sendmsg(sk->s_fd, (struct msghdr *) msg, (int) hdr);
-}
-
-/* Create and connect netlink socket */
-int nl_connect(struct nl_sock *sk, int protocol)
-{
- struct sockaddr addr;
- socklen_t addrlen;
- int rc;
-
- /* Create RX socket */
- sk->s_fd = socket(PF_NETLINK, SOCK_RAW, protocol);
- if (sk->s_fd < 0)
- return -errno;
-
- /* Set size of RX and TX buffers */
- if (nl_socket_set_buffer_size(sk, NL_BUFFER_SZ, NL_BUFFER_SZ) < 0)
- return -errno;
-
- /* Bind RX socket */
- rc = bind(sk->s_fd, (struct sockaddr *)&sk->s_local, \
- sizeof(sk->s_local));
- if (rc < 0)
- return -errno;
- addrlen = sizeof(addr);
- getsockname(sk->s_fd, &addr, &addrlen);
-
- return 0;
-
-}
diff --git a/libnl_2/object.c b/libnl_2/object.c
deleted file mode 100644
index c53accf..0000000
--- a/libnl_2/object.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include "netlink-types.h"
-
-void nl_object_put(struct nl_object *obj)
-{
- obj->ce_refcnt--;
- if (!obj->ce_refcnt)
- nl_object_free(obj);
-}
-
-void nl_object_free(struct nl_object *obj)
-{
- nl_cache_remove(obj);
-}
-
-
diff --git a/libnl_2/socket.c b/libnl_2/socket.c
deleted file mode 100644
index e94eb9e..0000000
--- a/libnl_2/socket.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <errno.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include "netlink-types.h"
-
-/* Join group */
-int nl_socket_add_membership(struct nl_sock *sk, int group)
-{
- return setsockopt(sk->s_fd, SOL_NETLINK,
- NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
-}
-
-/* Allocate new netlink socket. */
-static struct nl_sock *_nl_socket_alloc(void)
-{
- struct nl_sock *sk;
- struct timeval tv;
- struct nl_cb *cb;
-
- sk = (struct nl_sock *) malloc(sizeof(struct nl_sock));
- if (!sk)
- return NULL;
- memset(sk, 0, sizeof(*sk));
-
- /* Get current time */
-
- if (gettimeofday(&tv, NULL))
- goto fail;
- else
- sk->s_seq_next = (int) tv.tv_sec;
-
- /* Create local socket */
- sk->s_local.nl_family = AF_NETLINK;
- sk->s_local.nl_pid = 0; /* Kernel fills in pid */
- sk->s_local.nl_groups = 0; /* No groups */
-
- /* Create peer socket */
- sk->s_peer.nl_family = AF_NETLINK;
- sk->s_peer.nl_pid = 0; /* Kernel */
- sk->s_peer.nl_groups = 0; /* No groups */
-
- return sk;
-fail:
- free(sk);
- return NULL;
-}
-
-/* Allocate new netlink socket. */
-struct nl_sock *nl_socket_alloc(void)
-{
- struct nl_sock *sk = _nl_socket_alloc();
- struct nl_cb *cb;
-
- if (!sk)
- return NULL;
-
- cb = nl_cb_alloc(NL_CB_DEFAULT);
- if (!cb)
- goto cb_fail;
- sk->s_cb = cb;
- return sk;
-cb_fail:
- free(sk);
- return NULL;
-}
-
-/* Allocate new socket with custom callbacks. */
-struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb)
-{
- struct nl_sock *sk = _nl_socket_alloc();
-
- if (!sk)
- return NULL;
-
- sk->s_cb = cb;
- nl_cb_get(cb);
-
- return sk;
-}
-
-/* Free a netlink socket. */
-void nl_socket_free(struct nl_sock *sk)
-{
- nl_cb_put(sk->s_cb);
- close(sk->s_fd);
- free(sk);
-}
-
-/* Sets socket buffer size of netlink socket */
-int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
-{
- if (setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, \
- &rxbuf, (socklen_t) sizeof(rxbuf)))
- goto error;
-
- if (setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, \
- &txbuf, (socklen_t) sizeof(txbuf)))
- goto error;
-
- return 0;
-error:
- return -errno;
-
-}
-
-int nl_socket_get_fd(struct nl_sock *sk)
-{
- return sk->s_fd;
-}
-
-void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb)
-{
- nl_cb_put(sk->s_cb);
- sk->s_cb = cb;
- nl_cb_get(cb);
-}
-
-struct nl_cb *nl_socket_get_cb(struct nl_sock *sk)
-{
- return nl_cb_get(sk->s_cb);
-}
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index 484cf50..f1bd522 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -36,6 +36,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 := \
@@ -44,11 +45,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
#
@@ -67,6 +70,10 @@
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)
#
@@ -80,6 +87,10 @@
LOCAL_SRC_FILES_arm64 := $(PIXELFLINGER_SRC_FILES_arm64)
LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips)
LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
+# 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_STATIC_LIBRARY)
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
index 7446da2..d770302 100644
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -89,7 +89,7 @@
gExecutableStore = mmap(NULL, kMaxCodeCacheCapacity,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE, fd, 0);
- LOG_ALWAYS_FATAL_IF(gExecutableStore == NULL,
+ LOG_ALWAYS_FATAL_IF(gExecutableStore == MAP_FAILED,
"Creating code cache, mmap failed with error "
"'%s'", strerror(errno));
close(fd);
@@ -201,9 +201,9 @@
mCacheInUse += assemblySize;
mWhen++;
// synchronize caches...
- const long base = long(assembly->base());
- const long curr = base + long(assembly->size());
- __builtin___clear_cache((void*)base, (void*)curr);
+ char* base = reinterpret_cast<char*>(assembly->base());
+ char* curr = reinterpret_cast<char*>(base + assembly->size());
+ __builtin___clear_cache(base, curr);
}
pthread_mutex_unlock(&mLock);
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/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index f84a28a..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__)
+#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(__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
-#ifdef __mips__
+#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__)
+#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(__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 36db49c..961f323 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
@@ -5,6 +5,9 @@
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
@@ -16,4 +19,6 @@
LOCAL_MODULE_TAGS := tests
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_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 ac890c7..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 :=
@@ -13,4 +15,6 @@
LOCAL_MODULE_TAGS := tests
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
index baf4070..8f62f09 100644
--- a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
@@ -14,4 +14,6 @@
LOCAL_MODULE_TAGS := tests
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
index 1cce1bd..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 :=
@@ -13,4 +15,6 @@
LOCAL_MODULE_TAGS := tests
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/codegen/Android.mk b/libpixelflinger/tests/codegen/Android.mk
index aa320fc..bc07015 100644
--- a/libpixelflinger/tests/codegen/Android.mk
+++ b/libpixelflinger/tests/codegen/Android.mk
@@ -15,4 +15,4 @@
LOCAL_MODULE_TAGS := tests
-include $(BUILD_EXECUTABLE)
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/codegen/codegen.cpp b/libpixelflinger/tests/codegen/codegen.cpp
index e9f6c61..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__)
+#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 64f88b7..f479fa1 100644
--- a/libpixelflinger/tests/gglmul/Android.mk
+++ b/libpixelflinger/tests/gglmul/Android.mk
@@ -13,4 +13,4 @@
LOCAL_MODULE_TAGS := tests
-include $(BUILD_EXECUTABLE)
+include $(BUILD_NATIVE_TEST)
diff --git a/libprocessgroup/Android.mk b/libprocessgroup/Android.mk
new file mode 100644
index 0000000..051999a
--- /dev/null
+++ b/libprocessgroup/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := processgroup.cpp
+LOCAL_MODULE := libprocessgroup
+LOCAL_SHARED_LIBRARIES := liblog libutils
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_REQUIRED_MODULE := processgroup_cleanup
+include external/libcxx/libcxx.mk
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := cleanup.cpp
+LOCAL_MODULE := processgroup_cleanup
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_STATIC_LIBRARIES := libc libcutils
+include $(BUILD_EXECUTABLE)
diff --git a/libprocessgroup/cleanup.cpp b/libprocessgroup/cleanup.cpp
new file mode 100644
index 0000000..cca8dc4
--- /dev/null
+++ b/libprocessgroup/cleanup.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2014 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.
+ */
+#include <string.h>
+#include <unistd.h>
+#include <sys/syslimits.h>
+
+#include "processgroup_priv.h"
+
+int main(int argc, char **argv)
+{
+ char buf[PATH_MAX];
+ if (argc != 2)
+ return -1;
+
+ memcpy(buf, PROCESSGROUP_CGROUP_PATH, sizeof(PROCESSGROUP_CGROUP_PATH));
+ strlcat(buf, argv[1], sizeof(buf));
+ return rmdir(buf);
+}
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
new file mode 100644
index 0000000..11bd8cc
--- /dev/null
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#ifndef _PROCESSGROUP_H_
+#define _PROCESSGROUP_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+int killProcessGroup(uid_t uid, int initialPid, int signal);
+
+int createProcessGroup(uid_t uid, int initialPid);
+
+void removeAllProcessGroups(void);
+
+__END_DECLS
+
+#endif
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
new file mode 100644
index 0000000..4b09f24
--- /dev/null
+++ b/libprocessgroup/processgroup.cpp
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2014 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "libprocessgroup"
+
+#include <assert.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.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/SystemClock.h>
+
+#include <processgroup/processgroup.h>
+#include "processgroup_priv.h"
+
+struct ctx {
+ bool initialized;
+ int fd;
+ char buf[128];
+ char *buf_ptr;
+ size_t buf_len;
+};
+
+static int convertUidToPath(char *path, size_t size, uid_t uid)
+{
+ return snprintf(path, size, "%s/%s%d",
+ PROCESSGROUP_CGROUP_PATH,
+ PROCESSGROUP_UID_PREFIX,
+ uid);
+}
+
+static int convertUidPidToPath(char *path, size_t size, uid_t uid, int pid)
+{
+ return snprintf(path, size, "%s/%s%d/%s%d",
+ PROCESSGROUP_CGROUP_PATH,
+ PROCESSGROUP_UID_PREFIX,
+ uid,
+ PROCESSGROUP_PID_PREFIX,
+ pid);
+}
+
+static int initCtx(uid_t uid, int pid, struct ctx *ctx)
+{
+ int ret;
+ char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
+ convertUidPidToPath(path, sizeof(path), uid, pid);
+ strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
+
+ int fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ ret = -errno;
+ SLOGW("failed to open %s: %s", path, strerror(errno));
+ return ret;
+ }
+
+ ctx->fd = fd;
+ ctx->buf_ptr = ctx->buf;
+ ctx->buf_len = 0;
+ ctx->initialized = true;
+
+ SLOGV("Initialized context for %s", path);
+
+ return 0;
+}
+
+static int refillBuffer(struct ctx *ctx)
+{
+ memmove(ctx->buf, ctx->buf_ptr, ctx->buf_len);
+ ctx->buf_ptr = ctx->buf;
+
+ ssize_t ret = read(ctx->fd, ctx->buf_ptr + ctx->buf_len,
+ sizeof(ctx->buf) - ctx->buf_len - 1);
+ if (ret < 0) {
+ return -errno;
+ } else if (ret == 0) {
+ return 0;
+ }
+
+ ctx->buf_len += ret;
+ ctx->buf[ctx->buf_len] = 0;
+ SLOGV("Read %zd to buffer: %s", ret, ctx->buf);
+
+ assert(ctx->buf_len <= sizeof(ctx->buf));
+
+ return ret;
+}
+
+static pid_t getOneAppProcess(uid_t uid, int appProcessPid, struct ctx *ctx)
+{
+ if (!ctx->initialized) {
+ int ret = initCtx(uid, appProcessPid, ctx);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ char *eptr;
+ while ((eptr = (char *)memchr(ctx->buf_ptr, '\n', ctx->buf_len)) == NULL) {
+ int ret = refillBuffer(ctx);
+ if (ret == 0) {
+ return -ERANGE;
+ }
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ *eptr = '\0';
+ char *pid_eptr = NULL;
+ errno = 0;
+ long pid = strtol(ctx->buf_ptr, &pid_eptr, 10);
+ if (errno != 0) {
+ return -errno;
+ }
+ if (pid_eptr != eptr) {
+ return -EINVAL;
+ }
+
+ ctx->buf_len -= (eptr - ctx->buf_ptr) + 1;
+ ctx->buf_ptr = eptr + 1;
+
+ return (pid_t)pid;
+}
+
+static int removeProcessGroup(uid_t uid, int pid)
+{
+ int ret;
+ char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
+
+ convertUidPidToPath(path, sizeof(path), uid, pid);
+ ret = rmdir(path);
+
+ convertUidToPath(path, sizeof(path), uid);
+ rmdir(path);
+
+ return ret;
+}
+
+static void removeUidProcessGroups(const char *uid_path)
+{
+ DIR *uid = opendir(uid_path);
+ if (uid != NULL) {
+ struct dirent cur;
+ struct dirent *dir;
+ while ((readdir_r(uid, &cur, &dir) == 0) && dir) {
+ char path[PROCESSGROUP_MAX_PATH_LEN];
+
+ if (dir->d_type != DT_DIR) {
+ continue;
+ }
+
+ if (strncmp(dir->d_name, PROCESSGROUP_PID_PREFIX, strlen(PROCESSGROUP_PID_PREFIX))) {
+ continue;
+ }
+
+ snprintf(path, sizeof(path), "%s/%s", uid_path, dir->d_name);
+ SLOGV("removing %s\n", path);
+ rmdir(path);
+ }
+ closedir(uid);
+ }
+}
+
+void removeAllProcessGroups()
+{
+ SLOGV("removeAllProcessGroups()");
+ DIR *root = opendir(PROCESSGROUP_CGROUP_PATH);
+ if (root == NULL) {
+ SLOGE("failed to open %s: %s", PROCESSGROUP_CGROUP_PATH, strerror(errno));
+ } else {
+ struct dirent cur;
+ struct dirent *dir;
+ while ((readdir_r(root, &cur, &dir) == 0) && dir) {
+ char path[PROCESSGROUP_MAX_PATH_LEN];
+
+ if (dir->d_type != DT_DIR) {
+ continue;
+ }
+ if (strncmp(dir->d_name, PROCESSGROUP_UID_PREFIX, strlen(PROCESSGROUP_UID_PREFIX))) {
+ continue;
+ }
+
+ snprintf(path, sizeof(path), "%s/%s", PROCESSGROUP_CGROUP_PATH, dir->d_name);
+ removeUidProcessGroups(path);
+ SLOGV("removing %s\n", path);
+ rmdir(path);
+ }
+ closedir(root);
+ }
+}
+
+static int killProcessGroupOnce(uid_t uid, int initialPid, int signal)
+{
+ int processes = 0;
+ struct ctx ctx;
+ pid_t pid;
+
+ ctx.initialized = false;
+
+ while ((pid = getOneAppProcess(uid, initialPid, &ctx)) >= 0) {
+ processes++;
+ if (pid == 0) {
+ // Should never happen... but if it does, trying to kill this
+ // will boomerang right back and kill us! Let's not let that happen.
+ SLOGW("Yikes, we've been told to kill pid 0! How about we don't do that.");
+ continue;
+ }
+ if (pid != initialPid) {
+ // We want to be noisy about killing processes so we can understand
+ // what is going on in the log; however, don't be noisy about the base
+ // process, since that it something we always kill, and we have already
+ // logged elsewhere about killing it.
+ SLOGI("Killing pid %d in uid %d as part of process group %d", pid, uid, initialPid);
+ }
+ int ret = kill(pid, signal);
+ if (ret == -1) {
+ SLOGW("failed to kill pid %d: %s", pid, strerror(errno));
+ }
+ }
+
+ if (ctx.initialized) {
+ close(ctx.fd);
+ }
+
+ return processes;
+}
+
+int killProcessGroup(uid_t uid, int initialPid, int signal)
+{
+ int processes;
+ int sleep_us = 100;
+ int64_t startTime = android::uptimeMillis();
+
+ while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) {
+ SLOGV("killed %d processes for processgroup %d\n", processes, initialPid);
+ if (sleep_us < 128000) {
+ usleep(sleep_us);
+ sleep_us *= 2;
+ } else {
+ SLOGE("failed to kill %d processes for processgroup %d\n",
+ processes, initialPid);
+ break;
+ }
+ }
+
+ SLOGV("Killed process group uid %d pid %d in %" PRId64 "ms, %d procs remain", uid, initialPid,
+ android::uptimeMillis()-startTime, processes);
+
+ if (processes == 0) {
+ return removeProcessGroup(uid, initialPid);
+ } else {
+ return -1;
+ }
+}
+
+static int mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
+{
+ int ret;
+
+ ret = mkdir(path, mode);
+ if (ret < 0 && errno != EEXIST) {
+ return -errno;
+ }
+
+ ret = chown(path, uid, gid);
+ if (ret < 0) {
+ ret = -errno;
+ rmdir(path);
+ return ret;
+ }
+
+ return 0;
+}
+
+int createProcessGroup(uid_t uid, int initialPid)
+{
+ char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
+ int ret;
+
+ convertUidToPath(path, sizeof(path), uid);
+
+ ret = mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM);
+ if (ret < 0) {
+ SLOGE("failed to make and chown %s: %s", path, strerror(-ret));
+ return ret;
+ }
+
+ convertUidPidToPath(path, sizeof(path), uid, initialPid);
+
+ ret = mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM);
+ if (ret < 0) {
+ SLOGE("failed to make and chown %s: %s", path, strerror(-ret));
+ return ret;
+ }
+
+ strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
+
+ int fd = open(path, O_WRONLY);
+ if (fd < 0) {
+ ret = -errno;
+ SLOGE("failed to open %s: %s", path, strerror(errno));
+ return ret;
+ }
+
+ char pid[PROCESSGROUP_MAX_PID_LEN + 1] = {0};
+ int len = snprintf(pid, sizeof(pid), "%d", initialPid);
+
+ ret = write(fd, pid, len);
+ if (ret < 0) {
+ ret = -errno;
+ SLOGE("failed to write '%s' to %s: %s", pid, path, strerror(errno));
+ } else {
+ ret = 0;
+ }
+
+ close(fd);
+ return ret;
+}
+
diff --git a/libprocessgroup/processgroup_priv.h b/libprocessgroup/processgroup_priv.h
new file mode 100644
index 0000000..1895bf9
--- /dev/null
+++ b/libprocessgroup/processgroup_priv.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#ifndef _PROCESSGROUP_PRIV_H_
+#define _PROCESSGROUP_PRIV_H_
+
+#define PROCESSGROUP_CGROUP_PATH "/acct"
+#define PROCESSGROUP_UID_PREFIX "uid_"
+#define PROCESSGROUP_PID_PREFIX "pid_"
+#define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs"
+#define PROCESSGROUP_MAX_UID_LEN 11
+#define PROCESSGROUP_MAX_PID_LEN 11
+#define PROCESSGROUP_MAX_PATH_LEN \
+ (sizeof(PROCESSGROUP_CGROUP_PATH) + \
+ sizeof(PROCESSGROUP_UID_PREFIX) + 1 + \
+ PROCESSGROUP_MAX_UID_LEN + \
+ sizeof(PROCESSGROUP_PID_PREFIX) + 1 + \
+ PROCESSGROUP_MAX_PID_LEN + \
+ sizeof(PROCESSGROUP_CGROUP_PROCS_FILE) + \
+ 1)
+
+#endif
diff --git a/libsparse/Android.mk b/libsparse/Android.mk
index 02ab412..0abe33d 100644
--- a/libsparse/Android.mk
+++ b/libsparse/Android.mk
@@ -88,15 +88,18 @@
include $(BUILD_EXECUTABLE)
+ifneq ($(HOST_OS),windows)
+
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := simg2simg.c
-LOCAL_MODULE := simg2simg
+LOCAL_SRC_FILES := append2simg.c
+LOCAL_MODULE := append2simg
LOCAL_STATIC_LIBRARIES := \
libsparse_host \
libz
LOCAL_CFLAGS := -Werror
include $(BUILD_HOST_EXECUTABLE)
+endif
include $(CLEAR_VARS)
LOCAL_MODULE := simg_dump.py
diff --git a/libsparse/append2simg.c b/libsparse/append2simg.c
new file mode 100644
index 0000000..65e6cc2
--- /dev/null
+++ b/libsparse/append2simg.c
@@ -0,0 +1,140 @@
+/*
+ * 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 _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE 1
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sparse/sparse.h>
+#include "sparse_file.h"
+#include "backed_block.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#if defined(__APPLE__) && defined(__MACH__)
+#define lseek64 lseek
+#endif
+#if defined(__APPLE__) && defined(__MACH__)
+#define lseek64 lseek
+#define off64_t off_t
+#endif
+
+void usage()
+{
+ fprintf(stderr, "Usage: append2simg <output> <input>\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int output;
+ int output_block;
+ char *output_path;
+ struct sparse_file *sparse_output;
+
+ int input;
+ char *input_path;
+ off64_t input_len;
+
+ int tmp_fd;
+ char *tmp_path;
+
+ int ret;
+
+ if (argc == 3) {
+ output_path = argv[1];
+ input_path = argv[2];
+ } else {
+ usage();
+ exit(-1);
+ }
+
+ ret = asprintf(&tmp_path, "%s.append2simg", output_path);
+ if (ret < 0) {
+ fprintf(stderr, "Couldn't allocate filename\n");
+ exit(-1);
+ }
+
+ output = open(output_path, O_RDWR | O_BINARY);
+ if (output < 0) {
+ fprintf(stderr, "Couldn't open output file (%s)\n", strerror(errno));
+ exit(-1);
+ }
+
+ sparse_output = sparse_file_import_auto(output, true);
+ if (!sparse_output) {
+ fprintf(stderr, "Couldn't import output file\n");
+ exit(-1);
+ }
+
+ input = open(input_path, O_RDONLY | O_BINARY);
+ if (input < 0) {
+ fprintf(stderr, "Couldn't open input file (%s)\n", strerror(errno));
+ exit(-1);
+ }
+
+ input_len = lseek64(input, 0, SEEK_END);
+ if (input_len < 0) {
+ fprintf(stderr, "Couldn't get input file length (%s)\n", strerror(errno));
+ exit(-1);
+ } else if (input_len % sparse_output->block_size) {
+ fprintf(stderr, "Input file is not a multiple of the output file's block size");
+ exit(-1);
+ }
+ lseek64(input, 0, SEEK_SET);
+
+ output_block = sparse_output->len / sparse_output->block_size;
+ if (sparse_file_add_fd(sparse_output, input, 0, input_len, output_block) < 0) {
+ fprintf(stderr, "Couldn't add input file\n");
+ exit(-1);
+ }
+ sparse_output->len += input_len;
+
+ tmp_fd = open(tmp_path, O_WRONLY | O_CREAT | O_BINARY, 0664);
+ if (tmp_fd < 0) {
+ fprintf(stderr, "Couldn't open temporary file (%s)\n", strerror(errno));
+ exit(-1);
+ }
+
+ lseek64(output, 0, SEEK_SET);
+ if (sparse_file_write(sparse_output, tmp_fd, false, true, false) < 0) {
+ fprintf(stderr, "Failed to write sparse file\n");
+ exit(-1);
+ }
+
+ sparse_file_destroy(sparse_output);
+ close(tmp_fd);
+ close(output);
+ close(input);
+
+ ret = rename(tmp_path, output_path);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to rename temporary file (%s)\n", strerror(errno));
+ exit(-1);
+ }
+
+ free(tmp_path);
+
+ exit(0);
+}
diff --git a/libsuspend/Android.mk b/libsuspend/Android.mk
index a2fa3e0..1ba2f59 100644
--- a/libsuspend/Android.mk
+++ b/libsuspend/Android.mk
@@ -18,6 +18,7 @@
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_SHARED_LIBRARIES := $(libsuspend_libraries)
+LOCAL_CFLAGS := -Werror
#LOCAL_CFLAGS += -DLOG_NDEBUG=0
include $(BUILD_SHARED_LIBRARY)
@@ -27,5 +28,6 @@
LOCAL_MODULE_TAGS := optional
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
#LOCAL_CFLAGS += -DLOG_NDEBUG=0
include $(BUILD_STATIC_LIBRARY)
diff --git a/libsuspend/autosuspend.c b/libsuspend/autosuspend.c
index eb1f66e..edd1007 100644
--- a/libsuspend/autosuspend.c
+++ b/libsuspend/autosuspend.c
@@ -38,10 +38,13 @@
goto out;
}
+/* Remove autosleep so userspace can manager suspend/resume and keep stats */
+#if 0
autosuspend_ops = autosuspend_autosleep_init();
if (autosuspend_ops) {
goto out;
}
+#endif
autosuspend_ops = autosuspend_wakeup_count_init();
if (autosuspend_ops) {
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/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c
index a88e677..7483a8f 100644
--- a/libsuspend/autosuspend_wakeup_count.c
+++ b/libsuspend/autosuspend_wakeup_count.c
@@ -25,6 +25,7 @@
#include <unistd.h>
#define LOG_TAG "libsuspend"
+//#define LOG_NDEBUG 0
#include <cutils/log.h>
#include "autosuspend_ops.h"
@@ -37,6 +38,7 @@
static pthread_t suspend_thread;
static sem_t suspend_lockout;
static const char *sleep_state = "mem";
+static void (*wakeup_func)(void) = NULL;
static void *suspend_thread_func(void *arg __attribute__((unused)))
{
@@ -80,6 +82,11 @@
if (ret < 0) {
strerror_r(errno, buf, sizeof(buf));
ALOGE("Error writing to %s: %s\n", SYS_POWER_STATE, buf);
+ } else {
+ void (*func)(void) = wakeup_func;
+ if (func != NULL) {
+ (*func)();
+ }
}
}
@@ -131,6 +138,15 @@
return ret;
}
+void set_wakeup_callback(void (*func)(void))
+{
+ if (wakeup_func != NULL) {
+ ALOGE("Duplicate wakeup callback applied, keeping original");
+ return;
+ }
+ wakeup_func = func;
+}
+
struct autosuspend_ops autosuspend_wakeup_count_ops = {
.enable = autosuspend_wakeup_count_enable,
.disable = autosuspend_wakeup_count_disable,
diff --git a/libsuspend/include/suspend/autosuspend.h b/libsuspend/include/suspend/autosuspend.h
index f56fc6a..10e3d27 100644
--- a/libsuspend/include/suspend/autosuspend.h
+++ b/libsuspend/include/suspend/autosuspend.h
@@ -43,6 +43,13 @@
*/
int autosuspend_disable(void);
+/*
+ * set_wakeup_callback
+ *
+ * Set a function to be called each time the device wakes up from suspend.
+ */
+void set_wakeup_callback(void (*func)(void));
+
__END_DECLS
#endif
diff --git a/libsync/Android.mk b/libsync/Android.mk
index 626b762..fd1c88c 100644
--- a/libsync/Android.mk
+++ b/libsync/Android.mk
@@ -7,6 +7,7 @@
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
@@ -15,4 +16,5 @@
LOCAL_MODULE_TAGS := optional tests
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
diff --git a/libsync/tests/Android.mk b/libsync/tests/Android.mk
new file mode 100644
index 0000000..ad20e50
--- /dev/null
+++ b/libsync/tests/Android.mk
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+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
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/../include
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
+LOCAL_SRC_FILES := \
+ sync_test.cpp
+include $(BUILD_NATIVE_TEST)
diff --git a/libsync/tests/sync_test.cpp b/libsync/tests/sync_test.cpp
new file mode 100644
index 0000000..55cd687
--- /dev/null
+++ b/libsync/tests/sync_test.cpp
@@ -0,0 +1,615 @@
+#include <gtest/gtest.h>
+#include <sync/sync.h>
+#include <sw_sync.h>
+#include <fcntl.h>
+#include <vector>
+#include <string>
+#include <cassert>
+#include <iostream>
+#include <unistd.h>
+#include <thread>
+#include <poll.h>
+#include <mutex>
+#include <algorithm>
+#include <tuple>
+#include <random>
+#include <unordered_map>
+
+// TODO: better stress tests?
+// Handle more than 64 fd's simultaneously, i.e. fix sync_fence_info's 4k limit.
+// Handle wraparound in timelines like nvidia.
+
+using namespace std;
+
+namespace {
+
+// C++ wrapper class for sync timeline.
+class SyncTimeline {
+ int m_fd = -1;
+ bool m_fdInitialized = false;
+public:
+ SyncTimeline(const SyncTimeline &) = delete;
+ SyncTimeline& operator=(SyncTimeline&) = delete;
+ SyncTimeline() noexcept {
+ int fd = sw_sync_timeline_create();
+ if (fd == -1)
+ return;
+ m_fdInitialized = true;
+ m_fd = fd;
+ }
+ void destroy() {
+ if (m_fdInitialized) {
+ close(m_fd);
+ m_fd = -1;
+ m_fdInitialized = false;
+ }
+ }
+ ~SyncTimeline() {
+ destroy();
+ }
+ bool isValid() const {
+ if (m_fdInitialized) {
+ int status = fcntl(m_fd, F_GETFD, 0);
+ if (status == 0)
+ return true;
+ else
+ return false;
+ }
+ else {
+ return false;
+ }
+ }
+ int getFd() const {
+ return m_fd;
+ }
+ int inc(int val = 1) {
+ return sw_sync_timeline_inc(m_fd, val);
+ }
+};
+
+struct SyncPointInfo {
+ std::string driverName;
+ std::string objectName;
+ uint64_t timeStampNs;
+ int status; // 1 sig, 0 active, neg is err
+};
+
+// Wrapper class for sync fence.
+class SyncFence {
+ int m_fd = -1;
+ bool m_fdInitialized = false;
+ static int s_fenceCount;
+
+ void setFd(int fd) {
+ m_fd = fd;
+ m_fdInitialized = true;
+ }
+ void clearFd() {
+ m_fd = -1;
+ m_fdInitialized = false;
+ }
+public:
+ bool isValid() const {
+ if (m_fdInitialized) {
+ int status = fcntl(m_fd, F_GETFD, 0);
+ if (status == 0)
+ return true;
+ else
+ return false;
+ }
+ else {
+ return false;
+ }
+ }
+ SyncFence& operator=(SyncFence &&rhs) noexcept {
+ destroy();
+ if (rhs.isValid()) {
+ setFd(rhs.getFd());
+ rhs.clearFd();
+ }
+ return *this;
+ }
+ SyncFence(SyncFence &&fence) noexcept {
+ if (fence.isValid()) {
+ setFd(fence.getFd());
+ fence.clearFd();
+ }
+ }
+ SyncFence(const SyncFence &fence) noexcept {
+ // This is ok, as sync fences are immutable after construction, so a dup
+ // is basically the same thing as a copy.
+ if (fence.isValid()) {
+ int fd = dup(fence.getFd());
+ if (fd == -1)
+ return;
+ setFd(fd);
+ }
+ }
+ SyncFence(const SyncTimeline &timeline,
+ int value,
+ const char *name = nullptr) noexcept {
+ std::string autoName = "allocFence";
+ autoName += s_fenceCount;
+ s_fenceCount++;
+ int fd = sw_sync_fence_create(timeline.getFd(), name ? name : autoName.c_str(), value);
+ if (fd == -1)
+ return;
+ setFd(fd);
+ }
+ SyncFence(const SyncFence &a, const SyncFence &b, const char *name = nullptr) noexcept {
+ std::string autoName = "mergeFence";
+ autoName += s_fenceCount;
+ s_fenceCount++;
+ int fd = sync_merge(name ? name : autoName.c_str(), a.getFd(), b.getFd());
+ if (fd == -1)
+ return;
+ setFd(fd);
+ }
+ SyncFence(const vector<SyncFence> &sources) noexcept {
+ assert(sources.size());
+ SyncFence temp(*begin(sources));
+ for (auto itr = ++begin(sources); itr != end(sources); ++itr) {
+ temp = SyncFence(*itr, temp);
+ }
+ if (temp.isValid()) {
+ setFd(temp.getFd());
+ temp.clearFd();
+ }
+ }
+ void destroy() {
+ if (isValid()) {
+ close(m_fd);
+ clearFd();
+ }
+ }
+ ~SyncFence() {
+ destroy();
+ }
+ int getFd() const {
+ return m_fd;
+ }
+ int wait(int timeout = -1) {
+ return sync_wait(m_fd, timeout);
+ }
+ vector<SyncPointInfo> getInfo() const {
+ struct sync_pt_info *pointInfo = nullptr;
+ vector<SyncPointInfo> fenceInfo;
+ sync_fence_info_data *info = sync_fence_info(getFd());
+ if (!info) {
+ return fenceInfo;
+ }
+ while ((pointInfo = sync_pt_info(info, pointInfo))) {
+ fenceInfo.push_back(SyncPointInfo{
+ pointInfo->driver_name,
+ pointInfo->obj_name,
+ pointInfo->timestamp_ns,
+ pointInfo->status});
+ }
+ sync_fence_info_free(info);
+ return fenceInfo;
+ }
+ int getSize() const {
+ return getInfo().size();
+ }
+ int getSignaledCount() const {
+ return countWithStatus(1);
+ }
+ int getActiveCount() const {
+ return countWithStatus(0);
+ }
+ int getErrorCount() const {
+ return countWithStatus(-1);
+ }
+private:
+ int countWithStatus(int status) const {
+ int count = 0;
+ for (auto &info : getInfo()) {
+ if (info.status == status) {
+ count++;
+ }
+ }
+ return count;
+ }
+};
+
+int SyncFence::s_fenceCount = 0;
+
+TEST(AllocTest, Timeline) {
+ SyncTimeline timeline;
+ ASSERT_TRUE(timeline.isValid());
+}
+
+TEST(AllocTest, Fence) {
+ SyncTimeline timeline;
+ ASSERT_TRUE(timeline.isValid());
+
+ SyncFence fence(timeline, 1);
+ ASSERT_TRUE(fence.isValid());
+}
+
+TEST(AllocTest, FenceNegative) {
+ int timeline = sw_sync_timeline_create();
+ ASSERT_GT(timeline, 0);
+
+ // bad fd.
+ ASSERT_LT(sw_sync_fence_create(-1, "fence", 1), 0);
+
+ // No name - segfaults in user space.
+ // Maybe we should be friendlier here?
+ /*
+ ASSERT_LT(sw_sync_fence_create(timeline, nullptr, 1), 0);
+ */
+ close(timeline);
+}
+
+TEST(FenceTest, OneTimelineWait) {
+ SyncTimeline timeline;
+ ASSERT_TRUE(timeline.isValid());
+
+ SyncFence fence(timeline, 5);
+ ASSERT_TRUE(fence.isValid());
+
+ // Wait on fence until timeout.
+ ASSERT_EQ(fence.wait(0), -1);
+ ASSERT_EQ(errno, ETIME);
+
+ // Advance timeline from 0 -> 1
+ ASSERT_EQ(timeline.inc(1), 0);
+
+ // Wait on fence until timeout.
+ ASSERT_EQ(fence.wait(0), -1);
+ ASSERT_EQ(errno, ETIME);
+
+ // Signal the fence.
+ ASSERT_EQ(timeline.inc(4), 0);
+
+ // Wait successfully.
+ ASSERT_EQ(fence.wait(0), 0);
+
+ // Go even futher, and confirm wait still succeeds.
+ ASSERT_EQ(timeline.inc(10), 0);
+ ASSERT_EQ(fence.wait(0), 0);
+}
+
+TEST(FenceTest, OneTimelinePoll) {
+ SyncTimeline timeline;
+ ASSERT_TRUE(timeline.isValid());
+
+ SyncFence fence(timeline, 100);
+ ASSERT_TRUE(fence.isValid());
+
+ fd_set set;
+ FD_ZERO(&set);
+ FD_SET(fence.getFd(), &set);
+
+ // Poll the fence, and wait till timeout.
+ timeval time = {0};
+ ASSERT_EQ(select(fence.getFd() + 1, &set, nullptr, nullptr, &time), 0);
+
+ // Advance the timeline.
+ timeline.inc(100);
+ timeline.inc(100);
+
+ // Select should return that the fd is read for reading.
+ FD_ZERO(&set);
+ FD_SET(fence.getFd(), &set);
+
+ ASSERT_EQ(select(fence.getFd() + 1, &set, nullptr, nullptr, &time), 1);
+ ASSERT_TRUE(FD_ISSET(fence.getFd(), &set));
+}
+
+TEST(FenceTest, OneTimelineMerge) {
+ SyncTimeline timeline;
+ ASSERT_TRUE(timeline.isValid());
+
+ // create fence a,b,c and then merge them all into fence d.
+ SyncFence a(timeline, 1), b(timeline, 2), c(timeline, 3);
+ ASSERT_TRUE(a.isValid());
+ ASSERT_TRUE(b.isValid());
+ ASSERT_TRUE(c.isValid());
+
+ SyncFence d({a,b,c});
+ ASSERT_TRUE(d.isValid());
+
+ // confirm all fences have one active point (even d).
+ ASSERT_EQ(a.getActiveCount(), 1);
+ ASSERT_EQ(b.getActiveCount(), 1);
+ ASSERT_EQ(c.getActiveCount(), 1);
+ ASSERT_EQ(d.getActiveCount(), 1);
+
+ // confirm that d is not signaled until the max of a,b,c
+ timeline.inc(1);
+ ASSERT_EQ(a.getSignaledCount(), 1);
+ ASSERT_EQ(d.getActiveCount(), 1);
+
+ timeline.inc(1);
+ ASSERT_EQ(b.getSignaledCount(), 1);
+ ASSERT_EQ(d.getActiveCount(), 1);
+
+ timeline.inc(1);
+ ASSERT_EQ(c.getSignaledCount(), 1);
+ ASSERT_EQ(d.getActiveCount(), 0);
+ ASSERT_EQ(d.getSignaledCount(), 1);
+}
+
+TEST(FenceTest, MergeSameFence) {
+ SyncTimeline timeline;
+ ASSERT_TRUE(timeline.isValid());
+
+ SyncFence fence(timeline, 5);
+ ASSERT_TRUE(fence.isValid());
+
+ SyncFence selfMergeFence(fence, fence);
+ ASSERT_TRUE(selfMergeFence.isValid());
+
+ ASSERT_EQ(selfMergeFence.getSignaledCount(), 0);
+
+ timeline.inc(5);
+ ASSERT_EQ(selfMergeFence.getSignaledCount(), 1);
+}
+
+TEST(FenceTest, WaitOnDestroyedTimeline) {
+ SyncTimeline timeline;
+ ASSERT_TRUE(timeline.isValid());
+
+ SyncFence fenceSig(timeline, 100);
+ SyncFence fenceKill(timeline, 200);
+
+ // Spawn a thread to wait on a fence when the timeline is killed.
+ thread waitThread{
+ [&]() {
+ ASSERT_EQ(timeline.inc(100), 0);
+
+ ASSERT_EQ(fenceKill.wait(-1), -1);
+ ASSERT_EQ(errno, ENOENT);
+ }
+ };
+
+ // Wait for the thread to spool up.
+ fenceSig.wait();
+
+ // Kill the timeline.
+ timeline.destroy();
+
+ // wait for the thread to clean up.
+ waitThread.join();
+}
+
+TEST(FenceTest, PollOnDestroyedTimeline) {
+ SyncTimeline timeline;
+ ASSERT_TRUE(timeline.isValid());
+
+ SyncFence fenceSig(timeline, 100);
+ SyncFence fenceKill(timeline, 200);
+
+ // Spawn a thread to wait on a fence when the timeline is killed.
+ thread waitThread{
+ [&]() {
+ ASSERT_EQ(timeline.inc(100), 0);
+
+ // Wait on the fd.
+ struct pollfd fds;
+ fds.fd = fenceKill.getFd();
+ fds.events = POLLIN | POLLERR;
+ ASSERT_EQ(poll(&fds, 1, -1), 1);
+ ASSERT_TRUE(fds.revents & POLLERR);
+ }
+ };
+
+ // Wait for the thread to spool up.
+ fenceSig.wait();
+
+ // Kill the timeline.
+ timeline.destroy();
+
+ // wait for the thread to clean up.
+ waitThread.join();
+}
+
+TEST(FenceTest, MultiTimelineWait) {
+ SyncTimeline timelineA, timelineB, timelineC;
+
+ SyncFence fenceA(timelineA, 5);
+ SyncFence fenceB(timelineB, 5);
+ SyncFence fenceC(timelineC, 5);
+
+ // Make a larger fence using 3 other fences from different timelines.
+ SyncFence mergedFence({fenceA, fenceB, fenceC});
+ ASSERT_TRUE(mergedFence.isValid());
+
+ // Confirm fence isn't signaled
+ ASSERT_EQ(mergedFence.getActiveCount(), 3);
+ ASSERT_EQ(mergedFence.wait(0), -1);
+ ASSERT_EQ(errno, ETIME);
+
+ timelineA.inc(5);
+ ASSERT_EQ(mergedFence.getActiveCount(), 2);
+ ASSERT_EQ(mergedFence.getSignaledCount(), 1);
+
+ timelineB.inc(5);
+ ASSERT_EQ(mergedFence.getActiveCount(), 1);
+ ASSERT_EQ(mergedFence.getSignaledCount(), 2);
+
+ timelineC.inc(5);
+ ASSERT_EQ(mergedFence.getActiveCount(), 0);
+ ASSERT_EQ(mergedFence.getSignaledCount(), 3);
+
+ // confirm you can successfully wait.
+ ASSERT_EQ(mergedFence.wait(100), 0);
+}
+
+TEST(StressTest, TwoThreadsSharedTimeline) {
+ const int iterations = 1 << 16;
+ int counter = 0;
+ SyncTimeline timeline;
+ ASSERT_TRUE(timeline.isValid());
+
+ // Use a single timeline to synchronize two threads
+ // hammmering on the same counter.
+ auto threadMain = [&](int threadId) {
+ for (int i = 0; i < iterations; i++) {
+ SyncFence fence(timeline, i * 2 + threadId);
+ ASSERT_TRUE(fence.isValid());
+
+ // Wait on the prior thread to complete.
+ ASSERT_EQ(fence.wait(), 0);
+
+ // Confirm the previous thread's writes are visible and then inc.
+ ASSERT_EQ(counter, i * 2 + threadId);
+ counter++;
+
+ // Kick off the other thread.
+ ASSERT_EQ(timeline.inc(), 0);
+ }
+ };
+
+ thread a{threadMain, 0};
+ thread b{threadMain, 1};
+ a.join();
+ b.join();
+
+ // make sure the threads did not trample on one another.
+ ASSERT_EQ(counter, iterations * 2);
+}
+
+class ConsumerStressTest : public ::testing::TestWithParam<int> {};
+
+TEST_P(ConsumerStressTest, MultiProducerSingleConsumer) {
+ mutex lock;
+ int counter = 0;
+ int iterations = 1 << 12;
+
+ vector<SyncTimeline> producerTimelines(GetParam());
+ vector<thread> threads;
+ SyncTimeline consumerTimeline;
+
+ // Producer threads run this lambda.
+ auto threadMain = [&](int threadId) {
+ for (int i = 0; i < iterations; i++) {
+ SyncFence fence(consumerTimeline, i);
+ ASSERT_TRUE(fence.isValid());
+
+ // Wait for the consumer to finish. Use alternate
+ // means of waiting on the fence.
+ if ((iterations + threadId) % 8 != 0) {
+ ASSERT_EQ(fence.wait(), 0);
+ }
+ else {
+ while (fence.getSignaledCount() != 1) {
+ ASSERT_EQ(fence.getErrorCount(), 0);
+ }
+ }
+
+ // Every producer increments the counter, the consumer checks + erases it.
+ lock.lock();
+ counter++;
+ lock.unlock();
+
+ ASSERT_EQ(producerTimelines[threadId].inc(), 0);
+ }
+ };
+
+ for (int i = 0; i < GetParam(); i++) {
+ threads.push_back(thread{threadMain, i});
+ }
+
+ // Consumer thread runs this loop.
+ for (int i = 1; i <= iterations; i++) {
+ // Create a fence representing all producers final timelines.
+ vector<SyncFence> fences;
+ for (auto& timeline : producerTimelines) {
+ fences.push_back(SyncFence(timeline, i));
+ }
+ SyncFence mergeFence(fences);
+ ASSERT_TRUE(mergeFence.isValid());
+
+ // Make sure we see an increment from every producer thread. Vary
+ // the means by which we wait.
+ if (iterations % 8 != 0) {
+ ASSERT_EQ(mergeFence.wait(), 0);
+ }
+ else {
+ while (mergeFence.getSignaledCount() != mergeFence.getSize()) {
+ ASSERT_EQ(mergeFence.getErrorCount(), 0);
+ }
+ }
+ ASSERT_EQ(counter, GetParam()*i);
+
+ // Release the producer threads.
+ ASSERT_EQ(consumerTimeline.inc(), 0);
+ }
+
+ for_each(begin(threads), end(threads), [](thread& thread) { thread.join(); });
+}
+INSTANTIATE_TEST_CASE_P(
+ ParameterizedStressTest,
+ ConsumerStressTest,
+ ::testing::Values(2,4,16));
+
+class MergeStressTest : public ::testing::TestWithParam<tuple<int, int>> {};
+
+template <typename K, typename V> using dict = unordered_map<K,V>;
+
+TEST_P(MergeStressTest, RandomMerge) {
+ int timelineCount = get<0>(GetParam());
+ int mergeCount = get<1>(GetParam());
+
+ vector<SyncTimeline> timelines(timelineCount);
+
+ default_random_engine generator;
+ uniform_int_distribution<int> timelineDist(0, timelines.size()-1);
+ uniform_int_distribution<int> syncPointDist(0, numeric_limits<int>::max());
+
+ SyncFence fence(timelines[0], 0);
+ ASSERT_TRUE(fence.isValid());
+
+ unordered_map<int, int> fenceMap;
+ fenceMap.insert(make_tuple(0, 0));
+
+ // Randomly create syncpoints out of a fixed set of timelines, and merge them together.
+ for (int i = 0; i < mergeCount; i++) {
+
+ // Generate syncpoint.
+ int timelineOffset = timelineDist(generator);
+ const SyncTimeline& timeline = timelines[timelineOffset];
+ int syncPoint = syncPointDist(generator);
+
+ // Keep track of the latest syncpoint in each timeline.
+ auto itr = fenceMap.find(timelineOffset);
+ if (itr == end(fenceMap)) {
+ fenceMap.insert(tie(timelineOffset, syncPoint));
+ }
+ else {
+ int oldSyncPoint = itr->second;
+ fenceMap.erase(itr);
+ fenceMap.insert(tie(timelineOffset, max(syncPoint, oldSyncPoint)));
+ }
+
+ // Merge.
+ fence = SyncFence(fence, SyncFence(timeline, syncPoint));
+ ASSERT_TRUE(fence.isValid());
+ }
+
+ // Confirm our map matches the fence.
+ ASSERT_EQ(fence.getSize(), fenceMap.size());
+
+ // Trigger the merged fence.
+ for (auto& item: fenceMap) {
+ ASSERT_EQ(fence.wait(0), -1);
+ ASSERT_EQ(errno, ETIME);
+
+ // Increment the timeline to the last syncpoint.
+ timelines[item.first].inc(item.second);
+ }
+
+ // Check that the fence is triggered.
+ ASSERT_EQ(fence.wait(0), 0);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ ParameterizedMergeStressTest,
+ MergeStressTest,
+ ::testing::Combine(::testing::Values(16,32), ::testing::Values(32, 1024, 1024*32)));
+
+}
+
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 1c9c70a..9d596ef 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -29,6 +29,8 @@
#include <net/if.h>
#include <linux/if.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter_ipv4/ipt_ULOG.h>
/* From kernel's net/netfilter/xt_quota2.c */
@@ -46,6 +48,8 @@
const int NetlinkEvent::NlActionAddressUpdated = 6;
const int NetlinkEvent::NlActionAddressRemoved = 7;
const int NetlinkEvent::NlActionRdnss = 8;
+const int NetlinkEvent::NlActionRouteUpdated = 9;
+const int NetlinkEvent::NlActionRouteRemoved = 10;
NetlinkEvent::NetlinkEvent() {
mAction = NlActionUnknown;
@@ -78,32 +82,109 @@
}
/*
+ * Returns the message name for a message in the NETLINK_ROUTE family, or NULL
+ * if parsing that message is not supported.
+ */
+static const char *rtMessageName(int type) {
+#define NL_EVENT_RTM_NAME(rtm) case rtm: return #rtm;
+ switch (type) {
+ NL_EVENT_RTM_NAME(RTM_NEWLINK);
+ NL_EVENT_RTM_NAME(RTM_DELLINK);
+ NL_EVENT_RTM_NAME(RTM_NEWADDR);
+ NL_EVENT_RTM_NAME(RTM_DELADDR);
+ 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);
+ default:
+ return NULL;
+ }
+#undef NL_EVENT_RTM_NAME
+}
+
+/*
+ * Checks that a binary NETLINK_ROUTE message is long enough for a payload of
+ * size bytes.
+ */
+static bool checkRtNetlinkLength(const struct nlmsghdr *nh, size_t size) {
+ if (nh->nlmsg_len < NLMSG_LENGTH(size)) {
+ SLOGE("Got a short %s message\n", rtMessageName(nh->nlmsg_type));
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Utility function to log errors.
+ */
+static bool maybeLogDuplicateAttribute(bool isDup,
+ const char *attributeName,
+ const char *messageName) {
+ if (isDup) {
+ SLOGE("Multiple %s attributes in %s, ignoring\n", attributeName, messageName);
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Parse a RTM_NEWLINK message.
+ */
+bool NetlinkEvent::parseIfInfoMessage(const struct nlmsghdr *nh) {
+ struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(nh);
+ if (!checkRtNetlinkLength(nh, sizeof(*ifi)))
+ return false;
+
+ if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) {
+ return false;
+ }
+
+ int len = IFLA_PAYLOAD(nh);
+ struct rtattr *rta;
+ for (rta = IFLA_RTA(ifi); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
+ switch(rta->rta_type) {
+ case IFLA_IFNAME:
+ asprintf(&mParams[0], "INTERFACE=%s", (char *) RTA_DATA(rta));
+ mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? NlActionLinkUp :
+ NlActionLinkDown;
+ mSubsystem = strdup("net");
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*
* Parse a RTM_NEWADDR or RTM_DELADDR message.
*/
-bool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr,
- int rtasize) {
- struct rtattr *rta;
+bool NetlinkEvent::parseIfAddrMessage(const struct nlmsghdr *nh) {
+ struct ifaddrmsg *ifaddr = (struct ifaddrmsg *) NLMSG_DATA(nh);
struct ifa_cacheinfo *cacheinfo = NULL;
char addrstr[INET6_ADDRSTRLEN] = "";
+ char ifname[IFNAMSIZ];
+
+ if (!checkRtNetlinkLength(nh, sizeof(*ifaddr)))
+ return false;
// Sanity check.
+ int type = nh->nlmsg_type;
if (type != RTM_NEWADDR && type != RTM_DELADDR) {
SLOGE("parseIfAddrMessage on incorrect message type 0x%x\n", type);
return false;
}
// For log messages.
- const char *msgtype = (type == RTM_NEWADDR) ? "RTM_NEWADDR" : "RTM_DELADDR";
+ const char *msgtype = rtMessageName(type);
- for (rta = IFA_RTA(ifaddr); RTA_OK(rta, rtasize);
- rta = RTA_NEXT(rta, rtasize)) {
+ struct rtattr *rta;
+ int len = IFA_PAYLOAD(nh);
+ for (rta = IFA_RTA(ifaddr); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
if (rta->rta_type == IFA_ADDRESS) {
// Only look at the first address, because we only support notifying
// one change at a time.
- if (*addrstr != '\0') {
- SLOGE("Multiple IFA_ADDRESSes in %s, ignoring\n", msgtype);
+ if (maybeLogDuplicateAttribute(*addrstr != '\0', "IFA_ADDRESS", msgtype))
continue;
- }
// Convert the IP address to a string.
if (ifaddr->ifa_family == AF_INET) {
@@ -128,28 +209,15 @@
}
// Find the interface name.
- char ifname[IFNAMSIZ + 1];
if (!if_indextoname(ifaddr->ifa_index, ifname)) {
SLOGE("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype);
return false;
}
- // Fill in interface information.
- mAction = (type == RTM_NEWADDR) ? NlActionAddressUpdated :
- NlActionAddressRemoved;
- mSubsystem = strdup("net");
- asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
- ifaddr->ifa_prefixlen);
- asprintf(&mParams[1], "INTERFACE=%s", ifname);
- asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
- asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
} else if (rta->rta_type == IFA_CACHEINFO) {
// Address lifetime information.
- if (cacheinfo) {
- // We only support one address.
- SLOGE("Multiple IFA_CACHEINFOs in %s, ignoring\n", msgtype);
+ if (maybeLogDuplicateAttribute(cacheinfo, "IFA_CACHEINFO", msgtype))
continue;
- }
if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) {
SLOGE("Short IFA_CACHEINFO (%zu vs. %zu bytes) in %s",
@@ -158,10 +226,6 @@
}
cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta);
- asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered);
- asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid);
- asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp);
- asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp);
}
}
@@ -170,14 +234,145 @@
return false;
}
+ // Fill in netlink event information.
+ mAction = (type == RTM_NEWADDR) ? NlActionAddressUpdated :
+ NlActionAddressRemoved;
+ mSubsystem = strdup("net");
+ asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
+ ifaddr->ifa_prefixlen);
+ asprintf(&mParams[1], "INTERFACE=%s", ifname);
+ asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
+ asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
+
+ if (cacheinfo) {
+ asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered);
+ asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid);
+ asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp);
+ asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp);
+ }
+
+ return true;
+}
+
+/*
+ * Parse a QLOG_NL_EVENT message.
+ */
+bool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) {
+ const char *devname;
+ ulog_packet_msg_t *pm = (ulog_packet_msg_t *) NLMSG_DATA(nh);
+ if (!checkRtNetlinkLength(nh, sizeof(*pm)))
+ return false;
+
+ devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;
+ asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
+ asprintf(&mParams[1], "INTERFACE=%s", devname);
+ mSubsystem = strdup("qlog");
+ mAction = NlActionChange;
+ return true;
+}
+
+/*
+ * Parse a RTM_NEWROUTE or RTM_DELROUTE message.
+ */
+bool NetlinkEvent::parseRtMessage(const struct nlmsghdr *nh) {
+ uint8_t type = nh->nlmsg_type;
+ const char *msgname = rtMessageName(type);
+
+ // Sanity check.
+ if (type != RTM_NEWROUTE && type != RTM_DELROUTE) {
+ SLOGE("%s: incorrect message type %d (%s)\n", __func__, type, msgname);
+ return false;
+ }
+
+ struct rtmsg *rtm = (struct rtmsg *) NLMSG_DATA(nh);
+ if (!checkRtNetlinkLength(nh, sizeof(*rtm)))
+ return false;
+
+ if (// Ignore static routes we've set up ourselves.
+ (rtm->rtm_protocol != RTPROT_KERNEL &&
+ rtm->rtm_protocol != RTPROT_RA) ||
+ // We're only interested in global unicast routes.
+ (rtm->rtm_scope != RT_SCOPE_UNIVERSE) ||
+ (rtm->rtm_type != RTN_UNICAST) ||
+ // We don't support source routing.
+ (rtm->rtm_src_len != 0) ||
+ // Cloned routes aren't real routes.
+ (rtm->rtm_flags & RTM_F_CLONED)) {
+ return false;
+ }
+
+ int family = rtm->rtm_family;
+ int prefixLength = rtm->rtm_dst_len;
+
+ // Currently we only support: destination, (one) next hop, ifindex.
+ char dst[INET6_ADDRSTRLEN] = "";
+ char gw[INET6_ADDRSTRLEN] = "";
+ char dev[IFNAMSIZ] = "";
+
+ size_t len = RTM_PAYLOAD(nh);
+ struct rtattr *rta;
+ for (rta = RTM_RTA(rtm); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
+ switch (rta->rta_type) {
+ case RTA_DST:
+ if (maybeLogDuplicateAttribute(*dst, "RTA_DST", msgname))
+ continue;
+ if (!inet_ntop(family, RTA_DATA(rta), dst, sizeof(dst)))
+ return false;
+ continue;
+ case RTA_GATEWAY:
+ if (maybeLogDuplicateAttribute(*gw, "RTA_GATEWAY", msgname))
+ continue;
+ if (!inet_ntop(family, RTA_DATA(rta), gw, sizeof(gw)))
+ return false;
+ continue;
+ case RTA_OIF:
+ if (maybeLogDuplicateAttribute(*dev, "RTA_OIF", msgname))
+ continue;
+ if (!if_indextoname(* (int *) RTA_DATA(rta), dev))
+ return false;
+ default:
+ continue;
+ }
+ }
+
+ // If there's no RTA_DST attribute, then:
+ // - If the prefix length is zero, it's the default route.
+ // - If the prefix length is nonzero, there's something we don't understand.
+ // Ignore the event.
+ if (!*dst && !prefixLength) {
+ if (family == AF_INET) {
+ strncpy(dst, "0.0.0.0", sizeof(dst));
+ } else if (family == AF_INET6) {
+ strncpy(dst, "::", sizeof(dst));
+ }
+ }
+
+ // A useful route must have a destination and at least either a gateway or
+ // an interface.
+ if (!*dst || (!*gw && !*dev))
+ return false;
+
+ // Fill in netlink event information.
+ mAction = (type == RTM_NEWROUTE) ? NlActionRouteUpdated :
+ NlActionRouteRemoved;
+ mSubsystem = strdup("net");
+ asprintf(&mParams[0], "ROUTE=%s/%d", dst, prefixLength);
+ asprintf(&mParams[1], "GATEWAY=%s", (*gw) ? gw : "");
+ asprintf(&mParams[2], "INTERFACE=%s", (*dev) ? dev : "");
+
return true;
}
/*
* Parse a RTM_NEWNDUSEROPT message.
*/
-bool NetlinkEvent::parseNdUserOptMessage(struct nduseroptmsg *msg, int len) {
+bool NetlinkEvent::parseNdUserOptMessage(const struct nlmsghdr *nh) {
+ struct nduseroptmsg *msg = (struct nduseroptmsg *) NLMSG_DATA(nh);
+ if (!checkRtNetlinkLength(nh, sizeof(*msg)))
+ return false;
+
// Check the length is valid.
+ int len = NLMSG_PAYLOAD(nh, sizeof(*msg));
if (msg->nduseropt_opts_len > len) {
SLOGE("RTM_NEWNDUSEROPT invalid length %d > %d\n",
msg->nduseropt_opts_len, len);
@@ -200,7 +395,7 @@
}
// Find the interface name.
- char ifname[IFNAMSIZ + 1];
+ char ifname[IFNAMSIZ];
if (!if_indextoname(msg->nduseropt_ifindex, ifname)) {
SLOGE("RTM_NEWNDUSEROPT on unknown ifindex %d\n",
msg->nduseropt_ifindex);
@@ -273,6 +468,14 @@
/*
* Parse a binary message from a NETLINK_ROUTE netlink socket.
+ *
+ * Note that this function can only parse one message, because the message's
+ * content has to be stored in the class's member variables (mAction,
+ * mSubsystem, etc.). Invalid or unrecognized messages are skipped, but if
+ * there are multiple valid messages in the buffer, only the first one will be
+ * returned.
+ *
+ * TODO: consider only ever looking at the first message.
*/
bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
const struct nlmsghdr *nh;
@@ -281,93 +484,37 @@
NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE);
nh = NLMSG_NEXT(nh, size)) {
+ if (!rtMessageName(nh->nlmsg_type)) {
+ SLOGD("Unexpected netlink message type %d\n", nh->nlmsg_type);
+ continue;
+ }
+
if (nh->nlmsg_type == RTM_NEWLINK) {
- int len = nh->nlmsg_len - sizeof(*nh);
- struct ifinfomsg *ifi;
-
- if (sizeof(*ifi) > (size_t) len) {
- SLOGE("Got a short RTM_NEWLINK message\n");
- continue;
- }
-
- ifi = (ifinfomsg *)NLMSG_DATA(nh);
- if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) {
- continue;
- }
-
- struct rtattr *rta = (struct rtattr *)
- ((char *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
- len = NLMSG_PAYLOAD(nh, sizeof(*ifi));
-
- while(RTA_OK(rta, len)) {
- switch(rta->rta_type) {
- case IFLA_IFNAME:
- char buffer[16 + IFNAMSIZ];
- snprintf(buffer, sizeof(buffer), "INTERFACE=%s",
- (char *) RTA_DATA(rta));
- mParams[0] = strdup(buffer);
- mAction = (ifi->ifi_flags & IFF_LOWER_UP) ?
- NlActionLinkUp : NlActionLinkDown;
- mSubsystem = strdup("net");
- break;
- }
-
- rta = RTA_NEXT(rta, len);
- }
+ if (parseIfInfoMessage(nh))
+ return true;
} else if (nh->nlmsg_type == QLOG_NL_EVENT) {
- char *devname;
- ulog_packet_msg_t *pm;
- size_t len = nh->nlmsg_len - sizeof(*nh);
- if (sizeof(*pm) > len) {
- SLOGE("Got a short QLOG message\n");
- continue;
- }
- pm = (ulog_packet_msg_t *)NLMSG_DATA(nh);
- devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;
- asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
- asprintf(&mParams[1], "INTERFACE=%s", devname);
- mSubsystem = strdup("qlog");
- mAction = NlActionChange;
+ if (parseUlogPacketMessage(nh))
+ return true;
} else if (nh->nlmsg_type == RTM_NEWADDR ||
nh->nlmsg_type == RTM_DELADDR) {
- int len = nh->nlmsg_len - sizeof(*nh);
- struct ifaddrmsg *ifa;
+ if (parseIfAddrMessage(nh))
+ return true;
- if (sizeof(*ifa) > (size_t) len) {
- SLOGE("Got a short RTM_xxxADDR message\n");
- continue;
- }
-
- ifa = (ifaddrmsg *)NLMSG_DATA(nh);
- size_t rtasize = IFA_PAYLOAD(nh);
- if (!parseIfAddrMessage(nh->nlmsg_type, ifa, rtasize)) {
- continue;
- }
+ } else if (nh->nlmsg_type == RTM_NEWROUTE ||
+ nh->nlmsg_type == RTM_DELROUTE) {
+ if (parseRtMessage(nh))
+ return true;
} else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) {
- int len = nh->nlmsg_len - sizeof(*nh);
- struct nduseroptmsg *ndmsg = (struct nduseroptmsg *) NLMSG_DATA(nh);
+ if (parseNdUserOptMessage(nh))
+ return true;
- if (sizeof(*ndmsg) > (size_t) len) {
- SLOGE("Got a short RTM_NEWNDUSEROPT message\n");
- continue;
- }
-
- size_t optsize = NLMSG_PAYLOAD(nh, sizeof(*ndmsg));
- if (!parseNdUserOptMessage(ndmsg, optsize)) {
- continue;
- }
-
-
- } else {
- SLOGD("Unexpected netlink message. type=0x%x\n",
- nh->nlmsg_type);
}
}
- return true;
+ return false;
}
/* If the string between 'str' and 'end' begins with 'prefixlen' characters
diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp
index 9c447ca..81c5cc2 100644
--- a/libsysutils/src/NetlinkListener.cpp
+++ b/libsysutils/src/NetlinkListener.cpp
@@ -57,10 +57,12 @@
}
NetlinkEvent *evt = new NetlinkEvent();
- if (!evt->decode(mBuffer, count, mFormat)) {
- SLOGE("Error decoding NetlinkEvent");
- } else {
+ if (evt->decode(mBuffer, count, mFormat)) {
onEvent(evt);
+ } else if (mFormat != NETLINK_FORMAT_BINARY) {
+ // Don't complain if parseBinaryNetlinkMessage returns false. That can
+ // just mean that the buffer contained no messages we're interested in.
+ SLOGE("Error decoding NetlinkEvent");
}
delete evt;
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index d3ce8f5..8358823 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -220,7 +220,9 @@
sigaction(SIGPIPE, &old_action, &new_action);
- errno = e;
+ if (e != 0) {
+ errno = e;
+ }
return ret;
}
diff --git a/libusbhost/Android.mk b/libusbhost/Android.mk
index acfc020..5c12f2c 100644
--- a/libusbhost/Android.mk
+++ b/libusbhost/Android.mk
@@ -25,6 +25,7 @@
LOCAL_MODULE := libusbhost
LOCAL_SRC_FILES := usbhost.c
+LOCAL_CFLAGS := -Werror
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -38,7 +39,7 @@
LOCAL_MODULE := libusbhost
LOCAL_SRC_FILES := usbhost.c
-LOCAL_CFLAGS := -g -DUSE_LIBLOG
+LOCAL_CFLAGS := -g -DUSE_LIBLOG -Werror
# needed for logcat
LOCAL_SHARED_LIBRARIES := libcutils
@@ -52,5 +53,6 @@
LOCAL_MODULE := libusbhost
LOCAL_SRC_FILES := usbhost.c
+LOCAL_CFLAGS := -Werror
include $(BUILD_STATIC_LIBRARY)
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index cd8000a..684f401 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -454,6 +454,8 @@
int i, result;
int languageCount = 0;
+ if (id == 0) return NULL;
+
string[0] = 0;
memset(languages, 0, sizeof(languages));
@@ -487,31 +489,19 @@
char* usb_device_get_manufacturer_name(struct usb_device *device)
{
struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
-
- if (desc->iManufacturer)
- return usb_device_get_string(device, desc->iManufacturer);
- else
- return NULL;
+ return usb_device_get_string(device, desc->iManufacturer);
}
char* usb_device_get_product_name(struct usb_device *device)
{
struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
-
- if (desc->iProduct)
- return usb_device_get_string(device, desc->iProduct);
- else
- return NULL;
+ return usb_device_get_string(device, desc->iProduct);
}
char* usb_device_get_serial(struct usb_device *device)
{
struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
-
- if (desc->iSerialNumber)
- return usb_device_get_string(device, desc->iSerialNumber);
- else
- return NULL;
+ return usb_device_get_string(device, desc->iSerialNumber);
}
int usb_device_is_writeable(struct usb_device *device)
@@ -557,6 +547,21 @@
return ioctl(device->fd, USBDEVFS_IOCTL, &ctl);
}
+int usb_device_set_configuration(struct usb_device *device, int configuration)
+{
+ return ioctl(device->fd, USBDEVFS_SETCONFIGURATION, &configuration);
+}
+
+int usb_device_set_interface(struct usb_device *device, unsigned int interface,
+ unsigned int alt_setting)
+{
+ struct usbdevfs_setinterface ctl;
+
+ ctl.interface = interface;
+ ctl.altsetting = alt_setting;
+ return ioctl(device->fd, USBDEVFS_SETINTERFACE, &ctl);
+}
+
int usb_device_control_transfer(struct usb_device *device,
int requestType,
int request,
@@ -690,6 +695,6 @@
int usb_request_cancel(struct usb_request *req)
{
struct usbdevfs_urb *urb = ((struct usbdevfs_urb*)req->private_data);
- return ioctl(req->dev->fd, USBDEVFS_DISCARDURB, &urb);
+ return ioctl(req->dev->fd, USBDEVFS_DISCARDURB, urb);
}
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 1c48619..52de910 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -26,6 +26,7 @@
LinearAllocator.cpp \
LinearTransform.cpp \
Log.cpp \
+ NativeHandle.cpp \
Printer.cpp \
ProcessCallStack.cpp \
PropertyMap.cpp \
@@ -43,7 +44,7 @@
VectorImpl.cpp \
misc.cpp
-host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS)
+host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) -Werror
ifeq ($(HOST_OS),windows)
ifeq ($(strip $(USE_CYGWIN),),)
@@ -52,13 +53,6 @@
endif
endif
-host_commonLdlibs :=
-
-ifeq ($(TARGET_OS),linux)
-host_commonLdlibs += -lrt -ldl
-endif
-
-
# For the host
# =====================================================
include $(CLEAR_VARS)
@@ -66,22 +60,13 @@
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)
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-
-# For the host, 64-bit
-# =====================================================
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= $(commonSources)
-ifeq ($(HOST_OS), linux)
-LOCAL_SRC_FILES += Looper.cpp
-endif
-LOCAL_MODULE:= lib64utils
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS += $(host_commonCflags) -m64
+LOCAL_MULTILIB := both
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -99,10 +84,7 @@
ifeq ($(TARGET_ARCH),mips)
LOCAL_CFLAGS += -DALIGN_DOUBLE
endif
-
-LOCAL_C_INCLUDES += \
- bionic/libc/private \
- external/zlib
+LOCAL_CFLAGS += -Werror
LOCAL_STATIC_LIBRARIES := \
libcutils
@@ -112,8 +94,6 @@
liblog \
libdl
-include external/stlport/libstlport.mk
-
LOCAL_MODULE:= libutils
include $(BUILD_STATIC_LIBRARY)
@@ -126,9 +106,8 @@
libbacktrace \
libcutils \
libdl \
- liblog \
-
-include external/stlport/libstlport.mk
+ liblog
+LOCAL_CFLAGS := -Werror
include $(BUILD_SHARED_LIBRARY)
diff --git a/libutils/BlobCache.cpp b/libutils/BlobCache.cpp
index 660917b..0ea09cf 100644
--- a/libutils/BlobCache.cpp
+++ b/libutils/BlobCache.cpp
@@ -28,10 +28,10 @@
namespace android {
// BlobCache::Header::mMagicNumber value
-static const uint32_t blobCacheMagic = '_Bb$';
+static const uint32_t blobCacheMagic = ('_' << 24) + ('B' << 16) + ('b' << 8) + '$';
// BlobCache::Header::mBlobCacheVersion value
-static const uint32_t blobCacheVersion = 1;
+static const uint32_t blobCacheVersion = 2;
// BlobCache::Header::mDeviceVersion value
static const uint32_t blobCacheDeviceVersion = 1;
@@ -49,7 +49,7 @@
mRandState[1] = (now >> 16) & 0xFFFF;
mRandState[2] = (now >> 32) & 0xFFFF;
#endif
- ALOGV("initializing random seed using %lld", now);
+ ALOGV("initializing random seed using %lld", (unsigned long long)now);
}
void BlobCache::set(const void* key, size_t keySize, const void* value,
@@ -165,14 +165,13 @@
}
size_t BlobCache::getFlattenedSize() const {
- size_t size = sizeof(Header);
+ size_t size = align4(sizeof(Header));
for (size_t i = 0; i < mCacheEntries.size(); i++) {
const CacheEntry& e(mCacheEntries[i]);
sp<Blob> keyBlob = e.getKey();
sp<Blob> valueBlob = e.getValue();
- size = align4(size);
- size += sizeof(EntryHeader) + keyBlob->getSize() +
- valueBlob->getSize();
+ size += align4(sizeof(EntryHeader) + keyBlob->getSize() +
+ valueBlob->getSize());
}
return size;
}
@@ -200,7 +199,8 @@
size_t valueSize = valueBlob->getSize();
size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
- if (byteOffset + entrySize > size) {
+ size_t totalSize = align4(entrySize);
+ if (byteOffset + totalSize > size) {
ALOGE("flatten: not enough room for cache entries");
return BAD_VALUE;
}
@@ -213,7 +213,13 @@
memcpy(eheader->mData, keyBlob->getData(), keySize);
memcpy(eheader->mData + keySize, valueBlob->getData(), valueSize);
- byteOffset += align4(entrySize);
+ if (totalSize > entrySize) {
+ // We have padding bytes. Those will get written to storage, and contribute to the CRC,
+ // so make sure we zero-them to have reproducible results.
+ memset(eheader->mData + keySize + valueSize, 0, totalSize - entrySize);
+ }
+
+ byteOffset += totalSize;
}
return OK;
@@ -256,7 +262,8 @@
size_t valueSize = eheader->mValueSize;
size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
- if (byteOffset + entrySize > size) {
+ size_t totalSize = align4(entrySize);
+ if (byteOffset + totalSize > size) {
mCacheEntries.clear();
ALOGE("unflatten: not enough room for cache entry headers");
return BAD_VALUE;
@@ -265,7 +272,7 @@
const uint8_t* data = eheader->mData;
set(data, keySize, data + keySize, valueSize);
- byteOffset += align4(entrySize);
+ byteOffset += totalSize;
}
return OK;
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 933e7aa..f49b4f9 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -23,11 +23,17 @@
#include <utils/FileMap.h>
#include <utils/Log.h>
+#if defined(__MINGW32__) && !defined(__USE_MINGW_ANSI_STDIO)
+# define PRId32 "I32d"
+# define PRIx32 "I32x"
+# define PRId64 "I64d"
+#else
#include <inttypes.h>
+#endif
#include <stdio.h>
#include <stdlib.h>
-#ifdef HAVE_POSIX_FILEMAP
+#if !defined(__MINGW32__)
#include <sys/mman.h>
#endif
@@ -58,12 +64,7 @@
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() );
@@ -71,7 +72,10 @@
if (mFileMapping != INVALID_HANDLE_VALUE) {
CloseHandle(mFileMapping);
}
- CloseHandle(mFileHandle);
+#else
+ if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) {
+ ALOGD("munmap(%p, %zu) failed\n", mBasePtr, mBaseLength);
+ }
#endif
}
@@ -85,7 +89,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;
@@ -123,8 +127,7 @@
mFileMapping = INVALID_HANDLE_VALUE;
return false;
}
-#endif
-#ifdef HAVE_POSIX_FILEMAP
+#else // !defined(__MINGW32__)
int prot, flags, adjust;
off64_t adjOffset;
size_t adjLength;
@@ -169,12 +172,12 @@
goto try_again;
}
- ALOGE("mmap(%" PRId64 ",%zu) failed: %s\n",
- adjOffset, adjLength, strerror(errno));
+ 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;
@@ -191,9 +194,9 @@
}
// Provide guidance to the system.
+#if !defined(_WIN32)
int FileMap::advise(MapAdvice advice)
{
-#if HAVE_MADVISE
int cc, sysAdvice;
switch (advice) {
@@ -211,7 +214,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/LinearAllocator.cpp b/libutils/LinearAllocator.cpp
index a07a291..8b90696 100644
--- a/libutils/LinearAllocator.cpp
+++ b/libutils/LinearAllocator.cpp
@@ -92,7 +92,7 @@
: mNextPage(0)
{}
- void* operator new(size_t size, void* buf) { return buf; }
+ void* operator new(size_t /*size*/, void* buf) { return buf; }
void* start() {
return (void*) (((size_t)this) + sizeof(Page));
@@ -103,7 +103,7 @@
}
private:
- Page(const Page& other) {}
+ Page(const Page& /*other*/) {}
Page* mNextPage;
};
diff --git a/libutils/NativeHandle.cpp b/libutils/NativeHandle.cpp
new file mode 100644
index 0000000..e4daca7
--- /dev/null
+++ b/libutils/NativeHandle.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 <utils/NativeHandle.h>
+#include <cutils/native_handle.h>
+
+namespace android {
+
+sp<NativeHandle> NativeHandle::create(
+ native_handle_t* handle, bool ownsHandle) {
+ return handle ? new NativeHandle(handle, ownsHandle) : NULL;
+}
+
+NativeHandle::NativeHandle(native_handle_t* handle, bool ownsHandle)
+: mHandle(handle), mOwnsHandle(ownsHandle)
+{}
+
+NativeHandle::~NativeHandle() {
+ if (mOwnsHandle) {
+ native_handle_close(mHandle);
+ native_handle_delete(mHandle);
+ }
+}
+
+} // namespace android
diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp
index 263e740..1dc8632 100644
--- a/libutils/Printer.cpp
+++ b/libutils/Printer.cpp
@@ -25,10 +25,6 @@
#include <stdio.h>
#include <stdlib.h>
-#ifndef __BIONIC__
-#define fdprintf dprintf
-#endif
-
namespace android {
/*
@@ -120,7 +116,7 @@
}
#ifndef USE_MINGW
- fdprintf(mFd, mFormatString, mPrefix, string);
+ dprintf(mFd, mFormatString, mPrefix, string);
#endif
}
diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp
index f837bcb..db07e56 100644
--- a/libutils/ProcessCallStack.cpp
+++ b/libutils/ProcessCallStack.cpp
@@ -90,6 +90,11 @@
ALOGE("%s: Failed to open %s", __FUNCTION__, path);
}
+ if (procName == NULL) {
+ // Reading /proc/self/task/%d/comm failed due to a race
+ return String8::format("[err-unknown-tid-%d]", tid);
+ }
+
// Strip ending newline
strtok(procName, "\n");
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 385c226..02907ad 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -17,6 +17,14 @@
#define LOG_TAG "RefBase"
// #define LOG_NDEBUG 0
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <typeinfo>
+#include <unistd.h>
+
#include <utils/RefBase.h>
#include <utils/Atomic.h>
@@ -24,13 +32,9 @@
#include <utils/Log.h>
#include <utils/threads.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <typeinfo>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
// compile with refcounting debugging enabled
#define DEBUG_REFS 0
@@ -388,7 +392,7 @@
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->addWeakRef(id);
- const int32_t c = android_atomic_inc(&impl->mWeak);
+ const int32_t c __unused = android_atomic_inc(&impl->mWeak);
ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
@@ -615,7 +619,7 @@
{
}
-bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
+bool RefBase::onIncStrongAttempted(uint32_t flags, const void* /*id*/)
{
return (flags&FIRST_INC_STRONG) ? true : false;
}
@@ -626,13 +630,15 @@
// ---------------------------------------------------------------------------
-void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
#if DEBUG_REFS
+void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
for (size_t i=0 ; i<n ; i++) {
renamer(i);
}
-#endif
}
+#else
+void RefBase::renameRefs(size_t /*n*/, const ReferenceRenamer& /*renamer*/) { }
+#endif
void RefBase::renameRefId(weakref_type* ref,
const void* old_id, const void* new_id) {
diff --git a/libutils/StopWatch.cpp b/libutils/StopWatch.cpp
index b1708d6..8c7b596 100644
--- a/libutils/StopWatch.cpp
+++ b/libutils/StopWatch.cpp
@@ -21,7 +21,9 @@
#include <stdio.h>
/* for PRId64 */
+#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS 1
+#endif
#include <inttypes.h>
#include <utils/Log.h>
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index b09b728..91efdaa 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -16,7 +16,6 @@
#include <utils/String16.h>
-#include <utils/Debug.h>
#include <utils/Log.h>
#include <utils/Unicode.h>
#include <utils/String8.h>
@@ -67,8 +66,6 @@
return getEmptyString();
}
- const uint8_t* const u8end = u8cur + u8len;
-
SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)*(u16len+1));
if (buf) {
u8cur = (const uint8_t*) u8str;
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 8acb4d4..3323b82 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -408,6 +408,30 @@
return p ? p-mString : -1;
}
+bool String8::removeAll(const char* other) {
+ ssize_t index = find(other);
+ if (index < 0) return false;
+
+ char* buf = lockBuffer(size());
+ if (!buf) return false; // out of memory
+
+ size_t skip = strlen(other);
+ size_t len = size();
+ size_t tail = index;
+ while (size_t(index) < len) {
+ ssize_t next = find(other, index + skip);
+ if (next < 0) {
+ next = len;
+ }
+
+ memmove(buf + tail, buf + index + skip, next - index - skip);
+ tail += next - index - skip;
+ index = next;
+ }
+ unlockBuffer(tail);
+ return true;
+}
+
void String8::toLower()
{
toLower(0, size());
@@ -551,7 +575,6 @@
{
const char* lastSlash;
const char* lastDot;
- int extLen;
const char* const str = mString;
// only look at the filename
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
index 413250f..ac3dd98 100644
--- a/libutils/SystemClock.cpp
+++ b/libutils/SystemClock.cpp
@@ -68,13 +68,7 @@
*/
#define DEBUG_TIMESTAMP 0
-static const char *gettime_method_names[] = {
- "clock_gettime",
- "ioctl",
- "systemTime",
-};
-
-#if DEBUG_TIMESTAMP
+#if DEBUG_TIMESTAMP && defined(__arm__)
static inline void checkTimeStamps(int64_t timestamp,
int64_t volatile *prevTimestampPtr,
int volatile *prevMethodPtr,
@@ -85,11 +79,16 @@
* gettid, and int64_t is different on the ARM platform
* (ie long vs long long).
*/
-#ifdef ARCH_ARM
int64_t prevTimestamp = *prevTimestampPtr;
int prevMethod = *prevMethodPtr;
if (timestamp < prevTimestamp) {
+ static const char *gettime_method_names[] = {
+ "clock_gettime",
+ "ioctl",
+ "systemTime",
+ };
+
ALOGW("time going backwards: prev %lld(%s) vs now %lld(%s), tid=%d",
prevTimestamp, gettime_method_names[prevMethod],
timestamp, gettime_method_names[curMethod],
@@ -99,7 +98,6 @@
// write is interrupted or not observed as a whole.
*prevTimestampPtr = timestamp;
*prevMethodPtr = curMethod;
-#endif
}
#else
#define checkTimeStamps(timestamp, prevTimestampPtr, prevMethodPtr, curMethod)
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index ff74914..9bcd063 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -17,25 +17,17 @@
// #define LOG_NDEBUG 0
#define LOG_TAG "libutils.threads"
-#include <utils/threads.h>
-#include <utils/Log.h>
-
-#include <cutils/sched_policy.h>
-
+#include <assert.h>
+#include <errno.h>
+#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
-#include <memory.h>
-#include <errno.h>
-#include <assert.h>
#include <unistd.h>
#if defined(HAVE_PTHREADS)
# include <pthread.h>
# include <sched.h>
# include <sys/resource.h>
-#ifdef HAVE_ANDROID_OS
-# include <bionic_pthread.h>
-#endif
#elif defined(HAVE_WIN32_THREADS)
# include <windows.h>
# include <stdint.h>
@@ -47,6 +39,17 @@
#include <sys/prctl.h>
#endif
+#include <utils/threads.h>
+#include <utils/Log.h>
+
+#include <cutils/sched_policy.h>
+
+#ifdef HAVE_ANDROID_OS
+# define __android_unused
+#else
+# define __android_unused __attribute__((__unused__))
+#endif
+
/*
* ===========================================================================
* Thread wrappers
@@ -119,7 +122,7 @@
int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
void *userData,
- const char* threadName,
+ const char* threadName __android_unused,
int32_t threadPriority,
size_t threadStackSize,
android_thread_id_t *threadId)
@@ -251,9 +254,9 @@
int androidCreateRawThreadEtc(android_thread_func_t fn,
void *userData,
- const char* threadName,
- int32_t threadPriority,
- size_t threadStackSize,
+ const char* /*threadName*/,
+ int32_t /*threadPriority*/,
+ size_t /*threadStackSize*/,
android_thread_id_t *threadId)
{
return doCreateThread( fn, userData, threadId);
@@ -300,15 +303,6 @@
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)
{
@@ -858,7 +852,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 a431e92..4687d4d 100644
--- a/libutils/Timers.cpp
+++ b/libutils/Timers.cpp
@@ -32,9 +32,9 @@
#include <windows.h>
#endif
+#if defined(HAVE_ANDROID_OS)
nsecs_t systemTime(int clock)
{
-#if defined(HAVE_ANDROID_OS)
static const clockid_t clocks[] = {
CLOCK_REALTIME,
CLOCK_MONOTONIC,
@@ -46,7 +46,10 @@
t.tv_sec = t.tv_nsec = 0;
clock_gettime(clocks[clock], &t);
return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+}
#else
+nsecs_t systemTime(int /*clock*/)
+{
// Clock support varies widely across hosts. Mac OS doesn't support
// posix clocks, older glibcs don't support CLOCK_BOOTTIME and Windows
// is windows.
@@ -54,8 +57,8 @@
t.tv_sec = t.tv_usec = 0;
gettimeofday(&t, NULL);
return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL;
-#endif
}
+#endif
int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime)
{
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index a66e3bb..fb876c9 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -24,17 +24,10 @@
# undef nhtos
# undef htons
-# ifdef HAVE_LITTLE_ENDIAN
-# define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
-# define htonl(x) ntohl(x)
-# define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
-# define htons(x) ntohs(x)
-# else
-# define ntohl(x) (x)
-# define htonl(x) (x)
-# define ntohs(x) (x)
-# define htons(x) (x)
-# endif
+# define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
+# define htonl(x) ntohl(x)
+# define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
+# define htons(x) ntohs(x)
#else
# include <netinet/in.h>
#endif
@@ -47,8 +40,9 @@
// 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;
@@ -342,7 +336,8 @@
while (cur_utf16 < end_utf16) {
char32_t utf32;
// surrogate pairs
- if ((*cur_utf16 & 0xFC00) == 0xD800) {
+ if((*cur_utf16 & 0xFC00) == 0xD800 && (cur_utf16 + 1) < end_utf16
+ && (*(cur_utf16 + 1) & 0xFC00) == 0xDC00) {
utf32 = (*cur_utf16++ - 0xD800) << 10;
utf32 |= *cur_utf16++ - 0xDC00;
utf32 += 0x10000;
@@ -576,7 +571,7 @@
char16_t* utf8_to_utf16_n(const uint8_t* src, size_t srcLen, char16_t* dst, size_t dstLen) {
const uint8_t* const u8end = src + srcLen;
const uint8_t* u8cur = src;
- const uint16_t* const u16end = dst + dstLen;
+ const char16_t* const u16end = dst + dstLen;
char16_t* u16cur = dst;
while (u8cur < u8end && u16cur < u16end) {
diff --git a/libutils/tests/Android.mk b/libutils/tests/Android.mk
index caedaff..634f44f 100644
--- a/libutils/tests/Android.mk
+++ b/libutils/tests/Android.mk
@@ -1,9 +1,28 @@
-# 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_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_MODULE := libutils_tests
+
+LOCAL_SRC_FILES := \
BasicHashtable_test.cpp \
BlobCache_test.cpp \
BitSet_test.cpp \
@@ -11,24 +30,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/BitSet_test.cpp b/libutils/tests/BitSet_test.cpp
index 752e56d..38b668a 100644
--- a/libutils/tests/BitSet_test.cpp
+++ b/libutils/tests/BitSet_test.cpp
@@ -23,7 +23,7 @@
namespace android {
-class BitSetTest : public testing::Test {
+class BitSet32Test : public testing::Test {
protected:
BitSet32 b1;
BitSet32 b2;
@@ -34,7 +34,7 @@
};
-TEST_F(BitSetTest, BitWiseOr) {
+TEST_F(BitSet32Test, BitWiseOr) {
b1.markBit(2);
b2.markBit(4);
@@ -49,7 +49,7 @@
EXPECT_TRUE(b1.hasBit(2) && b1.hasBit(4));
EXPECT_TRUE(b2.hasBit(4) && b2.count() == 1u);
}
-TEST_F(BitSetTest, BitWiseAnd_Disjoint) {
+TEST_F(BitSet32Test, BitWiseAnd_Disjoint) {
b1.markBit(2);
b1.markBit(4);
b1.markBit(6);
@@ -65,7 +65,7 @@
EXPECT_TRUE(b1.hasBit(2) && b1.hasBit(4) && b1.hasBit(6));
}
-TEST_F(BitSetTest, BitWiseAnd_NonDisjoint) {
+TEST_F(BitSet32Test, BitWiseAnd_NonDisjoint) {
b1.markBit(2);
b1.markBit(4);
b1.markBit(6);
@@ -84,4 +84,187 @@
EXPECT_EQ(b2.count(), 3u);
EXPECT_TRUE(b2.hasBit(3) && b2.hasBit(6) && b2.hasBit(9));
}
+
+TEST_F(BitSet32Test, MarkFirstUnmarkedBit) {
+ b1.markBit(1);
+
+ b1.markFirstUnmarkedBit();
+ EXPECT_EQ(b1.count(), 2u);
+ EXPECT_TRUE(b1.hasBit(0) && b1.hasBit(1));
+
+ b1.markFirstUnmarkedBit();
+ EXPECT_EQ(b1.count(), 3u);
+ EXPECT_TRUE(b1.hasBit(0) && b1.hasBit(1) && b1.hasBit(2));
+}
+
+TEST_F(BitSet32Test, ClearFirstMarkedBit) {
+ b1.markBit(0);
+ b1.markBit(10);
+
+ b1.clearFirstMarkedBit();
+ EXPECT_EQ(b1.count(), 1u);
+ EXPECT_TRUE(b1.hasBit(10));
+
+ b1.markBit(30);
+ b1.clearFirstMarkedBit();
+ EXPECT_EQ(b1.count(), 1u);
+ EXPECT_TRUE(b1.hasBit(30));
+}
+
+TEST_F(BitSet32Test, ClearLastMarkedBit) {
+ b1.markBit(10);
+ b1.markBit(31);
+
+ b1.clearLastMarkedBit();
+ EXPECT_EQ(b1.count(), 1u);
+ EXPECT_TRUE(b1.hasBit(10));
+
+ b1.markBit(5);
+ b1.clearLastMarkedBit();
+ EXPECT_EQ(b1.count(), 1u);
+ EXPECT_TRUE(b1.hasBit(5));
+}
+
+TEST_F(BitSet32Test, FillAndClear) {
+ EXPECT_TRUE(b1.isEmpty());
+ for (size_t i = 0; i < 32; i++) {
+ b1.markFirstUnmarkedBit();
+ }
+ EXPECT_TRUE(b1.isFull());
+ b1.clear();
+ EXPECT_TRUE(b1.isEmpty());
+}
+
+TEST_F(BitSet32Test, GetIndexOfBit) {
+ b1.markBit(1);
+ b1.markBit(4);
+ EXPECT_EQ(b1.getIndexOfBit(1), 0);
+ EXPECT_EQ(b1.getIndexOfBit(4), 1);
+ b1.markFirstUnmarkedBit();
+ EXPECT_EQ(b1.getIndexOfBit(1), 1);
+ EXPECT_EQ(b1.getIndexOfBit(4), 2);
+}
+
+class BitSet64Test : public testing::Test {
+protected:
+ BitSet64 b1;
+ BitSet64 b2;
+ virtual void TearDown() {
+ b1.clear();
+ b2.clear();
+ }
+};
+
+
+TEST_F(BitSet64Test, BitWiseOr) {
+ b1.markBit(20);
+ b2.markBit(40);
+
+ BitSet64 tmp = b1 | b2;
+ EXPECT_EQ(tmp.count(), 2u);
+ EXPECT_TRUE(tmp.hasBit(20) && tmp.hasBit(40));
+ // Check that the operator is symmetric
+ EXPECT_TRUE((b2 | b1) == (b1 | b2));
+
+ b1 |= b2;
+ EXPECT_EQ(b1.count(), 2u);
+ EXPECT_TRUE(b1.hasBit(20) && b1.hasBit(40));
+ EXPECT_TRUE(b2.hasBit(40) && b2.count() == 1u);
+}
+TEST_F(BitSet64Test, BitWiseAnd_Disjoint) {
+ b1.markBit(20);
+ b1.markBit(40);
+ b1.markBit(60);
+
+ BitSet64 tmp = b1 & b2;
+ EXPECT_TRUE(tmp.isEmpty());
+ // Check that the operator is symmetric
+ EXPECT_TRUE((b2 & b1) == (b1 & b2));
+
+ b2 &= b1;
+ EXPECT_TRUE(b2.isEmpty());
+ EXPECT_EQ(b1.count(), 3u);
+ EXPECT_TRUE(b1.hasBit(20) && b1.hasBit(40) && b1.hasBit(60));
+}
+
+TEST_F(BitSet64Test, BitWiseAnd_NonDisjoint) {
+ b1.markBit(20);
+ b1.markBit(40);
+ b1.markBit(60);
+ b2.markBit(30);
+ b2.markBit(60);
+ b2.markBit(63);
+
+ BitSet64 tmp = b1 & b2;
+ EXPECT_EQ(tmp.count(), 1u);
+ EXPECT_TRUE(tmp.hasBit(60));
+ // Check that the operator is symmetric
+ EXPECT_TRUE((b2 & b1) == (b1 & b2));
+
+ b1 &= b2;
+ EXPECT_EQ(b1.count(), 1u);
+ EXPECT_EQ(b2.count(), 3u);
+ EXPECT_TRUE(b2.hasBit(30) && b2.hasBit(60) && b2.hasBit(63));
+}
+
+TEST_F(BitSet64Test, MarkFirstUnmarkedBit) {
+ b1.markBit(1);
+
+ b1.markFirstUnmarkedBit();
+ EXPECT_EQ(b1.count(), 2u);
+ EXPECT_TRUE(b1.hasBit(0) && b1.hasBit(1));
+
+ b1.markFirstUnmarkedBit();
+ EXPECT_EQ(b1.count(), 3u);
+ EXPECT_TRUE(b1.hasBit(0) && b1.hasBit(1) && b1.hasBit(2));
+}
+
+TEST_F(BitSet64Test, ClearFirstMarkedBit) {
+ b1.markBit(0);
+ b1.markBit(10);
+
+ b1.clearFirstMarkedBit();
+ EXPECT_EQ(b1.count(), 1u);
+ EXPECT_TRUE(b1.hasBit(10));
+
+ b1.markBit(50);
+ b1.clearFirstMarkedBit();
+ EXPECT_EQ(b1.count(), 1u);
+ EXPECT_TRUE(b1.hasBit(50));
+}
+
+TEST_F(BitSet64Test, ClearLastMarkedBit) {
+ b1.markBit(10);
+ b1.markBit(63);
+
+ b1.clearLastMarkedBit();
+ EXPECT_EQ(b1.count(), 1u);
+ EXPECT_TRUE(b1.hasBit(10));
+
+ b1.markBit(5);
+ b1.clearLastMarkedBit();
+ EXPECT_EQ(b1.count(), 1u);
+ EXPECT_TRUE(b1.hasBit(5));
+}
+
+TEST_F(BitSet64Test, FillAndClear) {
+ EXPECT_TRUE(b1.isEmpty());
+ for (size_t i = 0; i < 64; i++) {
+ b1.markFirstUnmarkedBit();
+ }
+ EXPECT_TRUE(b1.isFull());
+ b1.clear();
+ EXPECT_TRUE(b1.isEmpty());
+}
+
+TEST_F(BitSet64Test, GetIndexOfBit) {
+ b1.markBit(10);
+ b1.markBit(40);
+ EXPECT_EQ(b1.getIndexOfBit(10), 0);
+ EXPECT_EQ(b1.getIndexOfBit(40), 1);
+ b1.markFirstUnmarkedBit();
+ EXPECT_EQ(b1.getIndexOfBit(10), 1);
+ EXPECT_EQ(b1.getIndexOfBit(40), 2);
+}
+
} // namespace android
diff --git a/libutils/tests/BlobCache_test.cpp b/libutils/tests/BlobCache_test.cpp
index 7202123..dac4e2c 100644
--- a/libutils/tests/BlobCache_test.cpp
+++ b/libutils/tests/BlobCache_test.cpp
@@ -44,7 +44,7 @@
};
TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
ASSERT_EQ('e', buf[0]);
@@ -54,7 +54,7 @@
}
TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
- char buf[2] = { 0xee, 0xee };
+ unsigned char buf[2] = { 0xee, 0xee };
mBC->set("ab", 2, "cd", 2);
mBC->set("ef", 2, "gh", 2);
ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
@@ -66,7 +66,7 @@
}
TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
- char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf+1, 4));
ASSERT_EQ(0xee, buf[0]);
@@ -78,7 +78,7 @@
}
TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
- char buf[3] = { 0xee, 0xee, 0xee };
+ unsigned char buf[3] = { 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
ASSERT_EQ(0xee, buf[0]);
@@ -92,7 +92,7 @@
}
TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
mBC->set("abcd", 4, "ijkl", 4);
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
@@ -103,7 +103,7 @@
}
TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
- char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
@@ -115,7 +115,7 @@
TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) {
char key[MAX_KEY_SIZE+1];
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
for (int i = 0; i < MAX_KEY_SIZE+1; i++) {
key[i] = 'a';
}
@@ -165,7 +165,7 @@
TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) {
char key[MAX_KEY_SIZE];
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
for (int i = 0; i < MAX_KEY_SIZE; i++) {
key[i] = 'a';
}
@@ -214,7 +214,7 @@
}
TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
- char buf[1] = { 0xee };
+ unsigned char buf[1] = { 0xee };
mBC->set("x", 1, "y", 1);
ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
ASSERT_EQ('y', buf[0]);
@@ -282,7 +282,7 @@
};
TEST_F(BlobCacheFlattenTest, FlattenOneValue) {
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
roundTrip();
ASSERT_EQ(size_t(4), mBC2->get("abcd", 4, buf, 4));
@@ -348,7 +348,7 @@
}
TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadMagic) {
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
size_t size = mBC->getFlattenedSize();
@@ -365,7 +365,7 @@
}
TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheVersion) {
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
size_t size = mBC->getFlattenedSize();
@@ -384,7 +384,7 @@
}
TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheDeviceVersion) {
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
size_t size = mBC->getFlattenedSize();
@@ -403,7 +403,7 @@
}
TEST_F(BlobCacheFlattenTest, UnflattenCatchesBufferTooSmall) {
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
size_t size = mBC->getFlattenedSize();
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 1d48fea..ba7b74d 100644
--- a/libziparchive/Android.mk
+++ b/libziparchive/Android.mk
@@ -14,60 +14,64 @@
# 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_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := ${source_files}
-
LOCAL_STATIC_LIBRARIES := libz
LOCAL_SHARED_LIBRARIES := libutils
LOCAL_MODULE:= libziparchive
-
-LOCAL_C_INCLUDES += ${includes}
LOCAL_CFLAGS := -Werror
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
-LOCAL_MODULE := libziparchive
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := ${source_files}
-LOCAL_C_INCLUDES += ${includes}
-
LOCAL_STATIC_LIBRARIES := libz libutils
LOCAL_MODULE:= libziparchive-host
LOCAL_CFLAGS := -Werror
+ifneq ($(strip $(USE_MINGW)),)
+ LOCAL_CFLAGS += -mno-ms-bitfields
+endif
+LOCAL_MULTILIB := both
include $(BUILD_HOST_STATIC_LIBRARY)
include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := ${source_files}
+LOCAL_STATIC_LIBRARIES := libz libutils
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_MODULE:= libziparchive-host
+LOCAL_CFLAGS := -Werror
+LOCAL_MULTILIB := both
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+# Tests.
+include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
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_CFLAGS := -Werror
+LOCAL_SRC_FILES := zip_archive_test.cc entry_name_utils_test.cc
LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_STATIC_LIBRARIES := libziparchive libz libgtest libgtest_main libutils
+LOCAL_STATIC_LIBRARIES := libziparchive libz libutils
include $(BUILD_NATIVE_TEST)
include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
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
+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/zip_archive.cc b/libziparchive/zip_archive.cc
index 6781ebe..b6fd0d2 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -33,58 +33,175 @@
#include <JNIHelp.h> // TEMP_FAILURE_RETRY may or may not be in unistd
+#include "entry_name_utils-inl.h"
#include "ziparchive/zip_archive.h"
-// This is for windows. If we don't open a file in binary mode, weirds
+
+// 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
-/*
- * Zip file constants.
- */
-static const uint32_t kEOCDSignature = 0x06054b50;
-static const uint32_t kEOCDLen = 2;
-static const uint32_t kEOCDNumEntries = 8; // offset to #of entries in file
-static const uint32_t kEOCDSize = 12; // size of the central directory
-static const uint32_t kEOCDFileOffset = 16; // offset to central directory
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+ TypeName(); \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
-static const uint32_t kMaxCommentLen = 65535; // longest possible in ushort
-static const uint32_t kMaxEOCDSearch = (kMaxCommentLen + kEOCDLen);
+// 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
+// number of entries in the archive and the offset to the central
+// directory of the offset.
+struct EocdRecord {
+ static const uint32_t kSignature = 0x06054b50;
-static const uint32_t kLFHSignature = 0x04034b50;
-static const uint32_t kLFHLen = 30; // excluding variable-len fields
-static const uint32_t kLFHGPBFlags = 6; // general purpose bit flags
-static const uint32_t kLFHCRC = 14; // offset to CRC
-static const uint32_t kLFHCompLen = 18; // offset to compressed length
-static const uint32_t kLFHUncompLen = 22; // offset to uncompressed length
-static const uint32_t kLFHNameLen = 26; // offset to filename length
-static const uint32_t kLFHExtraLen = 28; // offset to extra length
+ // End of central directory signature, should always be
+ // |kSignature|.
+ uint32_t eocd_signature;
+ // The number of the current "disk", i.e, the "disk" that this
+ // central directory is on.
+ //
+ // This implementation assumes that each archive spans a single
+ // disk only. i.e, that disk_num == 1.
+ uint16_t disk_num;
+ // The disk where the central directory starts.
+ //
+ // This implementation assumes that each archive spans a single
+ // disk only. i.e, that cd_start_disk == 1.
+ uint16_t cd_start_disk;
+ // The number of central directory records on this disk.
+ //
+ // This implementation assumes that each archive spans a single
+ // disk only. i.e, that num_records_on_disk == num_records.
+ uint16_t num_records_on_disk;
+ // The total number of central directory records.
+ uint16_t num_records;
+ // The size of the central directory (in bytes).
+ uint32_t cd_size;
+ // The offset of the start of the central directory, relative
+ // to the start of the file.
+ uint32_t cd_start_offset;
+ // Length of the central directory comment.
+ uint16_t comment_length;
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(EocdRecord);
+} __attribute__((packed));
-static const uint32_t kCDESignature = 0x02014b50;
-static const uint32_t kCDELen = 46; // excluding variable-len fields
-static const uint32_t kCDEMethod = 10; // offset to compression method
-static const uint32_t kCDEModWhen = 12; // offset to modification timestamp
-static const uint32_t kCDECRC = 16; // offset to entry CRC
-static const uint32_t kCDECompLen = 20; // offset to compressed length
-static const uint32_t kCDEUncompLen = 24; // offset to uncompressed length
-static const uint32_t kCDENameLen = 28; // offset to filename length
-static const uint32_t kCDEExtraLen = 30; // offset to extra length
-static const uint32_t kCDECommentLen = 32; // offset to comment length
-static const uint32_t kCDELocalOffset = 42; // offset to local hdr
+// A structure representing the fixed length fields for a single
+// record in the central directory of the archive. In addition to
+// the fixed length fields listed here, each central directory
+// record contains a variable length "file_name" and "extra_field"
+// whose lengths are given by |file_name_length| and |extra_field_length|
+// respectively.
+struct CentralDirectoryRecord {
+ static const uint32_t kSignature = 0x02014b50;
-static const uint32_t kDDOptSignature = 0x08074b50; // *OPTIONAL* data descriptor signature
-static const uint32_t kDDSignatureLen = 4;
-static const uint32_t kDDLen = 12;
-static const uint32_t kDDMaxLen = 16; // max of 16 bytes with a signature, 12 bytes without
-static const uint32_t kDDCrc32 = 0; // offset to crc32
-static const uint32_t kDDCompLen = 4; // offset to compressed length
-static const uint32_t kDDUncompLen = 8; // offset to uncompressed length
+ // The start of record signature. Must be |kSignature|.
+ uint32_t record_signature;
+ // Tool version. Ignored by this implementation.
+ uint16_t version_made_by;
+ // Tool version. Ignored by this implementation.
+ uint16_t version_needed;
+ // The "general purpose bit flags" for this entry. The only
+ // flag value that we currently check for is the "data descriptor"
+ // flag.
+ uint16_t gpb_flags;
+ // The compression method for this entry, one of |kCompressStored|
+ // and |kCompressDeflated|.
+ uint16_t compression_method;
+ // The file modification time and date for this entry.
+ uint16_t last_mod_time;
+ uint16_t last_mod_date;
+ // The CRC-32 checksum for this entry.
+ uint32_t crc32;
+ // The compressed size (in bytes) of this entry.
+ uint32_t compressed_size;
+ // The uncompressed size (in bytes) of this entry.
+ uint32_t uncompressed_size;
+ // The length of the entry file name in bytes. The file name
+ // will appear immediately after this record.
+ uint16_t file_name_length;
+ // The length of the extra field info (in bytes). This data
+ // will appear immediately after the entry file name.
+ uint16_t extra_field_length;
+ // The length of the entry comment (in bytes). This data will
+ // appear immediately after the extra field.
+ uint16_t comment_length;
+ // The start disk for this entry. Ignored by this implementation).
+ uint16_t file_start_disk;
+ // File attributes. Ignored by this implementation.
+ uint16_t internal_file_attributes;
+ // File attributes. Ignored by this implementation.
+ uint32_t external_file_attributes;
+ // The offset to the local file header for this entry, from the
+ // beginning of this archive.
+ uint32_t local_file_header_offset;
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CentralDirectoryRecord);
+} __attribute__((packed));
-static const uint32_t kGPBDDFlagMask = 0x0008; // mask value that signifies that the entry has a DD
+// The local file header for a given entry. This duplicates information
+// present in the central directory of the archive. It is an error for
+// the information here to be different from the central directory
+// information for a given entry.
+struct LocalFileHeader {
+ static const uint32_t kSignature = 0x04034b50;
-static const uint32_t kMaxErrorLen = 1024;
+ // The local file header signature, must be |kSignature|.
+ uint32_t lfh_signature;
+ // Tool version. Ignored by this implementation.
+ uint16_t version_needed;
+ // The "general purpose bit flags" for this entry. The only
+ // flag value that we currently check for is the "data descriptor"
+ // flag.
+ uint16_t gpb_flags;
+ // The compression method for this entry, one of |kCompressStored|
+ // and |kCompressDeflated|.
+ uint16_t compression_method;
+ // The file modification time and date for this entry.
+ uint16_t last_mod_time;
+ uint16_t last_mod_date;
+ // The CRC-32 checksum for this entry.
+ uint32_t crc32;
+ // The compressed size (in bytes) of this entry.
+ uint32_t compressed_size;
+ // The uncompressed size (in bytes) of this entry.
+ uint32_t uncompressed_size;
+ // The length of the entry file name in bytes. The file name
+ // will appear immediately after this record.
+ uint16_t file_name_length;
+ // The length of the extra field info (in bytes). This data
+ // will appear immediately after the entry file name.
+ uint16_t extra_field_length;
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(LocalFileHeader);
+} __attribute__((packed));
+
+struct DataDescriptor {
+ // The *optional* data descriptor start signature.
+ static const uint32_t kOptSignature = 0x08074b50;
+
+ // CRC-32 checksum of the entry.
+ uint32_t crc32;
+ // Compressed size of the entry.
+ uint32_t compressed_size;
+ // Uncompressed size of the entry.
+ uint32_t uncompressed_size;
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DataDescriptor);
+} __attribute__((packed));
+
+#undef DISALLOW_IMPLICIT_CONSTRUCTORS
+
+static const uint32_t kGPBDDFlagMask = 0x0008; // mask value that signifies that the entry has a DD
+
+// The maximum size of a central directory or a file
+// comment in bytes.
+static const uint32_t kMaxCommentLen = 65535;
+
+// The maximum number of bytes to scan backwards for the EOCD start.
+static const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord);
static const char* kErrorMessages[] = {
"Unknown return code.",
@@ -171,7 +288,7 @@
*/
struct ZipArchive {
/* open Zip archive */
- int fd;
+ const int fd;
/* mapped central directory area */
off64_t directory_offset;
@@ -188,6 +305,25 @@
*/
uint32_t hash_table_size;
ZipEntryName* hash_table;
+
+ ZipArchive(const int fd) :
+ fd(fd),
+ directory_offset(0),
+ directory_map(NULL),
+ num_entries(0),
+ hash_table_size(0),
+ hash_table(NULL) {}
+
+ ~ZipArchive() {
+ if (fd >= 0) {
+ close(fd);
+ }
+
+ if (directory_map != NULL) {
+ directory_map->release();
+ }
+ free(hash_table);
+ }
};
// Returns 0 on success and negative values on failure.
@@ -250,8 +386,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++;
@@ -266,21 +404,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;
}
@@ -288,8 +426,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);
/*
@@ -297,53 +435,35 @@
* 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;
}
-/*
- * Get 2 little-endian bytes.
- */
-static uint16_t get2LE(const uint8_t* src) {
- return src[0] | (src[1] << 8);
-}
-
-/*
- * Get 4 little-endian bytes.
- */
-static uint32_t get4LE(const uint8_t* src) {
- uint32_t result;
-
- result = src[0];
- result |= src[1] << 8;
- result |= src[2] << 16;
- result |= src[3] << 24;
-
- return result;
-}
-
static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
ZipArchive* archive, off64_t file_length,
- uint32_t read_amount, uint8_t* scan_buffer) {
+ off64_t read_amount, uint8_t* scan_buffer) {
const off64_t search_start = file_length - read_amount;
if (lseek64(fd, search_start, SEEK_SET) != search_start) {
- ALOGW("Zip: seek %" PRId64 " failed: %s", (int64_t)search_start, strerror(errno));
+ ALOGW("Zip: seek %" PRId64 " failed: %s", static_cast<int64_t>(search_start),
+ strerror(errno));
return kIoError;
}
- ssize_t actual = TEMP_FAILURE_RETRY(read(fd, scan_buffer, read_amount));
- if (actual != (ssize_t) read_amount) {
- ALOGW("Zip: read %" PRIu32 " failed: %s", read_amount, strerror(errno));
+ ssize_t actual = TEMP_FAILURE_RETRY(
+ read(fd, scan_buffer, static_cast<size_t>(read_amount)));
+ if (actual != static_cast<ssize_t>(read_amount)) {
+ ALOGW("Zip: read %" PRId64 " failed: %s", static_cast<int64_t>(read_amount),
+ strerror(errno));
return kIoError;
}
@@ -353,9 +473,10 @@
* doing an initial minimal read; if we don't find it, retry with a
* second read as above.)
*/
- int i;
- for (i = read_amount - kEOCDLen; i >= 0; i--) {
- if (scan_buffer[i] == 0x50 && get4LE(&scan_buffer[i]) == kEOCDSignature) {
+ 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;
}
@@ -366,46 +487,52 @@
}
const off64_t eocd_offset = search_start + i;
- const uint8_t* eocd_ptr = scan_buffer + i;
-
- assert(eocd_offset < file_length);
+ const EocdRecord* eocd = reinterpret_cast<const EocdRecord*>(scan_buffer + i);
+ /*
+ * Verify that there's no trailing space at the end of the central directory
+ * and its comment.
+ */
+ const off64_t calculated_length = eocd_offset + sizeof(EocdRecord)
+ + eocd->comment_length;
+ if (calculated_length != file_length) {
+ ALOGW("Zip: %" PRId64 " extraneous bytes at the end of the central directory",
+ static_cast<int64_t>(file_length - calculated_length));
+ return kInvalidFile;
+ }
/*
* Grab the CD offset and size, and the number of entries in the
- * archive. Verify that they look reasonable. Widen dir_size and
- * dir_offset to the file offset type.
+ * archive and verify that they look reasonable.
*/
- const uint16_t num_entries = get2LE(eocd_ptr + kEOCDNumEntries);
- const off64_t dir_size = get4LE(eocd_ptr + kEOCDSize);
- const off64_t dir_offset = get4LE(eocd_ptr + kEOCDFileOffset);
-
- if (dir_offset + dir_size > eocd_offset) {
- ALOGW("Zip: bad offsets (dir %" PRId64 ", size %" PRId64 ", eocd %" PRId64 ")",
- (int64_t)dir_offset, (int64_t)dir_size, (int64_t)eocd_offset);
+ if (eocd->cd_start_offset + eocd->cd_size > eocd_offset) {
+ ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
+ eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
return kInvalidOffset;
}
- if (num_entries == 0) {
+ if (eocd->num_records == 0) {
ALOGW("Zip: empty archive?");
return kEmptyArchive;
}
- ALOGV("+++ num_entries=%d dir_size=%" PRId64 " dir_offset=%" PRId64,
- num_entries, (int64_t)dir_size, (int64_t)dir_offset);
+ ALOGV("+++ num_entries=%" PRIu32 "dir_size=%" PRIu32 " dir_offset=%" PRIu32,
+ eocd->num_records, eocd->cd_size, eocd->cd_start_offset);
/*
* It all looks good. Create a mapping for the CD, and set the fields
* in archive.
*/
- android::FileMap* map = MapFileSegment(fd, dir_offset, dir_size,
- true /* read only */, debug_file_name);
+ 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;
return kMmapFailed;
}
archive->directory_map = map;
- archive->num_entries = num_entries;
- archive->directory_offset = dir_offset;
+ archive->num_entries = eocd->num_records;
+ archive->directory_offset = eocd->cd_start_offset;
return 0;
}
@@ -431,12 +558,12 @@
}
if (file_length > (off64_t) 0xffffffff) {
- ALOGV("Zip: zip file too long %" PRId64, (int64_t)file_length);
+ ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length));
return kInvalidFile;
}
- if (file_length < (int64_t) kEOCDLen) {
- ALOGV("Zip: length %" PRId64 " is too small to be zip", (int64_t)file_length);
+ if (file_length < static_cast<off64_t>(sizeof(EocdRecord))) {
+ ALOGV("Zip: length %" PRId64 " is too small to be zip", static_cast<int64_t>(file_length));
return kInvalidFile;
}
@@ -452,12 +579,12 @@
*
* We start by pulling in the last part of the file.
*/
- uint32_t read_amount = kMaxEOCDSearch;
- if (file_length < (off64_t) read_amount) {
+ off64_t read_amount = kMaxEOCDSearch;
+ if (file_length < read_amount) {
read_amount = file_length;
}
- uint8_t* scan_buffer = (uint8_t*) malloc(read_amount);
+ uint8_t* scan_buffer = reinterpret_cast<uint8_t*>(malloc(read_amount));
int32_t result = MapCentralDirectory0(fd, debug_file_name, archive,
file_length, read_amount, scan_buffer);
@@ -473,9 +600,9 @@
*/
static int32_t ParseZipArchive(ZipArchive* archive) {
int32_t result = -1;
- const uint8_t* cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
- size_t cd_length = archive->directory_map->getDataLength();
- uint16_t num_entries = archive->num_entries;
+ const uint8_t* const cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
+ const size_t cd_length = archive->directory_map->getDataLength();
+ const uint16_t num_entries = archive->num_entries;
/*
* Create hash table. We have a minimum 75% load factor, possibly as
@@ -490,39 +617,51 @@
* Walk through the central directory, adding entries to the hash
* table and verifying values.
*/
+ const uint8_t* const cd_end = cd_ptr + cd_length;
const uint8_t* ptr = cd_ptr;
for (uint16_t i = 0; i < num_entries; i++) {
- if (get4LE(ptr) != kCDESignature) {
+ const CentralDirectoryRecord* cdr =
+ reinterpret_cast<const CentralDirectoryRecord*>(ptr);
+ if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
goto bail;
}
- if (ptr + kCDELen > cd_ptr + cd_length) {
+ if (ptr + sizeof(CentralDirectoryRecord) > cd_end) {
ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
goto bail;
}
- const off64_t local_header_offset = get4LE(ptr + kCDELocalOffset);
+ 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;
}
- const uint16_t file_name_length = get2LE(ptr + kCDENameLen);
- const uint16_t extra_length = get2LE(ptr + kCDEExtraLen);
- const uint16_t comment_length = get2LE(ptr + kCDECommentLen);
+ 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 uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord);
+
+ /* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */
+ if (!IsValidEntryName(file_name, file_name_length)) {
+ goto bail;
+ }
/* 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, (const char*) ptr + kCDELen, file_name_length);
+ archive->hash_table_size, entry_name);
if (add_result) {
ALOGW("Zip: Error adding entry to hash table %d", add_result);
result = add_result;
goto bail;
}
- ptr += kCDELen + file_name_length + extra_length + comment_length;
- if ((size_t)(ptr - cd_ptr) > cd_length) {
+ 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;
@@ -552,28 +691,20 @@
int32_t OpenArchiveFd(int fd, const char* debug_file_name,
ZipArchiveHandle* handle) {
- ZipArchive* archive = (ZipArchive*) malloc(sizeof(ZipArchive));
- memset(archive, 0, sizeof(*archive));
+ ZipArchive* archive = new ZipArchive(fd);
*handle = archive;
-
- archive->fd = fd;
-
return OpenArchiveInternal(archive, debug_file_name);
}
int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
- ZipArchive* archive = (ZipArchive*) malloc(sizeof(ZipArchive));
- memset(archive, 0, sizeof(*archive));
+ const int fd = open(fileName, O_RDONLY | O_BINARY, 0);
+ ZipArchive* archive = new ZipArchive(fd);
*handle = archive;
- const int fd = open(fileName, O_RDONLY | O_BINARY, 0);
if (fd < 0) {
ALOGW("Unable to open '%s': %s", fileName, strerror(errno));
return kIoError;
- } else {
- archive->fd = fd;
}
-
return OpenArchiveInternal(archive, fileName);
}
@@ -583,35 +714,24 @@
void CloseArchive(ZipArchiveHandle handle) {
ZipArchive* archive = (ZipArchive*) handle;
ALOGV("Closing archive %p", archive);
-
- if (archive->fd >= 0) {
- close(archive->fd);
- }
-
- if (archive->directory_map != NULL) {
- archive->directory_map->release();
- }
- free(archive->hash_table);
- free(archive);
+ delete archive;
}
static int32_t UpdateEntryFromDataDescriptor(int fd,
ZipEntry *entry) {
- uint8_t ddBuf[kDDMaxLen];
+ uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
ssize_t actual = TEMP_FAILURE_RETRY(read(fd, ddBuf, sizeof(ddBuf)));
if (actual != sizeof(ddBuf)) {
return kIoError;
}
- const uint32_t ddSignature = get4LE(ddBuf);
- uint16_t ddOffset = 0;
- if (ddSignature == kDDOptSignature) {
- ddOffset = 4;
- }
+ const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf));
+ const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
+ const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset);
- entry->crc32 = get4LE(ddBuf + ddOffset + kDDCrc32);
- entry->compressed_length = get4LE(ddBuf + ddOffset + kDDCompLen);
- entry->uncompressed_length = get4LE(ddBuf + ddOffset + kDDUncompLen);
+ entry->crc32 = descriptor->crc32;
+ entry->compressed_length = descriptor->compressed_size;
+ entry->uncompressed_length = descriptor->uncompressed_size;
return 0;
}
@@ -624,7 +744,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
@@ -636,30 +756,32 @@
}
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 unsigned char* ptr = (const unsigned char*) name;
- ptr -= kCDELen;
+ 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 unsigned char* base_ptr = (const unsigned char*)
- archive->directory_map->getDataPtr();
+ 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()) {
ALOGW("Zip: Invalid entry pointer");
return kInvalidOffset;
}
+ const CentralDirectoryRecord *cdr =
+ reinterpret_cast<const CentralDirectoryRecord*>(ptr);
+
// The offset of the start of the central directory in the zipfile.
// We keep this lying around so that we can sanity check all our lengths
// and our per-file structures.
@@ -668,22 +790,22 @@
// Fill out the compression method, modification time, crc32
// and other interesting attributes from the central directory. These
// will later be compared against values from the local file header.
- data->method = get2LE(ptr + kCDEMethod);
- data->mod_time = get4LE(ptr + kCDEModWhen);
- data->crc32 = get4LE(ptr + kCDECRC);
- data->compressed_length = get4LE(ptr + kCDECompLen);
- data->uncompressed_length = get4LE(ptr + kCDEUncompLen);
+ data->method = cdr->compression_method;
+ data->mod_time = cdr->last_mod_time;
+ data->crc32 = cdr->crc32;
+ data->compressed_length = cdr->compressed_size;
+ data->uncompressed_length = cdr->uncompressed_size;
// Figure out the local header offset from the central directory. The
// actual file data will begin after the local header and the name /
// extra comments.
- const off64_t local_header_offset = get4LE(ptr + kCDELocalOffset);
- if (local_header_offset + (off64_t) kLFHLen >= cd_offset) {
+ const off64_t local_header_offset = cdr->local_file_header_offset;
+ if (local_header_offset + static_cast<off64_t>(sizeof(LocalFileHeader)) >= cd_offset) {
ALOGW("Zip: bad local hdr offset in zip");
return kInvalidOffset;
}
- uint8_t lfh_buf[kLFHLen];
+ uint8_t lfh_buf[sizeof(LocalFileHeader)];
ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf),
local_header_offset);
if (actual != sizeof(lfh_buf)) {
@@ -691,30 +813,25 @@
return kIoError;
}
- if (get4LE(lfh_buf) != kLFHSignature) {
+ const LocalFileHeader *lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf);
+
+ if (lfh->lfh_signature != LocalFileHeader::kSignature) {
ALOGW("Zip: didn't find signature at start of lfh, offset=%" PRId64,
- (int64_t)local_header_offset);
+ static_cast<int64_t>(local_header_offset));
return kInvalidOffset;
}
// Paranoia: Match the values specified in the local file header
// to those specified in the central directory.
- const uint16_t lfhGpbFlags = get2LE(lfh_buf + kLFHGPBFlags);
- const uint16_t lfhNameLen = get2LE(lfh_buf + kLFHNameLen);
- const uint16_t lfhExtraLen = get2LE(lfh_buf + kLFHExtraLen);
-
- if ((lfhGpbFlags & kGPBDDFlagMask) == 0) {
- const uint32_t lfhCrc = get4LE(lfh_buf + kLFHCRC);
- const uint32_t lfhCompLen = get4LE(lfh_buf + kLFHCompLen);
- const uint32_t lfhUncompLen = get4LE(lfh_buf + kLFHUncompLen);
-
+ if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) {
data->has_data_descriptor = 0;
- if (data->compressed_length != lfhCompLen || data->uncompressed_length != lfhUncompLen
- || data->crc32 != lfhCrc) {
+ if (data->compressed_length != lfh->compressed_size
+ || data->uncompressed_length != lfh->uncompressed_size
+ || data->crc32 != lfh->crc32) {
ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32
", %" PRIx32 "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}",
data->compressed_length, data->uncompressed_length, data->crc32,
- lfhCompLen, lfhUncompLen, lfhCrc);
+ lfh->compressed_size, lfh->uncompressed_size, lfh->crc32);
return kInconsistentInformation;
}
} else {
@@ -723,9 +840,9 @@
// Check that the local file header name matches the declared
// name in the central directory.
- if (lfhNameLen == nameLen) {
- const off64_t name_offset = local_header_offset + kLFHLen;
- if (name_offset + lfhNameLen >= cd_offset) {
+ 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) {
ALOGW("Zip: Invalid declared length");
return kInvalidOffset;
}
@@ -740,7 +857,7 @@
return kIoError;
}
- if (memcmp(name, name_buf, nameLen)) {
+ if (memcmp(archive->hash_table[ent].name, name_buf, nameLen)) {
free(name_buf);
return kInconsistentInformation;
}
@@ -751,7 +868,8 @@
return kInconsistentInformation;
}
- const off64_t data_offset = local_header_offset + kLFHLen + lfhNameLen + lfhExtraLen;
+ 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);
return kInvalidOffset;
@@ -776,12 +894,28 @@
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) {
+int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
+ const ZipEntryName* optional_prefix) {
ZipArchive* archive = (ZipArchive *) handle;
if (archive == NULL || archive->hash_table == NULL) {
@@ -789,32 +923,32 @@
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);
+ 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;
}
@@ -839,7 +973,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);
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 3082216..4775de0 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -26,6 +26,7 @@
static std::string test_data_dir;
+static const std::string kMissingZip = "missing.zip";
static const std::string kValidZip = "valid.zip";
static const uint8_t kATxtContents[] = {
@@ -39,6 +40,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;
@@ -58,6 +80,14 @@
CloseArchive(handle);
}
+TEST(ziparchive, OpenMissing) {
+ ZipArchiveHandle handle;
+ ASSERT_NE(0, OpenArchiveWrapper(kMissingZip, &handle));
+
+ // Confirm the file descriptor is not going to be mistaken for a valid one.
+ ASSERT_EQ(-1, GetFileDescriptor(handle));
+}
+
TEST(ziparchive, Iteration) {
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
@@ -99,7 +129,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);
@@ -109,7 +142,10 @@
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);
}
@@ -120,7 +156,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];
@@ -129,7 +168,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];
@@ -140,11 +182,7 @@
CloseArchive(handle);
}
-TEST(ziparchive, EmptyEntries) {
- char temp_file_pattern[] = "empty_entries_test_XXXXXX";
- int fd = mkstemp(temp_file_pattern);
- ASSERT_NE(-1, fd);
- const uint32_t data[] = {
+static const uint32_t kEmptyEntriesZip[] = {
0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000,
0x00090000, 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13,
0x52e25c24, 0x000b7875, 0x42890401, 0x88040000, 0x50000013, 0x1e02014b,
@@ -152,20 +190,43 @@
0x00001800, 0x00000000, 0xa0000000, 0x00000081, 0x706d6500, 0x742e7974,
0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
- const ssize_t file_size = 168;
- ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, data, file_size)));
+
+static int make_temporary_file(const char* file_name_pattern) {
+ char full_path[1024];
+ // Account for differences between the host and the target.
+ //
+ // TODO: Maybe reuse bionic/tests/TemporaryFile.h.
+ snprintf(full_path, sizeof(full_path), "/data/local/tmp/%s", file_name_pattern);
+ int fd = mkstemp(full_path);
+ if (fd == -1) {
+ snprintf(full_path, sizeof(full_path), "/tmp/%s", file_name_pattern);
+ fd = mkstemp(full_path);
+ }
+
+ return fd;
+}
+
+TEST(ziparchive, EmptyEntries) {
+ char temp_file_pattern[] = "empty_entries_test_XXXXXX";
+ int fd = make_temporary_file(temp_file_pattern);
+ ASSERT_NE(-1, fd);
+ const ssize_t file_size = sizeof(kEmptyEntriesZip);
+ ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, kEmptyEntriesZip, file_size)));
ZipArchiveHandle handle;
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));
char output_file_pattern[] = "empty_entries_output_XXXXXX";
- int output_fd = mkstemp(output_file_pattern);
+ int output_fd = make_temporary_file(output_file_pattern);
ASSERT_NE(-1, output_fd);
ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd));
@@ -177,9 +238,25 @@
close(output_fd);
}
+TEST(ziparchive, TrailerAfterEOCD) {
+ char temp_file_pattern[] = "trailer_after_eocd_test_XXXXXX";
+ int fd = make_temporary_file(temp_file_pattern);
+ ASSERT_NE(-1, fd);
+
+ // Create a file with 8 bytes of random garbage.
+ static const uint8_t trailer[] = { 'A' ,'n', 'd', 'r', 'o', 'i', 'd', 'z' };
+ const ssize_t file_size = sizeof(kEmptyEntriesZip);
+ const ssize_t trailer_size = sizeof(trailer);
+ ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, kEmptyEntriesZip, file_size)));
+ ASSERT_EQ(trailer_size, TEMP_FAILURE_RETRY(write(fd, trailer, trailer_size)));
+
+ ZipArchiveHandle handle;
+ ASSERT_GT(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle));
+}
+
TEST(ziparchive, ExtractToFile) {
char kTempFilePattern[] = "zip_archive_input_XXXXXX";
- int fd = mkstemp(kTempFilePattern);
+ int fd = make_temporary_file(kTempFilePattern);
ASSERT_NE(-1, fd);
const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
const ssize_t data_size = sizeof(data);
@@ -190,7 +267,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));
@@ -209,7 +289,8 @@
sizeof(kATxtContents)));
// Assert that the total length of the file is sane
- ASSERT_EQ(data_size + sizeof(kATxtContents), lseek64(fd, 0, SEEK_END));
+ ASSERT_EQ(data_size + static_cast<ssize_t>(sizeof(kATxtContents)),
+ lseek64(fd, 0, SEEK_END));
close(fd);
}
@@ -247,4 +328,3 @@
return RUN_ALL_TESTS();
}
-
diff --git a/libzipfile/Android.mk b/libzipfile/Android.mk
index 614a460..f054e15 100644
--- a/libzipfile/Android.mk
+++ b/libzipfile/Android.mk
@@ -7,15 +7,14 @@
centraldir.c \
zipfile.c
-LOCAL_STATIC_LIBRARIES := \
- libunz
+LOCAL_STATIC_LIBRARIES := libz
LOCAL_MODULE:= libzipfile
-LOCAL_C_INCLUDES += external/zlib
-
LOCAL_CFLAGS := -Werror
+LOCAL_MULTILIB := both
+
include $(BUILD_HOST_STATIC_LIBRARY)
# build device static library
@@ -25,13 +24,10 @@
centraldir.c \
zipfile.c
-LOCAL_STATIC_LIBRARIES := \
- libunz
+LOCAL_STATIC_LIBRARIES := libz
LOCAL_MODULE:= libzipfile
-LOCAL_C_INCLUDES += external/zlib
-
LOCAL_CFLAGS := -Werror
include $(BUILD_STATIC_LIBRARY)
@@ -43,12 +39,10 @@
LOCAL_SRC_FILES:= \
test_zipfile.c
-LOCAL_STATIC_LIBRARIES := libzipfile libunz
+LOCAL_STATIC_LIBRARIES := libzipfile libz
LOCAL_MODULE := test_zipfile
-LOCAL_C_INCLUDES += external/zlib
-
LOCAL_CFLAGS := -Werror
include $(BUILD_HOST_EXECUTABLE)
diff --git a/lmkd/Android.mk b/lmkd/Android.mk
new file mode 100644
index 0000000..39081d6
--- /dev/null
+++ b/lmkd/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := lmkd.c
+LOCAL_SHARED_LIBRARIES := liblog libm libc libprocessgroup
+LOCAL_CFLAGS := -Werror
+
+LOCAL_MODULE := lmkd
+
+include $(BUILD_EXECUTABLE)
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
new file mode 100644
index 0000000..7bbc811
--- /dev/null
+++ b/lmkd/lmkd.c
@@ -0,0 +1,831 @@
+/*
+ * 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 LOG_TAG "lowmemorykiller"
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/cdefs.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/sockets.h>
+#include <log/log.h>
+#include <processgroup/processgroup.h>
+
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
+#define MEMCG_SYSFS_PATH "/dev/memcg/"
+#define MEMPRESSURE_WATCH_LEVEL "medium"
+#define ZONEINFO_PATH "/proc/zoneinfo"
+#define LINE_MAX 128
+
+#define INKERNEL_MINFREE_PATH "/sys/module/lowmemorykiller/parameters/minfree"
+#define INKERNEL_ADJ_PATH "/sys/module/lowmemorykiller/parameters/adj"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
+enum lmk_cmd {
+ LMK_TARGET,
+ LMK_PROCPRIO,
+ LMK_PROCREMOVE,
+};
+
+#define MAX_TARGETS 6
+/*
+ * longest is LMK_TARGET followed by MAX_TARGETS each minfree and minkillprio
+ * values
+ */
+#define CTRL_PACKET_MAX (sizeof(int) * (MAX_TARGETS * 2 + 1))
+
+/* default to old in-kernel interface if no memory pressure events */
+static int use_inkernel_interface = 1;
+
+/* memory pressure level medium event */
+static int mpevfd;
+
+/* control socket listen and data */
+static int ctrl_lfd;
+static int ctrl_dfd = -1;
+static int ctrl_dfd_reopened; /* did we reopen ctrl conn on this loop? */
+
+/* 1 memory pressure level, 1 ctrl listen socket, 1 ctrl data socket */
+#define MAX_EPOLL_EVENTS 3
+static int epollfd;
+static int maxevents;
+
+#define OOM_DISABLE (-17)
+/* inclusive */
+#define OOM_ADJUST_MIN (-16)
+#define OOM_ADJUST_MAX 15
+
+/* kernel OOM score values */
+#define OOM_SCORE_ADJ_MIN (-1000)
+#define OOM_SCORE_ADJ_MAX 1000
+
+static int lowmem_adj[MAX_TARGETS];
+static int lowmem_minfree[MAX_TARGETS];
+static int lowmem_targets_size;
+
+struct sysmeminfo {
+ int nr_free_pages;
+ int nr_file_pages;
+ int nr_shmem;
+ int totalreserve_pages;
+};
+
+struct adjslot_list {
+ struct adjslot_list *next;
+ struct adjslot_list *prev;
+};
+
+struct proc {
+ struct adjslot_list asl;
+ int pid;
+ uid_t uid;
+ int oomadj;
+ struct proc *pidhash_next;
+};
+
+#define PIDHASH_SZ 1024
+static struct proc *pidhash[PIDHASH_SZ];
+#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
+
+#define ADJTOSLOT(adj) (adj + -OOM_ADJUST_MIN)
+static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_ADJUST_MAX) + 1];
+
+/*
+ * Wait 1-2 seconds for the death report of a killed process prior to
+ * considering killing more processes.
+ */
+#define KILL_TIMEOUT 2
+/* Time of last process kill we initiated, stop me before I kill again */
+static time_t kill_lasttime;
+
+/* PAGE_SIZE / 1024 */
+static long page_k;
+
+static ssize_t read_all(int fd, char *buf, size_t max_len)
+{
+ ssize_t ret = 0;
+
+ while (max_len > 0) {
+ ssize_t r = read(fd, buf, max_len);
+ if (r == 0) {
+ break;
+ }
+ if (r == -1) {
+ return -1;
+ }
+ ret += r;
+ buf += r;
+ max_len -= r;
+ }
+
+ return ret;
+}
+
+static int lowmem_oom_adj_to_oom_score_adj(int oom_adj)
+{
+ if (oom_adj == OOM_ADJUST_MAX)
+ return OOM_SCORE_ADJ_MAX;
+ else
+ return (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
+}
+
+static struct proc *pid_lookup(int pid) {
+ struct proc *procp;
+
+ for (procp = pidhash[pid_hashfn(pid)]; procp && procp->pid != pid;
+ procp = procp->pidhash_next)
+ ;
+
+ return procp;
+}
+
+static void adjslot_insert(struct adjslot_list *head, struct adjslot_list *new)
+{
+ struct adjslot_list *next = head->next;
+ new->prev = head;
+ new->next = next;
+ next->prev = new;
+ head->next = new;
+}
+
+static void adjslot_remove(struct adjslot_list *old)
+{
+ struct adjslot_list *prev = old->prev;
+ struct adjslot_list *next = old->next;
+ next->prev = prev;
+ prev->next = next;
+}
+
+static struct adjslot_list *adjslot_tail(struct adjslot_list *head) {
+ struct adjslot_list *asl = head->prev;
+
+ return asl == head ? NULL : asl;
+}
+
+static void proc_slot(struct proc *procp) {
+ int adjslot = ADJTOSLOT(procp->oomadj);
+
+ adjslot_insert(&procadjslot_list[adjslot], &procp->asl);
+}
+
+static void proc_unslot(struct proc *procp) {
+ adjslot_remove(&procp->asl);
+}
+
+static void proc_insert(struct proc *procp) {
+ int hval = pid_hashfn(procp->pid);
+
+ procp->pidhash_next = pidhash[hval];
+ pidhash[hval] = procp;
+ proc_slot(procp);
+}
+
+static int pid_remove(int pid) {
+ int hval = pid_hashfn(pid);
+ struct proc *procp;
+ struct proc *prevp;
+
+ for (procp = pidhash[hval], prevp = NULL; procp && procp->pid != pid;
+ procp = procp->pidhash_next)
+ prevp = procp;
+
+ if (!procp)
+ return -1;
+
+ if (!prevp)
+ pidhash[hval] = procp->pidhash_next;
+ else
+ prevp->pidhash_next = procp->pidhash_next;
+
+ proc_unslot(procp);
+ free(procp);
+ return 0;
+}
+
+static void writefilestring(char *path, char *s) {
+ int fd = open(path, O_WRONLY);
+ int len = strlen(s);
+ int ret;
+
+ if (fd < 0) {
+ ALOGE("Error opening %s; errno=%d", path, errno);
+ return;
+ }
+
+ ret = write(fd, s, len);
+ if (ret < 0) {
+ ALOGE("Error writing %s; errno=%d", path, errno);
+ } else if (ret < len) {
+ ALOGE("Short write on %s; length=%d", path, ret);
+ }
+
+ close(fd);
+}
+
+static void cmd_procprio(int pid, int uid, int oomadj) {
+ struct proc *procp;
+ char path[80];
+ char val[20];
+
+ if (oomadj < OOM_DISABLE || oomadj > OOM_ADJUST_MAX) {
+ ALOGE("Invalid PROCPRIO oomadj argument %d", oomadj);
+ return;
+ }
+
+ snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", pid);
+ snprintf(val, sizeof(val), "%d", lowmem_oom_adj_to_oom_score_adj(oomadj));
+ writefilestring(path, val);
+
+ if (use_inkernel_interface)
+ return;
+
+ procp = pid_lookup(pid);
+ if (!procp) {
+ procp = malloc(sizeof(struct proc));
+ if (!procp) {
+ // Oh, the irony. May need to rebuild our state.
+ return;
+ }
+
+ procp->pid = pid;
+ procp->uid = uid;
+ procp->oomadj = oomadj;
+ proc_insert(procp);
+ } else {
+ proc_unslot(procp);
+ procp->oomadj = oomadj;
+ proc_slot(procp);
+ }
+}
+
+static void cmd_procremove(int pid) {
+ if (use_inkernel_interface)
+ return;
+
+ pid_remove(pid);
+ kill_lasttime = 0;
+}
+
+static void cmd_target(int ntargets, int *params) {
+ int i;
+
+ if (ntargets > (int)ARRAY_SIZE(lowmem_adj))
+ return;
+
+ for (i = 0; i < ntargets; i++) {
+ lowmem_minfree[i] = ntohl(*params++);
+ lowmem_adj[i] = ntohl(*params++);
+ }
+
+ lowmem_targets_size = ntargets;
+
+ if (use_inkernel_interface) {
+ char minfreestr[128];
+ char killpriostr[128];
+
+ minfreestr[0] = '\0';
+ killpriostr[0] = '\0';
+
+ for (i = 0; i < lowmem_targets_size; i++) {
+ char val[40];
+
+ if (i) {
+ strlcat(minfreestr, ",", sizeof(minfreestr));
+ strlcat(killpriostr, ",", sizeof(killpriostr));
+ }
+
+ snprintf(val, sizeof(val), "%d", lowmem_minfree[i]);
+ strlcat(minfreestr, val, sizeof(minfreestr));
+ snprintf(val, sizeof(val), "%d", lowmem_adj[i]);
+ strlcat(killpriostr, val, sizeof(killpriostr));
+ }
+
+ writefilestring(INKERNEL_MINFREE_PATH, minfreestr);
+ writefilestring(INKERNEL_ADJ_PATH, killpriostr);
+ }
+}
+
+static void ctrl_data_close(void) {
+ ALOGI("Closing Activity Manager data connection");
+ close(ctrl_dfd);
+ ctrl_dfd = -1;
+ maxevents--;
+}
+
+static int ctrl_data_read(char *buf, size_t bufsz) {
+ int ret = 0;
+
+ ret = read(ctrl_dfd, buf, bufsz);
+
+ if (ret == -1) {
+ ALOGE("control data socket read failed; errno=%d", errno);
+ } else if (ret == 0) {
+ ALOGE("Got EOF on control data socket");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static void ctrl_command_handler(void) {
+ int ibuf[CTRL_PACKET_MAX / sizeof(int)];
+ int len;
+ int cmd = -1;
+ int nargs;
+ int targets;
+
+ len = ctrl_data_read((char *)ibuf, CTRL_PACKET_MAX);
+ if (len <= 0)
+ return;
+
+ nargs = len / sizeof(int) - 1;
+ if (nargs < 0)
+ goto wronglen;
+
+ cmd = ntohl(ibuf[0]);
+
+ switch(cmd) {
+ case LMK_TARGET:
+ targets = nargs / 2;
+ if (nargs & 0x1 || targets > (int)ARRAY_SIZE(lowmem_adj))
+ goto wronglen;
+ cmd_target(targets, &ibuf[1]);
+ break;
+ case LMK_PROCPRIO:
+ if (nargs != 3)
+ goto wronglen;
+ cmd_procprio(ntohl(ibuf[1]), ntohl(ibuf[2]), ntohl(ibuf[3]));
+ break;
+ case LMK_PROCREMOVE:
+ if (nargs != 1)
+ goto wronglen;
+ cmd_procremove(ntohl(ibuf[1]));
+ break;
+ default:
+ ALOGE("Received unknown command code %d", cmd);
+ return;
+ }
+
+ return;
+
+wronglen:
+ ALOGE("Wrong control socket read length cmd=%d len=%d", cmd, len);
+}
+
+static void ctrl_data_handler(uint32_t events) {
+ if (events & EPOLLHUP) {
+ ALOGI("ActivityManager disconnected");
+ if (!ctrl_dfd_reopened)
+ ctrl_data_close();
+ } else if (events & EPOLLIN) {
+ ctrl_command_handler();
+ }
+}
+
+static void ctrl_connect_handler(uint32_t events __unused) {
+ struct sockaddr addr;
+ socklen_t alen;
+ struct epoll_event epev;
+
+ if (ctrl_dfd >= 0) {
+ ctrl_data_close();
+ ctrl_dfd_reopened = 1;
+ }
+
+ alen = sizeof(addr);
+ ctrl_dfd = accept(ctrl_lfd, &addr, &alen);
+
+ if (ctrl_dfd < 0) {
+ ALOGE("lmkd control socket accept failed; errno=%d", errno);
+ return;
+ }
+
+ ALOGI("ActivityManager connected");
+ maxevents++;
+ epev.events = EPOLLIN;
+ epev.data.ptr = (void *)ctrl_data_handler;
+ if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ctrl_dfd, &epev) == -1) {
+ ALOGE("epoll_ctl for data connection socket failed; errno=%d", errno);
+ ctrl_data_close();
+ return;
+ }
+}
+
+static int zoneinfo_parse_protection(char *cp) {
+ int max = 0;
+ int zoneval;
+ char *save_ptr;
+
+ for (cp = strtok_r(cp, "(), ", &save_ptr); cp; cp = strtok_r(NULL, "), ", &save_ptr)) {
+ zoneval = strtol(cp, &cp, 0);
+ if (zoneval > max)
+ max = zoneval;
+ }
+
+ return max;
+}
+
+static void zoneinfo_parse_line(char *line, struct sysmeminfo *mip) {
+ char *cp = line;
+ char *ap;
+ char *save_ptr;
+
+ cp = strtok_r(line, " ", &save_ptr);
+ if (!cp)
+ return;
+
+ ap = strtok_r(NULL, " ", &save_ptr);
+ if (!ap)
+ return;
+
+ if (!strcmp(cp, "nr_free_pages"))
+ mip->nr_free_pages += strtol(ap, NULL, 0);
+ else if (!strcmp(cp, "nr_file_pages"))
+ mip->nr_file_pages += strtol(ap, NULL, 0);
+ else if (!strcmp(cp, "nr_shmem"))
+ mip->nr_shmem += strtol(ap, NULL, 0);
+ else if (!strcmp(cp, "high"))
+ mip->totalreserve_pages += strtol(ap, NULL, 0);
+ else if (!strcmp(cp, "protection:"))
+ mip->totalreserve_pages += zoneinfo_parse_protection(ap);
+}
+
+static int zoneinfo_parse(struct sysmeminfo *mip) {
+ int fd;
+ ssize_t size;
+ char buf[PAGE_SIZE];
+ char *save_ptr;
+ char *line;
+
+ memset(mip, 0, sizeof(struct sysmeminfo));
+
+ fd = open(ZONEINFO_PATH, O_RDONLY);
+ if (fd == -1) {
+ ALOGE("%s open: errno=%d", ZONEINFO_PATH, errno);
+ return -1;
+ }
+
+ size = read_all(fd, buf, sizeof(buf) - 1);
+ if (size < 0) {
+ ALOGE("%s read: errno=%d", ZONEINFO_PATH, errno);
+ close(fd);
+ return -1;
+ }
+ ALOG_ASSERT((size_t)size < sizeof(buf) - 1, "/proc/zoneinfo too large");
+ buf[size] = 0;
+
+ for (line = strtok_r(buf, "\n", &save_ptr); line; line = strtok_r(NULL, "\n", &save_ptr))
+ zoneinfo_parse_line(line, mip);
+
+ close(fd);
+ return 0;
+}
+
+static int proc_get_size(int pid) {
+ char path[PATH_MAX];
+ char line[LINE_MAX];
+ int fd;
+ int rss = 0;
+ int total;
+ ssize_t ret;
+
+ snprintf(path, PATH_MAX, "/proc/%d/statm", pid);
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ ret = read_all(fd, line, sizeof(line) - 1);
+ if (ret < 0) {
+ close(fd);
+ return -1;
+ }
+
+ sscanf(line, "%d %d ", &total, &rss);
+ close(fd);
+ return rss;
+}
+
+static char *proc_get_name(int pid) {
+ char path[PATH_MAX];
+ static char line[LINE_MAX];
+ int fd;
+ char *cp;
+ ssize_t ret;
+
+ snprintf(path, PATH_MAX, "/proc/%d/cmdline", pid);
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return NULL;
+ ret = read_all(fd, line, sizeof(line) - 1);
+ close(fd);
+ if (ret < 0) {
+ return NULL;
+ }
+
+ cp = strchr(line, ' ');
+ if (cp)
+ *cp = '\0';
+
+ return line;
+}
+
+static struct proc *proc_adj_lru(int oomadj) {
+ return (struct proc *)adjslot_tail(&procadjslot_list[ADJTOSLOT(oomadj)]);
+}
+
+/* Kill one process specified by procp. Returns the size of the process killed */
+static int kill_one_process(struct proc *procp, int other_free, int other_file,
+ int minfree, int min_score_adj, bool first)
+{
+ int pid = procp->pid;
+ uid_t uid = procp->uid;
+ char *taskname;
+ int tasksize;
+ int r;
+
+ taskname = proc_get_name(pid);
+ if (!taskname) {
+ pid_remove(pid);
+ return -1;
+ }
+
+ tasksize = proc_get_size(pid);
+ if (tasksize <= 0) {
+ pid_remove(pid);
+ return -1;
+ }
+
+ ALOGI("Killing '%s' (%d), uid %d, adj %d\n"
+ " to free %ldkB because cache %s%ldkB is below limit %ldkB for oom_adj %d\n"
+ " Free memory is %s%ldkB %s reserved",
+ taskname, pid, uid, procp->oomadj, tasksize * page_k,
+ first ? "" : "~", other_file * page_k, minfree * page_k, min_score_adj,
+ first ? "" : "~", other_free * page_k, other_free >= 0 ? "above" : "below");
+ r = kill(pid, SIGKILL);
+ killProcessGroup(uid, pid, SIGKILL);
+ pid_remove(pid);
+
+ if (r) {
+ ALOGE("kill(%d): errno=%d", procp->pid, errno);
+ return -1;
+ } else {
+ return tasksize;
+ }
+}
+
+/*
+ * Find a process to kill based on the current (possibly estimated) free memory
+ * and cached memory sizes. Returns the size of the killed processes.
+ */
+static int find_and_kill_process(int other_free, int other_file, bool first)
+{
+ int i;
+ int min_score_adj = OOM_ADJUST_MAX + 1;
+ int minfree = 0;
+ int killed_size = 0;
+
+ for (i = 0; i < lowmem_targets_size; i++) {
+ minfree = lowmem_minfree[i];
+ if (other_free < minfree && other_file < minfree) {
+ min_score_adj = lowmem_adj[i];
+ break;
+ }
+ }
+
+ if (min_score_adj == OOM_ADJUST_MAX + 1)
+ return 0;
+
+ for (i = OOM_ADJUST_MAX; i >= min_score_adj; i--) {
+ struct proc *procp;
+
+retry:
+ procp = proc_adj_lru(i);
+
+ if (procp) {
+ killed_size = kill_one_process(procp, other_free, other_file, minfree, min_score_adj, first);
+ if (killed_size < 0) {
+ goto retry;
+ } else {
+ return killed_size;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void mp_event(uint32_t events __unused) {
+ int ret;
+ unsigned long long evcount;
+ struct sysmeminfo mi;
+ int other_free;
+ int other_file;
+ int killed_size;
+ bool first = true;
+
+ ret = read(mpevfd, &evcount, sizeof(evcount));
+ if (ret < 0)
+ ALOGE("Error reading memory pressure event fd; errno=%d",
+ errno);
+
+ if (time(NULL) - kill_lasttime < KILL_TIMEOUT)
+ return;
+
+ while (zoneinfo_parse(&mi) < 0) {
+ // Failed to read /proc/zoneinfo, assume ENOMEM and kill something
+ find_and_kill_process(0, 0, true);
+ }
+
+ other_free = mi.nr_free_pages - mi.totalreserve_pages;
+ other_file = mi.nr_file_pages - mi.nr_shmem;
+
+ do {
+ killed_size = find_and_kill_process(other_free, other_file, first);
+ if (killed_size > 0) {
+ first = false;
+ other_free += killed_size;
+ other_file += killed_size;
+ }
+ } while (killed_size > 0);
+}
+
+static int init_mp(char *levelstr, void *event_handler)
+{
+ int mpfd;
+ int evfd;
+ int evctlfd;
+ char buf[256];
+ struct epoll_event epev;
+ int ret;
+
+ mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY);
+ if (mpfd < 0) {
+ ALOGI("No kernel memory.pressure_level support (errno=%d)", errno);
+ goto err_open_mpfd;
+ }
+
+ evctlfd = open(MEMCG_SYSFS_PATH "cgroup.event_control", O_WRONLY);
+ if (evctlfd < 0) {
+ ALOGI("No kernel memory cgroup event control (errno=%d)", errno);
+ goto err_open_evctlfd;
+ }
+
+ evfd = eventfd(0, EFD_NONBLOCK);
+ if (evfd < 0) {
+ ALOGE("eventfd failed for level %s; errno=%d", levelstr, errno);
+ goto err_eventfd;
+ }
+
+ ret = snprintf(buf, sizeof(buf), "%d %d %s", evfd, mpfd, levelstr);
+ if (ret >= (ssize_t)sizeof(buf)) {
+ ALOGE("cgroup.event_control line overflow for level %s", levelstr);
+ goto err;
+ }
+
+ ret = write(evctlfd, buf, strlen(buf) + 1);
+ if (ret == -1) {
+ ALOGE("cgroup.event_control write failed for level %s; errno=%d",
+ levelstr, errno);
+ goto err;
+ }
+
+ epev.events = EPOLLIN;
+ epev.data.ptr = event_handler;
+ ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, evfd, &epev);
+ if (ret == -1) {
+ ALOGE("epoll_ctl for level %s failed; errno=%d", levelstr, errno);
+ goto err;
+ }
+ maxevents++;
+ mpevfd = evfd;
+ return 0;
+
+err:
+ close(evfd);
+err_eventfd:
+ close(evctlfd);
+err_open_evctlfd:
+ close(mpfd);
+err_open_mpfd:
+ return -1;
+}
+
+static int init(void) {
+ struct epoll_event epev;
+ int i;
+ int ret;
+
+ page_k = sysconf(_SC_PAGESIZE);
+ if (page_k == -1)
+ page_k = PAGE_SIZE;
+ page_k /= 1024;
+
+ epollfd = epoll_create(MAX_EPOLL_EVENTS);
+ if (epollfd == -1) {
+ ALOGE("epoll_create failed (errno=%d)", errno);
+ return -1;
+ }
+
+ ctrl_lfd = android_get_control_socket("lmkd");
+ if (ctrl_lfd < 0) {
+ ALOGE("get lmkd control socket failed");
+ return -1;
+ }
+
+ ret = listen(ctrl_lfd, 1);
+ if (ret < 0) {
+ ALOGE("lmkd control socket listen failed (errno=%d)", errno);
+ return -1;
+ }
+
+ epev.events = EPOLLIN;
+ epev.data.ptr = (void *)ctrl_connect_handler;
+ if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ctrl_lfd, &epev) == -1) {
+ ALOGE("epoll_ctl for lmkd control socket failed (errno=%d)", errno);
+ return -1;
+ }
+ maxevents++;
+
+ use_inkernel_interface = !access(INKERNEL_MINFREE_PATH, W_OK);
+
+ if (use_inkernel_interface) {
+ ALOGI("Using in-kernel low memory killer interface");
+ } else {
+ ret = init_mp(MEMPRESSURE_WATCH_LEVEL, (void *)&mp_event);
+ if (ret)
+ ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer");
+ }
+
+ for (i = 0; i <= ADJTOSLOT(OOM_ADJUST_MAX); i++) {
+ procadjslot_list[i].next = &procadjslot_list[i];
+ procadjslot_list[i].prev = &procadjslot_list[i];
+ }
+
+ return 0;
+}
+
+static void mainloop(void) {
+ while (1) {
+ struct epoll_event events[maxevents];
+ int nevents;
+ int i;
+
+ ctrl_dfd_reopened = 0;
+ nevents = epoll_wait(epollfd, events, maxevents, -1);
+
+ if (nevents == -1) {
+ if (errno == EINTR)
+ continue;
+ ALOGE("epoll_wait failed (errno=%d)", errno);
+ continue;
+ }
+
+ for (i = 0; i < nevents; ++i) {
+ if (events[i].events & EPOLLERR)
+ ALOGD("EPOLLERR on event #%d", i);
+ if (events[i].data.ptr)
+ (*(void (*)(uint32_t))events[i].data.ptr)(events[i].events);
+ }
+ }
+}
+
+int main(int argc __unused, char **argv __unused) {
+ struct sched_param param = {
+ .sched_priority = 1,
+ };
+
+ mlockall(MCL_FUTURE);
+ sched_setscheduler(0, SCHED_FIFO, ¶m);
+ if (!init())
+ mainloop();
+
+ ALOGI("exiting");
+ return 0;
+}
diff --git a/logcat/event.logtags b/logcat/event.logtags
index a325692..1b5c6f4 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -134,5 +134,7 @@
# libcore failure logging
90100 exp_det_cert_pin_failure (certs|4)
+1397638484 snet_event_log (subtag|3) (uid|1) (message|3)
+
# NOTE - the range 1000000-2000000 is reserved for partners and others who
# want to define their own log tags without conflicting with the core platform.
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index db4fddd..79f2ebd 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -4,6 +4,7 @@
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -80,15 +81,20 @@
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);
@@ -219,12 +225,15 @@
" -f <filename> Log to file. Default to stdout\n"
" -r [<kbytes>] Rotate log every kbytes. (16 if unspecified). 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"
" -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"
+ " -t '<time>' print most recent lines since specified time (implies -d)\n"
" -T <count> print only the most recent <count> lines (does not imply -d)\n"
+ " -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"
" -b <buffer> Request alternate ring buffer, 'main', 'system', 'radio',\n"
" 'events', 'crash' or 'all'. Multiple -b parameters are\n"
@@ -256,7 +265,7 @@
"\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");
+ "or defaults to \"threadtime\"\n\n");
@@ -336,7 +345,7 @@
for (;;) {
int ret;
- ret = getopt(argc, argv, "cdt:T:gG:sQf:r::n:v:b:BSpP:");
+ ret = getopt(argc, argv, "cdt:T:gG:sQf:r:n:v:b:BSpP:");
if (ret < 0) {
break;
@@ -446,36 +455,31 @@
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;
+ android::g_devCount = 0;
+ needBinary = false;
+ 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, *name);
+
+ 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++;
+ android::g_devCount++;
+ if (binary) {
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++;
- }
- }
break;
}
@@ -540,7 +544,9 @@
exit(-1);
}
- hasSetLogFormat = 1;
+ if (strcmp("color", optarg)) { // exception for modifiers
+ hasSetLogFormat = 1;
+ }
break;
case 'Q':
@@ -623,18 +629,14 @@
}
if (!devices) {
- devices = new log_device_t("main", false, 'm');
+ dev = devices = new log_device_t("main", false, 'm');
android::g_devCount = 1;
if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
- devices->next = new log_device_t("system", false, 's');
+ dev = dev->next = new log_device_t("system", false, 's');
android::g_devCount++;
}
if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
- if (devices->next) {
- devices->next->next = new log_device_t("crash", false, 'c');
- } else {
- devices->next = new log_device_t("crash", false, 'c');
- }
+ dev = dev->next = new log_device_t("crash", false, 'c');
android::g_devCount++;
}
}
@@ -654,11 +656,12 @@
if (logFormat != NULL) {
err = setLogFormat(logFormat);
-
if (err < 0) {
fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n",
logFormat);
}
+ } else {
+ setLogFormat("threadtime");
}
}
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index 5d4d29e..015a23d 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -16,11 +16,7 @@
LOCAL_PATH := $(call my-dir)
-# -----------------------------------------------------------------------------
-# Unit tests.
-# -----------------------------------------------------------------------------
-
-test_module := logcat-unit-tests
+test_module_prefix := logcat-
test_tags := tests
test_c_flags := \
@@ -28,7 +24,29 @@
-g \
-Wall -Wextra \
-Werror \
- -fno-builtin
+ -fno-builtin \
+ -std=gnu++11
+
+# -----------------------------------------------------------------------------
+# Benchmarks (actually a gTest where the result code does not matter)
+# ----------------------------------------------------------------------------
+
+benchmark_src_files := \
+ logcat_benchmark.cpp
+
+# Build benchmarks for the device. Run with:
+# adb shell /data/nativetest/logcat-benchmarks/logcat-benchmarks
+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)
+
+# -----------------------------------------------------------------------------
+# Unit tests.
+# -----------------------------------------------------------------------------
test_src_files := \
logcat_test.cpp \
@@ -36,7 +54,7 @@
# Build tests for the device (with .so). Run with:
# adb shell /data/nativetest/logcat-unit-tests/logcat-unit-tests
include $(CLEAR_VARS)
-LOCAL_MODULE := $(test_module)
+LOCAL_MODULE := $(test_module_prefix)unit-tests
LOCAL_MODULE_TAGS := $(test_tags)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CFLAGS += $(test_c_flags)
diff --git a/logcat/tests/logcat_benchmark.cpp b/logcat/tests/logcat_benchmark.cpp
new file mode 100644
index 0000000..be815be
--- /dev/null
+++ b/logcat/tests/logcat_benchmark.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2013-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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gtest/gtest.h>
+
+static const char begin[] = "--------- beginning of ";
+
+TEST(logcat, sorted_order) {
+ FILE *fp;
+
+ ASSERT_TRUE(NULL != (fp = popen(
+ "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
+ "r")));
+
+ class timestamp {
+ private:
+ int month;
+ int day;
+ int hour;
+ int minute;
+ int second;
+ int millisecond;
+ bool ok;
+
+ public:
+ void init(const char *buffer)
+ {
+ ok = false;
+ if (buffer != NULL) {
+ ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ",
+ &month, &day, &hour, &minute, &second, &millisecond) == 6;
+ }
+ }
+
+ timestamp(const char *buffer)
+ {
+ init(buffer);
+ }
+
+ bool operator< (timestamp &T)
+ {
+ return !ok || !T.ok
+ || (month < T.month)
+ || ((month == T.month)
+ && ((day < T.day)
+ || ((day == T.day)
+ && ((hour < T.hour)
+ || ((hour == T.hour)
+ && ((minute < T.minute)
+ || ((minute == T.minute)
+ && ((second < T.second)
+ || ((second == T.second)
+ && (millisecond < T.millisecond))))))))));
+ }
+
+ bool valid(void)
+ {
+ return ok;
+ }
+ } last(NULL);
+
+ char *last_buffer = NULL;
+ char buffer[5120];
+
+ int count = 0;
+ int next_lt_last = 0;
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
+ continue;
+ }
+ if (!last.valid()) {
+ free(last_buffer);
+ last_buffer = strdup(buffer);
+ last.init(buffer);
+ }
+ timestamp next(buffer);
+ if (next < last) {
+ if (last_buffer) {
+ fprintf(stderr, "<%s", last_buffer);
+ }
+ fprintf(stderr, ">%s", buffer);
+ ++next_lt_last;
+ }
+ if (next.valid()) {
+ free(last_buffer);
+ last_buffer = strdup(buffer);
+ last.init(buffer);
+ }
+ ++count;
+ }
+ free(last_buffer);
+
+ pclose(fp);
+
+ static const int max_ok = 2;
+
+ // Allow few fails, happens with readers active
+ fprintf(stderr, "%s: %d/%d out of order entries\n",
+ (next_lt_last)
+ ? ((next_lt_last <= max_ok)
+ ? "WARNING"
+ : "ERROR")
+ : "INFO",
+ next_lt_last, count);
+
+ EXPECT_GE(max_ok, next_lt_last);
+
+ // sample statistically too small
+ EXPECT_LT(100, count);
+}
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 2e8ae8b..b358485 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -17,6 +17,7 @@
#include <ctype.h>
#include <signal.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <gtest/gtest.h>
@@ -41,99 +42,6 @@
static const char begin[] = "--------- beginning of ";
-TEST(logcat, sorted_order) {
- FILE *fp;
-
- ASSERT_TRUE(NULL != (fp = popen(
- "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
- "r")));
-
- class timestamp {
- private:
- int month;
- int day;
- int hour;
- int minute;
- int second;
- int millisecond;
- bool ok;
-
- public:
- void init(const char *buffer)
- {
- ok = false;
- if (buffer != NULL) {
- ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ",
- &month, &day, &hour, &minute, &second, &millisecond) == 6;
- }
- }
-
- timestamp(const char *buffer)
- {
- init(buffer);
- }
-
- bool operator< (timestamp &T)
- {
- return !ok || !T.ok
- || (month < T.month)
- || ((month == T.month)
- && ((day < T.day)
- || ((day == T.day)
- && ((hour < T.hour)
- || ((hour == T.hour)
- && ((minute < T.minute)
- || ((minute == T.minute)
- && ((second < T.second)
- || ((second == T.second)
- && (millisecond < T.millisecond))))))))));
- }
-
- bool valid(void)
- {
- return ok;
- }
- } last(NULL);
-
- char *last_buffer = NULL;
- char buffer[5120];
-
- int count = 0;
- int next_lt_last = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
- continue;
- }
- if (!last.valid()) {
- free(last_buffer);
- last_buffer = strdup(buffer);
- last.init(buffer);
- }
- timestamp next(buffer);
- if (next < last) {
- if (last_buffer) {
- fprintf(stderr, "<%s", last_buffer);
- }
- fprintf(stderr, ">%s", buffer);
- ++next_lt_last;
- }
- if (next.valid()) {
- free(last_buffer);
- last_buffer = strdup(buffer);
- last.init(buffer);
- }
- ++count;
- }
- free(last_buffer);
-
- pclose(fp);
-
- EXPECT_EQ(0, next_lt_last);
-
- EXPECT_LT(100, count);
-}
-
TEST(logcat, buckets) {
FILE *fp;
@@ -335,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];
@@ -362,11 +270,12 @@
ASSERT_EQ(1, count);
}
-TEST(logcat, get_) {
+TEST(logcat, get_size) {
FILE *fp;
+ // 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];
@@ -375,13 +284,53 @@
while (fgets(buffer, sizeof(buffer), fp)) {
int size, consumed, max, payload;
+ char size_mult[2], consumed_mult[2];
+ long full_size, full_consumed;
size = consumed = max = payload = 0;
- if ((4 == sscanf(buffer, "%*s ring buffer is %dKb (%dKb consumed),"
- " max entry is %db, max payload is %db",
- &size, &consumed, &max, &payload))
- && ((size * 3) >= consumed)
- && ((size * 1024) > max)
+ // NB: crash log can be very small, not hit a Kb of consumed space
+ // doubly lucky we are not including it.
+ if (6 != sscanf(buffer, "%*s ring buffer is %d%2s (%d%2s consumed),"
+ " max entry is %db, max payload is %db",
+ &size, size_mult, &consumed, consumed_mult,
+ &max, &payload)) {
+ fprintf(stderr, "WARNING: Parse error: %s", buffer);
+ continue;
+ }
+ full_size = size;
+ switch(size_mult[0]) {
+ case 'G':
+ full_size *= 1024;
+ /* FALLTHRU */
+ case 'M':
+ full_size *= 1024;
+ /* FALLTHRU */
+ case 'K':
+ full_size *= 1024;
+ /* FALLTHRU */
+ case 'b':
+ break;
+ }
+ full_consumed = consumed;
+ switch(consumed_mult[0]) {
+ case 'G':
+ full_consumed *= 1024;
+ /* FALLTHRU */
+ case 'M':
+ full_consumed *= 1024;
+ /* FALLTHRU */
+ case 'K':
+ full_consumed *= 1024;
+ /* FALLTHRU */
+ case 'b':
+ break;
+ }
+ EXPECT_GT((full_size * 9) / 4, full_consumed);
+ EXPECT_GT(full_size, max);
+ EXPECT_GT(max, payload);
+
+ if ((((full_size * 9) / 4) >= full_consumed)
+ && (full_size > max)
&& (max > payload)) {
++count;
}
@@ -415,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];
@@ -484,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];
@@ -532,6 +481,102 @@
EXPECT_EQ(1, signals);
}
+TEST(logcat, logrotate) {
+ static const char form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
+ char buf[sizeof(form)];
+ ASSERT_TRUE(NULL != mkdtemp(strcpy(buf, form)));
+
+ static const char comm[] = "logcat -b radio -b events -b system -b main"
+ " -d -f %s/log.txt -n 7 -r 1";
+ char command[sizeof(buf) + sizeof(comm)];
+ sprintf(command, comm, buf);
+
+ int ret;
+ EXPECT_FALSE((ret = system(command)));
+ if (!ret) {
+ sprintf(command, "ls -s %s 2>/dev/null", buf);
+
+ FILE *fp;
+ EXPECT_TRUE(NULL != (fp = popen(command, "r")));
+ if (fp) {
+ char buffer[5120];
+ int count = 0;
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ static const char match_1[] = "4 log.txt";
+ static const char match_2[] = "8 log.txt";
+ static const char match_3[] = "16 log.txt";
+ static const char total[] = "total ";
+
+ 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)) {
+ ++count;
+ } else if (strncmp(buffer, total, sizeof(total) - 1)) {
+ fprintf(stderr, "WARNING: Parse error: %s", buffer);
+ }
+ }
+ pclose(fp);
+ EXPECT_TRUE(count == 7 || count == 8);
+ }
+ }
+ sprintf(command, "rm -rf %s", buf);
+ 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;
@@ -554,7 +599,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];
@@ -649,7 +694,7 @@
char buffer[5120];
- snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list);
+ snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list ? list : "");
fp = popen(buffer, "r");
if (fp == NULL) {
fprintf(stderr, "ERROR: %s\n", buffer);
@@ -662,10 +707,10 @@
++buf;
}
char *end = buf + strlen(buf);
- while (isspace(*--end) && (end >= buf)) {
+ while ((end > buf) && isspace(*--end)) {
*end = '\0';
}
- if (end < buf) {
+ if (end <= buf) {
continue;
}
fprintf(stderr, "%s\n", buf);
@@ -679,7 +724,7 @@
char *list = NULL;
char *adjust = NULL;
- ASSERT_EQ(true, get_white_black(&list));
+ get_white_black(&list);
static const char adjustment[] = "~! 300/20 300/25 2000 ~1000/5 ~1000/30";
ASSERT_EQ(true, set_white_black(adjustment));
@@ -696,8 +741,8 @@
adjust = NULL;
ASSERT_EQ(true, set_white_black(list));
- ASSERT_EQ(true, get_white_black(&adjust));
- EXPECT_STREQ(list, adjust);
+ get_white_black(&adjust);
+ EXPECT_STREQ(list ? list : "", adjust ? adjust : "");
free(adjust);
adjust = NULL;
diff --git a/logd/Android.mk b/logd/Android.mk
index 9f4c64f..188511f 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -17,7 +17,8 @@
LogStatistics.cpp \
LogWhiteBlackList.cpp \
libaudit.c \
- LogAudit.cpp
+ LogAudit.cpp \
+ event.logtags
LOCAL_SHARED_LIBRARIES := \
libsysutils \
@@ -25,7 +26,7 @@
libcutils \
libutils
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror $(shell sed -n 's/^\([0-9]*\)[ \t]*auditd[ \t].*/-DAUDITD_LOG_TAG=\1/p' $(LOCAL_PATH)/event.logtags)
include $(BUILD_EXECUTABLE)
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 9d7d152..d7088b4 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -74,9 +74,9 @@
int CommandListener::ClearCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
setname();
- if (!clientHasLogCredentials(cli)) {
- cli->sendMsg("Permission Denied");
- return 0;
+ uid_t uid = cli->getUid();
+ if (clientHasLogCredentials(cli)) {
+ uid = AID_ROOT;
}
if (argc < 2) {
@@ -90,7 +90,7 @@
return 0;
}
- mBuf.clear((log_id_t) id);
+ mBuf.clear((log_id_t) id, uid);
cli->sendMsg("success");
return 0;
}
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index add0f0e..c7c0249 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -19,24 +19,36 @@
#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 "libaudit.h"
#include "LogAudit.h"
-LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmsg)
+#define KMSG_PRIORITY(PRI) \
+ '<', \
+ '0' + (LOG_AUTH | (PRI)) / 10, \
+ '0' + (LOG_AUTH | (PRI)) % 10, \
+ '>'
+
+LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg)
: SocketListener(getLogSocket(), false)
, logbuf(buf)
, reader(reader)
- , fdDmesg(-1) {
- logDmesg();
- fdDmesg = fdDmsg;
+ , 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(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;
@@ -49,14 +61,12 @@
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;
}
-#define AUDIT_LOG_ID LOG_ID_MAIN
-#define AUDIT_LOG_PRIO ANDROID_LOG_WARN
-
int LogAudit::logPrint(const char *fmt, ...) {
if (fmt == NULL) {
return -EINVAL;
@@ -73,13 +83,24 @@
return rc;
}
- if (fdDmesg >= 0) {
- struct iovec iov[2];
+ char *cp;
+ while ((cp = strstr(str, " "))) {
+ memmove(cp, cp + 1, strlen(cp + 1) + 1);
+ }
- iov[0].iov_base = str;
- iov[0].iov_len = strlen(str);
- iov[1].iov_base = const_cast<char *>("\n");
- iov[1].iov_len = 1;
+ bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded ");
+ 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) };
+
+ iov[0].iov_base = info ? const_cast<char *>(log_info)
+ : const_cast<char *>(log_warning);
+ iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning);
+ iov[1].iov_base = str;
+ iov[1].iov_len = strlen(str);
+ iov[2].iov_base = const_cast<char *>("\n");
+ iov[2].iov_len = 1;
writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
}
@@ -91,12 +112,11 @@
static const char audit_str[] = " audit(";
char *timeptr = strstr(str, audit_str);
- char *cp;
if (timeptr
&& ((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q")))
&& (*cp == ':')) {
memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
- strcpy(timeptr + sizeof(audit_str) - 1 + 3, cp);
+ memmove(timeptr + sizeof(audit_str) - 1 + 3, cp, strlen(cp) + 1);
} else {
now.strptime("", ""); // side effect of setting CLOCK_REALTIME
}
@@ -112,82 +132,106 @@
}
tid = pid;
uid = logbuf->pidToUid(pid);
- strcpy(pidptr, cp);
+ memmove(pidptr, cp, strlen(cp) + 1);
}
- static const char comm_str[] = " comm=\"";
- char *comm = strstr(str, comm_str);
- if (comm) {
- cp = comm;
- comm += sizeof(comm_str) - 1;
- char *ecomm = strchr(comm, '"');
- if (ecomm) {
- *ecomm = '\0';
- }
- comm = strdup(comm);
- if (ecomm) {
- strcpy(cp, ecomm + 1);
- }
- } else if (pid == getpid()) {
- pid = tid;
- comm = strdup("auditd");
- } else if (!(comm = logbuf->pidToName(pid))) {
- comm = strdup("unknown");
- }
+ // log to events
- size_t l = strlen(comm) + 1;
- size_t n = l + strlen(str) + 2;
+ size_t l = strlen(str);
+ size_t n = l + sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
+
+ bool notify = false;
char *newstr = reinterpret_cast<char *>(malloc(n));
if (!newstr) {
- free(comm);
- free(str);
- return -ENOMEM;
+ rc = -ENOMEM;
+ } else {
+ cp = newstr;
+ *cp++ = AUDITD_LOG_TAG & 0xFF;
+ *cp++ = (AUDITD_LOG_TAG >> 8) & 0xFF;
+ *cp++ = (AUDITD_LOG_TAG >> 16) & 0xFF;
+ *cp++ = (AUDITD_LOG_TAG >> 24) & 0xFF;
+ *cp++ = EVENT_TYPE_STRING;
+ *cp++ = l & 0xFF;
+ *cp++ = (l >> 8) & 0xFF;
+ *cp++ = (l >> 16) & 0xFF;
+ *cp++ = (l >> 24) & 0xFF;
+ memcpy(cp, str, l);
+
+ logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid, newstr,
+ (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+ free(newstr);
+
+ notify = true;
}
- *newstr = AUDIT_LOG_PRIO;
- strcpy(newstr + 1, comm);
- free(comm);
- strcpy(newstr + 1 + l, str);
+ // log to main
+
+ static const char comm_str[] = " comm=\"";
+ const char *comm = strstr(str, comm_str);
+ const char *estr = str + strlen(str);
+ if (comm) {
+ estr = comm;
+ comm += sizeof(comm_str) - 1;
+ } else if (pid == getpid()) {
+ pid = tid;
+ comm = "auditd";
+ } else if (!(comm = logbuf->pidToName(pid))) {
+ comm = "unknown";
+ }
+
+ const char *ecomm = strchr(comm, '"');
+ if (ecomm) {
+ ++ecomm;
+ l = ecomm - comm;
+ } else {
+ l = strlen(comm) + 1;
+ ecomm = "";
+ }
+ n = (estr - str) + strlen(ecomm) + l + 2;
+
+ newstr = reinterpret_cast<char *>(malloc(n));
+ if (!newstr) {
+ rc = -ENOMEM;
+ } else {
+ *newstr = info ? ANDROID_LOG_INFO : ANDROID_LOG_WARN;
+ strlcpy(newstr + 1, comm, l);
+ 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);
+ free(newstr);
+
+ notify = true;
+ }
+
free(str);
- logbuf->log(AUDIT_LOG_ID, now, uid, pid, tid, newstr,
- (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
- reader->notifyNewLog();
-
- free(newstr);
+ if (notify) {
+ reader->notifyNewLog();
+ }
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 0;
}
- 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() {
@@ -195,7 +239,7 @@
if (fd < 0) {
return fd;
}
- if (audit_set_pid(fd, getpid(), WAIT_YES) < 0) {
+ if (audit_setup(fd, getpid()) < 0) {
audit_close(fd);
fd = -1;
}
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 ae167aa..1c74ba5 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -93,9 +93,9 @@
}
LogBuffer::LogBuffer(LastLogTimes *times)
- : mTimes(*times) {
+ : dgramQlenStatistics(false)
+ , mTimes(*times) {
pthread_mutex_init(&mLogElementsLock, NULL);
- dgram_qlen_statistics = false;
static const char global_tuneable[] = "persist.logd.size"; // Settings App
static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
@@ -147,13 +147,14 @@
// 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 (dgram_qlen_statistics) {
+ if (dgramQlenStatistics) {
LogBufferElementCollection::iterator ib = it;
unsigned short buckets, num = 1;
- for (unsigned short i = 0; (buckets = stats.dgram_qlen(i)); ++i) {
+ for (unsigned short i = 0; (buckets = stats.dgramQlen(i)); ++i) {
buckets -= num;
num += buckets;
while (buckets && (--ib != mLogElements.begin())) {
@@ -174,7 +175,7 @@
if (last == mLogElements.end()) {
mLogElements.push_back(elem);
} else {
- log_time end;
+ log_time end = log_time::EPOCH;
bool end_set = false;
bool end_always = false;
@@ -232,7 +233,7 @@
// prune "pruneRows" of type "id" from the buffer.
//
// mLogElementsLock must be held when this function is called.
-void LogBuffer::prune(log_id_t id, unsigned long pruneRows) {
+void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
LogTimeEntry *oldest = NULL;
LogTimeEntry::lock();
@@ -250,6 +251,37 @@
LogBufferElementCollection::iterator it;
+ if (caller_uid != AID_ROOT) {
+ for(it = mLogElements.begin(); it != mLogElements.end();) {
+ LogBufferElement *e = *it;
+
+ if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+ break;
+ }
+
+ if (e->getLogId() != id) {
+ ++it;
+ continue;
+ }
+
+ uid_t uid = e->getUid();
+
+ if (uid == caller_uid) {
+ it = mLogElements.erase(it);
+ stats.subtract(e->getMsgLen(), id, uid, e->getPid());
+ delete e;
+ pruneRows--;
+ if (pruneRows == 0) {
+ break;
+ }
+ } else {
+ ++it;
+ }
+ }
+ LogTimeEntry::unlock();
+ return;
+ }
+
// prune by worst offender by uid
while (pruneRows > 0) {
// recalculate the worst offender on every batched pass
@@ -286,23 +318,19 @@
uid_t uid = e->getUid();
- if (uid == worst) {
+ if ((uid == worst) || mPrune.naughty(e)) { // Worst or BlackListed
it = mLogElements.erase(it);
unsigned short len = e->getMsgLen();
- stats.subtract(len, id, worst, e->getPid());
- delete e;
- kick = true;
- pruneRows--;
- if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) {
- break;
- }
- worst_sizes -= len;
- } else if (mPrune.naughty(e)) { // BlackListed
- it = mLogElements.erase(it);
- stats.subtract(e->getMsgLen(), id, uid, e->getPid());
+ stats.subtract(len, id, uid, e->getPid());
delete e;
pruneRows--;
- if (pruneRows == 0) {
+ if (uid == worst) {
+ kick = true;
+ if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) {
+ break;
+ }
+ worst_sizes -= len;
+ } else if (pruneRows == 0) {
break;
}
} else {
@@ -375,9 +403,9 @@
}
// clear all rows of type "id" from the buffer.
-void LogBuffer::clear(log_id_t id) {
+void LogBuffer::clear(log_id_t id, uid_t uid) {
pthread_mutex_lock(&mLogElementsLock);
- prune(id, ULONG_MAX);
+ prune(id, ULONG_MAX, uid);
pthread_mutex_unlock(&mLogElementsLock);
}
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index b8a54b9..879baea 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -23,6 +23,8 @@
#include <sysutils/SocketClient.h>
#include <utils/List.h>
+#include <private/android_filesystem_config.h>
+
#include "LogBufferElement.h"
#include "LogTimes.h"
#include "LogStatistics.h"
@@ -35,8 +37,7 @@
pthread_mutex_t mLogElementsLock;
LogStatistics stats;
-
- bool dgram_qlen_statistics;
+ bool dgramQlenStatistics;
PruneList mPrune;
@@ -55,7 +56,7 @@
bool (*filter)(const LogBufferElement *element, void *arg) = NULL,
void *arg = NULL);
- void clear(log_id_t id);
+ void clear(log_id_t id, uid_t uid = AID_ROOT);
unsigned long getSize(log_id_t id);
int setSize(log_id_t id, unsigned long size);
unsigned long getSizeUsed(log_id_t id);
@@ -64,7 +65,11 @@
void enableDgramQlenStatistics() {
stats.enableDgramQlenStatistics();
- dgram_qlen_statistics = true;
+ dgramQlenStatistics = true;
+ }
+
+ void enableStatistics() {
+ stats.enableStatistics();
}
int initPrune(char *cp) { return mPrune.init(cp); }
@@ -77,7 +82,7 @@
private:
void maybePrune(log_id_t id);
- void prune(log_id_t id, unsigned long pruneRows);
+ void prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
};
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 8458c19..26df087 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -92,6 +92,11 @@
bool nonBlock = false;
if (strncmp(buffer, "dumpAndClose", 12) == 0) {
+ // Allow writer to get some cycles, and wait for pending notifications
+ sched_yield();
+ LogTimeEntry::lock();
+ LogTimeEntry::unlock();
+ sched_yield();
nonBlock = true;
}
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 81c9bab..6f3a088 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -51,11 +51,11 @@
}
bool PidStatistics::pidGone() {
- if (mGone) {
+ if (mGone || (pid == gone)) {
return true;
}
- if (pid == gone) {
- return true;
+ if (pid == 0) {
+ return false;
}
if (kill(pid, 0) && (errno != EPERM)) {
mGone = true;
@@ -90,9 +90,14 @@
}
// 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) {
char *retval = NULL;
- if (pid != gone) {
+ if (pid == 0) { // special case from auditd for kernel
+ retval = strdup("logd.auditd");
+ } else if (pid != gone) {
char buffer[512];
snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
int fd = open(buffer, O_RDONLY);
@@ -122,7 +127,7 @@
PidStatisticsCollection::iterator it;
for (it = begin(); it != end();) {
delete (*it);
- it = Pids.erase(it);
+ it = erase(it);
}
}
@@ -130,7 +135,7 @@
mSizes += size;
++mElements;
- PidStatistics *p;
+ PidStatistics *p = NULL;
PidStatisticsCollection::iterator last;
PidStatisticsCollection::iterator it;
for (last = it = begin(); it != end(); last = it, ++it) {
@@ -141,12 +146,12 @@
}
}
// insert if the gone entry.
- bool insert = (last != it) && (p->getPid() == p->gone);
+ bool insert_before_last = (last != it) && p && (p->getPid() == p->gone);
p = new PidStatistics(pid, pidToName(pid));
- if (insert) {
- Pids.insert(last, p);
+ if (insert_before_last) {
+ insert(last, p);
} else {
- Pids.push_back(p);
+ push_back(p);
}
p->add(size);
}
@@ -163,17 +168,17 @@
size_t szsTotal = p->sizesTotal();
size_t elsTotal = p->elementsTotal();
delete p;
- Pids.erase(it);
+ erase(it);
it = end();
--it;
if (it == end()) {
p = new PidStatistics(p->gone);
- Pids.push_back(p);
+ push_back(p);
} else {
p = *it;
if (p->getPid() != p->gone) {
p = new PidStatistics(p->gone);
- Pids.push_back(p);
+ push_back(p);
}
}
p->addTotal(szsTotal, elsTotal);
@@ -194,8 +199,8 @@
PidStatistics *n = (*it);
if ((n->getPid() != n->gone) && (n->sizes() > l->sizes())) {
pass = true;
- Pids.erase(it);
- Pids.insert(lt, n);
+ erase(it);
+ insert(lt, n);
it = lt;
n = l;
}
@@ -302,6 +307,10 @@
}
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;
@@ -384,24 +393,25 @@
}
LogStatistics::LogStatistics()
- : start(CLOCK_MONOTONIC) {
+ : mStatistics(false)
+ , dgramQlenStatistics(false)
+ , start(CLOCK_MONOTONIC) {
log_id_for_each(i) {
mSizes[i] = 0;
mElements[i] = 0;
}
- dgram_qlen_statistics = false;
- for(unsigned short bucket = 0; dgram_qlen(bucket); ++bucket) {
+ 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 dgram_qlen of log messages. By
+// Each bucket below represents a dgramQlen of log messages. By
// finding the minimum period of time from start to finish
-// of each dgram_qlen, we can get a performance expectation for
+// 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 dgram_qlen will give us the average time
+// 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
@@ -412,7 +422,7 @@
//
// for example (reformatted):
//
-// Minimum time between log events per dgram_qlen:
+// 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
//
@@ -426,12 +436,12 @@
// a large engineering margin so the rule of thumb that lead us to 100 is
// fine.
//
-// bucket dgram_qlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300
+// 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::dgram_qlen(unsigned short bucket) {
+unsigned short LogStatistics::dgramQlen(unsigned short bucket) {
if (bucket >= sizeof(mBuckets) / sizeof(mBuckets[0])) {
return 0;
}
@@ -455,6 +465,9 @@
log_id_t log_id, uid_t uid, pid_t pid) {
mSizes[log_id] += size;
++mElements[log_id];
+ if (!mStatistics) {
+ return;
+ }
id(log_id).add(size, uid, pid);
}
@@ -462,6 +475,9 @@
log_id_t log_id, uid_t uid, pid_t pid) {
mSizes[log_id] -= size;
--mElements[log_id];
+ if (!mStatistics) {
+ return;
+ }
id(log_id).subtract(size, uid, pid);
}
@@ -524,7 +540,7 @@
short spaces = 2;
log_id_for_each(i) {
- if (!logMask & (1 << i)) {
+ if (!(logMask & (1 << i))) {
continue;
}
oldLength = string.length();
@@ -545,25 +561,28 @@
spaces = 1;
log_time t(CLOCK_MONOTONIC);
- unsigned long long d = t.nsec() - start.nsec();
- string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu",
+ unsigned long long d;
+ if (mStatistics) {
+ d = t.nsec() - start.nsec();
+ string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu",
d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
(d / NS_PER_SEC) % 60, d % NS_PER_SEC);
- log_id_for_each(i) {
- if (!(logMask & (1 << i))) {
- continue;
+ log_id_for_each(i) {
+ if (!(logMask & (1 << i))) {
+ continue;
+ }
+ oldLength = string.length();
+ if (spaces < 0) {
+ spaces = 0;
+ }
+ string.appendFormat("%*s%zu/%zu", spaces, "",
+ sizesTotal(i), elementsTotal(i));
+ spaces += spaces_total + oldLength - string.length();
}
- oldLength = string.length();
- if (spaces < 0) {
- spaces = 0;
- }
- string.appendFormat("%*s%zu/%zu", spaces, "",
- sizesTotal(i), elementsTotal(i));
- spaces += spaces_total + oldLength - string.length();
+ spaces = 1;
}
- spaces = 1;
d = t.nsec() - oldest.nsec();
string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu",
d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
@@ -671,8 +690,11 @@
size_t sizesTotal = p->sizesTotal();
android::String8 sz("");
- sz.appendFormat((sizes != sizesTotal) ? "%zu/%zu" : "%zu",
- sizes, sizesTotal);
+ if (sizes == sizesTotal) {
+ sz.appendFormat("%zu", sizes);
+ } else {
+ sz.appendFormat("%zu/%zu", sizes, sizesTotal);
+ }
android::String8 pd("");
pd.appendFormat("%u%c", pid, p->pidGone() ? '?' : ' ');
@@ -686,23 +708,23 @@
pids.clear();
}
- if (dgram_qlen_statistics) {
+ 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 dgram_qlen:\n");
- for(unsigned short i = 0; dgram_qlen(i); ++i) {
+ 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, "", dgram_qlen(i));
+ 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 = dgram_qlen(i)); ++i) {
+ for(unsigned short i = 0; (n = dgramQlen(i)); ++i) {
unsigned long long duration = minimum(i);
if (duration) {
duration /= n;
@@ -724,8 +746,8 @@
/ (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));
+ (duration + (NS_PER_SEC / 2 / 1000000))
+ / (NS_PER_SEC / 1000000));
} else {
string.appendFormat("%llun", duration);
}
@@ -783,12 +805,15 @@
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');
+ if (!oneline) {
+ intermediate = string.format("%d", u);
+ } else if (p == PidStatistics::gone) {
+ intermediate = string.format("%d/?", u);
+ } else if (pp->pidGone()) {
+ intermediate = string.format("%d/%d?", u, p);
+ } else {
+ intermediate = string.format("%d/%d", u, p);
+ }
string.appendFormat(first ? "\n%-12s" : "%-12s",
intermediate.string());
intermediate.clear();
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 3733137..f6c4329 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -72,6 +72,10 @@
PidStatisticsCollection Pids;
+ void insert(PidStatisticsCollection::iterator i, PidStatistics *p)
+ { Pids.insert(i, p); }
+ void push_back(PidStatistics *p) { Pids.push_back(p); }
+
size_t mSizes;
size_t mElements;
@@ -81,6 +85,8 @@
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; }
@@ -138,7 +144,8 @@
size_t mSizes[LOG_ID_MAX];
size_t mElements[LOG_ID_MAX];
- bool dgram_qlen_statistics;
+ bool mStatistics;
+ bool dgramQlenStatistics;
static const unsigned short mBuckets[14];
log_time mMinimum[sizeof(mBuckets) / sizeof(mBuckets[0])];
@@ -150,8 +157,9 @@
LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; }
- void enableDgramQlenStatistics() { dgram_qlen_statistics = true; }
- static unsigned short dgram_qlen(unsigned short bucket);
+ 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);
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 1a9a548..ea4e8c8 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -33,7 +33,6 @@
, mRelease(false)
, mError(false)
, threadRunning(false)
- , threadTriggered(true)
, mReader(reader)
, mLogMask(logMask)
, mPid(pid)
@@ -45,7 +44,9 @@
, mStart(start)
, mNonBlock(nonBlock)
, mEnd(CLOCK_MONOTONIC)
-{ }
+{
+ pthread_cond_init(&threadTriggeredCondition, NULL);
+}
void LogTimeEntry::startReader_Locked(void) {
pthread_attr_t attr;
@@ -74,7 +75,6 @@
lock();
- me->threadRunning = false;
if (me->mNonBlock) {
me->error_Locked();
}
@@ -103,6 +103,7 @@
client->decRef();
}
+ me->threadRunning = false;
me->decRef_Locked();
unlock();
@@ -118,7 +119,7 @@
SocketClient *client = me->mClient;
if (!client) {
me->error();
- pthread_exit(NULL);
+ return NULL;
}
LogBuffer &logbuf = me->mReader.logbuf();
@@ -127,12 +128,7 @@
lock();
- me->threadTriggered = true;
-
- while(me->threadTriggered && !me->isError_Locked()) {
-
- me->threadTriggered = false;
-
+ while (me->threadRunning && !me->isError_Locked()) {
log_time start = me->mStart;
unlock();
@@ -142,24 +138,21 @@
}
start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me);
+ lock();
+
if (start == LogBufferElement::FLUSH_ERROR) {
- me->error();
+ me->error_Locked();
}
- if (me->mNonBlock) {
- lock();
+ if (me->mNonBlock || !me->threadRunning || me->isError_Locked()) {
break;
}
- sched_yield();
-
- lock();
+ pthread_cond_wait(&me->threadTriggeredCondition, ×Lock);
}
unlock();
- pthread_exit(NULL);
-
pthread_cleanup_pop(true);
return NULL;
@@ -193,6 +186,7 @@
if (me->skipAhead) {
me->skipAhead--;
+ goto skip;
}
me->mStart = element->getMonotonicTime();
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index beaf646..0bfa7a2 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -31,7 +31,7 @@
bool mRelease;
bool mError;
bool threadRunning;
- bool threadTriggered;
+ pthread_cond_t threadTriggeredCondition;
pthread_t mThread;
LogReader &mReader;
static void *threadStart(void *me);
@@ -63,12 +63,16 @@
bool runningReader_Locked(void) const {
return threadRunning || mRelease || mError || mNonBlock;
}
- void triggerReader_Locked(void) { threadTriggered = true; }
+ void triggerReader_Locked(void) {
+ pthread_cond_signal(&threadTriggeredCondition);
+ }
+
void triggerSkip_Locked(unsigned int skip) { skipAhead = skip; }
// Called after LogTimeEntry removed from list, lock implicitly held
void release_Locked(void) {
mRelease = true;
+ pthread_cond_signal(&threadTriggeredCondition);
if (mRefCount || threadRunning) {
return;
}
@@ -78,7 +82,7 @@
// Called to mark socket in jeopardy
void error_Locked(void) { mError = true; }
- void error(void) { lock(); mError = true; unlock(); }
+ void error(void) { lock(); error_Locked(); unlock(); }
bool isError_Locked(void) const { return mRelease || mError; }
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index e87b604..9728db1 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -39,10 +39,15 @@
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, "/");
}
}
diff --git a/logd/README.property b/logd/README.property
index f4b3c3c..b7fcece 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -4,6 +4,9 @@
logd.auditd bool true Enable selinux audit daemon
logd.auditd.dmesg bool true selinux audit messages duplicated and
sent on to dmesg log
+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
diff --git a/logd/event.logtags b/logd/event.logtags
new file mode 100644
index 0000000..a63f034
--- /dev/null
+++ b/logd/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.
+
+1003 auditd (avc|3)
diff --git a/logd/libaudit.c b/logd/libaudit.c
index ca88d1b..d00d579 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.c
@@ -162,7 +162,7 @@
return rc;
}
-int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode)
+int audit_setup(int fd, uint32_t pid)
{
int rc;
struct audit_message rep;
@@ -176,7 +176,8 @@
* and the the mask set to AUDIT_STATUS_PID
*/
status.pid = pid;
- status.mask = AUDIT_STATUS_PID;
+ status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT;
+ status.rate_limit = 20; // 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));
@@ -188,24 +189,21 @@
/*
* In a request where we need to wait for a response, wait for the message
* and discard it. This message confirms and sync's us with the kernel.
- * This daemon is now registered as the audit logger. Only wait if the
- * wmode is != WAIT_NO
+ * This daemon is now registered as the audit logger.
+ *
+ * TODO
+ * If the daemon dies and restarts the message didn't come back,
+ * so I went to non-blocking and it seemed to fix the bug.
+ * Need to investigate further.
*/
- if (wmode != WAIT_NO) {
- /* TODO
- * If the daemon dies and restarts the message didn't come back,
- * so I went to non-blocking and it seemed to fix the bug.
- * Need to investigate further.
- */
- audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
- }
+ audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
return 0;
}
int audit_open()
{
- return socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
+ return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
}
int audit_get_reply(int fd, struct audit_message *rep, reply_t block, int peek)
diff --git a/logd/libaudit.h b/logd/libaudit.h
index cb114f9..b9e330d 100644
--- a/logd/libaudit.h
+++ b/logd/libaudit.h
@@ -37,11 +37,6 @@
GET_REPLY_NONBLOCKING
} reply_t;
-typedef enum {
- WAIT_NO,
- WAIT_YES
-} rep_wait_t;
-
/* type == AUDIT_SIGNAL_INFO */
struct audit_sig_info {
uid_t uid;
@@ -92,12 +87,10 @@
* The fd returned by a call to audit_open()
* @param pid
* The pid whom to set as the reciever of audit messages
- * @param wmode
- * Whether or not to block on the underlying socket io calls.
* @return
* This function returns 0 on success, -errno on error.
*/
-extern int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode);
+extern int audit_setup(int fd, uint32_t pid);
__END_DECLS
diff --git a/logd/main.cpp b/logd/main.cpp
index ece5a3a..946a9a0 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -22,12 +22,12 @@
#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 <unistd.h>
-#include <linux/prctl.h>
-
#include <cutils/properties.h>
#include "private/android_filesystem_config.h"
@@ -153,6 +153,15 @@
if (property_get_bool("logd.statistics.dgram_qlen", false)) {
logBuf->enableDgramQlenStatistics();
}
+ {
+ char property[PROPERTY_VALUE_MAX];
+ property_get("ro.build.type", property, "");
+ if (property_get_bool("logd.statistics",
+ !!strcmp(property, "user")
+ && !property_get_bool("ro.config.low_ram", false))) {
+ logBuf->enableStatistics();
+ }
+ }
// LogReader listens on /dev/socket/logdr. When a client
// connects, log entries in the LogBuffer are written to the client.
@@ -187,6 +196,23 @@
if (auditd) {
// failure is an option ... messages are in dmesg (required by standard)
LogAudit *al = new LogAudit(logBuf, reader, fdDmesg);
+
+ int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
+ if (len > 0) {
+ len++;
+ char buf[len];
+
+ int rc = klogctl(KLOG_READ_ALL, buf, len);
+
+ buf[len - 1] = '\0';
+
+ for(char *ptr, *tok = buf;
+ (rc >= 0) && ((tok = strtok_r(tok, "\r\n", &ptr)));
+ tok = NULL) {
+ rc = al->log(tok);
+ }
+ }
+
if (al->startListener()) {
delete al;
close(fdDmesg);
diff --git a/logd/tests/Android.mk b/logd/tests/Android.mk
index 123e317..f851288 100644
--- a/logd/tests/Android.mk
+++ b/logd/tests/Android.mk
@@ -34,7 +34,7 @@
-Werror \
-fno-builtin \
-ifeq ($(TARGET_USES_LOGD),true)
+ifneq ($(TARGET_USES_LOGD),false)
test_c_flags += -DTARGET_USES_LOGD=1
endif
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 5b51b1f..96877a9 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -417,7 +417,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;
}
@@ -503,13 +507,11 @@
(user_logger_content) ? yes : no,
(kernel_logger_available) ? yes : no,
(kernel_logger_content) ? yes : no,
- (user_logger_available && kernel_logger_available) ? "WARNING" : "ok",
+ (user_logger_available && kernel_logger_available) ? "ERROR" : "ok",
(user_logger_content && kernel_logger_content) ? "ERROR" : "ok");
- if (user_logger_available && kernel_logger_available) {
- printf("WARNING: kernel & user logger; both consuming resources!!!\n");
- }
-
+ EXPECT_EQ(0, user_logger_available && kernel_logger_available);
+ EXPECT_EQ(0, !user_logger_available && !kernel_logger_available);
EXPECT_EQ(0, user_logger_content && kernel_logger_content);
EXPECT_EQ(0, !user_logger_content && !kernel_logger_content);
}
@@ -568,10 +570,11 @@
while (fgets(buffer, sizeof(buffer), fp)) {
for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) {
- if (strncmp(benchmarks[i], buffer, strlen(benchmarks[i]))) {
+ char *cp = strstr(buffer, benchmarks[i]);
+ if (!cp) {
continue;
}
- sscanf(buffer, "%*s %lu %lu", &ns[i], &ns[i]);
+ sscanf(cp, "%*s %lu %lu", &ns[i], &ns[i]);
fprintf(stderr, "%-22s%8lu\n", benchmarks[i], ns[i]);
}
}
@@ -592,15 +595,15 @@
#endif
#ifdef TARGET_USES_LOGD
- EXPECT_GE(25000UL, ns[log_maximum]); // 14055 user
+ EXPECT_GE(30000UL, ns[log_maximum]); // 27305 user
#else
EXPECT_GE(10000UL, ns[log_maximum]); // 5637 kernel
#endif
- EXPECT_GE(4000UL, ns[clock_overhead]); // 2008
+ EXPECT_GE(4096UL, ns[clock_overhead]); // 4095
#ifdef TARGET_USES_LOGD
- EXPECT_GE(250000UL, ns[log_overhead]); // 113219 user
+ EXPECT_GE(250000UL, ns[log_overhead]); // 121876 user
#else
EXPECT_GE(100000UL, ns[log_overhead]); // 50945 kernel
#endif
@@ -612,7 +615,7 @@
#endif
#ifdef TARGET_USES_LOGD
- EXPECT_GE(20000000UL, ns[log_delay]); // 9542541 user
+ EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
#else
EXPECT_GE(55000UL, ns[log_delay]); // 27341 kernel
#endif
@@ -642,36 +645,61 @@
// 0/4225? 7454388/303656 31488/755
// ^-- benchmark_statistics_found
- unsigned long nowSize = atol(benchmark_statistics_found);
+ unsigned long nowSpamSize = atol(benchmark_statistics_found);
delete [] buf;
- ASSERT_NE(0UL, nowSize);
+ ASSERT_NE(0UL, nowSpamSize);
+ // Determine if we have the spam filter enabled
int sock = socket_local_client("logd",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM);
+
+ ASSERT_TRUE(sock >= 0);
+
+ static const char getPruneList[] = "getPruneList";
+ if (write(sock, getPruneList, sizeof(getPruneList)) > 0) {
+ char buffer[80];
+ memset(buffer, 0, sizeof(buffer));
+ read(sock, buffer, sizeof(buffer));
+ char *cp = strchr(buffer, '\n');
+ if (!cp || (cp[1] != '~') || (cp[2] != '!')) {
+ close(sock);
+ fprintf(stderr,
+ "WARNING: "
+ "Logger has SPAM filtration turned off \"%s\"\n", buffer);
+ return;
+ }
+ } else {
+ int save_errno = errno;
+ close(sock);
+ FAIL() << "Can not send " << getPruneList << " to logger -- " << strerror(save_errno);
+ }
+
static const unsigned long expected_absolute_minimum_log_size = 65536UL;
unsigned long totalSize = expected_absolute_minimum_log_size;
- if (sock >= 0) {
- static const char getSize[] = {
- 'g', 'e', 't', 'L', 'o', 'g', 'S', 'i', 'z', 'e', ' ',
- LOG_ID_MAIN + '0', '\0'
- };
- if (write(sock, getSize, sizeof(getSize)) > 0) {
- char buffer[80];
- memset(buffer, 0, sizeof(buffer));
- read(sock, buffer, sizeof(buffer));
- totalSize = atol(buffer);
- if (totalSize < expected_absolute_minimum_log_size) {
- totalSize = expected_absolute_minimum_log_size;
- }
+ static const char getSize[] = {
+ 'g', 'e', 't', 'L', 'o', 'g', 'S', 'i', 'z', 'e', ' ',
+ LOG_ID_MAIN + '0', '\0'
+ };
+ if (write(sock, getSize, sizeof(getSize)) > 0) {
+ char buffer[80];
+ memset(buffer, 0, sizeof(buffer));
+ read(sock, buffer, sizeof(buffer));
+ totalSize = atol(buffer);
+ if (totalSize < expected_absolute_minimum_log_size) {
+ fprintf(stderr,
+ "WARNING: "
+ "Logger had unexpected referenced size \"%s\"\n", buffer);
+ totalSize = expected_absolute_minimum_log_size;
}
- close(sock);
}
+ close(sock);
+
// logd allows excursions to 110% of total size
totalSize = (totalSize * 11 ) / 10;
// 50% threshold for SPAM filter (<20% typical, lots of engineering margin)
- ASSERT_GT(totalSize, nowSize * 2);
+ ASSERT_GT(totalSize, nowSpamSize * 2);
}
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index d47c9b5..3a6276e 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -477,7 +477,6 @@
pid_t pid;
int parent_ptty;
int child_ptty;
- char *child_devname = NULL;
struct sigaction intact;
struct sigaction quitact;
sigset_t blockset;
@@ -498,8 +497,9 @@
goto err_open;
}
+ char child_devname[64];
if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
- ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
+ ptsname_r(parent_ptty, child_devname, sizeof(child_devname)) != 0) {
ERROR("Problem with /dev/ptmx\n");
rc = -1;
goto err_ptty;
diff --git a/netcfg/netcfg.c b/netcfg/netcfg.c
index 2308f37..4e83ba4 100644
--- a/netcfg/netcfg.c
+++ b/netcfg/netcfg.c
@@ -102,7 +102,6 @@
{ "dhcp", 1, do_dhcp },
{ "up", 1, ifc_up },
{ "down", 1, ifc_down },
- { "flhosts", 1, ifc_remove_host_routes },
{ "deldefault", 1, ifc_remove_default_route },
{ "hwaddr", 2, set_hwaddr },
{ 0, 0, 0 },
diff --git a/reboot/Android.mk b/reboot/Android.mk
index 4db0c1e..7a24f99 100644
--- a/reboot/Android.mk
+++ b/reboot/Android.mk
@@ -1,12 +1,14 @@
# Copyright 2013 The Android Open Source Project
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= reboot.c
+LOCAL_SRC_FILES := reboot.c
-LOCAL_SHARED_LIBRARIES:= libcutils
+LOCAL_SHARED_LIBRARIES := libcutils
-LOCAL_MODULE:= reboot
+LOCAL_MODULE := reboot
+
+LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 2c16084..3ecb1db 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -30,9 +30,18 @@
include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in
+# Regenerate init.environ.rc if PRODUCT_BOOTCLASSPATH has changed.
+bcp_md5 := $(word 1, $(shell echo $(PRODUCT_BOOTCLASSPATH) $(PRODUCT_SYSTEM_SERVER_CLASSPATH) | $(MD5SUM)))
+bcp_dep := $(intermediates)/$(bcp_md5).bcp.dep
+$(bcp_dep) :
+ $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.bcp.dep && touch $@
+
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in $(bcp_dep)
@echo "Generate: $< -> $@"
@mkdir -p $(dir $@)
$(hide) sed -e 's?%BOOTCLASSPATH%?$(PRODUCT_BOOTCLASSPATH)?g' $< >$@
+ $(hide) sed -i -e 's?%SYSTEMSERVERCLASSPATH%?$(PRODUCT_SYSTEM_SERVER_CLASSPATH)?g' $@
+bcp_md5 :=
+bcp_dep :=
#######################################
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/init.environ.rc.in b/rootdir/init.environ.rc.in
index 927c33d..30bef46 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -9,3 +9,4 @@
export ASEC_MOUNTPOINT /mnt/asec
export LOOP_MOUNTPOINT /mnt/obb
export BOOTCLASSPATH %BOOTCLASSPATH%
+ export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH%
diff --git a/rootdir/init.rc b/rootdir/init.rc
index ed756e0..9093b54 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -12,7 +12,7 @@
on early-init
# Set init and its forked children's oom_adj.
- write /proc/1/oom_adj -16
+ write /proc/1/oom_score_adj -1000
# Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
write /sys/fs/selinux/checkreqprot 0
@@ -26,29 +26,28 @@
start ueventd
-# create mountpoints
+ # create mountpoints
mkdir /mnt 0775 root system
on init
+ sysclktz 0
-sysclktz 0
+ loglevel 3
-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.
+ # Right now vendor lives on the same filesystem as system,
+ # but someday that may change.
symlink /system/vendor /vendor
-# Create cgroup mount point for cpu accounting
+ # Create cgroup mount point for cpu accounting
mkdir /acct
mount cgroup none /acct cpuacct
mkdir /acct/uid
-# Create cgroup mount point for memory
+ # Create cgroup mount point for memory
mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000
mkdir /sys/fs/cgroup/memory 0750 root system
mount cgroup none /sys/fs/cgroup/memory memory
@@ -89,6 +88,10 @@
mkdir /mnt/obb 0700 root system
mount tmpfs tmpfs /mnt/obb mode=0755,gid=1000
+ # memory control cgroup
+ mkdir /dev/memcg 0700 root system
+ mount cgroup none /dev/memcg memory
+
write /proc/sys/kernel/panic_on_oops 1
write /proc/sys/kernel/hung_task_timeout_secs 0
write /proc/cpu/alignment 4
@@ -98,7 +101,6 @@
write /proc/sys/kernel/sched_child_runs_first 0
write /proc/sys/kernel/randomize_va_space 2
write /proc/sys/kernel/kptr_restrict 2
- write /proc/sys/kernel/dmesg_restrict 1
write /proc/sys/vm/mmap_min_addr 32768
write /proc/sys/net/ipv4/ping_group_range "0 2147483647"
write /proc/sys/net/unix/max_dgram_qlen 300
@@ -112,7 +114,7 @@
# set fwmark on accepted sockets
write /proc/sys/net/ipv4/tcp_fwmark_accept 1
-# Create cgroup mount points for process groups
+ # Create cgroup mount points for process groups
mkdir /dev/cpuctl
mount cgroup none /dev/cpuctl cpu
chown system system /dev/cpuctl
@@ -137,20 +139,58 @@
write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_runtime_us 700000
write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_period_us 1000000
-# qtaguid will limit access to specific data based on group memberships.
-# net_bw_acct grants impersonation of socket owners.
-# net_bw_stats grants access to other apps' detailed tagged-socket stats.
+ # qtaguid will limit access to specific data based on group memberships.
+ # net_bw_acct grants impersonation of socket owners.
+ # net_bw_stats grants access to other apps' detailed tagged-socket stats.
chown root net_bw_acct /proc/net/xt_qtaguid/ctrl
chown root net_bw_stats /proc/net/xt_qtaguid/stats
-# Allow everybody to read the xt_qtaguid resource tracking misc dev.
-# This is needed by any process that uses socket tagging.
+ # Allow everybody to read the xt_qtaguid resource tracking misc dev.
+ # This is needed by any process that uses socket tagging.
chmod 0644 /dev/xt_qtaguid
-# Create location for fs_mgr to store abbreviated output from filesystem
-# checker programs.
+ # Create location for fs_mgr to store abbreviated output from filesystem
+ # checker programs.
mkdir /dev/fscklogs 0770 root system
+ # pstore/ramoops previous console log
+ mount pstore pstore /sys/fs/pstore
+ chown system log /sys/fs/pstore/console-ramoops
+ chmod 0440 /sys/fs/pstore/console-ramoops
+
+# Healthd can trigger a full boot from charger mode by signaling this
+# property when the power button is held.
+on property:sys.boot_from_charger_mode=1
+ class_stop charger
+ trigger late-init
+
+# Load properties from /system/ + /factory after fs mount.
+on load_all_props_action
+ load_all_props
+
+# Indicate to fw loaders that the relevant mounts are up.
+on firmware_mounts_complete
+ rm /dev/.booting
+
+# Mount filesystems and start core system services.
+on late-init
+ trigger early-fs
+ trigger fs
+ trigger post-fs
+ trigger post-fs-data
+
+ # Load properties from /system/ + /factory after fs mount. Place
+ # this in another action so that the load will be scheduled after the prior
+ # issued fs triggers have completed.
+ trigger load_all_props_action
+
+ # Remove a file to wake up anything waiting for firmware.
+ trigger firmware_mounts_complete
+
+ trigger early-boot
+ trigger boot
+
+
on post-fs
# once everything is setup, no need to modify /
mount rootfs rootfs / ro remount
@@ -161,13 +201,11 @@
chown system cache /cache
chmod 0770 /cache
# We restorecon /cache in case the cache partition has been reset.
- restorecon /cache
+ restorecon_recursive /cache
# This may have been created by the recovery system with odd permissions
chown system cache /cache/recovery
chmod 0770 /cache/recovery
- # This may have been created by the recovery system with the wrong context.
- restorecon /cache/recovery
#change permissions on vmallocinfo so we can grab it from bugreports
chown root log /proc/vmallocinfo
@@ -223,15 +261,19 @@
mkdir /data/misc/bluetooth 0770 system system
mkdir /data/misc/keystore 0700 keystore keystore
mkdir /data/misc/keychain 0771 system system
+ mkdir /data/misc/net 0750 root shell
mkdir /data/misc/radio 0770 system radio
mkdir /data/misc/sms 0770 system radio
mkdir /data/misc/zoneinfo 0775 system system
mkdir /data/misc/vpn 0770 system vpn
+ mkdir /data/misc/shared_relro 0771 shared_relro shared_relro
mkdir /data/misc/systemkeys 0700 system system
mkdir /data/misc/wifi 0770 wifi wifi
mkdir /data/misc/wifi/sockets 0770 wifi wifi
mkdir /data/misc/wifi/wpa_supplicant 0770 wifi wifi
+ mkdir /data/misc/ethernet 0770 system system
mkdir /data/misc/dhcp 0770 dhcp dhcp
+ mkdir /data/misc/user 0771 root root
# give system access to wpa_supplicant.conf for backup and restore
chmod 0660 /data/misc/wifi/wpa_supplicant.conf
mkdir /data/local 0751 root root
@@ -246,11 +288,10 @@
mkdir /data/app-lib 0771 system system
mkdir /data/app 0771 system system
mkdir /data/property 0700 root root
- mkdir /data/ssh 0750 root shell
- mkdir /data/ssh/empty 0700 root root
# create dalvik-cache, so as to enforce our permissions
- mkdir /data/dalvik-cache 0771 system system
+ mkdir /data/dalvik-cache 0771 root root
+ mkdir /data/dalvik-cache/profiles 0711 system system
# create resource-cache and double-check the perms
mkdir /data/resource-cache 0771 system system
@@ -268,6 +309,8 @@
# the following directory.
mkdir /data/mediadrm 0770 mediadrm mediadrm
+ mkdir /data/adb 0700 root root
+
# symlink to bugreport storage location
symlink /data/data/com.android.shell/files/bugreports /data/bugreports
@@ -287,23 +330,23 @@
#setprop vold.post_fs_data_done 1
on boot
-# basic network init
+ # basic network init
ifup lo
hostname localhost
domainname localdomain
-# set RLIMIT_NICE to allow priorities from 19 to -20
+ # set RLIMIT_NICE to allow priorities from 19 to -20
setrlimit 13 40 40
-# Memory management. Basic kernel parameters, and allow the high
-# level system server to be able to adjust the kernel OOM driver
-# parameters to match how it is managing things.
+ # Memory management. Basic kernel parameters, and allow the high
+ # level system server to be able to adjust the kernel OOM driver
+ # parameters to match how it is managing things.
write /proc/sys/vm/overcommit_memory 1
write /proc/sys/vm/min_free_order_shift 4
chown root system /sys/module/lowmemorykiller/parameters/adj
- chmod 0664 /sys/module/lowmemorykiller/parameters/adj
+ chmod 0220 /sys/module/lowmemorykiller/parameters/adj
chown root system /sys/module/lowmemorykiller/parameters/minfree
- chmod 0664 /sys/module/lowmemorykiller/parameters/minfree
+ chmod 0220 /sys/module/lowmemorykiller/parameters/minfree
# Tweak background writeout
write /proc/sys/vm/dirty_expire_centisecs 200
@@ -373,27 +416,25 @@
chown system system /sys/kernel/ipv4/tcp_rmem_max
chown root radio /proc/cmdline
-# Define TCP buffer sizes for various networks
-# ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
- setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208
- setprop net.tcp.buffersize.wifi 524288,1048576,2097152,262144,524288,1048576
- setprop net.tcp.buffersize.ethernet 524288,1048576,3145728,524288,1048576,2097152
- setprop net.tcp.buffersize.lte 524288,1048576,2097152,262144,524288,1048576
- setprop net.tcp.buffersize.umts 58254,349525,1048576,58254,349525,1048576
- setprop net.tcp.buffersize.hspa 40778,244668,734003,16777,100663,301990
- setprop net.tcp.buffersize.hsupa 40778,244668,734003,16777,100663,301990
- setprop net.tcp.buffersize.hsdpa 61167,367002,1101005,8738,52429,262114
- setprop net.tcp.buffersize.hspap 122334,734003,2202010,32040,192239,576717
- setprop net.tcp.buffersize.edge 4093,26280,70800,4096,16384,70800
- setprop net.tcp.buffersize.gprs 4092,8760,48000,4096,8760,48000
- setprop net.tcp.buffersize.evdo 4094,87380,262144,4096,16384,262144
+ # Define default initial receive window size in segments.
+ setprop net.tcp.default_init_rwnd 60
class_start core
- class_start main
on nonencrypted
+ class_start main
class_start late_start
+on property:vold.decrypt=trigger_default_encryption
+ start defaultcrypto
+
+on property:vold.decrypt=trigger_encryption
+ start surfaceflinger
+ start encrypt
+
+on property:sys.init_log_level=*
+ loglevel ${sys.init_log_level}
+
on charger
class_start charger
@@ -420,10 +461,17 @@
on property:sys.powerctl=*
powerctl ${sys.powerctl}
-# system server cannot write to /proc/sys files, so proxy it through init
+# system server cannot write to /proc/sys files,
+# and chown/chmod does not work for /proc/sys/ entries.
+# So proxy writes through init.
on property:sys.sysctl.extra_free_kbytes=*
write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes}
+# "tcp_default_init_rwnd" Is too long!
+on property:sys.sysctl.tcp_def_init_rwnd=*
+ write /proc/sys/net/ipv4/tcp_default_init_rwnd ${sys.sysctl.tcp_def_init_rwnd}
+
+
## Daemon processes to be run by init.
##
service ueventd /sbin/ueventd
@@ -443,17 +491,12 @@
critical
seclabel u:r:healthd:s0
-service healthd-charger /sbin/healthd -n
- class charger
- critical
- seclabel u:r:healthd:s0
-
service console /system/bin/sh
class core
console
disabled
user shell
- group log
+ group shell log
seclabel u:r:shell:s0
on property:ro.debuggable=1
@@ -470,6 +513,11 @@
on property:ro.kernel.qemu=1
start adbd
+service lmkd /system/bin/lmkd
+ class core
+ critical
+ socket lmkd seqpacket 0660 system system
+
service servicemanager /system/bin/servicemanager
class core
user system
@@ -507,7 +555,7 @@
group radio cache inet misc audio log
service surfaceflinger /system/bin/surfaceflinger
- class main
+ class core
user system
group graphics drmrpc
onrestart restart zygote
@@ -523,10 +571,24 @@
group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
ioprio rt 4
+# One shot invocation to deal with encrypted volume.
+service defaultcrypto /system/bin/vdc --wait cryptfs mountdefaultencrypted
+ disabled
+ oneshot
+ # vold will set vold.decrypt to trigger_restart_framework (default
+ # encryption) or trigger_restart_min_framework (other encryption)
+
+# One shot invocation to encrypt unencrypted volumes
+service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace default
+ disabled
+ oneshot
+ # vold will set vold.decrypt to trigger_restart_framework (default
+ # encryption)
+
service bootanim /system/bin/bootanimation
- class main
+ class core
user graphics
- group graphics
+ group graphics audio
disabled
oneshot
@@ -534,8 +596,9 @@
class main
socket installd stream 600 system system
-service flash_recovery /system/etc/install-recovery.sh
+service flash_recovery /system/bin/install-recovery.sh
class main
+ seclabel u:r:install_recovery:s0
oneshot
service racoon /system/bin/racoon
@@ -565,10 +628,6 @@
disabled
oneshot
-service sshd /system/bin/start-ssh
- class main
- disabled
-
service mdnsd /system/bin/mdnsd
class main
user mdnsr
@@ -576,3 +635,8 @@
socket mdnsd stream 0660 mdnsr inet
disabled
oneshot
+
+service pre-recovery /system/bin/uncrypt
+ class main
+ disabled
+ oneshot
diff --git a/rootdir/init.trace.rc b/rootdir/init.trace.rc
index 50944e6..cd8d350 100644
--- a/rootdir/init.trace.rc
+++ b/rootdir/init.trace.rc
@@ -1,6 +1,6 @@
## Permissions to allow system-wide tracing to the kernel trace buffer.
##
-on boot
+on early-boot
# Allow writing to the kernel trace log.
chmod 0222 /sys/kernel/debug/tracing/trace_marker
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index 15467cc..e290ca4 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -17,12 +17,12 @@
setprop sys.usb.state ${sys.usb.config}
# adb only USB configuration
-# This should only be used during device bringup
-# and as a fallback if the USB manager fails to set a standard configuration
+# This is the fallback configuration if the
+# USB manager fails to set a standard configuration
on property:sys.usb.config=adb
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/idVendor 18d1
- write /sys/class/android_usb/android0/idProduct D002
+ write /sys/class/android_usb/android0/idProduct 4EE7
write /sys/class/android_usb/android0/functions ${sys.usb.config}
write /sys/class/android_usb/android0/enable 1
start adbd
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
new file mode 100644
index 0000000..979ab3b
--- /dev/null
+++ b/rootdir/init.zygote64_32.rc
@@ -0,0 +1,12 @@
+service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
+ class main
+ socket zygote stream 660 root system
+ onrestart write /sys/android_power/request_state wake
+ onrestart write /sys/power/state on
+ onrestart restart media
+ onrestart restart netd
+
+service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
+ class main
+ socket zygote_secondary stream 660 root system
+ onrestart restart zygote
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
index 4630db9..63b0f41 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -1,10 +1,10 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= sdcard.c
-LOCAL_MODULE:= sdcard
-LOCAL_CFLAGS := -Wall -Wno-unused-parameter
+LOCAL_SRC_FILES := sdcard.c
+LOCAL_MODULE := sdcard
+LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
LOCAL_SHARED_LIBRARIES := libc libcutils
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 7baad63..2318978 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -14,10 +14,13 @@
* limitations under the License.
*/
+#define LOG_TAG "sdcard"
+
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <limits.h>
#include <linux/fuse.h>
#include <pthread.h>
@@ -26,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>
@@ -35,6 +39,7 @@
#include <cutils/fs.h>
#include <cutils/hashmap.h>
+#include <cutils/log.h>
#include <cutils/multiuser.h>
#include <private/android_filesystem_config.h>
@@ -90,12 +95,12 @@
#define FUSE_TRACE 0
#if FUSE_TRACE
-#define TRACE(x...) fprintf(stderr,x)
+#define TRACE(x...) ALOGD(x)
#else
#define TRACE(x...) do {} while (0)
#endif
-#define ERROR(x...) fprintf(stderr,x)
+#define ERROR(x...) ALOGE(x)
#define FUSE_UNKNOWN_INO 0xffffffff
@@ -139,6 +144,8 @@
PERM_ANDROID_DATA,
/* This node is "/Android/obb" */
PERM_ANDROID_OBB,
+ /* This node is "/Android/media" */
+ PERM_ANDROID_MEDIA,
/* This node is "/Android/user" */
PERM_ANDROID_USER,
} perm_t;
@@ -384,12 +391,12 @@
attr->ino = node->nid;
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;
@@ -475,6 +482,10 @@
/* Single OBB directory is always shared */
node->graft_path = fuse->obbpath;
node->graft_pathlen = strlen(fuse->obbpath);
+ } else if (!strcasecmp(node->name, "media")) {
+ /* App-specific directories inside; let anyone traverse */
+ node->perm = PERM_ANDROID_MEDIA;
+ node->mode = 0771;
} else if (!strcasecmp(node->name, "user")) {
/* User directories must only be accessible to system, protected
* by sdcard_all. Zygote will bind mount the appropriate user-
@@ -486,6 +497,7 @@
break;
case PERM_ANDROID_DATA:
case PERM_ANDROID_OBB:
+ case PERM_ANDROID_MEDIA:
appid = (appid_t) (uintptr_t) hashmapGet(fuse->package_to_appid, node->name);
if (appid != 0) {
node->uid = multiuser_get_uid(parent->userid, appid);
@@ -818,7 +830,7 @@
pthread_mutex_lock(&fuse->lock);
parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
parent_path, sizeof(parent_path));
- TRACE("[%d] LOOKUP %s @ %llx (%s)\n", handler->token, name, hdr->nodeid,
+ TRACE("[%d] LOOKUP %s @ %"PRIx64" (%s)\n", handler->token, name, hdr->nodeid,
parent_node ? parent_node->name : "?");
pthread_mutex_unlock(&fuse->lock);
@@ -840,7 +852,7 @@
pthread_mutex_lock(&fuse->lock);
node = lookup_node_by_id_locked(fuse, hdr->nodeid);
- TRACE("[%d] FORGET #%lld @ %llx (%s)\n", handler->token, req->nlookup,
+ TRACE("[%d] FORGET #%"PRIu64" @ %"PRIx64" (%s)\n", handler->token, req->nlookup,
hdr->nodeid, node ? node->name : "?");
if (node) {
__u64 n = req->nlookup;
@@ -860,7 +872,7 @@
pthread_mutex_lock(&fuse->lock);
node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
- TRACE("[%d] GETATTR flags=%x fh=%llx @ %llx (%s)\n", handler->token,
+ TRACE("[%d] GETATTR flags=%x fh=%"PRIx64" @ %"PRIx64" (%s)\n", handler->token,
req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
pthread_mutex_unlock(&fuse->lock);
@@ -885,7 +897,7 @@
pthread_mutex_lock(&fuse->lock);
has_rw = get_caller_has_rw_locked(fuse, hdr);
node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
- TRACE("[%d] SETATTR fh=%llx valid=%x @ %llx (%s)\n", handler->token,
+ TRACE("[%d] SETATTR fh=%"PRIx64" valid=%x @ %"PRIx64" (%s)\n", handler->token,
req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
pthread_mutex_unlock(&fuse->lock);
@@ -899,7 +911,7 @@
/* XXX: incomplete implementation on purpose.
* chmod/chown should NEVER be implemented.*/
- if ((req->valid & FATTR_SIZE) && truncate(path, req->size) < 0) {
+ if ((req->valid & FATTR_SIZE) && truncate64(path, req->size) < 0) {
return -errno;
}
@@ -950,7 +962,7 @@
has_rw = get_caller_has_rw_locked(fuse, hdr);
parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
parent_path, sizeof(parent_path));
- TRACE("[%d] MKNOD %s 0%o @ %llx (%s)\n", handler->token,
+ TRACE("[%d] MKNOD %s 0%o @ %"PRIx64" (%s)\n", handler->token,
name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
pthread_mutex_unlock(&fuse->lock);
@@ -981,7 +993,7 @@
has_rw = get_caller_has_rw_locked(fuse, hdr);
parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
parent_path, sizeof(parent_path));
- TRACE("[%d] MKDIR %s 0%o @ %llx (%s)\n", handler->token,
+ TRACE("[%d] MKDIR %s 0%o @ %"PRIx64" (%s)\n", handler->token,
name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
pthread_mutex_unlock(&fuse->lock);
@@ -1030,7 +1042,7 @@
has_rw = get_caller_has_rw_locked(fuse, hdr);
parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
parent_path, sizeof(parent_path));
- TRACE("[%d] UNLINK %s @ %llx (%s)\n", handler->token,
+ TRACE("[%d] UNLINK %s @ %"PRIx64" (%s)\n", handler->token,
name, hdr->nodeid, parent_node ? parent_node->name : "?");
pthread_mutex_unlock(&fuse->lock);
@@ -1059,7 +1071,7 @@
has_rw = get_caller_has_rw_locked(fuse, hdr);
parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
parent_path, sizeof(parent_path));
- TRACE("[%d] RMDIR %s @ %llx (%s)\n", handler->token,
+ TRACE("[%d] RMDIR %s @ %"PRIx64" (%s)\n", handler->token,
name, hdr->nodeid, parent_node ? parent_node->name : "?");
pthread_mutex_unlock(&fuse->lock);
@@ -1097,7 +1109,7 @@
old_parent_path, sizeof(old_parent_path));
new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
new_parent_path, sizeof(new_parent_path));
- TRACE("[%d] RENAME %s->%s @ %llx (%s) -> %llx (%s)\n", handler->token,
+ TRACE("[%d] RENAME %s->%s @ %"PRIx64" (%s) -> %"PRIx64" (%s)\n", handler->token,
old_name, new_name,
hdr->nodeid, old_parent_node ? old_parent_node->name : "?",
req->newdir, new_parent_node ? new_parent_node->name : "?");
@@ -1181,7 +1193,7 @@
pthread_mutex_lock(&fuse->lock);
has_rw = get_caller_has_rw_locked(fuse, hdr);
node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
- TRACE("[%d] OPEN 0%o @ %llx (%s)\n", handler->token,
+ TRACE("[%d] OPEN 0%o @ %"PRIx64" (%s)\n", handler->token,
req->flags, hdr->nodeid, node ? node->name : "?");
pthread_mutex_unlock(&fuse->lock);
@@ -1223,8 +1235,8 @@
* overlaps the request buffer and will clobber data in the request. This
* saves us 128KB per request handler thread at the cost of this scary comment. */
- TRACE("[%d] READ %p(%d) %u@%llu\n", handler->token,
- h, h->fd, size, offset);
+ TRACE("[%d] READ %p(%d) %u@%"PRIu64"\n", handler->token,
+ h, h->fd, size, (uint64_t) offset);
if (size > MAX_READ) {
return -EINVAL;
}
@@ -1250,13 +1262,14 @@
buffer = (const __u8*) aligned_buffer;
}
- TRACE("[%d] WRITE %p(%d) %u@%llu\n", handler->token,
+ TRACE("[%d] WRITE %p(%d) %u@%"PRIu64"\n", handler->token,
h, h->fd, req->size, req->offset);
res = pwrite64(h->fd, buffer, req->size, req->offset);
if (res < 0) {
return -errno;
}
out.size = res;
+ out.padding = 0;
fuse_reply(fuse, hdr->unique, &out, sizeof(out));
return NO_STATUS;
}
@@ -1306,14 +1319,23 @@
static int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
{
- int is_data_sync = req->fsync_flags & 1;
- struct handle *h = id_to_ptr(req->fh);
- int res;
+ bool is_dir = (hdr->opcode == FUSE_FSYNCDIR);
+ bool is_data_sync = req->fsync_flags & 1;
- TRACE("[%d] FSYNC %p(%d) is_data_sync=%d\n", handler->token,
- h, h->fd, is_data_sync);
- res = is_data_sync ? fdatasync(h->fd) : fsync(h->fd);
- if (res < 0) {
+ int fd = -1;
+ if (is_dir) {
+ struct dirhandle *dh = id_to_ptr(req->fh);
+ fd = dirfd(dh->d);
+ } else {
+ struct handle *h = id_to_ptr(req->fh);
+ fd = h->fd;
+ }
+
+ TRACE("[%d] %s %p(%d) is_data_sync=%d\n", handler->token,
+ is_dir ? "FSYNCDIR" : "FSYNC",
+ id_to_ptr(req->fh), fd, is_data_sync);
+ int res = is_data_sync ? fdatasync(fd) : fsync(fd);
+ if (res == -1) {
return -errno;
}
return 0;
@@ -1336,7 +1358,7 @@
pthread_mutex_lock(&fuse->lock);
node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
- TRACE("[%d] OPENDIR @ %llx (%s)\n", handler->token,
+ TRACE("[%d] OPENDIR @ %"PRIx64" (%s)\n", handler->token,
hdr->nodeid, node ? node->name : "?");
pthread_mutex_unlock(&fuse->lock);
@@ -1407,17 +1429,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;
}
@@ -1537,7 +1584,7 @@
}
default: {
- TRACE("[%d] NOTIMPL op=%d uniq=%llx nid=%llx\n",
+ TRACE("[%d] NOTIMPL op=%d uniq=%"PRIx64" nid=%"PRIx64"\n",
handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
return -ENOSYS;
}
@@ -1640,7 +1687,7 @@
}
}
- TRACE("read_package_list: found %d packages, %d with write_gid\n",
+ TRACE("read_package_list: found %zu packages, %zu with write_gid\n",
hashmapSize(fuse->package_to_appid),
hashmapSize(fuse->appid_with_rw));
fclose(file);
@@ -1787,7 +1834,7 @@
"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, opts);
+ res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC, opts);
if (res < 0) {
ERROR("cannot mount fuse filesystem: %s\n", strerror(errno));
goto error;
@@ -1837,6 +1884,7 @@
bool split_perms = false;
int i;
struct rlimit rlim;
+ int fs_version;
int opt;
while ((opt = getopt(argc, argv, "u:g:w:t:dls")) != -1) {
@@ -1911,6 +1959,11 @@
ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);
}
+ while ((fs_read_atomic_int("/data/.layout_version", &fs_version) == -1) || (fs_version < 3)) {
+ ERROR("installd fs upgrade not yet complete. Waiting...\n");
+ sleep(1);
+ }
+
res = run(source_path, dest_path, uid, gid, write_gid, num_threads, derive, split_perms);
return res < 0 ? 1 : 0;
}
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 5383b83..249f91e 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -1,112 +1,192 @@
LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-TOOLS := \
- ls \
- mount \
- cat \
- ps \
- kill \
- ln \
- insmod \
- rmmod \
- lsmod \
- ifconfig \
- rm \
- mkdir \
- rmdir \
- getevent \
- sendevent \
- date \
- wipe \
- sync \
- umount \
- start \
- stop \
- notify \
- cmp \
- dmesg \
- route \
- hd \
- dd \
- df \
- getprop \
- setprop \
- watchprops \
- log \
- sleep \
- renice \
- printenv \
- smd \
- chmod \
- chown \
- newfs_msdos \
- netstat \
- ioctl \
- mv \
- schedtop \
- top \
- iftop \
- id \
- uptime \
- vmstat \
- nandread \
- ionice \
- touch \
- lsof \
- du \
- md5 \
- clear \
- getenforce \
- setenforce \
- chcon \
- restorecon \
- runcon \
- getsebool \
- setsebool \
- load_policy \
- swapon \
- swapoff \
- mkswap \
- readlink
-ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-TOOLS += r
-endif
-
-ALL_TOOLS = $(TOOLS)
-ALL_TOOLS += \
- cp \
- grep
-
-LOCAL_SRC_FILES := \
- cp/cp.c \
- cp/utils.c \
- dynarray.c \
- grep/fastgrep.c \
- grep/file.c \
- grep/grep.c \
- grep/queue.c \
- grep/util.c \
- $(patsubst %,%.c,$(TOOLS)) \
- toolbox.c \
- uid_from_user.c \
-
-LOCAL_C_INCLUDES := bionic/libc/bionic
-
-LOCAL_CFLAGS += \
+common_cflags := \
-std=gnu99 \
- -Wno-unused-parameter \
+ -Werror -Wno-unused-parameter \
+ -I$(LOCAL_PATH)/upstream-netbsd/include/ \
-include bsd-compatibility.h \
+# Temporary, remove after cleanup. b/18632512
+common_cflags += -Wno-unused-variable \
+ -Wno-unused-but-set-variable
+
+
+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
+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/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/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)
+
+BSD_TOOLS := \
+ cat \
+ chown \
+ cp \
+ dd \
+ du \
+ grep \
+ ln \
+ mv \
+ rm \
+ rmdir \
+
+OUR_TOOLS := \
+ chcon \
+ chmod \
+ cmp \
+ date \
+ df \
+ getenforce \
+ getevent \
+ getprop \
+ getsebool \
+ hd \
+ id \
+ ifconfig \
+ iftop \
+ ioctl \
+ ionice \
+ load_policy \
+ log \
+ ls \
+ lsof \
+ md5 \
+ mkdir \
+ mknod \
+ mount \
+ nandread \
+ netstat \
+ newfs_msdos \
+ notify \
+ ps \
+ renice \
+ restorecon \
+ route \
+ runcon \
+ schedtop \
+ sendevent \
+ setenforce \
+ setprop \
+ setsebool \
+ smd \
+ start \
+ stop \
+ top \
+ touch \
+ umount \
+ uptime \
+ watchprops \
+ wipe \
+
+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 \
+
+LOCAL_CFLAGS += $(common_cflags)
+
+LOCAL_C_INCLUDES += external/openssl/include
+
LOCAL_SHARED_LIBRARIES := \
- libcutils \
- liblog \
- libc \
- libusbhost \
- libselinux
+ libcrypto \
+ libcutils \
+ libselinux \
+
+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).
#
@@ -121,19 +201,12 @@
$(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) $@
-ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS)
-
-# We need this so that the installed files could be picked up based on the
-# local module name
-ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \
- $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(SYMLINKS)
+# We 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
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_EXECUTABLE)
diff --git a/toolbox/NOTICE b/toolbox/NOTICE
index 895b49a..e9ab58d 100644
--- a/toolbox/NOTICE
+++ b/toolbox/NOTICE
@@ -1,5 +1,20 @@
+Copyright (C) 2010 The Android Open Source Project
-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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2014, The Android Open Source Project
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -9,12 +24,8 @@
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
+ the documentation and/or other materials provided with the
distribution.
- * Neither the name of The Android Open Source Project 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
@@ -23,86 +34,16 @@
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
+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.
+-------------------------------------------------------------------
-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 The Android Open Source Project 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.
-
-
-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 The Android Open Source Project 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.
-
-
-Copyright (c) 1998 Robert Nordier
-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.
-This code is derived from software contributed to Berkeley by
-Keith Muller of the University of California, San Diego and Lance
-Visser of Convex Computer Corporation.
-This code is derived from software contributed to Berkeley by
-Mike Muuss.
+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
@@ -128,66 +69,919 @@
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
+-------------------------------------------------------------------
- Copyright (c) 1989, 1993
- The Regents of the University of California. All rights reserved.
+Copyright (c) 1987, 1993, 1994
+ 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.
- 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.
- 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.
+-------------------------------------------------------------------
+Copyright (c) 1988, 1993
+ The Regents of the University of California. All rights reserved.
- Copyright (c) 1991, 1993, 1994
- The Regents of the University of California. All rights reserved.
+This code is derived from software contributed to Berkeley by
+Jeffrey Mogul.
- This code is derived from software contributed to Berkeley by
- Keith Muller of the University of California, San Diego and Lance
- Visser of Convex Computer Corporation.
+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.
- 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.
- 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.
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+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
+Chris Newcomb.
+
+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.
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1991, 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.
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1991, 1993, 1994
+ The Regents of the University of California. All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Keith Muller of the University of California, San Diego and Lance
+Visser of Convex Computer Corporation.
+
+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.
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1998 Robert Nordier
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+Copyright (C) 2008 Gabor Kovesdan <gabor@FreeBSD.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
+Copyright (C) 2010 Dimitry Andric <dimitry@andric.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+Copyright (c) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Luke Mewburn.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2007 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Luke Mewburn.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2010 The NetBSD Foundation, 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:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2010, 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.
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
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 a304631..36ddca9 100644
--- a/toolbox/bsd-compatibility.h
+++ b/toolbox/bsd-compatibility.h
@@ -26,13 +26,64 @@
* SUCH DAMAGE.
*/
+#include <stdbool.h>
#include <sys/types.h>
/* We want chown to support user.group as well as user:group. */
#define SUPPORT_DOT
+/* We don't localize /system/bin! */
+#define WITHOUT_NLS
+
+// NetBSD uses _DIAGASSERT to null-check arguments and the like.
+#include <assert.h>
+#define _DIAGASSERT(e) ((e) ? (void) 0 : __assert2(__FILE__, __LINE__, __func__, #e))
+
+// TODO: update our <sys/cdefs.h> to support this properly.
+#define __type_fit(t, a) (0 == 0)
+
+// TODO: should this be in our <sys/cdefs.h>?
+#define __arraycount(a) (sizeof(a) / sizeof(a[0]))
+
+// This at least matches GNU dd(1) behavior.
+#define SIGINFO SIGUSR1
+
+#define S_ISWHT(x) false
+
__BEGIN_DECLS
-extern int uid_from_user(const char* name, uid_t* uid);
+/* 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
+#define HN_B 0x04
+#define HN_DIVISOR_1000 0x08
+#define HN_GETSCALE 0x10
+#define HN_AUTOSCALE 0x20
+int humanize_number(char *, size_t, int64_t, const char *, int, int);
+int dehumanize_number(const char *, int64_t *);
+char *getbsize(int *, long *);
+long long strsuftoll(const char *, const char *, long long, long long);
+long long strsuftollx(const char *, const char *, long long, long long,
+ char *, size_t);
+
+/* From NetBSD <string.h>. */
+void strmode(mode_t, char*);
+
+/* From NetBSD <sys/param.h>. */
+#define MAXBSIZE 65536
+
+/* From NetBSD <sys/stat.h>. */
+#define DEFFILEMODE (S_IRUSR | S_IWUSR)
+
+/* From NetBSD <unistd.h>. */
+void swab(const void * __restrict, void * __restrict, ssize_t);
+
+/* From NetBSD <util.h>. */
+int raise_default_signal(int);
__END_DECLS
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/date.c b/toolbox/date.c
index aa3b72e..70ce1d5 100644
--- a/toolbox/date.c
+++ b/toolbox/date.c
@@ -140,14 +140,12 @@
int date_main(int argc, char *argv[])
{
- int c;
+ int c;
int res;
- struct tm tm;
- time_t t;
- struct timeval tv;
- struct timespec ts;
- char strbuf[260];
- int fd;
+ struct tm tm;
+ time_t t;
+ struct timeval tv;
+ char strbuf[260];
int useutc = 0;
@@ -177,7 +175,6 @@
int hasfmt = argc == optind + 1 && argv[optind][0] == '+';
if(optind == argc || hasfmt) {
- char buf[2000];
time(&t);
if (useutc) {
gmtime_r(&t, &tm);
diff --git a/toolbox/dd.c b/toolbox/dd.c
deleted file mode 100644
index 6b61ffb..0000000
--- a/toolbox/dd.c
+++ /dev/null
@@ -1,1313 +0,0 @@
-/* $NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * 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) 1991, 1993, 1994\n\
- The Regents of the University of California. All rights reserved.\n");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "dd.h"
-
-//#define NO_CONV
-
-//#include "extern.h"
-void block(void);
-void block_close(void);
-void dd_out(int);
-void def(void);
-void def_close(void);
-void jcl(char **);
-void pos_in(void);
-void pos_out(void);
-void summary(void);
-void summaryx(int);
-void terminate(int);
-void unblock(void);
-void unblock_close(void);
-ssize_t bwrite(int, const void *, size_t);
-
-extern IO in, out;
-extern STAT st;
-extern void (*cfunc)(void);
-extern uint64_t cpy_cnt;
-extern uint64_t cbsz;
-extern u_int ddflags;
-extern u_int files_cnt;
-extern int progress;
-extern const u_char *ctab;
-
-#define DEFFILEMODE (S_IRUSR | S_IWUSR)
-
-static void dd_close(void);
-static void dd_in(void);
-static void getfdtype(IO *);
-static int redup_clean_fd(int);
-static void setup(void);
-
-
-IO in, out; /* input/output state */
-STAT st; /* statistics */
-void (*cfunc)(void); /* conversion function */
-uint64_t cpy_cnt; /* # of blocks to copy */
-static off_t pending = 0; /* pending seek if sparse */
-u_int ddflags; /* conversion options */
-uint64_t cbsz; /* conversion block size */
-u_int files_cnt = 1; /* # of files to copy */
-int progress = 0; /* display sign of life */
-const u_char *ctab; /* conversion table */
-sigset_t infoset; /* a set blocking SIGINFO */
-
-int
-dd_main(int argc, char *argv[])
-{
- int ch;
-
- while ((ch = getopt(argc, argv, "")) != -1) {
- switch (ch) {
- default:
- fprintf(stderr, "usage: dd [operand ...]\n");
- exit(1);
- /* NOTREACHED */
- }
- }
- argc -= (optind - 1);
- argv += (optind - 1);
-
- jcl(argv);
- setup();
-
-// (void)signal(SIGINFO, summaryx);
- (void)signal(SIGINT, terminate);
- (void)sigemptyset(&infoset);
-// (void)sigaddset(&infoset, SIGINFO);
-
- (void)atexit(summary);
-
- while (files_cnt--)
- dd_in();
-
- dd_close();
- exit(0);
- /* NOTREACHED */
-}
-
-static void
-setup(void)
-{
-
- if (in.name == NULL) {
- in.name = "stdin";
- in.fd = STDIN_FILENO;
- } else {
- in.fd = open(in.name, O_RDONLY, 0);
- if (in.fd < 0) {
- fprintf(stderr, "%s: cannot open for read: %s\n",
- in.name, strerror(errno));
- exit(1);
- /* NOTREACHED */
- }
-
- /* Ensure in.fd is outside the stdio descriptor range */
- in.fd = redup_clean_fd(in.fd);
- }
-
- getfdtype(&in);
-
- if (files_cnt > 1 && !(in.flags & ISTAPE)) {
- fprintf(stderr,
- "files is not supported for non-tape devices\n");
- exit(1);
- /* NOTREACHED */
- }
-
- if (out.name == NULL) {
- /* No way to check for read access here. */
- out.fd = STDOUT_FILENO;
- out.name = "stdout";
- } else {
-#define OFLAGS \
- (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
- out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE);
- /*
- * May not have read access, so try again with write only.
- * Without read we may have a problem if output also does
- * not support seeks.
- */
- if (out.fd < 0) {
- out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
- out.flags |= NOREAD;
- }
- if (out.fd < 0) {
- fprintf(stderr, "%s: cannot open for write: %s\n",
- out.name, strerror(errno));
- exit(1);
- /* NOTREACHED */
- }
-
- /* Ensure out.fd is outside the stdio descriptor range */
- out.fd = redup_clean_fd(out.fd);
- }
-
- getfdtype(&out);
-
- /*
- * Allocate space for the input and output buffers. If not doing
- * record oriented I/O, only need a single buffer.
- */
- if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
- if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) {
- exit(1);
- /* NOTREACHED */
- }
- out.db = in.db;
- } else if ((in.db =
- malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
- (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) {
- exit(1);
- /* NOTREACHED */
- }
- in.dbp = in.db;
- out.dbp = out.db;
-
- /* Position the input/output streams. */
- if (in.offset)
- pos_in();
- if (out.offset)
- pos_out();
-
- /*
- * Truncate the output file; ignore errors because it fails on some
- * kinds of output files, tapes, for example.
- */
- if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
- (void)ftruncate(out.fd, (off_t)out.offset * out.dbsz);
-
- (void)gettimeofday(&st.start, NULL); /* Statistics timestamp. */
-}
-
-static void
-getfdtype(IO *io)
-{
-// struct mtget mt;
- struct stat sb;
-
- if (fstat(io->fd, &sb)) {
- fprintf(stderr, "%s: cannot fstat: %s\n",
- io->name, strerror(errno));
- exit(1);
- /* NOTREACHED */
- }
- if (S_ISCHR(sb.st_mode))
- io->flags |= /*ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE; */ ISCHR;
- else if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
- io->flags |= ISPIPE; /* XXX fixed in 4.4BSD */
-}
-
-/*
- * Move the parameter file descriptor to a descriptor that is outside the
- * stdio descriptor range, if necessary. This is required to avoid
- * accidentally outputting completion or error messages into the
- * output file that were intended for the tty.
- */
-static int
-redup_clean_fd(int fd)
-{
- int newfd;
-
- if (fd != STDIN_FILENO && fd != STDOUT_FILENO &&
- fd != STDERR_FILENO)
- /* File descriptor is ok, return immediately. */
- return fd;
-
- /*
- * 3 is the first descriptor greater than STD*_FILENO. Any
- * free descriptor valued 3 or above is acceptable...
- */
- newfd = fcntl(fd, F_DUPFD, 3);
- if (newfd < 0) {
- fprintf(stderr, "dupfd IO: %s\n", strerror(errno));
- exit(1);
- /* NOTREACHED */
- }
-
- close(fd);
-
- return newfd;
-}
-
-static void
-dd_in(void)
-{
- int flags;
- int64_t n;
-
- for (flags = ddflags;;) {
- if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
- return;
-
- /*
- * Clear the buffer first if doing "sync" on input.
- * If doing block operations use spaces. This will
- * affect not only the C_NOERROR case, but also the
- * last partial input block which should be padded
- * with zero and not garbage.
- */
- if (flags & C_SYNC) {
- if (flags & (C_BLOCK|C_UNBLOCK))
- (void)memset(in.dbp, ' ', in.dbsz);
- else
- (void)memset(in.dbp, 0, in.dbsz);
- }
-
- n = read(in.fd, in.dbp, in.dbsz);
- if (n == 0) {
- in.dbrcnt = 0;
- return;
- }
-
- /* Read error. */
- if (n < 0) {
-
- /*
- * If noerror not specified, die. POSIX requires that
- * the warning message be followed by an I/O display.
- */
- fprintf(stderr, "%s: read error: %s\n",
- in.name, strerror(errno));
- if (!(flags & C_NOERROR)) {
- exit(1);
- /* NOTREACHED */
- }
- summary();
-
- /*
- * If it's not a tape drive or a pipe, seek past the
- * error. If your OS doesn't do the right thing for
- * raw disks this section should be modified to re-read
- * in sector size chunks.
- */
- if (!(in.flags & (ISPIPE|ISTAPE)) &&
- lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
- fprintf(stderr, "%s: seek error: %s\n",
- in.name, strerror(errno));
-
- /* If sync not specified, omit block and continue. */
- if (!(ddflags & C_SYNC))
- continue;
-
- /* Read errors count as full blocks. */
- in.dbcnt += in.dbrcnt = in.dbsz;
- ++st.in_full;
-
- /* Handle full input blocks. */
- } else if (n == in.dbsz) {
- in.dbcnt += in.dbrcnt = n;
- ++st.in_full;
-
- /* Handle partial input blocks. */
- } else {
- /* If sync, use the entire block. */
- if (ddflags & C_SYNC)
- in.dbcnt += in.dbrcnt = in.dbsz;
- else
- in.dbcnt += in.dbrcnt = n;
- ++st.in_part;
- }
-
- /*
- * POSIX states that if bs is set and no other conversions
- * than noerror, notrunc or sync are specified, the block
- * is output without buffering as it is read.
- */
- if (ddflags & C_BS) {
- out.dbcnt = in.dbcnt;
- dd_out(1);
- in.dbcnt = 0;
- continue;
- }
-
-/* if (ddflags & C_SWAB) {
- if ((n = in.dbrcnt) & 1) {
- ++st.swab;
- --n;
- }
- swab(in.dbp, in.dbp, n);
- }
-*/
- in.dbp += in.dbrcnt;
- (*cfunc)();
- }
-}
-
-/*
- * Cleanup any remaining I/O and flush output. If necesssary, output file
- * is truncated.
- */
-static void
-dd_close(void)
-{
-
- if (cfunc == def)
- def_close();
- else if (cfunc == block)
- block_close();
- else if (cfunc == unblock)
- unblock_close();
- if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
- (void)memset(out.dbp, 0, out.dbsz - out.dbcnt);
- out.dbcnt = out.dbsz;
- }
- /* If there are pending sparse blocks, make sure
- * to write out the final block un-sparse
- */
- if ((out.dbcnt == 0) && pending) {
- memset(out.db, 0, out.dbsz);
- out.dbcnt = out.dbsz;
- out.dbp = out.db + out.dbcnt;
- pending -= out.dbsz;
- }
- if (out.dbcnt)
- dd_out(1);
-
- /*
- * Reporting nfs write error may be defered until next
- * write(2) or close(2) system call. So, we need to do an
- * extra check. If an output is stdout, the file structure
- * may be shared among with other processes and close(2) just
- * decreases the reference count.
- */
- if (out.fd == STDOUT_FILENO && fsync(out.fd) == -1 && errno != EINVAL) {
- fprintf(stderr, "fsync stdout: %s\n", strerror(errno));
- exit(1);
- /* NOTREACHED */
- }
- if (close(out.fd) == -1) {
- fprintf(stderr, "close: %s\n", strerror(errno));
- exit(1);
- /* NOTREACHED */
- }
-}
-
-void
-dd_out(int force)
-{
- static int warned;
- int64_t cnt, n, nw;
- u_char *outp;
-
- /*
- * Write one or more blocks out. The common case is writing a full
- * output block in a single write; increment the full block stats.
- * Otherwise, we're into partial block writes. If a partial write,
- * and it's a character device, just warn. If a tape device, quit.
- *
- * The partial writes represent two cases. 1: Where the input block
- * was less than expected so the output block was less than expected.
- * 2: Where the input block was the right size but we were forced to
- * write the block in multiple chunks. The original versions of dd(1)
- * never wrote a block in more than a single write, so the latter case
- * never happened.
- *
- * One special case is if we're forced to do the write -- in that case
- * we play games with the buffer size, and it's usually a partial write.
- */
- outp = out.db;
- for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
- for (cnt = n;; cnt -= nw) {
-
- if (!force && ddflags & C_SPARSE) {
- int sparse, i;
- sparse = 1; /* Is buffer sparse? */
- for (i = 0; i < cnt; i++)
- if (outp[i] != 0) {
- sparse = 0;
- break;
- }
- if (sparse) {
- pending += cnt;
- outp += cnt;
- nw = 0;
- break;
- }
- }
- if (pending != 0) {
- if (lseek(out.fd, pending, SEEK_CUR) ==
- -1) {
- fprintf(stderr,
- "%s: seek error creating "
- "sparse file: %s\n",
- out.name, strerror(errno));
- exit(1);
- }
- }
- nw = bwrite(out.fd, outp, cnt);
- if (nw <= 0) {
- if (nw == 0) {
- fprintf(stderr, "%s: end of device\n",
- out.name);
- exit(1);
- /* NOTREACHED */
- }
- if (errno != EINTR) {
- fprintf(stderr, "%s: write error: %s\n",
- out.name, strerror(errno));
- /* NOTREACHED */
- exit(1);
- }
- nw = 0;
- }
- if (pending) {
- st.bytes += pending;
- st.sparse += pending/out.dbsz;
- st.out_full += pending/out.dbsz;
- pending = 0;
- }
- outp += nw;
- st.bytes += nw;
- if (nw == n) {
- if (n != out.dbsz)
- ++st.out_part;
- else
- ++st.out_full;
- break;
- }
- ++st.out_part;
- if (nw == cnt)
- break;
- if (out.flags & ISCHR && !warned) {
- warned = 1;
- fprintf(stderr, "%s: short write on character "
- "device\n", out.name);
- }
- if (out.flags & ISTAPE) {
- fprintf(stderr,
- "%s: short write on tape device",
- out.name);
- exit(1);
- /* NOTREACHED */
- }
- }
- if ((out.dbcnt -= n) < out.dbsz)
- break;
- }
-
- /* Reassemble the output block. */
- if (out.dbcnt)
- (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
- out.dbp = out.db + out.dbcnt;
-
- if (progress)
- (void)write(STDERR_FILENO, ".", 1);
-}
-
-/*
- * A protected against SIGINFO write
- */
-ssize_t
-bwrite(int fd, const void *buf, size_t len)
-{
- sigset_t oset;
- ssize_t rv;
- int oerrno;
-
- (void)sigprocmask(SIG_BLOCK, &infoset, &oset);
- rv = write(fd, buf, len);
- oerrno = errno;
- (void)sigprocmask(SIG_SETMASK, &oset, NULL);
- errno = oerrno;
- return (rv);
-}
-
-/*
- * Position input/output data streams before starting the copy. Device type
- * dependent. Seekable devices use lseek, and the rest position by reading.
- * Seeking past the end of file can cause null blocks to be written to the
- * output.
- */
-void
-pos_in(void)
-{
- int bcnt, cnt, nr, warned;
-
- /* If not a pipe or tape device, try to seek on it. */
- if (!(in.flags & (ISPIPE|ISTAPE))) {
- if (lseek64(in.fd,
- (off64_t)in.offset * (off64_t)in.dbsz, SEEK_CUR) == -1) {
- fprintf(stderr, "%s: seek error: %s",
- in.name, strerror(errno));
- exit(1);
- /* NOTREACHED */
- }
- return;
- /* NOTREACHED */
- }
-
- /*
- * Read the data. If a pipe, read until satisfy the number of bytes
- * being skipped. No differentiation for reading complete and partial
- * blocks for other devices.
- */
- for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) {
- if ((nr = read(in.fd, in.db, bcnt)) > 0) {
- if (in.flags & ISPIPE) {
- if (!(bcnt -= nr)) {
- bcnt = in.dbsz;
- --cnt;
- }
- } else
- --cnt;
- continue;
- }
-
- if (nr == 0) {
- if (files_cnt > 1) {
- --files_cnt;
- continue;
- }
- fprintf(stderr, "skip reached end of input\n");
- exit(1);
- /* NOTREACHED */
- }
-
- /*
- * Input error -- either EOF with no more files, or I/O error.
- * If noerror not set die. POSIX requires that the warning
- * message be followed by an I/O display.
- */
- if (ddflags & C_NOERROR) {
- if (!warned) {
-
- fprintf(stderr, "%s: error occurred\n",
- in.name);
- warned = 1;
- summary();
- }
- continue;
- }
- fprintf(stderr, "%s: read error: %s", in.name, strerror(errno));
- exit(1);
- /* NOTREACHED */
- }
-}
-
-void
-pos_out(void)
-{
-// struct mtop t_op;
- int cnt, n;
-
- /*
- * If not a tape, try seeking on the file. Seeking on a pipe is
- * going to fail, but don't protect the user -- they shouldn't
- * have specified the seek operand.
- */
- if (!(out.flags & ISTAPE)) {
- if (lseek64(out.fd,
- (off64_t)out.offset * (off64_t)out.dbsz, SEEK_SET) == -1) {
- fprintf(stderr, "%s: seek error: %s\n",
- out.name, strerror(errno));
- exit(1);
- /* NOTREACHED */
- }
- return;
- }
-
- /* If no read access, try using mtio. */
- if (out.flags & NOREAD) {
-/* t_op.mt_op = MTFSR;
- t_op.mt_count = out.offset;
-
- if (ioctl(out.fd, MTIOCTOP, &t_op) < 0)*/
- fprintf(stderr, "%s: cannot read", out.name);
- exit(1);
- /* NOTREACHED */
- return;
- }
-
- /* Read it. */
- for (cnt = 0; cnt < out.offset; ++cnt) {
- if ((n = read(out.fd, out.db, out.dbsz)) > 0)
- continue;
-
- if (n < 0) {
- fprintf(stderr, "%s: cannot position by reading: %s\n",
- out.name, strerror(errno));
- exit(1);
- /* NOTREACHED */
- }
-
- /*
- * If reach EOF, fill with NUL characters; first, back up over
- * the EOF mark. Note, cnt has not yet been incremented, so
- * the EOF read does not count as a seek'd block.
- */
-/* t_op.mt_op = MTBSR;
- t_op.mt_count = 1;
- if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) */ {
- fprintf(stderr, "%s: cannot position\n", out.name);
- exit(1);
- /* NOTREACHED */
- }
-
- while (cnt++ < out.offset)
- if ((n = bwrite(out.fd, out.db, out.dbsz)) != out.dbsz) {
- fprintf(stderr, "%s: cannot position "
- "by writing: %s\n",
- out.name, strerror(errno));
- exit(1);
- /* NOTREACHED */
- }
- break;
- }
-}
-
-/*
- * def --
- * Copy input to output. Input is buffered until reaches obs, and then
- * output until less than obs remains. Only a single buffer is used.
- * Worst case buffer calculation is (ibs + obs - 1).
- */
-void
-def(void)
-{
- uint64_t cnt;
- u_char *inp;
- const u_char *t;
-
- if ((t = ctab) != NULL)
- for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
- *inp = t[*inp];
-
- /* Make the output buffer look right. */
- out.dbp = in.dbp;
- out.dbcnt = in.dbcnt;
-
- if (in.dbcnt >= out.dbsz) {
- /* If the output buffer is full, write it. */
- dd_out(0);
-
- /*
- * Ddout copies the leftover output to the beginning of
- * the buffer and resets the output buffer. Reset the
- * input buffer to match it.
- */
- in.dbp = out.dbp;
- in.dbcnt = out.dbcnt;
- }
-}
-
-void
-def_close(void)
-{
- if (ddflags & C_FDATASYNC) {
- fdatasync(out.fd);
- }
-
- /* Just update the count, everything is already in the buffer. */
- if (in.dbcnt)
- out.dbcnt = in.dbcnt;
-}
-
-#ifdef NO_CONV
-/* Build a smaller version (i.e. for a miniroot) */
-/* These can not be called, but just in case... */
-static const char no_block[] = "unblock and -DNO_CONV?\n";
-void block(void) { fprintf(stderr, "%s", no_block + 2); exit(1); }
-void block_close(void) { fprintf(stderr, "%s", no_block + 2); exit(1); }
-void unblock(void) { fprintf(stderr, "%s", no_block); exit(1); }
-void unblock_close(void) { fprintf(stderr, "%s", no_block); exit(1); }
-#else /* NO_CONV */
-
-/*
- * Copy variable length newline terminated records with a max size cbsz
- * bytes to output. Records less than cbs are padded with spaces.
- *
- * max in buffer: MAX(ibs, cbsz)
- * max out buffer: obs + cbsz
- */
-void
-block(void)
-{
- static int intrunc;
- int ch = 0; /* pacify gcc */
- uint64_t cnt, maxlen;
- u_char *inp, *outp;
- const u_char *t;
-
- /*
- * Record truncation can cross block boundaries. If currently in a
- * truncation state, keep tossing characters until reach a newline.
- * Start at the beginning of the buffer, as the input buffer is always
- * left empty.
- */
- if (intrunc) {
- for (inp = in.db, cnt = in.dbrcnt;
- cnt && *inp++ != '\n'; --cnt);
- if (!cnt) {
- in.dbcnt = 0;
- in.dbp = in.db;
- return;
- }
- intrunc = 0;
- /* Adjust the input buffer numbers. */
- in.dbcnt = cnt - 1;
- in.dbp = inp + cnt - 1;
- }
-
- /*
- * Copy records (max cbsz size chunks) into the output buffer. The
- * translation is done as we copy into the output buffer.
- */
- for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
- maxlen = MIN(cbsz, in.dbcnt);
- if ((t = ctab) != NULL)
- for (cnt = 0;
- cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
- *outp++ = t[ch];
- else
- for (cnt = 0;
- cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
- *outp++ = ch;
- /*
- * Check for short record without a newline. Reassemble the
- * input block.
- */
- if (ch != '\n' && in.dbcnt < cbsz) {
- (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
- break;
- }
-
- /* Adjust the input buffer numbers. */
- in.dbcnt -= cnt;
- if (ch == '\n')
- --in.dbcnt;
-
- /* Pad short records with spaces. */
- if (cnt < cbsz)
- (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
- else {
- /*
- * If the next character wouldn't have ended the
- * block, it's a truncation.
- */
- if (!in.dbcnt || *inp != '\n')
- ++st.trunc;
-
- /* Toss characters to a newline. */
- for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
- if (!in.dbcnt)
- intrunc = 1;
- else
- --in.dbcnt;
- }
-
- /* Adjust output buffer numbers. */
- out.dbp += cbsz;
- if ((out.dbcnt += cbsz) >= out.dbsz)
- dd_out(0);
- outp = out.dbp;
- }
- in.dbp = in.db + in.dbcnt;
-}
-
-void
-block_close(void)
-{
-
- /*
- * Copy any remaining data into the output buffer and pad to a record.
- * Don't worry about truncation or translation, the input buffer is
- * always empty when truncating, and no characters have been added for
- * translation. The bottom line is that anything left in the input
- * buffer is a truncated record. Anything left in the output buffer
- * just wasn't big enough.
- */
- if (in.dbcnt) {
- ++st.trunc;
- (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
- (void)memset(out.dbp + in.dbcnt,
- ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
- out.dbcnt += cbsz;
- }
-}
-
-/*
- * Convert fixed length (cbsz) records to variable length. Deletes any
- * trailing blanks and appends a newline.
- *
- * max in buffer: MAX(ibs, cbsz) + cbsz
- * max out buffer: obs + cbsz
- */
-void
-unblock(void)
-{
- uint64_t cnt;
- u_char *inp;
- const u_char *t;
-
- /* Translation and case conversion. */
- if ((t = ctab) != NULL)
- for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--)
- *inp = t[*inp];
- /*
- * Copy records (max cbsz size chunks) into the output buffer. The
- * translation has to already be done or we might not recognize the
- * spaces.
- */
- for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
- for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
- if (t >= inp) {
- cnt = t - inp + 1;
- (void)memmove(out.dbp, inp, cnt);
- out.dbp += cnt;
- out.dbcnt += cnt;
- }
- ++out.dbcnt;
- *out.dbp++ = '\n';
- if (out.dbcnt >= out.dbsz)
- dd_out(0);
- }
- if (in.dbcnt)
- (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
- in.dbp = in.db + in.dbcnt;
-}
-
-void
-unblock_close(void)
-{
- uint64_t cnt;
- u_char *t;
-
- if (in.dbcnt) {
- warnx("%s: short input record", in.name);
- for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
- if (t >= in.db) {
- cnt = t - in.db + 1;
- (void)memmove(out.dbp, in.db, cnt);
- out.dbp += cnt;
- out.dbcnt += cnt;
- }
- ++out.dbcnt;
- *out.dbp++ = '\n';
- }
-}
-
-#endif /* NO_CONV */
-
-#define tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000)
-
-void
-summary(void)
-{
- char buf[100];
- int64_t mS;
- struct timeval tv;
-
- if (progress)
- (void)write(STDERR_FILENO, "\n", 1);
-
- (void)gettimeofday(&tv, NULL);
- mS = tv2mS(tv) - tv2mS(st.start);
- if (mS == 0)
- mS = 1;
- /* Use snprintf(3) so that we don't reenter stdio(3). */
- (void)snprintf(buf, sizeof(buf),
- "%llu+%llu records in\n%llu+%llu records out\n",
- (unsigned long long)st.in_full, (unsigned long long)st.in_part,
- (unsigned long long)st.out_full, (unsigned long long)st.out_part);
- (void)write(STDERR_FILENO, buf, strlen(buf));
- if (st.swab) {
- (void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n",
- (unsigned long long)st.swab,
- (st.swab == 1) ? "block" : "blocks");
- (void)write(STDERR_FILENO, buf, strlen(buf));
- }
- if (st.trunc) {
- (void)snprintf(buf, sizeof(buf), "%llu truncated %s\n",
- (unsigned long long)st.trunc,
- (st.trunc == 1) ? "block" : "blocks");
- (void)write(STDERR_FILENO, buf, strlen(buf));
- }
- if (st.sparse) {
- (void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n",
- (unsigned long long)st.sparse,
- (st.sparse == 1) ? "block" : "blocks");
- (void)write(STDERR_FILENO, buf, strlen(buf));
- }
- (void)snprintf(buf, sizeof(buf),
- "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n",
- (unsigned long long) st.bytes,
- (long) (mS / 1000),
- (int) (mS % 1000),
- (unsigned long long) (st.bytes * 1000LL / mS));
- (void)write(STDERR_FILENO, buf, strlen(buf));
-}
-
-void
-terminate(int notused)
-{
-
- exit(0);
- /* NOTREACHED */
-}
-
-static int c_arg(const void *, const void *);
-#ifndef NO_CONV
-static int c_conv(const void *, const void *);
-#endif
-static void f_bs(char *);
-static void f_cbs(char *);
-static void f_conv(char *);
-static void f_count(char *);
-static void f_files(char *);
-static void f_ibs(char *);
-static void f_if(char *);
-static void f_obs(char *);
-static void f_of(char *);
-static void f_seek(char *);
-static void f_skip(char *);
-static void f_progress(char *);
-
-static const struct arg {
- const char *name;
- void (*f)(char *);
- u_int set, noset;
-} args[] = {
- /* the array needs to be sorted by the first column so
- bsearch() can be used to find commands quickly */
- { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC },
- { "cbs", f_cbs, C_CBS, C_CBS },
- { "conv", f_conv, 0, 0 },
- { "count", f_count, C_COUNT, C_COUNT },
- { "files", f_files, C_FILES, C_FILES },
- { "ibs", f_ibs, C_IBS, C_BS|C_IBS },
- { "if", f_if, C_IF, C_IF },
- { "obs", f_obs, C_OBS, C_BS|C_OBS },
- { "of", f_of, C_OF, C_OF },
- { "progress", f_progress, 0, 0 },
- { "seek", f_seek, C_SEEK, C_SEEK },
- { "skip", f_skip, C_SKIP, C_SKIP },
-};
-
-/*
- * args -- parse JCL syntax of dd.
- */
-void
-jcl(char **argv)
-{
- struct arg *ap, tmp;
- char *oper, *arg;
-
- in.dbsz = out.dbsz = 512;
-
- while ((oper = *++argv) != NULL) {
- if ((arg = strchr(oper, '=')) == NULL) {
- fprintf(stderr, "unknown operand %s\n", oper);
- exit(1);
- /* NOTREACHED */
- }
- *arg++ = '\0';
- if (!*arg) {
- fprintf(stderr, "no value specified for %s\n", oper);
- exit(1);
- /* NOTREACHED */
- }
- tmp.name = oper;
- if (!(ap = (struct arg *)bsearch(&tmp, args,
- sizeof(args)/sizeof(struct arg), sizeof(struct arg),
- c_arg))) {
- fprintf(stderr, "unknown operand %s\n", tmp.name);
- exit(1);
- /* NOTREACHED */
- }
- if (ddflags & ap->noset) {
- fprintf(stderr,
- "%s: illegal argument combination or already set\n",
- tmp.name);
- exit(1);
- /* NOTREACHED */
- }
- ddflags |= ap->set;
- ap->f(arg);
- }
-
- /* Final sanity checks. */
-
- if (ddflags & C_BS) {
- /*
- * Bs is turned off by any conversion -- we assume the user
- * just wanted to set both the input and output block sizes
- * and didn't want the bs semantics, so we don't warn.
- */
- if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
- C_UNBLOCK | C_OSYNC | C_ASCII | C_EBCDIC | C_SPARSE)) {
- ddflags &= ~C_BS;
- ddflags |= C_IBS|C_OBS;
- }
-
- /* Bs supersedes ibs and obs. */
- if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
- fprintf(stderr, "bs supersedes ibs and obs\n");
- }
-
- /*
- * Ascii/ebcdic and cbs implies block/unblock.
- * Block/unblock requires cbs and vice-versa.
- */
- if (ddflags & (C_BLOCK|C_UNBLOCK)) {
- if (!(ddflags & C_CBS)) {
- fprintf(stderr, "record operations require cbs\n");
- exit(1);
- /* NOTREACHED */
- }
- cfunc = ddflags & C_BLOCK ? block : unblock;
- } else if (ddflags & C_CBS) {
- if (ddflags & (C_ASCII|C_EBCDIC)) {
- if (ddflags & C_ASCII) {
- ddflags |= C_UNBLOCK;
- cfunc = unblock;
- } else {
- ddflags |= C_BLOCK;
- cfunc = block;
- }
- } else {
- fprintf(stderr,
- "cbs meaningless if not doing record operations\n");
- exit(1);
- /* NOTREACHED */
- }
- } else
- cfunc = def;
-
- /* Read, write and seek calls take off_t as arguments.
- *
- * The following check is not done because an off_t is a quad
- * for current NetBSD implementations.
- *
- * if (in.offset > INT_MAX/in.dbsz || out.offset > INT_MAX/out.dbsz)
- * errx(1, "seek offsets cannot be larger than %d", INT_MAX);
- */
-}
-
-static int
-c_arg(const void *a, const void *b)
-{
-
- return (strcmp(((const struct arg *)a)->name,
- ((const struct arg *)b)->name));
-}
-
-static long long strsuftoll(const char* name, const char* arg, int def, unsigned int max)
-{
- long long result;
-
- if (sscanf(arg, "%lld", &result) == 0)
- result = def;
- return result;
-}
-
-static void
-f_bs(char *arg)
-{
-
- in.dbsz = out.dbsz = strsuftoll("block size", arg, 1, UINT_MAX);
-}
-
-static void
-f_cbs(char *arg)
-{
-
- cbsz = strsuftoll("conversion record size", arg, 1, UINT_MAX);
-}
-
-static void
-f_count(char *arg)
-{
-
- cpy_cnt = strsuftoll("block count", arg, 0, LLONG_MAX);
- if (!cpy_cnt)
- terminate(0);
-}
-
-static void
-f_files(char *arg)
-{
-
- files_cnt = (u_int)strsuftoll("file count", arg, 0, UINT_MAX);
- if (!files_cnt)
- terminate(0);
-}
-
-static void
-f_ibs(char *arg)
-{
-
- if (!(ddflags & C_BS))
- in.dbsz = strsuftoll("input block size", arg, 1, UINT_MAX);
-}
-
-static void
-f_if(char *arg)
-{
-
- in.name = arg;
-}
-
-static void
-f_obs(char *arg)
-{
-
- if (!(ddflags & C_BS))
- out.dbsz = strsuftoll("output block size", arg, 1, UINT_MAX);
-}
-
-static void
-f_of(char *arg)
-{
-
- out.name = arg;
-}
-
-static void
-f_seek(char *arg)
-{
-
- out.offset = strsuftoll("seek blocks", arg, 0, LLONG_MAX);
-}
-
-static void
-f_skip(char *arg)
-{
-
- in.offset = strsuftoll("skip blocks", arg, 0, LLONG_MAX);
-}
-
-static void
-f_progress(char *arg)
-{
-
- if (*arg != '0')
- progress = 1;
-}
-
-#ifdef NO_CONV
-/* Build a small version (i.e. for a ramdisk root) */
-static void
-f_conv(char *arg)
-{
-
- fprintf(stderr, "conv option disabled\n");
- exit(1);
- /* NOTREACHED */
-}
-#else /* NO_CONV */
-
-static const struct conv {
- const char *name;
- u_int set, noset;
- const u_char *ctab;
-} clist[] = {
- { "block", C_BLOCK, C_UNBLOCK, NULL },
- { "fdatasync", C_FDATASYNC, 0, NULL },
- { "noerror", C_NOERROR, 0, NULL },
- { "notrunc", C_NOTRUNC, 0, NULL },
- { "osync", C_OSYNC, C_BS, NULL },
- { "sparse", C_SPARSE, 0, NULL },
- { "swab", C_SWAB, 0, NULL },
- { "sync", C_SYNC, 0, NULL },
- { "unblock", C_UNBLOCK, C_BLOCK, NULL },
- /* If you add items to this table, be sure to add the
- * conversions to the C_BS check in the jcl routine above.
- */
-};
-
-static void
-f_conv(char *arg)
-{
- struct conv *cp, tmp;
-
- while (arg != NULL) {
- tmp.name = strsep(&arg, ",");
- if (!(cp = (struct conv *)bsearch(&tmp, clist,
- sizeof(clist)/sizeof(struct conv), sizeof(struct conv),
- c_conv))) {
- errx(EXIT_FAILURE, "unknown conversion %s", tmp.name);
- /* NOTREACHED */
- }
- if (ddflags & cp->noset) {
- errx(EXIT_FAILURE, "%s: illegal conversion combination", tmp.name);
- /* NOTREACHED */
- }
- ddflags |= cp->set;
- if (cp->ctab)
- ctab = cp->ctab;
- }
-}
-
-static int
-c_conv(const void *a, const void *b)
-{
-
- return (strcmp(((const struct conv *)a)->name,
- ((const struct conv *)b)->name));
-}
-
-#endif /* NO_CONV */
-
-
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/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/getevent.c b/toolbox/getevent.c
index ed381f5..da83ec3 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -295,6 +295,7 @@
{
int version;
int fd;
+ int clkid = CLOCK_MONOTONIC;
struct pollfd *new_ufds;
char **new_device_names;
char name[80];
@@ -335,6 +336,11 @@
idstr[0] = '\0';
}
+ if (ioctl(fd, EVIOCSCLOCKID, &clkid) != 0) {
+ fprintf(stderr, "Can't enable monotonic clock reporting: %s\n", strerror(errno));
+ // a non-fatal error
+ }
+
new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
if(new_ufds == NULL) {
fprintf(stderr, "out of memory\n");
@@ -470,9 +476,9 @@
return 0;
}
-static void usage(int argc, char *argv[])
+static void usage(char *name)
{
- fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", argv[0]);
+ fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", name);
fprintf(stderr, " -t: show time stamps\n");
fprintf(stderr, " -n: don't print newlines\n");
fprintf(stderr, " -s: print switch states for given bits\n");
@@ -492,13 +498,11 @@
int c;
int i;
int res;
- int pollres;
int get_time = 0;
int print_device = 0;
char *newline = "\n";
uint16_t get_switch = 0;
struct input_event event;
- int version;
int print_flags = 0;
int print_flags_set = 0;
int dont_block = -1;
@@ -570,7 +574,7 @@
fprintf(stderr, "%s: invalid option -%c\n",
argv[0], optopt);
case 'h':
- usage(argc, argv);
+ usage(argv[0]);
exit(1);
}
} while (1);
@@ -582,7 +586,7 @@
optind++;
}
if (optind != argc) {
- usage(argc, argv);
+ usage(argv[0]);
exit(1);
}
nfds = 1;
@@ -629,7 +633,8 @@
return 0;
while(1) {
- pollres = poll(ufds, nfds, -1);
+ //int pollres =
+ poll(ufds, nfds, -1);
//printf("poll %d, returned %d\n", nfds, pollres);
if(ufds[0].revents & POLLIN) {
read_notify(device_path, ufds[0].fd, print_flags);
diff --git a/toolbox/getevent.h b/toolbox/getevent.h
index 2b76209..0482d04 100644
--- a/toolbox/getevent.h
+++ b/toolbox/getevent.h
@@ -652,6 +652,7 @@
LABEL_END,
};
+#if 0
static struct label id_labels[] = {
LABEL(ID_BUS),
LABEL(ID_VENDOR),
@@ -682,6 +683,7 @@
LABEL(BUS_SPI),
LABEL_END,
};
+#endif
static struct label mt_tool_labels[] = {
LABEL(MT_TOOL_FINGER),
diff --git a/toolbox/getprop.c b/toolbox/getprop.c
index 7fd694d..dcc0ea0 100644
--- a/toolbox/getprop.c
+++ b/toolbox/getprop.c
@@ -32,8 +32,6 @@
int getprop_main(int argc, char *argv[])
{
- int n = 0;
-
if (argc == 1) {
list_properties();
} else {
diff --git a/toolbox/hd.c b/toolbox/hd.c
index 0d2f96a..7c9998e 100644
--- a/toolbox/hd.c
+++ b/toolbox/hd.c
@@ -14,7 +14,6 @@
unsigned char buf[4096];
int res;
int read_len;
- int rv = 0;
int i;
int filepos = 0;
int sum;
diff --git a/toolbox/ifconfig.c b/toolbox/ifconfig.c
index 80c0e5c..b953176 100644
--- a/toolbox/ifconfig.c
+++ b/toolbox/ifconfig.c
@@ -61,11 +61,11 @@
{
struct ifreq ifr;
int s;
- unsigned int addr, mask, flags;
+ unsigned int flags;
char astring[20];
char mstring[20];
char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
-
+
argc--;
argv++;
@@ -85,13 +85,17 @@
perror(ifr.ifr_name);
return -1;
} else
- addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+ 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
- mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+ strlcpy(mstring,
+ inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr),
+ sizeof(mstring));
if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
perror(ifr.ifr_name);
@@ -99,16 +103,6 @@
} else
flags = ifr.ifr_flags;
- sprintf(astring, "%d.%d.%d.%d",
- addr & 0xff,
- ((addr >> 8) & 0xff),
- ((addr >> 16) & 0xff),
- ((addr >> 24) & 0xff));
- sprintf(mstring, "%d.%d.%d.%d",
- mask & 0xff,
- ((mask >> 8) & 0xff),
- ((mask >> 16) & 0xff),
- ((mask >> 24) & 0xff));
printf("%s: ip %s mask %s flags [", ifr.ifr_name,
astring,
mstring
diff --git a/toolbox/insmod.c b/toolbox/insmod.c
deleted file mode 100644
index fb1448b..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]), 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 fb555d2..73539d1 100644
--- a/toolbox/ioctl.c
+++ b/toolbox/ioctl.c
@@ -21,9 +21,9 @@
int arg_size = 4;
int direct_arg = 0;
uint32_t ioctl_nr;
- void *ioctl_args;
+ void *ioctl_args = NULL;
uint8_t *ioctl_argp;
- uint8_t *ioctl_argp_save;
+ uint8_t *ioctl_argp_save = NULL;
int rem;
do {
@@ -45,7 +45,7 @@
break;
case 'h':
fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
- " -l <lenght> Length of io buffer\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"
@@ -63,10 +63,14 @@
exit(1);
}
- fd = open(argv[optind], O_RDWR | O_SYNC);
- if (fd < 0) {
- fprintf(stderr, "cannot open %s\n", argv[optind]);
- return 1;
+ if (!strcmp(argv[optind], "-")) {
+ 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;
+ }
}
optind++;
@@ -112,6 +116,7 @@
else
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;
}
@@ -124,5 +129,6 @@
}
printf("\n");
}
+ free(ioctl_args);
return 0;
}
diff --git a/toolbox/kill.c b/toolbox/kill.c
deleted file mode 100644
index fa2f649..0000000
--- a/toolbox/kill.c
+++ /dev/null
@@ -1,148 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include <sys/types.h>
-#include <signal.h>
-
-static struct {
- unsigned int number;
- char *name;
-} signals[] = {
-#define _SIG(name) {SIG##name, #name}
- /* Single Unix Specification signals */
- _SIG(ABRT),
- _SIG(ALRM),
- _SIG(FPE),
- _SIG(HUP),
- _SIG(ILL),
- _SIG(INT),
- _SIG(KILL),
- _SIG(PIPE),
- _SIG(QUIT),
- _SIG(SEGV),
- _SIG(TERM),
- _SIG(USR1),
- _SIG(USR2),
- _SIG(CHLD),
- _SIG(CONT),
- _SIG(STOP),
- _SIG(TSTP),
- _SIG(TTIN),
- _SIG(TTOU),
- _SIG(BUS),
- _SIG(POLL),
- _SIG(PROF),
- _SIG(SYS),
- _SIG(TRAP),
- _SIG(URG),
- _SIG(VTALRM),
- _SIG(XCPU),
- _SIG(XFSZ),
- /* non-SUS signals */
- _SIG(IO),
- _SIG(PWR),
-#ifdef SIGSTKFLT
- _SIG(STKFLT),
-#endif
- _SIG(WINCH),
-#undef _SIG
-};
-
-/* To indicate a matching signal was not found */
-static const unsigned int SENTINEL = (unsigned int) -1;
-
-void list_signals()
-{
- unsigned int sorted_signals[_NSIG];
- unsigned int i;
- unsigned int num;
-
- memset(sorted_signals, SENTINEL, sizeof(sorted_signals));
-
- // Sort the signals
- for (i = 0; i < sizeof(signals)/sizeof(signals[0]); i++) {
- sorted_signals[signals[i].number] = i;
- }
-
- num = 0;
- for (i = 1; i < _NSIG; i++) {
- unsigned int index = sorted_signals[i];
- if (index == SENTINEL) {
- continue;
- }
-
- fprintf(stderr, "%2d) SIG%-9s ", i, signals[index].name);
-
- if ((num++ % 4) == 3) {
- fprintf(stderr, "\n");
- }
- }
-
- if ((num % 4) == 3) {
- fprintf(stderr, "\n");
- }
-}
-
-unsigned int name_to_signal(const char* name)
-{
- unsigned int i;
-
- for (i = 1; i < sizeof(signals) / sizeof(signals[0]); i++) {
- if (!strcasecmp(name, signals[i].name)) {
- return signals[i].number;
- }
- }
-
- return SENTINEL;
-}
-
-int kill_main(int argc, char **argv)
-{
- unsigned int sig = SIGTERM;
- int result = 0;
-
- argc--;
- argv++;
-
- if (argc >= 1 && argv[0][0] == '-') {
- char *endptr;
- size_t arg_len = strlen(argv[0]);
- if (arg_len < 2) {
- fprintf(stderr, "invalid argument: -\n");
- return -1;
- }
-
- char* arg = argv[0] + 1;
- if (arg_len == 2 && *arg == 'l') {
- list_signals();
- return 0;
- }
-
- sig = strtol(arg, &endptr, 10);
- if (*endptr != '\0') {
- sig = name_to_signal(arg);
- if (sig == SENTINEL) {
- fprintf(stderr, "invalid signal name: %s\n", arg);
- return -1;
- }
- }
-
- argc--;
- argv++;
- }
-
- while(argc > 0){
- int pid = atoi(argv[0]);
- int err = kill(pid, sig);
- if (err < 0) {
- result = err;
- fprintf(stderr, "could not kill pid %d: %s\n", pid, strerror(errno));
- }
-
- argc--;
- argv++;
- }
-
- return result;
-}
diff --git a/toolbox/ln.c b/toolbox/ln.c
deleted file mode 100644
index dcd5e3a..0000000
--- a/toolbox/ln.c
+++ /dev/null
@@ -1,34 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-
-static int usage()
-{
- fprintf(stderr,"ln [-s] <target> <name>\n");
- return -1;
-}
-
-int ln_main(int argc, char *argv[])
-{
- int symbolic = 0;
- int ret;
- if(argc < 2) return usage();
-
- if(!strcmp(argv[1],"-s")) {
- symbolic = 1;
- argc--;
- argv++;
- }
-
- if(argc < 3) return usage();
-
- if(symbolic) {
- ret = symlink(argv[1], argv[2]);
- } else {
- ret = link(argv[1], argv[2]);
- }
- if(ret < 0)
- fprintf(stderr, "link failed %s\n", strerror(errno));
- return ret;
-}
diff --git a/toolbox/load_policy.c b/toolbox/load_policy.c
index eb5aba6..90d48c4 100644
--- a/toolbox/load_policy.c
+++ b/toolbox/load_policy.c
@@ -10,7 +10,7 @@
int load_policy_main(int argc, char **argv)
{
- int fd, rc, vers;
+ int fd, rc;
struct stat sb;
void *map;
const char *path;
diff --git a/toolbox/ls.c b/toolbox/ls.c
index 06910ee..963fcb5 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -33,7 +33,7 @@
// fwd
static int listpath(const char *name, int flags);
-static char mode2kind(unsigned mode)
+static char mode2kind(mode_t mode)
{
switch(mode & S_IFMT){
case S_IFSOCK: return 's';
@@ -47,7 +47,7 @@
}
}
-static void mode2str(unsigned mode, char *out)
+void strmode(mode_t mode, char *out)
{
*out++ = mode2kind(mode);
@@ -180,7 +180,7 @@
name++;
}
- mode2str(s->st_mode, mode);
+ strmode(s->st_mode, mode);
if (flags & LIST_LONG_NUMERIC) {
snprintf(user, sizeof(user), "%u", s->st_uid);
snprintf(group, sizeof(group), "%u", s->st_gid);
@@ -260,7 +260,7 @@
return -1;
}
- mode2str(s->st_mode, mode);
+ strmode(s->st_mode, mode);
user2str(s->st_uid, user, sizeof(user));
group2str(s->st_gid, group, sizeof(group));
@@ -443,7 +443,6 @@
int ls_main(int argc, char **argv)
{
int flags = 0;
- int listed = 0;
if(argc > 1) {
int i;
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 af321af..bee981d 100644
--- a/toolbox/lsof.c
+++ b/toolbox/lsof.c
@@ -99,10 +99,7 @@
static void print_maps(struct pid_info_t* info)
{
FILE *maps;
- char buffer[PATH_MAX + 100];
-
size_t offset;
- int major, minor;
char device[10];
long int inode;
char file[PATH_MAX];
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
index 2fb8b05..5de4d9e 100644
--- a/toolbox/md5.c
+++ b/toolbox/md5.c
@@ -4,12 +4,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <md5.h>
-
-/* When this was written, bionic's md5.h did not define this. */
-#ifndef MD5_DIGEST_LENGTH
-#define MD5_DIGEST_LENGTH 16
-#endif
+#include <openssl/md5.h>
static int usage()
{
@@ -30,7 +25,6 @@
return -1;
}
- /* Note that bionic's MD5_* functions return void. */
MD5_Init(&md5_ctx);
while (1) {
diff --git a/toolbox/mkdir.c b/toolbox/mkdir.c
index 656970a..398d350 100644
--- a/toolbox/mkdir.c
+++ b/toolbox/mkdir.c
@@ -15,7 +15,6 @@
int mkdir_main(int argc, char *argv[])
{
- int symbolic = 0;
int ret;
if(argc < 2 || strcmp(argv[1], "--help") == 0) {
return usage();
diff --git a/toolbox/mknod.c b/toolbox/mknod.c
new file mode 100644
index 0000000..0fedece
--- /dev/null
+++ b/toolbox/mknod.c
@@ -0,0 +1,95 @@
+/*
+ * 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/mv.c b/toolbox/mv.c
deleted file mode 100644
index a5bc225..0000000
--- a/toolbox/mv.c
+++ /dev/null
@@ -1,59 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-
-int mv_main(int argc, char *argv[])
-{
- const char* dest;
- struct stat st;
- int i;
-
- if (argc < 3) {
- fprintf(stderr,"USAGE: %s <source...> <destination>\n", argv[0]);
- return -1;
- }
-
- /* check if destination exists */
- dest = argv[argc - 1];
- if (stat(dest, &st)) {
- /* an error, unless the destination was missing */
- if (errno != ENOENT) {
- fprintf(stderr, "failed on %s - %s\n", dest, strerror(errno));
- return -1;
- }
- st.st_mode = 0;
- }
-
- for (i = 1; i < argc - 1; i++) {
- const char *source = argv[i];
- char fullDest[PATH_MAX + 1 + PATH_MAX + 1];
- /* assume we build "dest/source", and let rename() fail on pathsize */
- if (strlen(dest) + 1 + strlen(source) + 1 > sizeof(fullDest)) {
- fprintf(stderr, "path too long\n");
- return -1;
- }
- strcpy(fullDest, dest);
-
- /* if destination is a directory, concat the source file name */
- if (S_ISDIR(st.st_mode)) {
- const char *fileName = strrchr(source, '/');
- if (fullDest[strlen(fullDest)-1] != '/') {
- strcat(fullDest, "/");
- }
- strcat(fullDest, fileName ? fileName + 1 : source);
- }
-
- /* attempt to move it */
- if (rename(source, fullDest)) {
- fprintf(stderr, "failed on '%s' - %s\n", source, strerror(errno));
- return -1;
- }
- }
-
- return 0;
-}
-
diff --git a/toolbox/nandread.c b/toolbox/nandread.c
index 971c232..bd19942 100644
--- a/toolbox/nandread.c
+++ b/toolbox/nandread.c
@@ -1,9 +1,10 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include <mtd/mtd-user.h>
@@ -189,18 +190,18 @@
for (pos = start, opos = 0; pos < end; pos += mtdinfo.writesize) {
bad_block = 0;
if (verbose > 3)
- printf("reading at %llx\n", pos);
+ printf("reading at %" PRIx64 "\n", pos);
lseek64(fd, pos, SEEK_SET);
ret = read(fd, buffer, mtdinfo.writesize + rawmode);
if (ret < (int)mtdinfo.writesize) {
- fprintf(stderr, "short read at %llx, %d\n", pos, ret);
+ fprintf(stderr, "short read at %" PRIx64 ", %d\n", pos, ret);
bad_block = 2;
}
if (!rawmode) {
oobbuf.start = pos;
ret = ioctl(fd, MEMREADOOB, &oobbuf);
if (ret) {
- fprintf(stderr, "failed to read oob data at %llx, %d\n", pos, ret);
+ fprintf(stderr, "failed to read oob data at %" PRIx64 ", %d\n", pos, ret);
bad_block = 2;
}
}
@@ -213,17 +214,17 @@
bpos = pos / mtdinfo.erasesize * mtdinfo.erasesize;
ret = ioctl(fd, MEMGETBADBLOCK, &bpos);
if (ret && errno != EOPNOTSUPP) {
- printf("badblock at %llx\n", pos);
+ printf("badblock at %" PRIx64 "\n", pos);
bad_block = 1;
}
if (ecc.corrected != last_ecc.corrected)
- printf("ecc corrected, %u, at %llx\n", ecc.corrected - last_ecc.corrected, pos);
+ printf("ecc corrected, %u, at %" PRIx64 "\n", ecc.corrected - last_ecc.corrected, pos);
if (ecc.failed != last_ecc.failed)
- printf("ecc failed, %u, at %llx\n", ecc.failed - last_ecc.failed, pos);
+ printf("ecc failed, %u, at %" PRIx64 "\n", ecc.failed - last_ecc.failed, pos);
if (ecc.badblocks != last_ecc.badblocks)
- printf("ecc badblocks, %u, at %llx\n", ecc.badblocks - last_ecc.badblocks, pos);
+ printf("ecc badblocks, %u, at %" PRIx64 "\n", ecc.badblocks - last_ecc.badblocks, pos);
if (ecc.bbtblocks != last_ecc.bbtblocks)
- printf("ecc bbtblocks, %u, at %llx\n", ecc.bbtblocks - last_ecc.bbtblocks, pos);
+ printf("ecc bbtblocks, %u, at %" PRIx64 "\n", ecc.bbtblocks - last_ecc.bbtblocks, pos);
if (!rawmode) {
oob_fixed = (uint8_t *)oob_data;
@@ -241,18 +242,18 @@
if (outfd >= 0) {
ret = write(outfd, buffer, mtdinfo.writesize + spare_size);
if (ret < (int)(mtdinfo.writesize + spare_size)) {
- fprintf(stderr, "short write at %llx, %d\n", pos, ret);
+ fprintf(stderr, "short write at %" PRIx64 ", %d\n", pos, ret);
close(outfd);
outfd = -1;
}
if (ecc.corrected != last_ecc.corrected)
- fprintf(statusfile, "%08llx: ecc corrected\n", opos);
+ fprintf(statusfile, "%08" PRIx64 ": ecc corrected\n", opos);
if (ecc.failed != last_ecc.failed)
- fprintf(statusfile, "%08llx: ecc failed\n", opos);
+ fprintf(statusfile, "%08" PRIx64 ": ecc failed\n", opos);
if (bad_block == 1)
- fprintf(statusfile, "%08llx: badblock\n", opos);
+ fprintf(statusfile, "%08" PRIx64 ": badblock\n", opos);
if (bad_block == 2)
- fprintf(statusfile, "%08llx: read error\n", opos);
+ fprintf(statusfile, "%08" PRIx64 ": read error\n", opos);
opos += mtdinfo.writesize + spare_size;
}
@@ -261,7 +262,7 @@
if (test_empty(buffer, mtdinfo.writesize + mtdinfo.oobsize + spare_size))
empty_pages++;
else if (verbose > 2 || (verbose > 1 && !(pos & (mtdinfo.erasesize - 1))))
- printf("page at %llx (%d oobbytes): %08x %08x %08x %08x "
+ printf("page at %" PRIx64 " (%d oobbytes): %08x %08x %08x %08x "
"%08x %08x %08x %08x\n", pos, oobbuf.start,
oob_data[0], oob_data[1], oob_data[2], oob_data[3],
oob_data[4], oob_data[5], oob_data[6], oob_data[7]);
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index 27dca42..01517fd 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -27,20 +27,20 @@
#ifndef lint
static const char rcsid[] =
- "$FreeBSD: src/sbin/newfs_msdos/newfs_msdos.c,v 1.33 2009/04/11 14:56:29 ed Exp $";
+ "$FreeBSD: src/sbin/newfs_msdos/newfs_msdos.c,v 1.33 2009/04/11 14:56:29 ed Exp $";
#endif /* not lint */
#include <sys/param.h>
#ifndef ANDROID
- #include <sys/fdcio.h>
- #include <sys/disk.h>
- #include <sys/disklabel.h>
- #include <sys/mount.h>
+#include <sys/fdcio.h>
+#include <sys/disk.h>
+#include <sys/disklabel.h>
+#include <sys/mount.h>
#else
- #include <stdarg.h>
- #include <linux/fs.h>
- #include <linux/hdreg.h>
+#include <stdarg.h>
+#include <linux/fs.h>
+#include <linux/hdreg.h>
#endif
#include <sys/stat.h>
@@ -58,44 +58,44 @@
#include <time.h>
#include <unistd.h>
-#define MAXU16 0xffff /* maximum unsigned 16-bit quantity */
-#define BPN 4 /* bits per nibble */
-#define NPB 2 /* nibbles per byte */
+#define MAXU16 0xffff /* maximum unsigned 16-bit quantity */
+#define BPN 4 /* bits per nibble */
+#define NPB 2 /* nibbles per byte */
-#define DOSMAGIC 0xaa55 /* DOS magic number */
-#define MINBPS 512 /* minimum bytes per sector */
-#define MAXSPC 128 /* maximum sectors per cluster */
-#define MAXNFT 16 /* maximum number of FATs */
-#define DEFBLK 4096 /* default block size */
-#define DEFBLK16 2048 /* default block size FAT16 */
-#define DEFRDE 512 /* default root directory entries */
-#define RESFTE 2 /* reserved FAT entries */
-#define MINCLS12 1 /* minimum FAT12 clusters */
-#define MINCLS16 0x1000 /* minimum FAT16 clusters */
-#define MINCLS32 2 /* minimum FAT32 clusters */
-#define MAXCLS12 0xfed /* maximum FAT12 clusters */
-#define MAXCLS16 0xfff5 /* maximum FAT16 clusters */
-#define MAXCLS32 0xffffff5 /* maximum FAT32 clusters */
+#define DOSMAGIC 0xaa55 /* DOS magic number */
+#define MINBPS 512 /* minimum bytes per sector */
+#define MAXSPC 128 /* maximum sectors per cluster */
+#define MAXNFT 16 /* maximum number of FATs */
+#define DEFBLK 4096 /* default block size */
+#define DEFBLK16 2048 /* default block size FAT16 */
+#define DEFRDE 512 /* default root directory entries */
+#define RESFTE 2 /* reserved FAT entries */
+#define MINCLS12 1 /* minimum FAT12 clusters */
+#define MINCLS16 0x1000 /* minimum FAT16 clusters */
+#define MINCLS32 2 /* minimum FAT32 clusters */
+#define MAXCLS12 0xfed /* maximum FAT12 clusters */
+#define MAXCLS16 0xfff5 /* maximum FAT16 clusters */
+#define MAXCLS32 0xffffff5 /* maximum FAT32 clusters */
-#define mincls(fat) ((fat) == 12 ? MINCLS12 : \
- (fat) == 16 ? MINCLS16 : \
- MINCLS32)
+#define mincls(fat) ((fat) == 12 ? MINCLS12 : \
+ (fat) == 16 ? MINCLS16 : \
+ MINCLS32)
-#define maxcls(fat) ((fat) == 12 ? MAXCLS12 : \
- (fat) == 16 ? MAXCLS16 : \
- MAXCLS32)
+#define maxcls(fat) ((fat) == 12 ? MAXCLS12 : \
+ (fat) == 16 ? MAXCLS16 : \
+ MAXCLS32)
-#define mk1(p, x) \
+#define mk1(p, x) \
(p) = (u_int8_t)(x)
-#define mk2(p, x) \
- (p)[0] = (u_int8_t)(x), \
+#define mk2(p, x) \
+ (p)[0] = (u_int8_t)(x), \
(p)[1] = (u_int8_t)((x) >> 010)
-#define mk4(p, x) \
- (p)[0] = (u_int8_t)(x), \
- (p)[1] = (u_int8_t)((x) >> 010), \
- (p)[2] = (u_int8_t)((x) >> 020), \
+#define mk4(p, x) \
+ (p)[0] = (u_int8_t)(x), \
+ (p)[1] = (u_int8_t)((x) >> 010), \
+ (p)[2] = (u_int8_t)((x) >> 020), \
(p)[3] = (u_int8_t)((x) >> 030)
#define argto1(arg, lo, msg) argtou(arg, lo, 0xff, msg)
@@ -104,71 +104,71 @@
#define argtox(arg, lo, msg) argtou(arg, lo, UINT_MAX, msg)
struct bs {
- u_int8_t jmp[3]; /* bootstrap entry point */
- u_int8_t oem[8]; /* OEM name and version */
+ u_int8_t jmp[3]; /* bootstrap entry point */
+ u_int8_t oem[8]; /* OEM name and version */
};
struct bsbpb {
- u_int8_t bps[2]; /* bytes per sector */
- u_int8_t spc; /* sectors per cluster */
- u_int8_t res[2]; /* reserved sectors */
- u_int8_t nft; /* number of FATs */
- u_int8_t rde[2]; /* root directory entries */
- u_int8_t sec[2]; /* total sectors */
- u_int8_t mid; /* media descriptor */
- u_int8_t spf[2]; /* sectors per FAT */
- u_int8_t spt[2]; /* sectors per track */
- u_int8_t hds[2]; /* drive heads */
- u_int8_t hid[4]; /* hidden sectors */
- u_int8_t bsec[4]; /* big total sectors */
+ u_int8_t bps[2]; /* bytes per sector */
+ u_int8_t spc; /* sectors per cluster */
+ u_int8_t res[2]; /* reserved sectors */
+ u_int8_t nft; /* number of FATs */
+ u_int8_t rde[2]; /* root directory entries */
+ u_int8_t sec[2]; /* total sectors */
+ u_int8_t mid; /* media descriptor */
+ u_int8_t spf[2]; /* sectors per FAT */
+ u_int8_t spt[2]; /* sectors per track */
+ u_int8_t hds[2]; /* drive heads */
+ u_int8_t hid[4]; /* hidden sectors */
+ u_int8_t bsec[4]; /* big total sectors */
};
struct bsxbpb {
- u_int8_t bspf[4]; /* big sectors per FAT */
- u_int8_t xflg[2]; /* FAT control flags */
- u_int8_t vers[2]; /* file system version */
- u_int8_t rdcl[4]; /* root directory start cluster */
- u_int8_t infs[2]; /* file system info sector */
- u_int8_t bkbs[2]; /* backup boot sector */
- u_int8_t rsvd[12]; /* reserved */
+ u_int8_t bspf[4]; /* big sectors per FAT */
+ u_int8_t xflg[2]; /* FAT control flags */
+ u_int8_t vers[2]; /* file system version */
+ u_int8_t rdcl[4]; /* root directory start cluster */
+ u_int8_t infs[2]; /* file system info sector */
+ u_int8_t bkbs[2]; /* backup boot sector */
+ u_int8_t rsvd[12]; /* reserved */
};
struct bsx {
- u_int8_t drv; /* drive number */
- u_int8_t rsvd; /* reserved */
- u_int8_t sig; /* extended boot signature */
- u_int8_t volid[4]; /* volume ID number */
- u_int8_t label[11]; /* volume label */
- u_int8_t type[8]; /* file system type */
+ u_int8_t drv; /* drive number */
+ u_int8_t rsvd; /* reserved */
+ u_int8_t sig; /* extended boot signature */
+ u_int8_t volid[4]; /* volume ID number */
+ u_int8_t label[11]; /* volume label */
+ u_int8_t type[8]; /* file system type */
};
struct de {
- u_int8_t namext[11]; /* name and extension */
- u_int8_t attr; /* attributes */
- u_int8_t rsvd[10]; /* reserved */
- u_int8_t time[2]; /* creation time */
- u_int8_t date[2]; /* creation date */
- u_int8_t clus[2]; /* starting cluster */
- u_int8_t size[4]; /* size */
+ u_int8_t namext[11]; /* name and extension */
+ u_int8_t attr; /* attributes */
+ u_int8_t rsvd[10]; /* reserved */
+ u_int8_t time[2]; /* creation time */
+ u_int8_t date[2]; /* creation date */
+ u_int8_t clus[2]; /* starting cluster */
+ u_int8_t size[4]; /* size */
};
struct bpb {
- u_int bps; /* bytes per sector */
- u_int spc; /* sectors per cluster */
- u_int res; /* reserved sectors */
- u_int nft; /* number of FATs */
- u_int rde; /* root directory entries */
- u_int sec; /* total sectors */
- u_int mid; /* media descriptor */
- u_int spf; /* sectors per FAT */
- u_int spt; /* sectors per track */
- u_int hds; /* drive heads */
- u_int hid; /* hidden sectors */
- u_int bsec; /* big total sectors */
- u_int bspf; /* big sectors per FAT */
- u_int rdcl; /* root directory start cluster */
- u_int infs; /* file system info sector */
- u_int bkbs; /* backup boot sector */
+ u_int bps; /* bytes per sector */
+ u_int spc; /* sectors per cluster */
+ u_int res; /* reserved sectors */
+ u_int nft; /* number of FATs */
+ u_int rde; /* root directory entries */
+ u_int sec; /* total sectors */
+ u_int mid; /* media descriptor */
+ u_int spf; /* sectors per FAT */
+ u_int spt; /* sectors per track */
+ u_int hds; /* drive heads */
+ u_int hid; /* hidden sectors */
+ u_int bsec; /* big total sectors */
+ u_int bspf; /* big sectors per FAT */
+ u_int rdcl; /* root directory start cluster */
+ u_int infs; /* file system info sector */
+ u_int bkbs; /* backup boot sector */
};
#define BPBGAP 0, 0, 0, 0, 0, 0
@@ -181,35 +181,35 @@
{"180", {512, 1, 1, 2, 64, 360, 0xfc, 2, 9, 1, BPBGAP}},
{"320", {512, 2, 1, 2, 112, 640, 0xff, 1, 8, 2, BPBGAP}},
{"360", {512, 2, 1, 2, 112, 720, 0xfd, 2, 9, 2, BPBGAP}},
- {"640", {512, 2, 1, 2, 112, 1280, 0xfb, 2, 8, 2, BPBGAP}},
+ {"640", {512, 2, 1, 2, 112, 1280, 0xfb, 2, 8, 2, BPBGAP}},
{"720", {512, 2, 1, 2, 112, 1440, 0xf9, 3, 9, 2, BPBGAP}},
{"1200", {512, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2, BPBGAP}},
- {"1232", {1024,1, 1, 2, 192, 1232, 0xfe, 2, 8, 2, BPBGAP}},
+ {"1232", {1024,1, 1, 2, 192, 1232, 0xfe, 2, 8, 2, BPBGAP}},
{"1440", {512, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2, BPBGAP}},
{"2880", {512, 2, 1, 2, 240, 5760, 0xf0, 9, 36, 2, BPBGAP}}
};
static const u_int8_t bootcode[] = {
- 0xfa, /* cli */
- 0x31, 0xc0, /* xor ax,ax */
- 0x8e, 0xd0, /* mov ss,ax */
- 0xbc, 0x00, 0x7c, /* mov sp,7c00h */
- 0xfb, /* sti */
- 0x8e, 0xd8, /* mov ds,ax */
- 0xe8, 0x00, 0x00, /* call $ + 3 */
- 0x5e, /* pop si */
- 0x83, 0xc6, 0x19, /* add si,+19h */
- 0xbb, 0x07, 0x00, /* mov bx,0007h */
- 0xfc, /* cld */
- 0xac, /* lodsb */
- 0x84, 0xc0, /* test al,al */
- 0x74, 0x06, /* jz $ + 8 */
- 0xb4, 0x0e, /* mov ah,0eh */
- 0xcd, 0x10, /* int 10h */
- 0xeb, 0xf5, /* jmp $ - 9 */
- 0x30, 0xe4, /* xor ah,ah */
- 0xcd, 0x16, /* int 16h */
- 0xcd, 0x19, /* int 19h */
+ 0xfa, /* cli */
+ 0x31, 0xc0, /* xor ax,ax */
+ 0x8e, 0xd0, /* mov ss,ax */
+ 0xbc, 0x00, 0x7c, /* mov sp,7c00h */
+ 0xfb, /* sti */
+ 0x8e, 0xd8, /* mov ds,ax */
+ 0xe8, 0x00, 0x00, /* call $ + 3 */
+ 0x5e, /* pop si */
+ 0x83, 0xc6, 0x19, /* add si,+19h */
+ 0xbb, 0x07, 0x00, /* mov bx,0007h */
+ 0xfc, /* cld */
+ 0xac, /* lodsb */
+ 0x84, 0xc0, /* test al,al */
+ 0x74, 0x06, /* jz $ + 8 */
+ 0xb4, 0x0e, /* mov ah,0eh */
+ 0xcd, 0x10, /* int 10h */
+ 0xeb, 0xf5, /* jmp $ - 9 */
+ 0x30, 0xe4, /* xor ah,ah */
+ 0xcd, 0x16, /* int 16h */
+ 0xcd, 0x19, /* int 19h */
0x0d, 0x0a,
'N', 'o', 'n', '-', 's', 'y', 's', 't',
'e', 'm', ' ', 'd', 'i', 's', 'k',
@@ -223,8 +223,7 @@
static void check_mounted(const char *, mode_t);
static void getstdfmt(const char *, struct bpb *);
-static void getdiskinfo(int, const char *, const char *, int,
- struct bpb *);
+static void getdiskinfo(int, const char *, const char *, int, struct bpb *);
static void print_bpb(struct bpb *);
static u_int ckgeom(const char *, u_int, const char *);
static u_int argtou(const char *, u_int, u_int, const char *);
@@ -237,14 +236,14 @@
/*
* Construct a FAT12, FAT16, or FAT32 file system.
*/
-int
-newfs_msdos_main(int argc, char *argv[])
+int newfs_msdos_main(int argc, char *argv[])
{
- static const char opts[] = "@:NB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:";
+ static const char opts[] = "@:NAB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:";
const char *opt_B = NULL, *opt_L = NULL, *opt_O = NULL, *opt_f = NULL;
u_int opt_F = 0, opt_I = 0, opt_S = 0, opt_a = 0, opt_b = 0, opt_c = 0;
u_int opt_e = 0, opt_h = 0, opt_i = 0, opt_k = 0, opt_m = 0, opt_n = 0;
u_int opt_o = 0, opt_r = 0, opt_s = 0, opt_u = 0;
+ u_int opt_A = 0;
int opt_N = 0;
int Iflag = 0, mflag = 0, oflag = 0;
char buf[MAXPATHLEN];
@@ -262,462 +261,486 @@
ssize_t n;
time_t now;
u_int fat, bss, rds, cls, dir, lsn, x, x1, x2;
+ u_int extra_res, alignment=0, set_res, set_spf, set_spc, tempx, attempts=0;
int ch, fd, fd1;
off_t opt_create = 0, opt_ofs = 0;
while ((ch = getopt(argc, argv, opts)) != -1)
- switch (ch) {
- case '@':
- opt_ofs = argtooff(optarg, "offset");
- break;
- case 'N':
- opt_N = 1;
- break;
- case 'B':
- opt_B = optarg;
- break;
- case 'C':
- opt_create = argtooff(optarg, "create size");
- break;
- case 'F':
- if (strcmp(optarg, "12") &&
- strcmp(optarg, "16") &&
- strcmp(optarg, "32"))
- errx(1, "%s: bad FAT type", optarg);
- opt_F = atoi(optarg);
- break;
- case 'I':
- opt_I = argto4(optarg, 0, "volume ID");
- Iflag = 1;
- break;
- case 'L':
- if (!oklabel(optarg))
- errx(1, "%s: bad volume label", optarg);
- opt_L = optarg;
- break;
- case 'O':
- if (strlen(optarg) > 8)
- errx(1, "%s: bad OEM string", optarg);
- opt_O = optarg;
- break;
- case 'S':
- opt_S = argto2(optarg, 1, "bytes/sector");
- break;
- case 'a':
- opt_a = argto4(optarg, 1, "sectors/FAT");
- break;
- case 'b':
- opt_b = argtox(optarg, 1, "block size");
- opt_c = 0;
- break;
- case 'c':
- opt_c = argto1(optarg, 1, "sectors/cluster");
- opt_b = 0;
- break;
- case 'e':
- opt_e = argto2(optarg, 1, "directory entries");
- break;
- case 'f':
- opt_f = optarg;
- break;
- case 'h':
- opt_h = argto2(optarg, 1, "drive heads");
- break;
- case 'i':
- opt_i = argto2(optarg, 1, "info sector");
- break;
- case 'k':
- opt_k = argto2(optarg, 1, "backup sector");
- break;
- case 'm':
- opt_m = argto1(optarg, 0, "media descriptor");
- mflag = 1;
- break;
- case 'n':
- opt_n = argto1(optarg, 1, "number of FATs");
- break;
- case 'o':
- opt_o = argto4(optarg, 0, "hidden sectors");
- oflag = 1;
- break;
- case 'r':
- opt_r = argto2(optarg, 1, "reserved sectors");
- break;
- case 's':
- opt_s = argto4(optarg, 1, "file system size");
- break;
- case 'u':
- opt_u = argto2(optarg, 1, "sectors/track");
- break;
- default:
- usage();
- }
+ switch (ch) {
+ case '@':
+ opt_ofs = argtooff(optarg, "offset");
+ break;
+ case 'N':
+ opt_N = 1;
+ break;
+ case 'A':
+ opt_A = 1;
+ break;
+ case 'B':
+ opt_B = optarg;
+ break;
+ case 'C':
+ opt_create = argtooff(optarg, "create size");
+ break;
+ case 'F':
+ if (strcmp(optarg, "12") && strcmp(optarg, "16") && strcmp(optarg, "32"))
+ errx(1, "%s: bad FAT type", optarg);
+ opt_F = atoi(optarg);
+ break;
+ case 'I':
+ opt_I = argto4(optarg, 0, "volume ID");
+ Iflag = 1;
+ break;
+ case 'L':
+ if (!oklabel(optarg))
+ errx(1, "%s: bad volume label", optarg);
+ opt_L = optarg;
+ break;
+ case 'O':
+ if (strlen(optarg) > 8)
+ errx(1, "%s: bad OEM string", optarg);
+ opt_O = optarg;
+ break;
+ case 'S':
+ opt_S = argto2(optarg, 1, "bytes/sector");
+ break;
+ case 'a':
+ opt_a = argto4(optarg, 1, "sectors/FAT");
+ break;
+ case 'b':
+ opt_b = argtox(optarg, 1, "block size");
+ opt_c = 0;
+ break;
+ case 'c':
+ opt_c = argto1(optarg, 1, "sectors/cluster");
+ opt_b = 0;
+ break;
+ case 'e':
+ opt_e = argto2(optarg, 1, "directory entries");
+ break;
+ case 'f':
+ opt_f = optarg;
+ break;
+ case 'h':
+ opt_h = argto2(optarg, 1, "drive heads");
+ break;
+ case 'i':
+ opt_i = argto2(optarg, 1, "info sector");
+ break;
+ case 'k':
+ opt_k = argto2(optarg, 1, "backup sector");
+ break;
+ case 'm':
+ opt_m = argto1(optarg, 0, "media descriptor");
+ mflag = 1;
+ break;
+ case 'n':
+ opt_n = argto1(optarg, 1, "number of FATs");
+ break;
+ case 'o':
+ opt_o = argto4(optarg, 0, "hidden sectors");
+ oflag = 1;
+ break;
+ case 'r':
+ opt_r = argto2(optarg, 1, "reserved sectors");
+ break;
+ case 's':
+ opt_s = argto4(optarg, 1, "file system size");
+ break;
+ case 'u':
+ opt_u = argto2(optarg, 1, "sectors/track");
+ break;
+ default:
+ usage();
+ }
argc -= optind;
argv += optind;
if (argc < 1 || argc > 2)
- usage();
+ usage();
fname = *argv++;
if (!opt_create && !strchr(fname, '/')) {
- snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
- if (!(fname = strdup(buf)))
- err(1, NULL);
+ snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
+ if (!(fname = strdup(buf)))
+ err(1, "%s", buf);
}
dtype = *argv;
+ if (opt_A) {
+ if (opt_r)
+ errx(1, "align (-A) is incompatible with -r");
+ if (opt_N)
+ errx(1, "align (-A) is incompatible with -N");
+ }
if (opt_create) {
- if (opt_N)
- errx(1, "create (-C) is incompatible with -N");
- fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644);
- if (fd == -1)
- errx(1, "failed to create %s", fname);
- if (ftruncate(fd, opt_create))
- errx(1, "failed to initialize %jd bytes", (intmax_t)opt_create);
+ if (opt_N)
+ errx(1, "create (-C) is incompatible with -N");
+ fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1)
+ errx(1, "failed to create %s", fname);
+ if (ftruncate(fd, opt_create))
+ errx(1, "failed to initialize %jd bytes", (intmax_t)opt_create);
} else if ((fd = open(fname, opt_N ? O_RDONLY : O_RDWR)) == -1)
- err(1, "%s", fname);
+ err(1, "%s", fname);
if (fstat(fd, &sb))
- err(1, "%s", fname);
+ err(1, "%s", fname);
if (opt_create) {
- if (!S_ISREG(sb.st_mode))
- warnx("warning, %s is not a regular file", fname);
+ if (!S_ISREG(sb.st_mode))
+ warnx("warning, %s is not a regular file", fname);
} else {
- if (!S_ISCHR(sb.st_mode))
- warnx("warning, %s is not a character device", fname);
+ if (!S_ISCHR(sb.st_mode))
+ warnx("warning, %s is not a character device", fname);
}
if (!opt_N)
- check_mounted(fname, sb.st_mode);
+ check_mounted(fname, sb.st_mode);
if (opt_ofs && opt_ofs != lseek(fd, opt_ofs, SEEK_SET))
- errx(1, "cannot seek to %jd", (intmax_t)opt_ofs);
+ errx(1, "cannot seek to %jd", (intmax_t)opt_ofs);
memset(&bpb, 0, sizeof(bpb));
if (opt_f) {
- getstdfmt(opt_f, &bpb);
- bpb.bsec = bpb.sec;
- bpb.sec = 0;
- bpb.bspf = bpb.spf;
- bpb.spf = 0;
+ getstdfmt(opt_f, &bpb);
+ bpb.bsec = bpb.sec;
+ bpb.sec = 0;
+ bpb.bspf = bpb.spf;
+ bpb.spf = 0;
}
if (opt_h)
- bpb.hds = opt_h;
+ bpb.hds = opt_h;
if (opt_u)
- bpb.spt = opt_u;
+ bpb.spt = opt_u;
if (opt_S)
- bpb.bps = opt_S;
+ bpb.bps = opt_S;
if (opt_s)
- bpb.bsec = opt_s;
+ bpb.bsec = opt_s;
if (oflag)
- bpb.hid = opt_o;
+ bpb.hid = opt_o;
if (!(opt_f || (opt_h && opt_u && opt_S && opt_s && oflag))) {
- off_t delta;
- getdiskinfo(fd, fname, dtype, oflag, &bpb);
+ off_t delta;
+ getdiskinfo(fd, fname, dtype, oflag, &bpb);
if (opt_s) {
bpb.bsec = opt_s;
}
- bpb.bsec -= (opt_ofs / bpb.bps);
- delta = bpb.bsec % bpb.spt;
- if (delta != 0) {
- warnx("trim %d sectors from %d to adjust to a multiple of %d",
- (int)delta, bpb.bsec, bpb.spt);
- bpb.bsec -= delta;
- }
- if (bpb.spc == 0) { /* set defaults */
- if (bpb.bsec <= 6000) /* about 3MB -> 512 bytes */
- bpb.spc = 1;
- else if (bpb.bsec <= (1<<17)) /* 64M -> 4k */
- bpb.spc = 8;
- else if (bpb.bsec <= (1<<19)) /* 256M -> 8k */
- bpb.spc = 16;
- else if (bpb.bsec <= (1<<22)) /* 2G -> 16k, some versions of windows
- require a minimum of 65527 clusters */
- bpb.spc = 32;
- else
- bpb.spc = 64; /* otherwise 32k */
- }
+ bpb.bsec -= (opt_ofs / bpb.bps);
+ delta = bpb.bsec % bpb.spt;
+ if (delta != 0) {
+ warnx("trim %d sectors from %d to adjust to a multiple of %d",
+ (int)delta, bpb.bsec, bpb.spt);
+ bpb.bsec -= delta;
+ }
+ if (bpb.spc == 0) { /* set defaults */
+ if (bpb.bsec <= 6000) /* about 3MB -> 512 bytes */
+ bpb.spc = 1;
+ else if (bpb.bsec <= (1<<17)) /* 64M -> 4k */
+ bpb.spc = 8;
+ else if (bpb.bsec <= (1<<19)) /* 256M -> 8k */
+ bpb.spc = 16;
+ else if (bpb.bsec <= (1<<22)) /* 2G -> 16k, some versions of windows
+ require a minimum of 65527 clusters */
+ bpb.spc = 32;
+ else
+ bpb.spc = 64; /* otherwise 32k */
+ }
}
if (!powerof2(bpb.bps))
- errx(1, "bytes/sector (%u) is not a power of 2", bpb.bps);
+ errx(1, "bytes/sector (%u) is not a power of 2", bpb.bps);
if (bpb.bps < MINBPS)
- errx(1, "bytes/sector (%u) is too small; minimum is %u",
- bpb.bps, MINBPS);
+ errx(1, "bytes/sector (%u) is too small; minimum is %u",
+ bpb.bps, MINBPS);
if (!(fat = opt_F)) {
- if (opt_f)
- fat = 12;
- else if (!opt_e && (opt_i || opt_k))
- fat = 32;
+ if (opt_f)
+ fat = 12;
+ else if (!opt_e && (opt_i || opt_k))
+ fat = 32;
}
if ((fat == 32 && opt_e) || (fat != 32 && (opt_i || opt_k)))
- errx(1, "-%c is not a legal FAT%s option",
- fat == 32 ? 'e' : opt_i ? 'i' : 'k',
- fat == 32 ? "32" : "12/16");
+ errx(1, "-%c is not a legal FAT%s option",
+ fat == 32 ? 'e' : opt_i ? 'i' : 'k',
+ fat == 32 ? "32" : "12/16");
if (opt_f && fat == 32)
- bpb.rde = 0;
+ bpb.rde = 0;
if (opt_b) {
- if (!powerof2(opt_b))
- errx(1, "block size (%u) is not a power of 2", opt_b);
- if (opt_b < bpb.bps)
- errx(1, "block size (%u) is too small; minimum is %u",
- opt_b, bpb.bps);
- if (opt_b > bpb.bps * MAXSPC)
- errx(1, "block size (%u) is too large; maximum is %u",
- opt_b, bpb.bps * MAXSPC);
- bpb.spc = opt_b / bpb.bps;
+ if (!powerof2(opt_b))
+ errx(1, "block size (%u) is not a power of 2", opt_b);
+ if (opt_b < bpb.bps)
+ errx(1, "block size (%u) is too small; minimum is %u",
+ opt_b, bpb.bps);
+ if (opt_b > bpb.bps * MAXSPC)
+ errx(1, "block size (%u) is too large; maximum is %u", opt_b, bpb.bps * MAXSPC);
+ bpb.spc = opt_b / bpb.bps;
}
if (opt_c) {
- if (!powerof2(opt_c))
- errx(1, "sectors/cluster (%u) is not a power of 2", opt_c);
- bpb.spc = opt_c;
+ if (!powerof2(opt_c))
+ errx(1, "sectors/cluster (%u) is not a power of 2", opt_c);
+ bpb.spc = opt_c;
}
if (opt_r)
- bpb.res = opt_r;
+ bpb.res = opt_r;
if (opt_n) {
- if (opt_n > MAXNFT)
- errx(1, "number of FATs (%u) is too large; maximum is %u",
- opt_n, MAXNFT);
- bpb.nft = opt_n;
+ if (opt_n > MAXNFT)
+ errx(1, "number of FATs (%u) is too large; maximum is %u", opt_n, MAXNFT);
+ bpb.nft = opt_n;
}
if (opt_e)
- bpb.rde = opt_e;
+ bpb.rde = opt_e;
if (mflag) {
- if (opt_m < 0xf0)
- errx(1, "illegal media descriptor (%#x)", opt_m);
- bpb.mid = opt_m;
+ if (opt_m < 0xf0)
+ errx(1, "illegal media descriptor (%#x)", opt_m);
+ bpb.mid = opt_m;
}
if (opt_a)
- bpb.bspf = opt_a;
+ bpb.bspf = opt_a;
if (opt_i)
- bpb.infs = opt_i;
+ bpb.infs = opt_i;
if (opt_k)
- bpb.bkbs = opt_k;
+ bpb.bkbs = opt_k;
bss = 1;
bname = NULL;
fd1 = -1;
if (opt_B) {
- bname = opt_B;
- if (!strchr(bname, '/')) {
- snprintf(buf, sizeof(buf), "/boot/%s", bname);
- if (!(bname = strdup(buf)))
- err(1, NULL);
- }
- if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb))
- err(1, "%s", bname);
- if (!S_ISREG(sb.st_mode) || sb.st_size % bpb.bps ||
- sb.st_size < bpb.bps || sb.st_size > bpb.bps * MAXU16)
- errx(1, "%s: inappropriate file type or format", bname);
- bss = sb.st_size / bpb.bps;
+ bname = opt_B;
+ if (!strchr(bname, '/')) {
+ snprintf(buf, sizeof(buf), "/boot/%s", bname);
+ if (!(bname = strdup(buf)))
+ err(1, "%s", buf);
+ }
+ if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb))
+ err(1, "%s", bname);
+ if (!S_ISREG(sb.st_mode) || sb.st_size % bpb.bps ||
+ sb.st_size < bpb.bps || sb.st_size > bpb.bps * MAXU16)
+ errx(1, "%s: inappropriate file type or format", bname);
+ bss = sb.st_size / bpb.bps;
}
if (!bpb.nft)
- bpb.nft = 2;
+ bpb.nft = 2;
if (!fat) {
- if (bpb.bsec < (bpb.res ? bpb.res : bss) +
- howmany((RESFTE + (bpb.spc ? MINCLS16 : MAXCLS12 + 1)) *
- ((bpb.spc ? 16 : 12) / BPN), bpb.bps * NPB) *
- bpb.nft +
- howmany(bpb.rde ? bpb.rde : DEFRDE,
- bpb.bps / sizeof(struct de)) +
- (bpb.spc ? MINCLS16 : MAXCLS12 + 1) *
- (bpb.spc ? bpb.spc : howmany(DEFBLK, bpb.bps)))
- fat = 12;
- else if (bpb.rde || bpb.bsec <
- (bpb.res ? bpb.res : bss) +
- howmany((RESFTE + MAXCLS16) * 2, bpb.bps) * bpb.nft +
- howmany(DEFRDE, bpb.bps / sizeof(struct de)) +
- (MAXCLS16 + 1) *
- (bpb.spc ? bpb.spc : howmany(8192, bpb.bps)))
- fat = 16;
- else
- fat = 32;
+ if (bpb.bsec < (bpb.res ? bpb.res : bss) +
+ howmany((RESFTE + (bpb.spc ? MINCLS16 : MAXCLS12 + 1)) *
+ ((bpb.spc ? 16 : 12) / BPN), bpb.bps * NPB) *
+ bpb.nft +
+ howmany(bpb.rde ? bpb.rde : DEFRDE,
+ bpb.bps / sizeof(struct de)) +
+ (bpb.spc ? MINCLS16 : MAXCLS12 + 1) *
+ (bpb.spc ? bpb.spc : howmany(DEFBLK, bpb.bps)))
+ fat = 12;
+ else if (bpb.rde || bpb.bsec <
+ (bpb.res ? bpb.res : bss) +
+ howmany((RESFTE + MAXCLS16) * 2, bpb.bps) * bpb.nft +
+ howmany(DEFRDE, bpb.bps / sizeof(struct de)) +
+ (MAXCLS16 + 1) *
+ (bpb.spc ? bpb.spc : howmany(8192, bpb.bps)))
+ fat = 16;
+ else
+ fat = 32;
}
x = bss;
if (fat == 32) {
- if (!bpb.infs) {
- if (x == MAXU16 || x == bpb.bkbs)
- errx(1, "no room for info sector");
- bpb.infs = x;
- }
- if (bpb.infs != MAXU16 && x <= bpb.infs)
- x = bpb.infs + 1;
- if (!bpb.bkbs) {
- if (x == MAXU16)
- errx(1, "no room for backup sector");
- bpb.bkbs = x;
- } else if (bpb.bkbs != MAXU16 && bpb.bkbs == bpb.infs)
- errx(1, "backup sector would overwrite info sector");
- if (bpb.bkbs != MAXU16 && x <= bpb.bkbs)
- x = bpb.bkbs + 1;
+ if (!bpb.infs) {
+ if (x == MAXU16 || x == bpb.bkbs)
+ errx(1, "no room for info sector");
+ bpb.infs = x;
+ }
+ if (bpb.infs != MAXU16 && x <= bpb.infs)
+ x = bpb.infs + 1;
+ if (!bpb.bkbs) {
+ if (x == MAXU16)
+ errx(1, "no room for backup sector");
+ bpb.bkbs = x;
+ } else if (bpb.bkbs != MAXU16 && bpb.bkbs == bpb.infs)
+ errx(1, "backup sector would overwrite info sector");
+ if (bpb.bkbs != MAXU16 && x <= bpb.bkbs)
+ x = bpb.bkbs + 1;
}
- if (!bpb.res)
- bpb.res = fat == 32 ? MAX(x, MAX(16384 / bpb.bps, 4)) : x;
- else if (bpb.res < x)
- errx(1, "too few reserved sectors");
- if (fat != 32 && !bpb.rde)
- bpb.rde = DEFRDE;
- rds = howmany(bpb.rde, bpb.bps / sizeof(struct de));
- if (!bpb.spc)
- for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bps);
- bpb.spc < MAXSPC &&
- bpb.res +
- howmany((RESFTE + maxcls(fat)) * (fat / BPN),
- bpb.bps * NPB) * bpb.nft +
- rds +
- (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec;
- bpb.spc <<= 1);
- if (fat != 32 && bpb.bspf > MAXU16)
- errx(1, "too many sectors/FAT for FAT12/16");
- x1 = bpb.res + rds;
- x = bpb.bspf ? bpb.bspf : 1;
- if (x1 + (u_int64_t)x * bpb.nft > bpb.bsec)
- errx(1, "meta data exceeds file system size");
- x1 += x * bpb.nft;
- x = (u_int64_t)(bpb.bsec - x1) * bpb.bps * NPB /
- (bpb.spc * bpb.bps * NPB + fat / BPN * bpb.nft);
- x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN),
- bpb.bps * NPB);
- if (!bpb.bspf) {
- bpb.bspf = x2;
- x1 += (bpb.bspf - 1) * bpb.nft;
- }
+
+ extra_res = 0;
+ set_res = !bpb.res;
+ set_spf = !bpb.bspf;
+ set_spc = !bpb.spc;
+ tempx = x;
+ /*
+ * Attempt to align if opt_A is set. This is done by increasing the number
+ * of reserved blocks. This can cause other factors to change, which can in
+ * turn change the alignment. This should take at most 2 iterations, as
+ * increasing the reserved amount may cause the FAT size to decrease by 1,
+ * requiring another nft reserved blocks. If spc changes, it will
+ * be half of its previous size, and thus will not throw off alignment.
+ */
+ do {
+ x = tempx;
+ if (set_res)
+ bpb.res = (fat == 32 ? MAX(x, MAX(16384 / bpb.bps, 4)) : x) + extra_res;
+ else if (bpb.res < x)
+ errx(1, "too few reserved sectors");
+ if (fat != 32 && !bpb.rde)
+ bpb.rde = DEFRDE;
+ rds = howmany(bpb.rde, bpb.bps / sizeof(struct de));
+ if (set_spc)
+ for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bps);
+ bpb.spc < MAXSPC &&
+ bpb.res +
+ howmany((RESFTE + maxcls(fat)) * (fat / BPN),
+ bpb.bps * NPB) * bpb.nft +
+ rds +
+ (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec;
+ bpb.spc <<= 1);
+ if (fat != 32 && bpb.bspf > MAXU16)
+ errx(1, "too many sectors/FAT for FAT12/16");
+ x1 = bpb.res + rds;
+ x = bpb.bspf ? bpb.bspf : 1;
+ if (x1 + (u_int64_t)x * bpb.nft > bpb.bsec)
+ errx(1, "meta data exceeds file system size");
+ x1 += x * bpb.nft;
+ x = (u_int64_t)(bpb.bsec - x1) * bpb.bps * NPB /
+ (bpb.spc * bpb.bps * NPB + fat / BPN * bpb.nft);
+ x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN), bpb.bps * NPB);
+ if (set_spf) {
+ if (!bpb.bspf) {
+ bpb.bspf = x2;
+ }
+ x1 += (bpb.bspf - 1) * bpb.nft;
+ }
+ if(set_res) {
+ /* attempt to align root directory */
+ alignment = (bpb.res + bpb.bspf * bpb.nft) % bpb.spc;
+ extra_res += bpb.spc - alignment;
+ }
+ attempts++;
+ } while(opt_A && alignment != 0 && attempts < 2);
+ if (alignment != 0)
+ warnx("warning: Alignment failed.");
+
cls = (bpb.bsec - x1) / bpb.spc;
x = (u_int64_t)bpb.bspf * bpb.bps * NPB / (fat / BPN) - RESFTE;
if (cls > x)
- cls = x;
+ cls = x;
if (bpb.bspf < x2)
- warnx("warning: sectors/FAT limits file system to %u clusters",
- cls);
+ warnx("warning: sectors/FAT limits file system to %u clusters", cls);
if (cls < mincls(fat))
- errx(1, "%u clusters too few clusters for FAT%u, need %u", cls, fat,
- mincls(fat));
+ errx(1, "%u clusters too few clusters for FAT%u, need %u", cls, fat, mincls(fat));
if (cls > maxcls(fat)) {
- cls = maxcls(fat);
- bpb.bsec = x1 + (cls + 1) * bpb.spc - 1;
- warnx("warning: FAT type limits file system to %u sectors",
- bpb.bsec);
+ cls = maxcls(fat);
+ bpb.bsec = x1 + (cls + 1) * bpb.spc - 1;
+ warnx("warning: FAT type limits file system to %u sectors", bpb.bsec);
}
- printf("%s: %u sector%s in %u FAT%u cluster%s "
- "(%u bytes/cluster)\n", fname, cls * bpb.spc,
- cls * bpb.spc == 1 ? "" : "s", cls, fat,
- cls == 1 ? "" : "s", bpb.bps * bpb.spc);
+ printf("%s: %u sector%s in %u FAT%u cluster%s (%u bytes/cluster)\n",
+ fname, cls * bpb.spc, cls * bpb.spc == 1 ? "" : "s", cls, fat,
+ cls == 1 ? "" : "s", bpb.bps * bpb.spc);
if (!bpb.mid)
- bpb.mid = !bpb.hid ? 0xf0 : 0xf8;
+ bpb.mid = !bpb.hid ? 0xf0 : 0xf8;
if (fat == 32)
- bpb.rdcl = RESFTE;
+ bpb.rdcl = RESFTE;
if (bpb.hid + bpb.bsec <= MAXU16) {
- bpb.sec = bpb.bsec;
- bpb.bsec = 0;
+ bpb.sec = bpb.bsec;
+ bpb.bsec = 0;
}
if (fat != 32) {
- bpb.spf = bpb.bspf;
- bpb.bspf = 0;
+ bpb.spf = bpb.bspf;
+ bpb.bspf = 0;
}
print_bpb(&bpb);
if (!opt_N) {
- gettimeofday(&tv, NULL);
- now = tv.tv_sec;
- tm = localtime(&now);
- if (!(img = malloc(bpb.bps)))
- err(1, NULL);
- dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft;
- for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) {
- x = lsn;
- if (opt_B &&
- fat == 32 && bpb.bkbs != MAXU16 &&
- bss <= bpb.bkbs && x >= bpb.bkbs) {
- x -= bpb.bkbs;
- if (!x && lseek(fd1, opt_ofs, SEEK_SET))
- err(1, "%s", bname);
- }
- if (opt_B && x < bss) {
- if ((n = read(fd1, img, bpb.bps)) == -1)
- err(1, "%s", bname);
- if ((unsigned)n != bpb.bps)
- errx(1, "%s: can't read sector %u", bname, x);
- } else
- memset(img, 0, bpb.bps);
- if (!lsn ||
- (fat == 32 && bpb.bkbs != MAXU16 && lsn == bpb.bkbs)) {
- x1 = sizeof(struct bs);
- bsbpb = (struct bsbpb *)(img + x1);
- mk2(bsbpb->bps, bpb.bps);
- mk1(bsbpb->spc, bpb.spc);
- mk2(bsbpb->res, bpb.res);
- mk1(bsbpb->nft, bpb.nft);
- mk2(bsbpb->rde, bpb.rde);
- mk2(bsbpb->sec, bpb.sec);
- mk1(bsbpb->mid, bpb.mid);
- mk2(bsbpb->spf, bpb.spf);
- mk2(bsbpb->spt, bpb.spt);
- mk2(bsbpb->hds, bpb.hds);
- mk4(bsbpb->hid, bpb.hid);
- mk4(bsbpb->bsec, bpb.bsec);
- x1 += sizeof(struct bsbpb);
- if (fat == 32) {
- bsxbpb = (struct bsxbpb *)(img + x1);
- mk4(bsxbpb->bspf, bpb.bspf);
- mk2(bsxbpb->xflg, 0);
- mk2(bsxbpb->vers, 0);
- mk4(bsxbpb->rdcl, bpb.rdcl);
- mk2(bsxbpb->infs, bpb.infs);
- mk2(bsxbpb->bkbs, bpb.bkbs);
- x1 += sizeof(struct bsxbpb);
- }
- bsx = (struct bsx *)(img + x1);
- mk1(bsx->sig, 0x29);
- if (Iflag)
- x = opt_I;
- else
- x = (((u_int)(1 + tm->tm_mon) << 8 |
- (u_int)tm->tm_mday) +
- ((u_int)tm->tm_sec << 8 |
- (u_int)(tv.tv_usec / 10))) << 16 |
- ((u_int)(1900 + tm->tm_year) +
- ((u_int)tm->tm_hour << 8 |
- (u_int)tm->tm_min));
- mk4(bsx->volid, x);
- mklabel(bsx->label, opt_L ? opt_L : "NO NAME");
- sprintf(buf, "FAT%u", fat);
- setstr(bsx->type, buf, sizeof(bsx->type));
- if (!opt_B) {
- x1 += sizeof(struct bsx);
- bs = (struct bs *)img;
- mk1(bs->jmp[0], 0xeb);
- mk1(bs->jmp[1], x1 - 2);
- mk1(bs->jmp[2], 0x90);
- setstr(bs->oem, opt_O ? opt_O : "BSD 4.4",
- sizeof(bs->oem));
- memcpy(img + x1, bootcode, sizeof(bootcode));
- mk2(img + MINBPS - 2, DOSMAGIC);
- }
- } else if (fat == 32 && bpb.infs != MAXU16 &&
- (lsn == bpb.infs ||
- (bpb.bkbs != MAXU16 &&
- lsn == bpb.bkbs + bpb.infs))) {
- mk4(img, 0x41615252);
- mk4(img + MINBPS - 28, 0x61417272);
- mk4(img + MINBPS - 24, 0xffffffff);
- mk4(img + MINBPS - 20, bpb.rdcl);
- mk2(img + MINBPS - 2, DOSMAGIC);
- } else if (lsn >= bpb.res && lsn < dir &&
- !((lsn - bpb.res) %
- (bpb.spf ? bpb.spf : bpb.bspf))) {
- mk1(img[0], bpb.mid);
- for (x = 1; x < fat * (fat == 32 ? 3 : 2) / 8; x++)
- mk1(img[x], fat == 32 && x % 4 == 3 ? 0x0f : 0xff);
- } else if (lsn == dir && opt_L) {
- de = (struct de *)img;
- mklabel(de->namext, opt_L);
- mk1(de->attr, 050);
- x = (u_int)tm->tm_hour << 11 |
- (u_int)tm->tm_min << 5 |
- (u_int)tm->tm_sec >> 1;
- mk2(de->time, x);
- x = (u_int)(tm->tm_year - 80) << 9 |
- (u_int)(tm->tm_mon + 1) << 5 |
- (u_int)tm->tm_mday;
- mk2(de->date, x);
- }
- if ((n = write(fd, img, bpb.bps)) == -1)
- err(1, "%s", fname);
- if ((unsigned)n != bpb.bps) {
- errx(1, "%s: can't write sector %u", fname, lsn);
+ gettimeofday(&tv, NULL);
+ now = tv.tv_sec;
+ tm = localtime(&now);
+ if (!(img = malloc(bpb.bps)))
+ err(1, "%u", bpb.bps);
+ dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft;
+ for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) {
+ x = lsn;
+ if (opt_B && fat == 32 && bpb.bkbs != MAXU16 && bss <= bpb.bkbs && x >= bpb.bkbs) {
+ x -= bpb.bkbs;
+ if (!x && lseek(fd1, opt_ofs, SEEK_SET))
+ err(1, "%s", bname);
+ }
+ if (opt_B && x < bss) {
+ if ((n = read(fd1, img, bpb.bps)) == -1)
+ err(1, "%s", bname);
+ if ((unsigned)n != bpb.bps)
+ errx(1, "%s: can't read sector %u", bname, x);
+ } else
+ memset(img, 0, bpb.bps);
+ if (!lsn || (fat == 32 && bpb.bkbs != MAXU16 && lsn == bpb.bkbs)) {
+ x1 = sizeof(struct bs);
+ bsbpb = (struct bsbpb *)(img + x1);
+ mk2(bsbpb->bps, bpb.bps);
+ mk1(bsbpb->spc, bpb.spc);
+ mk2(bsbpb->res, bpb.res);
+ mk1(bsbpb->nft, bpb.nft);
+ mk2(bsbpb->rde, bpb.rde);
+ mk2(bsbpb->sec, bpb.sec);
+ mk1(bsbpb->mid, bpb.mid);
+ mk2(bsbpb->spf, bpb.spf);
+ mk2(bsbpb->spt, bpb.spt);
+ mk2(bsbpb->hds, bpb.hds);
+ mk4(bsbpb->hid, bpb.hid);
+ mk4(bsbpb->bsec, bpb.bsec);
+ x1 += sizeof(struct bsbpb);
+ if (fat == 32) {
+ bsxbpb = (struct bsxbpb *)(img + x1);
+ mk4(bsxbpb->bspf, bpb.bspf);
+ mk2(bsxbpb->xflg, 0);
+ mk2(bsxbpb->vers, 0);
+ mk4(bsxbpb->rdcl, bpb.rdcl);
+ mk2(bsxbpb->infs, bpb.infs);
+ mk2(bsxbpb->bkbs, bpb.bkbs);
+ x1 += sizeof(struct bsxbpb);
+ }
+ bsx = (struct bsx *)(img + x1);
+ mk1(bsx->sig, 0x29);
+ if (Iflag)
+ x = opt_I;
+ else
+ x = (((u_int)(1 + tm->tm_mon) << 8 |
+ (u_int)tm->tm_mday) +
+ ((u_int)tm->tm_sec << 8 |
+ (u_int)(tv.tv_usec / 10))) << 16 |
+ ((u_int)(1900 + tm->tm_year) +
+ ((u_int)tm->tm_hour << 8 |
+ (u_int)tm->tm_min));
+ mk4(bsx->volid, x);
+ mklabel(bsx->label, opt_L ? opt_L : "NO NAME");
+ sprintf(buf, "FAT%u", fat);
+ setstr(bsx->type, buf, sizeof(bsx->type));
+ if (!opt_B) {
+ x1 += sizeof(struct bsx);
+ bs = (struct bs *)img;
+ mk1(bs->jmp[0], 0xeb);
+ mk1(bs->jmp[1], x1 - 2);
+ mk1(bs->jmp[2], 0x90);
+ setstr(bs->oem, opt_O ? opt_O : "BSD 4.4",
+ sizeof(bs->oem));
+ memcpy(img + x1, bootcode, sizeof(bootcode));
+ mk2(img + MINBPS - 2, DOSMAGIC);
+ }
+ } else if (fat == 32 && bpb.infs != MAXU16 &&
+ (lsn == bpb.infs || (bpb.bkbs != MAXU16 &&
+ lsn == bpb.bkbs + bpb.infs))) {
+ mk4(img, 0x41615252);
+ mk4(img + MINBPS - 28, 0x61417272);
+ mk4(img + MINBPS - 24, 0xffffffff);
+ mk4(img + MINBPS - 20, bpb.rdcl);
+ mk2(img + MINBPS - 2, DOSMAGIC);
+ } else if (lsn >= bpb.res && lsn < dir &&
+ !((lsn - bpb.res) % (bpb.spf ? bpb.spf : bpb.bspf))) {
+ mk1(img[0], bpb.mid);
+ for (x = 1; x < fat * (fat == 32 ? 3 : 2) / 8; x++)
+ mk1(img[x], fat == 32 && x % 4 == 3 ? 0x0f : 0xff);
+ } else if (lsn == dir && opt_L) {
+ de = (struct de *)img;
+ mklabel(de->namext, opt_L);
+ mk1(de->attr, 050);
+ x = (u_int)tm->tm_hour << 11 |
+ (u_int)tm->tm_min << 5 |
+ (u_int)tm->tm_sec >> 1;
+ mk2(de->time, x);
+ x = (u_int)(tm->tm_year - 80) << 9 |
+ (u_int)(tm->tm_mon + 1) << 5 |
+ (u_int)tm->tm_mday;
+ mk2(de->date, x);
+ }
+ if ((n = write(fd, img, bpb.bps)) == -1)
+ err(1, "%s", fname);
+ if ((unsigned)n != bpb.bps) {
+ errx(1, "%s: can't write sector %u", fname, lsn);
exit(1);
}
- }
+ }
}
return 0;
}
@@ -725,31 +748,29 @@
/*
* Exit with error if file system is mounted.
*/
-static void
-check_mounted(const char *fname, mode_t mode)
+static void check_mounted(const char *fname, mode_t mode)
{
+#ifdef ANDROID
+ warnx("Skipping mount checks");
+#else
struct statfs *mp;
const char *s1, *s2;
size_t len;
int n, r;
-#ifdef ANDROID
- warnx("Skipping mount checks");
-#else
if (!(n = getmntinfo(&mp, MNT_NOWAIT)))
- err(1, "getmntinfo");
+ err(1, "getmntinfo");
len = strlen(_PATH_DEV);
s1 = fname;
if (!strncmp(s1, _PATH_DEV, len))
- s1 += len;
+ s1 += len;
r = S_ISCHR(mode) && s1 != fname && *s1 == 'r';
for (; n--; mp++) {
- s2 = mp->f_mntfromname;
- if (!strncmp(s2, _PATH_DEV, len))
- s2 += len;
- if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) ||
- !strcmp(s1, s2))
- errx(1, "%s is mounted on %s", fname, mp->f_mntonname);
+ s2 = mp->f_mntfromname;
+ if (!strncmp(s2, _PATH_DEV, len))
+ s2 += len;
+ if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) || !strcmp(s1, s2))
+ errx(1, "%s is mounted on %s", fname, mp->f_mntonname);
}
#endif
}
@@ -757,15 +778,14 @@
/*
* Get a standard format.
*/
-static void
-getstdfmt(const char *fmt, struct bpb *bpb)
+static void getstdfmt(const char *fmt, struct bpb *bpb)
{
u_int x, i;
x = sizeof(stdfmt) / sizeof(stdfmt[0]);
for (i = 0; i < x && strcmp(fmt, stdfmt[i].name); i++);
if (i == x)
- errx(1, "%s: unknown standard format", fmt);
+ errx(1, "%s: unknown standard format", fmt);
*bpb = stdfmt[i].bpb;
}
@@ -774,9 +794,8 @@
*/
#ifdef ANDROID
-static void
-getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag,
- struct bpb *bpb)
+static void getdiskinfo(int fd, const char *fname, const char *dtype,
+ __unused int oflag,struct bpb *bpb)
{
struct hd_geometry geom;
@@ -817,9 +836,8 @@
#else
-static void
-getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag,
- struct bpb *bpb)
+static void getdiskinfo(int fd, const char *fname, const char *dtype,
+ __unused int oflag, struct bpb *bpb)
{
struct disklabel *lp, dlp;
struct fd_type type;
@@ -829,97 +847,96 @@
/* If the user specified a disk type, try to use that */
if (dtype != NULL) {
- lp = getdiskbyname(dtype);
+ lp = getdiskbyname(dtype);
}
/* Maybe it's a floppy drive */
if (lp == NULL) {
- if (ioctl(fd, DIOCGMEDIASIZE, &ms) == -1) {
- struct stat st;
+ if (ioctl(fd, DIOCGMEDIASIZE, &ms) == -1) {
+ struct stat st;
- if (fstat(fd, &st))
- err(1, "Cannot get disk size");
- /* create a fake geometry for a file image */
- ms = st.st_size;
- dlp.d_secsize = 512;
- dlp.d_nsectors = 63;
- dlp.d_ntracks = 255;
- dlp.d_secperunit = ms / dlp.d_secsize;
- lp = &dlp;
- } else if (ioctl(fd, FD_GTYPE, &type) != -1) {
- dlp.d_secsize = 128 << type.secsize;
- dlp.d_nsectors = type.sectrac;
- dlp.d_ntracks = type.heads;
- dlp.d_secperunit = ms / dlp.d_secsize;
- lp = &dlp;
- }
+ if (fstat(fd, &st))
+ err(1, "Cannot get disk size");
+ /* create a fake geometry for a file image */
+ ms = st.st_size;
+ dlp.d_secsize = 512;
+ dlp.d_nsectors = 63;
+ dlp.d_ntracks = 255;
+ dlp.d_secperunit = ms / dlp.d_secsize;
+ lp = &dlp;
+ } else if (ioctl(fd, FD_GTYPE, &type) != -1) {
+ dlp.d_secsize = 128 << type.secsize;
+ dlp.d_nsectors = type.sectrac;
+ dlp.d_ntracks = type.heads;
+ dlp.d_secperunit = ms / dlp.d_secsize;
+ lp = &dlp;
+ }
}
/* Maybe it's a fixed drive */
if (lp == NULL) {
- if (ioctl(fd, DIOCGDINFO, &dlp) == -1) {
- if (bpb->bps == 0 && ioctl(fd, DIOCGSECTORSIZE, &dlp.d_secsize) == -1)
- errx(1, "Cannot get sector size, %s", strerror(errno));
+ if (ioctl(fd, DIOCGDINFO, &dlp) == -1) {
+ if (bpb->bps == 0 && ioctl(fd, DIOCGSECTORSIZE, &dlp.d_secsize) == -1)
+ errx(1, "Cannot get sector size, %s", strerror(errno));
- /* XXX Should we use bpb->bps if it's set? */
- dlp.d_secperunit = ms / dlp.d_secsize;
+ /* XXX Should we use bpb->bps if it's set? */
+ dlp.d_secperunit = ms / dlp.d_secsize;
- if (bpb->spt == 0 && ioctl(fd, DIOCGFWSECTORS, &dlp.d_nsectors) == -1) {
- warnx("Cannot get number of sectors per track, %s", strerror(errno));
- dlp.d_nsectors = 63;
- }
- if (bpb->hds == 0 && ioctl(fd, DIOCGFWHEADS, &dlp.d_ntracks) == -1) {
- warnx("Cannot get number of heads, %s", strerror(errno));
- if (dlp.d_secperunit <= 63*1*1024)
- dlp.d_ntracks = 1;
- else if (dlp.d_secperunit <= 63*16*1024)
- dlp.d_ntracks = 16;
- else
- dlp.d_ntracks = 255;
- }
- }
+ if (bpb->spt == 0 && ioctl(fd, DIOCGFWSECTORS, &dlp.d_nsectors) == -1) {
+ warnx("Cannot get number of sectors per track, %s", strerror(errno));
+ dlp.d_nsectors = 63;
+ }
+ if (bpb->hds == 0 && ioctl(fd, DIOCGFWHEADS, &dlp.d_ntracks) == -1) {
+ warnx("Cannot get number of heads, %s", strerror(errno));
+ if (dlp.d_secperunit <= 63*1*1024)
+ dlp.d_ntracks = 1;
+ else if (dlp.d_secperunit <= 63*16*1024)
+ dlp.d_ntracks = 16;
+ else
+ dlp.d_ntracks = 255;
+ }
+ }
- hs = (ms / dlp.d_secsize) - dlp.d_secperunit;
- lp = &dlp;
+ hs = (ms / dlp.d_secsize) - dlp.d_secperunit;
+ lp = &dlp;
}
if (bpb->bps == 0)
- bpb->bps = ckgeom(fname, lp->d_secsize, "bytes/sector");
+ bpb->bps = ckgeom(fname, lp->d_secsize, "bytes/sector");
if (bpb->spt == 0)
- bpb->spt = ckgeom(fname, lp->d_nsectors, "sectors/track");
+ bpb->spt = ckgeom(fname, lp->d_nsectors, "sectors/track");
if (bpb->hds == 0)
- bpb->hds = ckgeom(fname, lp->d_ntracks, "drive heads");
+ bpb->hds = ckgeom(fname, lp->d_ntracks, "drive heads");
if (bpb->bsec == 0)
- bpb->bsec = lp->d_secperunit;
+ bpb->bsec = lp->d_secperunit;
if (bpb->hid == 0)
- bpb->hid = hs;
+ bpb->hid = hs;
}
#endif
/*
* Print out BPB values.
*/
-static void
-print_bpb(struct bpb *bpb)
+static void print_bpb(struct bpb *bpb)
{
printf("bps=%u spc=%u res=%u nft=%u", bpb->bps, bpb->spc, bpb->res,
- bpb->nft);
+ bpb->nft);
if (bpb->rde)
- printf(" rde=%u", bpb->rde);
+ printf(" rde=%u", bpb->rde);
if (bpb->sec)
- printf(" sec=%u", bpb->sec);
+ printf(" sec=%u", bpb->sec);
printf(" mid=%#x", bpb->mid);
if (bpb->spf)
- printf(" spf=%u", bpb->spf);
+ printf(" spf=%u", bpb->spf);
printf(" spt=%u hds=%u hid=%u", bpb->spt, bpb->hds, bpb->hid);
if (bpb->bsec)
- printf(" bsec=%u", bpb->bsec);
+ printf(" bsec=%u", bpb->bsec);
if (!bpb->spf) {
- printf(" bspf=%u rdcl=%u", bpb->bspf, bpb->rdcl);
- printf(" infs=");
- printf(bpb->infs == MAXU16 ? "%#x" : "%u", bpb->infs);
- printf(" bkbs=");
- printf(bpb->bkbs == MAXU16 ? "%#x" : "%u", bpb->bkbs);
+ printf(" bspf=%u rdcl=%u", bpb->bspf, bpb->rdcl);
+ printf(" infs=");
+ printf(bpb->infs == MAXU16 ? "%#x" : "%u", bpb->infs);
+ printf(" bkbs=");
+ printf(bpb->bkbs == MAXU16 ? "%#x" : "%u", bpb->bkbs);
}
printf("\n");
}
@@ -927,21 +944,19 @@
/*
* Check a disk geometry value.
*/
-static u_int
-ckgeom(const char *fname, u_int val, const char *msg)
+static u_int ckgeom(const char *fname, u_int val, const char *msg)
{
if (!val)
- errx(1, "%s: no default %s", fname, msg);
+ errx(1, "%s: no default %s", fname, msg);
if (val > MAXU16)
- errx(1, "%s: illegal %s %d", fname, msg, val);
+ errx(1, "%s: illegal %s %d", fname, msg, val);
return val;
}
/*
* Convert and check a numeric option argument.
*/
-static u_int
-argtou(const char *arg, u_int lo, u_int hi, const char *msg)
+static u_int argtou(const char *arg, u_int lo, u_int hi, const char *msg)
{
char *s;
u_long x;
@@ -949,15 +964,14 @@
errno = 0;
x = strtoul(arg, &s, 0);
if (errno || !*arg || *s || x < lo || x > hi)
- errx(1, "%s: bad %s", arg, msg);
+ errx(1, "%s: bad %s", arg, msg);
return x;
}
/*
* Same for off_t, with optional skmgpP suffix
*/
-static off_t
-argtooff(const char *arg, const char *msg)
+static off_t argtooff(const char *arg, const char *msg)
{
char *s;
off_t x;
@@ -965,40 +979,40 @@
x = strtoll(arg, &s, 0);
/* allow at most one extra char */
if (errno || x < 0 || (s[0] && s[1]) )
- errx(1, "%s: bad %s", arg, msg);
- if (*s) { /* the extra char is the multiplier */
- switch (*s) {
- default:
- errx(1, "%s: bad %s", arg, msg);
- /* notreached */
-
- case 's': /* sector */
- case 'S':
- x <<= 9; /* times 512 */
- break;
+ errx(1, "%s: bad %s", arg, msg);
+ if (*s) { /* the extra char is the multiplier */
+ switch (*s) {
+ default:
+ errx(1, "%s: bad %s", arg, msg);
+ /* notreached */
- case 'k': /* kilobyte */
- case 'K':
- x <<= 10; /* times 1024 */
- break;
+ case 's': /* sector */
+ case 'S':
+ x <<= 9; /* times 512 */
+ break;
- case 'm': /* megabyte */
- case 'M':
- x <<= 20; /* times 1024*1024 */
- break;
+ case 'k': /* kilobyte */
+ case 'K':
+ x <<= 10; /* times 1024 */
+ break;
- case 'g': /* gigabyte */
- case 'G':
- x <<= 30; /* times 1024*1024*1024 */
- break;
+ case 'm': /* megabyte */
+ case 'M':
+ x <<= 20; /* times 1024*1024 */
+ break;
- case 'p': /* partition start */
- case 'P': /* partition start */
- case 'l': /* partition length */
- case 'L': /* partition length */
- errx(1, "%s: not supported yet %s", arg, msg);
- /* notreached */
- }
+ case 'g': /* gigabyte */
+ case 'G':
+ x <<= 30; /* times 1024*1024*1024 */
+ break;
+
+ case 'p': /* partition start */
+ case 'P': /* partition start */
+ case 'l': /* partition length */
+ case 'L': /* partition length */
+ errx(1, "%s: not supported yet %s", arg, msg);
+ /* notreached */
+ }
}
return x;
}
@@ -1006,15 +1020,14 @@
/*
* Check a volume label.
*/
-static int
-oklabel(const char *src)
+static int oklabel(const char *src)
{
int c, i;
for (i = 0; i <= 11; i++) {
- c = (u_char)*src++;
- if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c))
- break;
+ c = (u_char)*src++;
+ if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c))
+ break;
}
return i && !c;
}
@@ -1022,58 +1035,56 @@
/*
* Make a volume label.
*/
-static void
-mklabel(u_int8_t *dest, const char *src)
+static void mklabel(u_int8_t *dest, const char *src)
{
int c, i;
for (i = 0; i < 11; i++) {
- c = *src ? toupper(*src++) : ' ';
- *dest++ = !i && c == '\xe5' ? 5 : c;
+ c = *src ? toupper(*src++) : ' ';
+ *dest++ = !i && c == '\xe5' ? 5 : c;
}
}
/*
* Copy string, padding with spaces.
*/
-static void
-setstr(u_int8_t *dest, const char *src, size_t len)
+static void setstr(u_int8_t *dest, const char *src, size_t len)
{
while (len--)
- *dest++ = *src ? *src++ : ' ';
+ *dest++ = *src ? *src++ : ' ';
}
/*
* Print usage message.
*/
-static void
-usage(void)
+static void usage(void)
{
- fprintf(stderr,
- "usage: newfs_msdos [ -options ] special [disktype]\n"
- "where the options are:\n"
- "\t-@ create file system at specified offset\n"
- "\t-B get bootstrap from file\n"
- "\t-C create image file with specified size\n"
- "\t-F FAT type (12, 16, or 32)\n"
- "\t-I volume ID\n"
- "\t-L volume label\n"
- "\t-N don't create file system: just print out parameters\n"
- "\t-O OEM string\n"
- "\t-S bytes/sector\n"
- "\t-a sectors/FAT\n"
- "\t-b block size\n"
- "\t-c sectors/cluster\n"
- "\t-e root directory entries\n"
- "\t-f standard format\n"
- "\t-h drive heads\n"
- "\t-i file system info sector\n"
- "\t-k backup boot sector\n"
- "\t-m media descriptor\n"
- "\t-n number of FATs\n"
- "\t-o hidden sectors\n"
- "\t-r reserved sectors\n"
- "\t-s file system size (sectors)\n"
- "\t-u sectors/track\n");
- exit(1);
+ fprintf(stderr,
+ "usage: newfs_msdos [ -options ] special [disktype]\n"
+ "where the options are:\n"
+ "\t-@ create file system at specified offset\n"
+ "\t-A Attempt to cluster align root directory\n"
+ "\t-B get bootstrap from file\n"
+ "\t-C create image file with specified size\n"
+ "\t-F FAT type (12, 16, or 32)\n"
+ "\t-I volume ID\n"
+ "\t-L volume label\n"
+ "\t-N don't create file system: just print out parameters\n"
+ "\t-O OEM string\n"
+ "\t-S bytes/sector\n"
+ "\t-a sectors/FAT\n"
+ "\t-b block size\n"
+ "\t-c sectors/cluster\n"
+ "\t-e root directory entries\n"
+ "\t-f standard format\n"
+ "\t-h drive heads\n"
+ "\t-i file system info sector\n"
+ "\t-k backup boot sector\n"
+ "\t-m media descriptor\n"
+ "\t-n number of FATs\n"
+ "\t-o hidden sectors\n"
+ "\t-r reserved sectors\n"
+ "\t-s file system size (sectors)\n"
+ "\t-u sectors/track\n");
+ exit(1);
}
diff --git a/toolbox/notify.c b/toolbox/notify.c
index c983ed5..8ce346c 100644
--- a/toolbox/notify.c
+++ b/toolbox/notify.c
@@ -101,14 +101,17 @@
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];
+ char* filename = file_names[event->wd + id_offset];
+ char* alloc_buf = NULL;
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);
+ if(asprintf(&alloc_buf, "%s/%s", filename, event->name) < 0) {
+ fprintf(stderr, "asprintf failed, %s\n", strerror(errno));
+ return 1;
+ }
+ filename = alloc_buf;
}
ffd = open(filename, O_RDONLY);
display_name = (verbose >= 2 || event->len == 0) ? filename : event->name;
@@ -132,6 +135,7 @@
printf("%s: %s", display_name, buf);
}
close(ffd);
+ free(alloc_buf);
}
if(event_count && --event_count == 0)
return 0;
diff --git a/toolbox/printenv.c b/toolbox/printenv.c
deleted file mode 100644
index d5ea531..0000000
--- a/toolbox/printenv.c
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-extern char** environ;
-
-int printenv_main (int argc, char **argv)
-{
- char** e;
- char* v;
- int i;
-
- if (argc == 1) {
- e = environ;
- while (*e) {
- printf("%s\n", *e);
- e++;
- }
- } else {
- for (i=1; i<argc; i++) {
- v = getenv(argv[i]);
- if (v) {
- printf("%s\n", v);
- }
- }
- }
-
- return 0;
-}
-
diff --git a/toolbox/ps.c b/toolbox/ps.c
index e9fba0b..4f001b8 100644
--- a/toolbox/ps.c
+++ b/toolbox/ps.c
@@ -28,7 +28,8 @@
#define SHOW_POLICY 4
#define SHOW_CPU 8
#define SHOW_MACLABEL 16
-#define SHOW_ABI 32
+#define SHOW_NUMERIC_UID 32
+#define SHOW_ABI 64
static int display_flags = 0;
@@ -43,12 +44,12 @@
struct stat stats;
int fd, r;
char *ptr, *name, *state;
- int ppid, tty;
+ int ppid;
unsigned wchan, rss, vss, eip;
unsigned utime, stime;
int prio, nice, rtprio, sched, psr;
struct passwd *pw;
-
+
sprintf(statline, "/proc/%d", pid);
stat(statline, &stats);
@@ -70,7 +71,7 @@
}
cmdline[r] = 0;
}
-
+
fd = open(statline, O_RDONLY);
if(fd == 0) return -1;
r = read(fd, statline, 1023);
@@ -91,8 +92,7 @@
ppid = atoi(nexttok(&ptr));
nexttok(&ptr); // pgrp
nexttok(&ptr); // sid
- tty = atoi(nexttok(&ptr));
-
+ nexttok(&ptr); // tty
nexttok(&ptr); // tpgid
nexttok(&ptr); // flags
nexttok(&ptr); // minflt
@@ -132,22 +132,22 @@
psr = atoi(nexttok(&ptr)); // processor
rtprio = atoi(nexttok(&ptr)); // rt_priority
sched = atoi(nexttok(&ptr)); // scheduling policy
-
- tty = atoi(nexttok(&ptr));
-
+
+ nexttok(&ptr); // tty
+
if(tid != 0) {
ppid = pid;
pid = tid;
}
pw = getpwuid(stats.st_uid);
- if(pw == 0) {
+ if(pw == 0 || (display_flags & SHOW_NUMERIC_UID)) {
sprintf(user,"%d",(int)stats.st_uid);
} else {
strcpy(user,pw->pw_name);
}
-
- if(!namefilter || !strncmp(name, namefilter, strlen(namefilter))) {
+
+ if(!namefilter || !strncmp(cmdline[0] ? cmdline : name, namefilter, strlen(namefilter))) {
if (display_flags & SHOW_MACLABEL) {
fd = open(macline, O_RDONLY);
strcpy(macline, "-");
@@ -229,7 +229,7 @@
sprintf(tmp,"/proc/%d/task",pid);
d = opendir(tmp);
if(d == 0) return;
-
+
while((de = readdir(d)) != 0){
if(isdigit(de->d_name[0])){
int tid = atoi(de->d_name);
@@ -237,7 +237,7 @@
ps_line(pid, tid, namefilter);
}
}
- closedir(d);
+ closedir(d);
}
int ps_main(int argc, char **argv)
@@ -247,13 +247,15 @@
char *namefilter = 0;
int pidfilter = 0;
int threads = 0;
-
+
d = opendir("/proc");
if(d == 0) return -1;
while(argc > 1){
if(!strcmp(argv[1],"-t")) {
threads = 1;
+ } else if(!strcmp(argv[1],"-n")) {
+ display_flags |= SHOW_NUMERIC_UID;
} else if(!strcmp(argv[1],"-x")) {
display_flags |= SHOW_TIME;
} else if(!strcmp(argv[1], "-Z")) {
diff --git a/toolbox/uid_from_user.c b/toolbox/pwcache.c
similarity index 75%
rename from toolbox/uid_from_user.c
rename to toolbox/pwcache.c
index fd48d3c..9d81981 100644
--- a/toolbox/uid_from_user.c
+++ b/toolbox/pwcache.c
@@ -26,7 +26,9 @@
* 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) {
@@ -37,3 +39,23 @@
*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..6183677 100644
--- a/toolbox/r.c
+++ b/toolbox/r.c
@@ -18,7 +18,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/rm.c b/toolbox/rm.c
deleted file mode 100644
index 957b586..0000000
--- a/toolbox/rm.c
+++ /dev/null
@@ -1,126 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <dirent.h>
-#include <limits.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#define OPT_RECURSIVE 1
-#define OPT_FORCE 2
-
-static int usage()
-{
- fprintf(stderr,"Usage: rm [-rR] [-f] <target>\n");
- return -1;
-}
-
-/* return -1 on failure, with errno set to the first error */
-static int unlink_recursive(const char* name, int flags)
-{
- struct stat st;
- DIR *dir;
- struct dirent *de;
- int fail = 0;
-
- /* is it a file or directory? */
- if (lstat(name, &st) < 0)
- return ((flags & OPT_FORCE) && errno == ENOENT) ? 0 : -1;
-
- /* a file, so unlink it */
- if (!S_ISDIR(st.st_mode))
- return unlink(name);
-
- /* a directory, so open handle */
- dir = opendir(name);
- if (dir == NULL)
- return -1;
-
- /* recurse over components */
- errno = 0;
- while ((de = readdir(dir)) != NULL) {
- char dn[PATH_MAX];
- if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, "."))
- continue;
- sprintf(dn, "%s/%s", name, de->d_name);
- if (unlink_recursive(dn, flags) < 0) {
- if (!(flags & OPT_FORCE)) {
- fail = 1;
- break;
- }
- }
- errno = 0;
- }
- /* in case readdir or unlink_recursive failed */
- if (fail || errno < 0) {
- int save = errno;
- closedir(dir);
- errno = save;
- return -1;
- }
-
- /* close directory handle */
- if (closedir(dir) < 0)
- return -1;
-
- /* delete target directory */
- return rmdir(name);
-}
-
-int rm_main(int argc, char *argv[])
-{
- int ret;
- int i, c;
- int flags = 0;
- int something_failed = 0;
-
- if (argc < 2)
- return usage();
-
- /* check flags */
- do {
- c = getopt(argc, argv, "frR");
- if (c == EOF)
- break;
- switch (c) {
- case 'f':
- flags |= OPT_FORCE;
- break;
- case 'r':
- case 'R':
- flags |= OPT_RECURSIVE;
- break;
- }
- } while (1);
-
- if (optind < 1 || optind >= argc) {
- usage();
- return -1;
- }
-
- /* loop over the file/directory args */
- for (i = optind; i < argc; i++) {
-
- if (flags & OPT_RECURSIVE) {
- ret = unlink_recursive(argv[i], flags);
- } else {
- ret = unlink(argv[i]);
- if (ret < 0 && errno == ENOENT && (flags & OPT_FORCE)) {
- continue;
- }
- }
-
- if (ret < 0) {
- fprintf(stderr, "rm failed for %s, %s\n", argv[i], strerror(errno));
- if (!(flags & OPT_FORCE)) {
- return -1;
- } else {
- something_failed = 1;
- }
- }
- }
-
- return something_failed;
-}
-
diff --git a/toolbox/rmdir.c b/toolbox/rmdir.c
deleted file mode 100644
index 06f3df2..0000000
--- a/toolbox/rmdir.c
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-
-static int usage()
-{
- fprintf(stderr,"rmdir <directory>\n");
- return -1;
-}
-
-int rmdir_main(int argc, char *argv[])
-{
- int symbolic = 0;
- int ret;
- if(argc < 2) return usage();
-
- while(argc > 1) {
- argc--;
- argv++;
- ret = rmdir(argv[0]);
- if(ret < 0) {
- fprintf(stderr, "rmdir failed for %s, %s\n", argv[0], strerror(errno));
- return ret;
- }
- }
-
- 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/schedtop.c b/toolbox/schedtop.c
index 0c85e76..2fccd2e 100644
--- a/toolbox/schedtop.c
+++ b/toolbox/schedtop.c
@@ -227,7 +227,6 @@
}
for (i = 0; i < last_processes.active; i++) {
int pid = last_processes.data[i].pid;
- int tid = last_processes.data[i].tid;
for (j = 0; j < processes.active; j++)
if (pid == processes.data[j].pid)
break;
@@ -270,9 +269,6 @@
{
int c;
DIR *d;
- struct dirent *de;
- char *namefilter = 0;
- int pidfilter = 0;
uint32_t flags = 0;
int delay = 3000000;
float delay_f;
diff --git a/toolbox/sendevent.c b/toolbox/sendevent.c
index 1608e6c..4b5a761 100644
--- a/toolbox/sendevent.c
+++ b/toolbox/sendevent.c
@@ -1,55 +1,16 @@
+#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>
-
-
int sendevent_main(int argc, char *argv[])
{
- int i;
int fd;
- int ret;
+ ssize_t ret;
int version;
struct input_event event;
@@ -72,7 +33,7 @@
event.code = atoi(argv[3]);
event.value = atoi(argv[4]);
ret = write(fd, &event, sizeof(event));
- if(ret < sizeof(event)) {
+ if(ret < (ssize_t) sizeof(event)) {
fprintf(stderr, "write event failed, %s\n", strerror(errno));
return -1;
}
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/sleep.c b/toolbox/sleep.c
deleted file mode 100644
index c09ae03..0000000
--- a/toolbox/sleep.c
+++ /dev/null
@@ -1,64 +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 <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-static void
-usage(const char *s)
-{
- fprintf(stderr, "USAGE: %s SECONDS\n", s);
- exit(-1);
-}
-
-int sleep_main(int argc, char *argv[])
-{
- unsigned long seconds;
- char *endptr;
-
- if (argc != 2) {
- usage(argv[0]);
- }
-
- seconds = strtoul(argv[1], &endptr, 10);
-
- if (endptr == argv[1]) {
- usage(argv[0]);
- }
-
-
- sleep((unsigned int)seconds);
-
- return 0;
-}
-
-
diff --git a/toolbox/start.c b/toolbox/start.c
index 26344da..6c8a3f2 100644
--- a/toolbox/start.c
+++ b/toolbox/start.c
@@ -7,12 +7,11 @@
int start_main(int argc, char *argv[])
{
- char buf[1024];
-
if(argc > 1) {
property_set("ctl.start", argv[1]);
} else {
/* defaults to starting the common services stopped by stop.c */
+ property_set("ctl.start", "netd");
property_set("ctl.start", "surfaceflinger");
property_set("ctl.start", "zygote");
property_set("ctl.start", "zygote_secondary");
diff --git a/toolbox/stop.c b/toolbox/stop.c
index 6552c7c..5e3ce3c 100644
--- a/toolbox/stop.c
+++ b/toolbox/stop.c
@@ -5,8 +5,6 @@
int stop_main(int argc, char *argv[])
{
- char buf[1024];
-
if(argc > 1) {
property_set("ctl.stop", argv[1]);
} else{
@@ -14,6 +12,7 @@
property_set("ctl.stop", "zygote_secondary");
property_set("ctl.stop", "zygote");
property_set("ctl.stop", "surfaceflinger");
+ property_set("ctl.stop", "netd");
}
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 21d2287..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>
-
-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);
-}
-
-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/sync.c b/toolbox/sync.c
deleted file mode 100644
index 8284276..0000000
--- a/toolbox/sync.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include <unistd.h>
-
-int sync_main(int argc, char **argv)
-{
- sync();
- return 0;
-}
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/top.c b/toolbox/top.c
index 7382f1f..b1a275c 100644
--- a/toolbox/top.c
+++ b/toolbox/top.c
@@ -32,6 +32,7 @@
#include <ctype.h>
#include <dirent.h>
#include <grp.h>
+#include <inttypes.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -59,13 +60,13 @@
char name[PROC_NAME_LEN];
char tname[THREAD_NAME_LEN];
char state;
- long unsigned utime;
- long unsigned stime;
- long unsigned delta_utime;
- long unsigned delta_stime;
- long unsigned delta_time;
- long vss;
- long rss;
+ uint64_t utime;
+ uint64_t stime;
+ uint64_t delta_utime;
+ uint64_t delta_stime;
+ uint64_t delta_time;
+ uint64_t vss;
+ uint64_t rss;
int prs;
int num_threads;
char policy[POLICY_NAME_LEN];
@@ -328,7 +329,6 @@
static int read_stat(char *filename, struct proc_info *proc) {
FILE *file;
char buf[MAX_LINE], *open_paren, *close_paren;
- int res, idx;
file = fopen(filename, "r");
if (!file) return 1;
@@ -345,10 +345,19 @@
proc->tname[THREAD_NAME_LEN-1] = 0;
/* Scan rest of string. */
- sscanf(close_paren + 1, " %c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
- "%lu %lu %*d %*d %*d %*d %*d %*d %*d %lu %ld "
- "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d",
- &proc->state, &proc->utime, &proc->stime, &proc->vss, &proc->rss, &proc->prs);
+ sscanf(close_paren + 1,
+ " %c " "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
+ "%" SCNu64
+ "%" SCNu64 "%*d %*d %*d %*d %*d %*d %*d "
+ "%" SCNu64
+ "%" SCNu64 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
+ "%d",
+ &proc->state,
+ &proc->utime,
+ &proc->stime,
+ &proc->vss,
+ &proc->rss,
+ &proc->prs);
return 0;
}
@@ -414,9 +423,7 @@
struct proc_info *old_proc, *proc;
long unsigned total_delta_time;
struct passwd *user;
- struct group *group;
char *user_str, user_buf[20];
- char *group_str, group_buf[20];
for (i = 0; i < num_new_procs; i++) {
if (new_procs[i]) {
@@ -467,25 +474,21 @@
if (!proc || (max_procs && (i >= max_procs)))
break;
user = getpwuid(proc->uid);
- group = getgrgid(proc->gid);
if (user && user->pw_name) {
user_str = user->pw_name;
} else {
snprintf(user_buf, 20, "%d", proc->uid);
user_str = user_buf;
}
- if (group && group->gr_name) {
- group_str = group->gr_name;
+ if (!threads) {
+ printf("%5d %2d %3" PRIu64 "%% %c %5d %6" PRIu64 "K %6" PRIu64 "K %3s %-8.8s %s\n",
+ proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
+ proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->name[0] != 0 ? proc->name : proc->tname);
} else {
- snprintf(group_buf, 20, "%d", proc->gid);
- group_str = group_buf;
+ printf("%5d %5d %2d %3" PRIu64 "%% %c %6" PRIu64 "K %6" PRIu64 "K %3s %-8.8s %-15s %s\n",
+ proc->pid, proc->tid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state,
+ proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->tname, proc->name);
}
- if (!threads)
- printf("%5d %2d %3ld%% %c %5d %6ldK %6ldK %3s %-8.8s %s\n", proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
- proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->name[0] != 0 ? proc->name : proc->tname);
- else
- printf("%5d %5d %2d %3ld%% %c %6ldK %6ldK %3s %-8.8s %-15s %s\n", proc->pid, proc->tid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state,
- proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->tname, proc->name);
}
}
diff --git a/toolbox/umount.c b/toolbox/umount.c
index 890e870..3e17396 100644
--- a/toolbox/umount.c
+++ b/toolbox/umount.c
@@ -33,7 +33,6 @@
char mount_path[256];
char rest[256];
int result = 0;
- int path_length = strlen(path);
f = fopen("/proc/mounts", "r");
if (!f) {
diff --git a/toolbox/cat.c b/toolbox/upstream-netbsd/bin/cat/cat.c
similarity index 67%
rename from toolbox/cat.c
rename to toolbox/upstream-netbsd/bin/cat/cat.c
index 6ac31f8..cca8cf5 100644
--- a/toolbox/cat.c
+++ b/toolbox/upstream-netbsd/bin/cat/cat.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cat.c,v 1.43 2004/01/04 03:31:28 jschauma Exp $ */
+/* $NetBSD: cat.c,v 1.54 2013/12/08 08:32:13 spz Exp $ */
/*
* Copyright (c) 1989, 1993
@@ -32,208 +32,59 @@
* 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>
-#define CAT_BUFSIZ (4096)
-
static int bflag, eflag, fflag, lflag, nflag, sflag, tflag, vflag;
+static size_t bsize;
static int rval;
static const char *filename;
-static void
-cook_buf(FILE *fp)
-{
- int ch, gobble, line, prev;
- int stdout_err = 0;
-
- line = gobble = 0;
- for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
- if (prev == '\n') {
- if (ch == '\n') {
- if (sflag) {
- if (!gobble && putchar(ch) == EOF)
- break;
- gobble = 1;
- continue;
- }
- if (nflag) {
- if (!bflag) {
- if (fprintf(stdout,
- "%6d\t", ++line) < 0) {
- stdout_err++;
- break;
- }
- } else if (eflag) {
- if (fprintf(stdout,
- "%6s\t", "") < 0) {
- stdout_err++;
- break;
- }
- }
- }
- } else if (nflag) {
- if (fprintf(stdout, "%6d\t", ++line) < 0) {
- stdout_err++;
- 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 = (ch) & 0x7f;
- }
- if (iscntrl(ch)) {
- if (putchar('^') == EOF ||
- putchar(ch == '\177' ? '?' :
- ch | 0100) == EOF)
- break;
- continue;
- }
- }
- if (putchar(ch) == EOF)
- break;
- }
- if (stdout_err) {
- perror(filename);
- rval = 1;
- }
-}
-
-static 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) {
- perror("fopen");
- rval = 1;
- ++argv;
- continue;
- }
- filename = *argv++;
- }
- cook_buf(fp);
- if (fp != stdin)
- fclose(fp);
- } while (*argv);
-}
-
-static void
-raw_cat(int rfd)
-{
- static char *buf;
- static char fb_buf[CAT_BUFSIZ];
- static size_t bsize;
-
- struct stat sbuf;
- ssize_t nr, nw, off;
- int wfd;
-
- wfd = fileno(stdout);
- if (buf == NULL) {
- if (fstat(wfd, &sbuf) == 0) {
- bsize = sbuf.st_blksize > CAT_BUFSIZ ?
- sbuf.st_blksize : CAT_BUFSIZ;
- buf = malloc(bsize);
- }
- if (buf == NULL) {
- buf = fb_buf;
- bsize = CAT_BUFSIZ;
- }
- }
- 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)
- {
- perror("write");
- exit(EXIT_FAILURE);
- }
- if (nr < 0) {
- fprintf(stderr,"%s: invalid length\n", filename);
- rval = 1;
- }
-}
-
-static void
-raw_args(char **argv)
-{
- int fd;
-
- fd = fileno(stdin);
- filename = "stdin";
- do {
- if (*argv) {
- if (!strcmp(*argv, "-"))
- fd = fileno(stdin);
- 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);
- errno = EINVAL;
- goto skipnomsg;
- }
- }
- else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
-skip:
- perror(*argv);
-skipnomsg:
- rval = 1;
- ++argv;
- continue;
- }
- filename = *argv++;
- }
- raw_cat(fd);
- if (fd != fileno(stdin))
- close(fd);
- } while (*argv);
-}
+void cook_args(char *argv[]);
+void cook_buf(FILE *);
+void raw_args(char *argv[]);
+void raw_cat(int);
int
-cat_main(int argc, char *argv[])
+main(int argc, char *argv[])
{
int ch;
struct flock stdout_lock;
- while ((ch = getopt(argc, argv, "beflnstv")) != -1)
+ 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;
@@ -255,14 +106,18 @@
case 't':
tflag = vflag = 1; /* -t implies -v */
break;
+ case 'u':
+ setbuf(stdout, NULL);
+ break;
case 'v':
vflag = 1;
break;
default:
case '?':
- fprintf(stderr,
- "usage: cat [-beflnstv] [-] [file ...]\n");
- exit(EXIT_FAILURE);
+ (void)fprintf(stderr,
+ "Usage: %s [-beflnstuv] [-B bsize] [-] "
+ "[file ...]\n", getprogname());
+ return EXIT_FAILURE;
}
argv += optind;
@@ -272,10 +127,7 @@
stdout_lock.l_type = F_WRLCK;
stdout_lock.l_whence = SEEK_SET;
if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1)
- {
- perror("fcntl");
- exit(EXIT_FAILURE);
- }
+ err(EXIT_FAILURE, "stdout");
}
if (bflag || eflag || nflag || sflag || tflag || vflag)
@@ -283,9 +135,195 @@
else
raw_args(argv);
if (fclose(stdout))
- {
- perror("fclose");
- exit(EXIT_FAILURE);
+ 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;
}
- exit(rval);
+ 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/cp/cp.c b/toolbox/upstream-netbsd/bin/cp/cp.c
similarity index 95%
rename from toolbox/cp/cp.c
rename to toolbox/upstream-netbsd/bin/cp/cp.c
index bd3c70e..4bbe1b7 100644
--- a/toolbox/cp/cp.c
+++ b/toolbox/upstream-netbsd/bin/cp/cp.c
@@ -49,11 +49,11 @@
/*
* 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
@@ -103,20 +103,18 @@
}
int
-cp_main(int argc, char *argv[])
+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;
-#ifndef ANDROID
setprogname(argv[0]);
-#endif
(void)setlocale(LC_ALL, "");
Hflag = Lflag = Pflag = Rflag = 0;
- while ((ch = getopt(argc, argv, "HLNPRfailprv")) != -1)
+ while ((ch = getopt(argc, argv, "HLNPRfailprv")) != -1)
switch (ch) {
case 'H':
Hflag = 1;
@@ -164,14 +162,14 @@
break;
case '?':
default:
- cp_usage();
+ usage();
/* NOTREACHED */
}
argc -= optind;
argv += optind;
if (argc < 2)
- cp_usage();
+ usage();
fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
if (rflag) {
@@ -218,12 +216,10 @@
to.target_end = to.p_end;
/* Set end of argument list for fts(3). */
- argv[argc] = NULL;
-
-#ifndef ANDROID
+ argv[argc] = NULL;
+
(void)signal(SIGINFO, progress);
-#endif
-
+
/*
* Cp has two distinct cases:
*
@@ -249,9 +245,9 @@
if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
/*
* Case (1). Target is not a directory.
- */
+ */
if (argc > 1)
- cp_usage();
+ usage();
/*
* Need to detect the case:
* cp -R dir foo
@@ -268,7 +264,7 @@
err(EXIT_FAILURE, "%s", *argv);
/* NOTREACHED */
}
-
+
if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag))
type = DIR_TO_DNE;
else
@@ -357,8 +353,8 @@
}
/*
- * If we are in case (2) or (3) above, we need to append the
- * source name to the target name.
+ * 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 +
@@ -391,10 +387,10 @@
if (curr->fts_level == FTS_ROOTLEVEL) {
if (type != DIR_TO_DNE) {
p = strrchr(curr->fts_path, '/');
- base = (p == NULL) ? 0 :
+ base = (p == NULL) ? 0 :
(int)(p - curr->fts_path + 1);
- if (!strcmp(&curr->fts_path[base],
+ if (!strcmp(&curr->fts_path[base],
".."))
base += 1;
} else
@@ -451,7 +447,7 @@
((fts_options & FTS_COMFOLLOW) && curr->fts_level == 0)) {
if (copy_file(curr, dne))
this_failed = any_failed = 1;
- } else {
+ } else {
if (copy_link(curr, !dne))
this_failed = any_failed = 1;
}
@@ -483,7 +479,7 @@
*/
pushdne(dne);
if (dne) {
- if (mkdir(to.p_path,
+ if (mkdir(to.p_path,
curr->fts_statp->st_mode | S_IRWXU) < 0)
err(EXIT_FAILURE, "%s",
to.p_path);
@@ -499,14 +495,14 @@
{
/*
* 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.
+ * 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,
+ (void)chmod(to.p_path,
curr->fts_statp->st_mode);
}
else
@@ -531,7 +527,7 @@
if (Rflag) {
if (copy_fifo(curr->fts_statp, !dne))
this_failed = any_failed = 1;
- } else
+ } else
if (copy_file(curr, dne))
this_failed = any_failed = 1;
break;
diff --git a/toolbox/cp/extern.h b/toolbox/upstream-netbsd/bin/cp/extern.h
similarity index 97%
rename from toolbox/cp/extern.h
rename to toolbox/upstream-netbsd/bin/cp/extern.h
index ffbadf7..e393844 100644
--- a/toolbox/cp/extern.h
+++ b/toolbox/upstream-netbsd/bin/cp/extern.h
@@ -55,7 +55,7 @@
int copy_special(struct stat *, int);
int set_utimes(const char *, struct stat *);
int setfile(struct stat *, int);
-void cp_usage(void) __attribute__((__noreturn__));
+void usage(void) __attribute__((__noreturn__));
__END_DECLS
#endif /* !_EXTERN_H_ */
diff --git a/toolbox/cp/utils.c b/toolbox/upstream-netbsd/bin/cp/utils.c
similarity index 92%
rename from toolbox/cp/utils.c
rename to toolbox/upstream-netbsd/bin/cp/utils.c
index b682bbe..d8f900a 100644
--- a/toolbox/cp/utils.c
+++ b/toolbox/upstream-netbsd/bin/cp/utils.c
@@ -1,4 +1,4 @@
-/* $NetBSD: utils.c,v 1.41 2012/01/04 15:58:37 christos Exp $ */
+/* $NetBSD: utils.c,v 1.42 2013/12/11 06:00:11 dholland Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
@@ -34,7 +34,7 @@
#if 0
static char sccsid[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94";
#else
-__RCSID("$NetBSD: utils.c,v 1.41 2012/01/04 15:58:37 christos Exp $");
+__RCSID("$NetBSD: utils.c,v 1.42 2013/12/11 06:00:11 dholland Exp $");
#endif
#endif /* not lint */
@@ -42,9 +42,7 @@
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
-#ifndef ANDROID
#include <sys/extattr.h>
-#endif
#include <err.h>
#include <errno.h>
@@ -58,10 +56,6 @@
#include "extern.h"
-#ifdef ANDROID
-#define MAXBSIZE 65536
-#endif
-
#define MMAP_MAX_SIZE (8 * 1048576)
#define MMAP_MAX_WRITE (64 * 1024)
@@ -70,7 +64,7 @@
{
static struct timeval tv[2];
-#ifdef ANDROID
+#ifdef __ANDROID__
tv[0].tv_sec = fs->st_atime;
tv[0].tv_usec = 0;
tv[1].tv_sec = fs->st_mtime;
@@ -85,8 +79,8 @@
TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
if (lutimes(file, tv)) {
- warn("lutimes: %s", file);
- return (1);
+ warn("lutimes: %s", file);
+ return (1);
}
#endif
return (0);
@@ -116,7 +110,7 @@
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);
@@ -192,13 +186,14 @@
}
return (0);
}
- /* NOTREACHED */
/*
* 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;
@@ -273,9 +268,11 @@
rval = 1;
}
}
+#ifndef __ANDROID__
}
+#endif
-#ifndef ANDROID
+#ifndef __ANDROID__
if (pflag && (fcpxattr(from_fd, to_fd) != 0))
warn("%s: error copying extended attributes", to.p_path);
#endif
@@ -311,7 +308,7 @@
rval = 1;
}
/* set the mod/access times now after close of the fd */
- if (pflag && set_utimes(to.p_path, fs)) {
+ if (pflag && set_utimes(to.p_path, fs)) {
rval = 1;
}
return (rval);
@@ -400,16 +397,16 @@
}
fs->st_mode &= ~(S_ISUID | S_ISGID);
}
-#ifdef ANDROID
- if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
+#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)) {
+ if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
#endif
- warn("chmod: %s", to.p_path);
- rval = 1;
- }
+ warn("chmod: %s", to.p_path);
+ rval = 1;
+ }
-#ifndef ANDROID
+#ifndef __ANDROID__
if (!islink && !Nflag) {
unsigned long fflags = fs->st_flags;
/*
@@ -436,11 +433,12 @@
}
void
-cp_usage(void)
+usage(void)
{
(void)fprintf(stderr,
- "usage: cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src target\n"
- " cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src1 ... srcN directory\n");
+ "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/dd/args.c b/toolbox/upstream-netbsd/bin/dd/args.c
new file mode 100644
index 0000000..207e300
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/dd/args.c
@@ -0,0 +1,391 @@
+/* $NetBSD: args.c,v 1.38 2013/07/17 12:55:48 christos Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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[] = "@(#)args.c 8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: args.c,v 1.38 2013/07/17 12:55:48 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dd.h"
+#include "extern.h"
+
+static int c_arg(const void *, const void *);
+
+#ifdef NO_MSGFMT
+static void f_msgfmt(char *) __dead;
+#else
+static void f_msgfmt(char *);
+#endif /* NO_MSGFMT */
+
+#ifdef NO_CONV
+static void f_conv(char *) __dead;
+#else
+static void f_conv(char *);
+static int c_conv(const void *, const void *);
+#endif /* NO_CONV */
+
+static void f_bs(char *);
+static void f_cbs(char *);
+static void f_count(char *);
+static void f_files(char *);
+static void f_ibs(char *);
+static void f_if(char *);
+static void f_obs(char *);
+static void f_of(char *);
+static void f_seek(char *);
+static void f_skip(char *);
+static void f_progress(char *);
+
+static const struct arg {
+ const char *name;
+ void (*f)(char *);
+ u_int set, noset;
+} args[] = {
+ /* the array needs to be sorted by the first column so
+ bsearch() can be used to find commands quickly */
+ { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC },
+ { "cbs", f_cbs, C_CBS, C_CBS },
+ { "conv", f_conv, 0, 0 },
+ { "count", f_count, C_COUNT, C_COUNT },
+ { "files", f_files, C_FILES, C_FILES },
+ { "ibs", f_ibs, C_IBS, C_BS|C_IBS },
+ { "if", f_if, C_IF, C_IF },
+ { "iseek", f_skip, C_SKIP, C_SKIP },
+ { "msgfmt", f_msgfmt, 0, 0 },
+ { "obs", f_obs, C_OBS, C_BS|C_OBS },
+ { "of", f_of, C_OF, C_OF },
+ { "oseek", f_seek, C_SEEK, C_SEEK },
+ { "progress", f_progress, 0, 0 },
+ { "seek", f_seek, C_SEEK, C_SEEK },
+ { "skip", f_skip, C_SKIP, C_SKIP },
+};
+
+/*
+ * args -- parse JCL syntax of dd.
+ */
+void
+jcl(char **argv)
+{
+ struct arg *ap, tmp;
+ char *oper, *arg;
+
+ in.dbsz = out.dbsz = 512;
+
+ while ((oper = *++argv) != NULL) {
+ if ((oper = strdup(oper)) == NULL) {
+ errx(EXIT_FAILURE,
+ "unable to allocate space for the argument %s",
+ *argv);
+ /* NOTREACHED */
+ }
+ if ((arg = strchr(oper, '=')) == NULL) {
+ errx(EXIT_FAILURE, "unknown operand %s", oper);
+ /* NOTREACHED */
+ }
+ *arg++ = '\0';
+ if (!*arg) {
+ errx(EXIT_FAILURE, "no value specified for %s", oper);
+ /* NOTREACHED */
+ }
+ tmp.name = oper;
+ if (!(ap = bsearch(&tmp, args,
+ __arraycount(args), sizeof(*args), c_arg))) {
+ errx(EXIT_FAILURE, "unknown operand %s", tmp.name);
+ /* NOTREACHED */
+ }
+ if (ddflags & ap->noset) {
+ errx(EXIT_FAILURE,
+ "%s: illegal argument combination or already set",
+ tmp.name);
+ /* NOTREACHED */
+ }
+ ddflags |= ap->set;
+ ap->f(arg);
+ }
+
+ /* Final sanity checks. */
+
+ if (ddflags & C_BS) {
+ /*
+ * Bs is turned off by any conversion -- we assume the user
+ * just wanted to set both the input and output block sizes
+ * and didn't want the bs semantics, so we don't warn.
+ */
+ if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
+ C_UNBLOCK | C_OSYNC | C_ASCII | C_EBCDIC | C_SPARSE)) {
+ ddflags &= ~C_BS;
+ ddflags |= C_IBS|C_OBS;
+ }
+
+ /* Bs supersedes ibs and obs. */
+ if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
+ warnx("bs supersedes ibs and obs");
+ }
+
+ /*
+ * Ascii/ebcdic and cbs implies block/unblock.
+ * Block/unblock requires cbs and vice-versa.
+ */
+ if (ddflags & (C_BLOCK|C_UNBLOCK)) {
+ if (!(ddflags & C_CBS)) {
+ errx(EXIT_FAILURE, "record operations require cbs");
+ /* NOTREACHED */
+ }
+ cfunc = ddflags & C_BLOCK ? block : unblock;
+ } else if (ddflags & C_CBS) {
+ if (ddflags & (C_ASCII|C_EBCDIC)) {
+ if (ddflags & C_ASCII) {
+ ddflags |= C_UNBLOCK;
+ cfunc = unblock;
+ } else {
+ ddflags |= C_BLOCK;
+ cfunc = block;
+ }
+ } else {
+ errx(EXIT_FAILURE,
+ "cbs meaningless if not doing record operations");
+ /* NOTREACHED */
+ }
+ } else
+ cfunc = def;
+
+ /* Read, write and seek calls take off_t as arguments.
+ *
+ * The following check is not done because an off_t is a quad
+ * for current NetBSD implementations.
+ *
+ * if (in.offset > INT_MAX/in.dbsz || out.offset > INT_MAX/out.dbsz)
+ * errx(1, "seek offsets cannot be larger than %d", INT_MAX);
+ */
+}
+
+static int
+c_arg(const void *a, const void *b)
+{
+
+ return (strcmp(((const struct arg *)a)->name,
+ ((const struct arg *)b)->name));
+}
+
+static void
+f_bs(char *arg)
+{
+
+ in.dbsz = out.dbsz = strsuftoll("block size", arg, 1, UINT_MAX);
+}
+
+static void
+f_cbs(char *arg)
+{
+
+ cbsz = strsuftoll("conversion record size", arg, 1, UINT_MAX);
+}
+
+static void
+f_count(char *arg)
+{
+
+ cpy_cnt = strsuftoll("block count", arg, 0, LLONG_MAX);
+ if (!cpy_cnt)
+ terminate(0);
+}
+
+static void
+f_files(char *arg)
+{
+
+ files_cnt = (u_int)strsuftoll("file count", arg, 0, UINT_MAX);
+ if (!files_cnt)
+ terminate(0);
+}
+
+static void
+f_ibs(char *arg)
+{
+
+ if (!(ddflags & C_BS))
+ in.dbsz = strsuftoll("input block size", arg, 1, UINT_MAX);
+}
+
+static void
+f_if(char *arg)
+{
+
+ in.name = arg;
+}
+
+#ifdef NO_MSGFMT
+/* Build a small version (i.e. for a ramdisk root) */
+static void
+f_msgfmt(char *arg)
+{
+
+ errx(EXIT_FAILURE, "msgfmt option disabled");
+ /* NOTREACHED */
+}
+#else /* NO_MSGFMT */
+static void
+f_msgfmt(char *arg)
+{
+
+ /*
+ * If the format string is not valid, dd_write_msg() will print
+ * an error and exit.
+ */
+ dd_write_msg(arg, 0);
+
+ msgfmt = arg;
+}
+#endif /* NO_MSGFMT */
+
+static void
+f_obs(char *arg)
+{
+
+ if (!(ddflags & C_BS))
+ out.dbsz = strsuftoll("output block size", arg, 1, UINT_MAX);
+}
+
+static void
+f_of(char *arg)
+{
+
+ out.name = arg;
+}
+
+static void
+f_seek(char *arg)
+{
+
+ out.offset = strsuftoll("seek blocks", arg, 0, LLONG_MAX);
+}
+
+static void
+f_skip(char *arg)
+{
+
+ in.offset = strsuftoll("skip blocks", arg, 0, LLONG_MAX);
+}
+
+static void
+f_progress(char *arg)
+{
+
+ progress = strsuftoll("progress blocks", arg, 0, LLONG_MAX);
+}
+
+#ifdef NO_CONV
+/* Build a small version (i.e. for a ramdisk root) */
+static void
+f_conv(char *arg)
+{
+
+ errx(EXIT_FAILURE, "conv option disabled");
+ /* NOTREACHED */
+}
+#else /* NO_CONV */
+
+static const struct conv {
+ const char *name;
+ u_int set, noset;
+ const u_char *ctab;
+} clist[] = {
+ { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX },
+ { "block", C_BLOCK, C_UNBLOCK, NULL },
+ { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX },
+ { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX },
+ { "lcase", C_LCASE, C_UCASE, NULL },
+ { "noerror", C_NOERROR, 0, NULL },
+ { "notrunc", C_NOTRUNC, 0, NULL },
+ { "oldascii", C_ASCII, C_EBCDIC, e2a_32V },
+ { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V },
+ { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V },
+ { "osync", C_OSYNC, C_BS, NULL },
+ { "sparse", C_SPARSE, 0, NULL },
+ { "swab", C_SWAB, 0, NULL },
+ { "sync", C_SYNC, 0, NULL },
+ { "ucase", C_UCASE, C_LCASE, NULL },
+ { "unblock", C_UNBLOCK, C_BLOCK, NULL },
+ /* If you add items to this table, be sure to add the
+ * conversions to the C_BS check in the jcl routine above.
+ */
+};
+
+static void
+f_conv(char *arg)
+{
+ struct conv *cp, tmp;
+
+ while (arg != NULL) {
+ tmp.name = strsep(&arg, ",");
+ if (!(cp = bsearch(&tmp, clist,
+ __arraycount(clist), sizeof(*clist), c_conv))) {
+ errx(EXIT_FAILURE, "unknown conversion %s", tmp.name);
+ /* NOTREACHED */
+ }
+ if (ddflags & cp->noset) {
+ errx(EXIT_FAILURE,
+ "%s: illegal conversion combination", tmp.name);
+ /* NOTREACHED */
+ }
+ ddflags |= cp->set;
+ if (cp->ctab)
+ ctab = cp->ctab;
+ }
+}
+
+static int
+c_conv(const void *a, const void *b)
+{
+
+ return (strcmp(((const struct conv *)a)->name,
+ ((const struct conv *)b)->name));
+}
+
+#endif /* NO_CONV */
diff --git a/toolbox/upstream-netbsd/bin/dd/conv.c b/toolbox/upstream-netbsd/bin/dd/conv.c
new file mode 100644
index 0000000..d4a8a09
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/dd/conv.c
@@ -0,0 +1,283 @@
+/* $NetBSD: conv.c,v 1.17 2003/08/07 09:05:10 agc Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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[] = "@(#)conv.c 8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: conv.c,v 1.17 2003/08/07 09:05:10 agc Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "dd.h"
+#include "extern.h"
+
+/*
+ * def --
+ * Copy input to output. Input is buffered until reaches obs, and then
+ * output until less than obs remains. Only a single buffer is used.
+ * Worst case buffer calculation is (ibs + obs - 1).
+ */
+void
+def(void)
+{
+ uint64_t cnt;
+ u_char *inp;
+ const u_char *t;
+
+ if ((t = ctab) != NULL)
+ for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
+ *inp = t[*inp];
+
+ /* Make the output buffer look right. */
+ out.dbp = in.dbp;
+ out.dbcnt = in.dbcnt;
+
+ if (in.dbcnt >= out.dbsz) {
+ /* If the output buffer is full, write it. */
+ dd_out(0);
+
+ /*
+ * Ddout copies the leftover output to the beginning of
+ * the buffer and resets the output buffer. Reset the
+ * input buffer to match it.
+ */
+ in.dbp = out.dbp;
+ in.dbcnt = out.dbcnt;
+ }
+}
+
+void
+def_close(void)
+{
+
+ /* Just update the count, everything is already in the buffer. */
+ if (in.dbcnt)
+ out.dbcnt = in.dbcnt;
+}
+
+#ifdef NO_CONV
+/* Build a smaller version (i.e. for a miniroot) */
+/* These can not be called, but just in case... */
+static const char no_block[] = "unblock and -DNO_CONV?";
+void block(void) { errx(EXIT_FAILURE, "%s", no_block + 2); }
+void block_close(void) { errx(EXIT_FAILURE, "%s", no_block + 2); }
+void unblock(void) { errx(EXIT_FAILURE, "%s", no_block); }
+void unblock_close(void) { errx(EXIT_FAILURE, "%s", no_block); }
+#else /* NO_CONV */
+
+/*
+ * Copy variable length newline terminated records with a max size cbsz
+ * bytes to output. Records less than cbs are padded with spaces.
+ *
+ * max in buffer: MAX(ibs, cbsz)
+ * max out buffer: obs + cbsz
+ */
+void
+block(void)
+{
+ static int intrunc;
+ int ch = 0; /* pacify gcc */
+ uint64_t cnt, maxlen;
+ u_char *inp, *outp;
+ const u_char *t;
+
+ /*
+ * Record truncation can cross block boundaries. If currently in a
+ * truncation state, keep tossing characters until reach a newline.
+ * Start at the beginning of the buffer, as the input buffer is always
+ * left empty.
+ */
+ if (intrunc) {
+ for (inp = in.db, cnt = in.dbrcnt;
+ cnt && *inp++ != '\n'; --cnt);
+ if (!cnt) {
+ in.dbcnt = 0;
+ in.dbp = in.db;
+ return;
+ }
+ intrunc = 0;
+ /* Adjust the input buffer numbers. */
+ in.dbcnt = cnt - 1;
+ in.dbp = inp + cnt - 1;
+ }
+
+ /*
+ * Copy records (max cbsz size chunks) into the output buffer. The
+ * translation is done as we copy into the output buffer.
+ */
+ for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
+ maxlen = MIN(cbsz, in.dbcnt);
+ if ((t = ctab) != NULL)
+ for (cnt = 0;
+ cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
+ *outp++ = t[ch];
+ else
+ for (cnt = 0;
+ cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
+ *outp++ = ch;
+ /*
+ * Check for short record without a newline. Reassemble the
+ * input block.
+ */
+ if (ch != '\n' && in.dbcnt < cbsz) {
+ (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
+ break;
+ }
+
+ /* Adjust the input buffer numbers. */
+ in.dbcnt -= cnt;
+ if (ch == '\n')
+ --in.dbcnt;
+
+ /* Pad short records with spaces. */
+ if (cnt < cbsz)
+ (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
+ else {
+ /*
+ * If the next character wouldn't have ended the
+ * block, it's a truncation.
+ */
+ if (!in.dbcnt || *inp != '\n')
+ ++st.trunc;
+
+ /* Toss characters to a newline. */
+ for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
+ if (!in.dbcnt)
+ intrunc = 1;
+ else
+ --in.dbcnt;
+ }
+
+ /* Adjust output buffer numbers. */
+ out.dbp += cbsz;
+ if ((out.dbcnt += cbsz) >= out.dbsz)
+ dd_out(0);
+ outp = out.dbp;
+ }
+ in.dbp = in.db + in.dbcnt;
+}
+
+void
+block_close(void)
+{
+
+ /*
+ * Copy any remaining data into the output buffer and pad to a record.
+ * Don't worry about truncation or translation, the input buffer is
+ * always empty when truncating, and no characters have been added for
+ * translation. The bottom line is that anything left in the input
+ * buffer is a truncated record. Anything left in the output buffer
+ * just wasn't big enough.
+ */
+ if (in.dbcnt) {
+ ++st.trunc;
+ (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
+ (void)memset(out.dbp + in.dbcnt,
+ ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
+ out.dbcnt += cbsz;
+ }
+}
+
+/*
+ * Convert fixed length (cbsz) records to variable length. Deletes any
+ * trailing blanks and appends a newline.
+ *
+ * max in buffer: MAX(ibs, cbsz) + cbsz
+ * max out buffer: obs + cbsz
+ */
+void
+unblock(void)
+{
+ uint64_t cnt;
+ u_char *inp;
+ const u_char *t;
+
+ /* Translation and case conversion. */
+ if ((t = ctab) != NULL)
+ for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--)
+ *inp = t[*inp];
+ /*
+ * Copy records (max cbsz size chunks) into the output buffer. The
+ * translation has to already be done or we might not recognize the
+ * spaces.
+ */
+ for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
+ for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
+ if (t >= inp) {
+ cnt = t - inp + 1;
+ (void)memmove(out.dbp, inp, cnt);
+ out.dbp += cnt;
+ out.dbcnt += cnt;
+ }
+ ++out.dbcnt;
+ *out.dbp++ = '\n';
+ if (out.dbcnt >= out.dbsz)
+ dd_out(0);
+ }
+ if (in.dbcnt)
+ (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
+ in.dbp = in.db + in.dbcnt;
+}
+
+void
+unblock_close(void)
+{
+ uint64_t cnt;
+ u_char *t;
+
+ if (in.dbcnt) {
+ warnx("%s: short input record", in.name);
+ for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
+ if (t >= in.db) {
+ cnt = t - in.db + 1;
+ (void)memmove(out.dbp, in.db, cnt);
+ out.dbp += cnt;
+ out.dbcnt += cnt;
+ }
+ ++out.dbcnt;
+ *out.dbp++ = '\n';
+ }
+}
+
+#endif /* NO_CONV */
diff --git a/toolbox/upstream-netbsd/bin/dd/dd.c b/toolbox/upstream-netbsd/bin/dd/dd.c
new file mode 100644
index 0000000..03d080c
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/dd/dd.c
@@ -0,0 +1,598 @@
+/* $NetBSD: dd.c,v 1.49 2012/02/21 01:49:01 matt Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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) 1991, 1993, 1994\
+ The Regents of the University of California. All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: dd.c,v 1.49 2012/02/21 01:49:01 matt Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+#include <sys/time.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "dd.h"
+#include "extern.h"
+
+static void dd_close(void);
+static void dd_in(void);
+static void getfdtype(IO *);
+static void redup_clean_fd(IO *);
+static void setup(void);
+
+int main(int, char *[]);
+
+IO in, out; /* input/output state */
+STAT st; /* statistics */
+void (*cfunc)(void); /* conversion function */
+uint64_t cpy_cnt; /* # of blocks to copy */
+static off_t pending = 0; /* pending seek if sparse */
+u_int ddflags; /* conversion options */
+uint64_t cbsz; /* conversion block size */
+u_int files_cnt = 1; /* # of files to copy */
+uint64_t progress = 0; /* display sign of life */
+const u_char *ctab; /* conversion table */
+sigset_t infoset; /* a set blocking SIGINFO */
+const char *msgfmt = "posix"; /* default summary() message format */
+
+/*
+ * Ops for stdin/stdout and crunch'd dd. These are always host ops.
+ */
+static const struct ddfops ddfops_stdfd = {
+ .op_open = open,
+ .op_close = close,
+ .op_fcntl = fcntl,
+ .op_ioctl = ioctl,
+ .op_fstat = fstat,
+ .op_fsync = fsync,
+ .op_ftruncate = ftruncate,
+ .op_lseek = lseek,
+ .op_read = read,
+ .op_write = write,
+};
+extern const struct ddfops ddfops_prog;
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+
+ setprogname(argv[0]);
+ (void)setlocale(LC_ALL, "");
+
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch (ch) {
+ default:
+ errx(EXIT_FAILURE, "usage: dd [operand ...]");
+ /* NOTREACHED */
+ }
+ }
+ argc -= (optind - 1);
+ argv += (optind - 1);
+
+ jcl(argv);
+#ifndef CRUNCHOPS
+ if (ddfops_prog.op_init && ddfops_prog.op_init() == -1)
+ err(1, "prog init");
+#endif
+ setup();
+
+ (void)signal(SIGINFO, summaryx);
+ (void)signal(SIGINT, terminate);
+ (void)sigemptyset(&infoset);
+ (void)sigaddset(&infoset, SIGINFO);
+
+ (void)atexit(summary);
+
+ while (files_cnt--)
+ dd_in();
+
+ dd_close();
+ exit(0);
+ /* NOTREACHED */
+}
+
+static void
+setup(void)
+{
+#ifdef CRUNCHOPS
+ const struct ddfops *prog_ops = &ddfops_stdfd;
+#else
+ const struct ddfops *prog_ops = &ddfops_prog;
+#endif
+
+ if (in.name == NULL) {
+ in.name = "stdin";
+ in.fd = STDIN_FILENO;
+ in.ops = &ddfops_stdfd;
+ } else {
+ in.ops = prog_ops;
+ in.fd = ddop_open(in, in.name, O_RDONLY, 0);
+ if (in.fd < 0)
+ err(EXIT_FAILURE, "%s", in.name);
+ /* NOTREACHED */
+
+ /* Ensure in.fd is outside the stdio descriptor range */
+ redup_clean_fd(&in);
+ }
+
+ getfdtype(&in);
+
+ if (files_cnt > 1 && !(in.flags & ISTAPE)) {
+ errx(EXIT_FAILURE, "files is not supported for non-tape devices");
+ /* NOTREACHED */
+ }
+
+ if (out.name == NULL) {
+ /* No way to check for read access here. */
+ out.fd = STDOUT_FILENO;
+ out.name = "stdout";
+ out.ops = &ddfops_stdfd;
+ } else {
+ out.ops = prog_ops;
+#define OFLAGS \
+ (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
+ out.fd = ddop_open(out, out.name, O_RDWR | OFLAGS, DEFFILEMODE);
+ /*
+ * May not have read access, so try again with write only.
+ * Without read we may have a problem if output also does
+ * not support seeks.
+ */
+ if (out.fd < 0) {
+ out.fd = ddop_open(out, out.name, O_WRONLY | OFLAGS,
+ DEFFILEMODE);
+ out.flags |= NOREAD;
+ }
+ if (out.fd < 0) {
+ err(EXIT_FAILURE, "%s", out.name);
+ /* NOTREACHED */
+ }
+
+ /* Ensure out.fd is outside the stdio descriptor range */
+ redup_clean_fd(&out);
+ }
+
+ getfdtype(&out);
+
+ /*
+ * Allocate space for the input and output buffers. If not doing
+ * record oriented I/O, only need a single buffer.
+ */
+ if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
+ size_t dbsz = out.dbsz;
+ if (!(ddflags & C_BS))
+ dbsz += in.dbsz - 1;
+ if ((in.db = malloc(dbsz)) == NULL) {
+ err(EXIT_FAILURE, NULL);
+ /* NOTREACHED */
+ }
+ out.db = in.db;
+ } else if ((in.db =
+ malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
+ (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) {
+ err(EXIT_FAILURE, NULL);
+ /* NOTREACHED */
+ }
+ in.dbp = in.db;
+ out.dbp = out.db;
+
+ /* Position the input/output streams. */
+ if (in.offset)
+ pos_in();
+ if (out.offset)
+ pos_out();
+
+ /*
+ * Truncate the output file; ignore errors because it fails on some
+ * kinds of output files, tapes, for example.
+ */
+ if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
+ (void)ddop_ftruncate(out, out.fd, (off_t)out.offset * out.dbsz);
+
+ /*
+ * If converting case at the same time as another conversion, build a
+ * table that does both at once. If just converting case, use the
+ * built-in tables.
+ */
+ if (ddflags & (C_LCASE|C_UCASE)) {
+#ifdef NO_CONV
+ /* Should not get here, but just in case... */
+ errx(EXIT_FAILURE, "case conv and -DNO_CONV");
+ /* NOTREACHED */
+#else /* NO_CONV */
+ u_int cnt;
+
+ if (ddflags & C_ASCII || ddflags & C_EBCDIC) {
+ if (ddflags & C_LCASE) {
+ for (cnt = 0; cnt < 256; ++cnt)
+ casetab[cnt] = tolower(ctab[cnt]);
+ } else {
+ for (cnt = 0; cnt < 256; ++cnt)
+ casetab[cnt] = toupper(ctab[cnt]);
+ }
+ } else {
+ if (ddflags & C_LCASE) {
+ for (cnt = 0; cnt < 256; ++cnt)
+ casetab[cnt] = tolower(cnt);
+ } else {
+ for (cnt = 0; cnt < 256; ++cnt)
+ casetab[cnt] = toupper(cnt);
+ }
+ }
+
+ ctab = casetab;
+#endif /* NO_CONV */
+ }
+
+ (void)gettimeofday(&st.start, NULL); /* Statistics timestamp. */
+}
+
+static void
+getfdtype(IO *io)
+{
+ struct mtget mt;
+ struct stat sb;
+
+ if (io->ops->op_fstat(io->fd, &sb)) {
+ err(EXIT_FAILURE, "%s", io->name);
+ /* NOTREACHED */
+ }
+ if (S_ISCHR(sb.st_mode))
+ io->flags |= io->ops->op_ioctl(io->fd, MTIOCGET, &mt)
+ ? ISCHR : ISTAPE;
+ else if (io->ops->op_lseek(io->fd, (off_t)0, SEEK_CUR) == -1
+ && errno == ESPIPE)
+ io->flags |= ISPIPE; /* XXX fixed in 4.4BSD */
+}
+
+/*
+ * Move the parameter file descriptor to a descriptor that is outside the
+ * stdio descriptor range, if necessary. This is required to avoid
+ * accidentally outputting completion or error messages into the
+ * output file that were intended for the tty.
+ */
+static void
+redup_clean_fd(IO *io)
+{
+ int fd = io->fd;
+ int newfd;
+
+ if (fd != STDIN_FILENO && fd != STDOUT_FILENO &&
+ fd != STDERR_FILENO)
+ /* File descriptor is ok, return immediately. */
+ return;
+
+ /*
+ * 3 is the first descriptor greater than STD*_FILENO. Any
+ * free descriptor valued 3 or above is acceptable...
+ */
+ newfd = io->ops->op_fcntl(fd, F_DUPFD, 3);
+ if (newfd < 0) {
+ err(EXIT_FAILURE, "dupfd IO");
+ /* NOTREACHED */
+ }
+
+ io->ops->op_close(fd);
+ io->fd = newfd;
+}
+
+static void
+dd_in(void)
+{
+ int flags;
+ int64_t n;
+
+ for (flags = ddflags;;) {
+ if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
+ return;
+
+ /*
+ * Clear the buffer first if doing "sync" on input.
+ * If doing block operations use spaces. This will
+ * affect not only the C_NOERROR case, but also the
+ * last partial input block which should be padded
+ * with zero and not garbage.
+ */
+ if (flags & C_SYNC) {
+ if (flags & (C_BLOCK|C_UNBLOCK))
+ (void)memset(in.dbp, ' ', in.dbsz);
+ else
+ (void)memset(in.dbp, 0, in.dbsz);
+ }
+
+ n = ddop_read(in, in.fd, in.dbp, in.dbsz);
+ if (n == 0) {
+ in.dbrcnt = 0;
+ return;
+ }
+
+ /* Read error. */
+ if (n < 0) {
+
+ /*
+ * If noerror not specified, die. POSIX requires that
+ * the warning message be followed by an I/O display.
+ */
+ if (!(flags & C_NOERROR)) {
+ err(EXIT_FAILURE, "%s", in.name);
+ /* NOTREACHED */
+ }
+ warn("%s", in.name);
+ summary();
+
+ /*
+ * If it's not a tape drive or a pipe, seek past the
+ * error. If your OS doesn't do the right thing for
+ * raw disks this section should be modified to re-read
+ * in sector size chunks.
+ */
+ if (!(in.flags & (ISPIPE|ISTAPE)) &&
+ ddop_lseek(in, in.fd, (off_t)in.dbsz, SEEK_CUR))
+ warn("%s", in.name);
+
+ /* If sync not specified, omit block and continue. */
+ if (!(ddflags & C_SYNC))
+ continue;
+
+ /* Read errors count as full blocks. */
+ in.dbcnt += in.dbrcnt = in.dbsz;
+ ++st.in_full;
+
+ /* Handle full input blocks. */
+ } else if ((uint64_t)n == in.dbsz) {
+ in.dbcnt += in.dbrcnt = n;
+ ++st.in_full;
+
+ /* Handle partial input blocks. */
+ } else {
+ /* If sync, use the entire block. */
+ if (ddflags & C_SYNC)
+ in.dbcnt += in.dbrcnt = in.dbsz;
+ else
+ in.dbcnt += in.dbrcnt = n;
+ ++st.in_part;
+ }
+
+ /*
+ * POSIX states that if bs is set and no other conversions
+ * than noerror, notrunc or sync are specified, the block
+ * is output without buffering as it is read.
+ */
+ if (ddflags & C_BS) {
+ out.dbcnt = in.dbcnt;
+ dd_out(1);
+ in.dbcnt = 0;
+ continue;
+ }
+
+ if (ddflags & C_SWAB) {
+ if ((n = in.dbrcnt) & 1) {
+ ++st.swab;
+ --n;
+ }
+ swab(in.dbp, in.dbp, n);
+ }
+
+ in.dbp += in.dbrcnt;
+ (*cfunc)();
+ }
+}
+
+/*
+ * Cleanup any remaining I/O and flush output. If necessary, output file
+ * is truncated.
+ */
+static void
+dd_close(void)
+{
+
+ if (cfunc == def)
+ def_close();
+ else if (cfunc == block)
+ block_close();
+ else if (cfunc == unblock)
+ unblock_close();
+ if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
+ (void)memset(out.dbp, 0, out.dbsz - out.dbcnt);
+ out.dbcnt = out.dbsz;
+ }
+ /* If there are pending sparse blocks, make sure
+ * to write out the final block un-sparse
+ */
+ if ((out.dbcnt == 0) && pending) {
+ memset(out.db, 0, out.dbsz);
+ out.dbcnt = out.dbsz;
+ out.dbp = out.db + out.dbcnt;
+ pending -= out.dbsz;
+ }
+ if (out.dbcnt)
+ dd_out(1);
+
+ /*
+ * Reporting nfs write error may be deferred until next
+ * write(2) or close(2) system call. So, we need to do an
+ * extra check. If an output is stdout, the file structure
+ * may be shared with other processes and close(2) just
+ * decreases the reference count.
+ */
+ if (out.fd == STDOUT_FILENO && ddop_fsync(out, out.fd) == -1
+ && errno != EINVAL) {
+ err(EXIT_FAILURE, "fsync stdout");
+ /* NOTREACHED */
+ }
+ if (ddop_close(out, out.fd) == -1) {
+ err(EXIT_FAILURE, "close");
+ /* NOTREACHED */
+ }
+}
+
+void
+dd_out(int force)
+{
+ static int warned;
+ int64_t cnt, n, nw;
+ u_char *outp;
+
+ /*
+ * Write one or more blocks out. The common case is writing a full
+ * output block in a single write; increment the full block stats.
+ * Otherwise, we're into partial block writes. If a partial write,
+ * and it's a character device, just warn. If a tape device, quit.
+ *
+ * The partial writes represent two cases. 1: Where the input block
+ * was less than expected so the output block was less than expected.
+ * 2: Where the input block was the right size but we were forced to
+ * write the block in multiple chunks. The original versions of dd(1)
+ * never wrote a block in more than a single write, so the latter case
+ * never happened.
+ *
+ * One special case is if we're forced to do the write -- in that case
+ * we play games with the buffer size, and it's usually a partial write.
+ */
+ outp = out.db;
+ for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
+ for (cnt = n;; cnt -= nw) {
+
+ if (!force && ddflags & C_SPARSE) {
+ int sparse, i;
+ sparse = 1; /* Is buffer sparse? */
+ for (i = 0; i < cnt; i++)
+ if (outp[i] != 0) {
+ sparse = 0;
+ break;
+ }
+ if (sparse) {
+ pending += cnt;
+ outp += cnt;
+ nw = 0;
+ break;
+ }
+ }
+ if (pending != 0) {
+ if (ddop_lseek(out,
+ out.fd, pending, SEEK_CUR) == -1)
+ err(EXIT_FAILURE, "%s: seek error creating sparse file",
+ out.name);
+ }
+ nw = bwrite(&out, outp, cnt);
+ if (nw <= 0) {
+ if (nw == 0)
+ errx(EXIT_FAILURE,
+ "%s: end of device", out.name);
+ /* NOTREACHED */
+ if (errno != EINTR)
+ err(EXIT_FAILURE, "%s", out.name);
+ /* NOTREACHED */
+ nw = 0;
+ }
+ if (pending) {
+ st.bytes += pending;
+ st.sparse += pending/out.dbsz;
+ st.out_full += pending/out.dbsz;
+ pending = 0;
+ }
+ outp += nw;
+ st.bytes += nw;
+ if (nw == n) {
+ if ((uint64_t)n != out.dbsz)
+ ++st.out_part;
+ else
+ ++st.out_full;
+ break;
+ }
+ ++st.out_part;
+ if (nw == cnt)
+ break;
+ if (out.flags & ISCHR && !warned) {
+ warned = 1;
+ warnx("%s: short write on character device", out.name);
+ }
+ if (out.flags & ISTAPE)
+ errx(EXIT_FAILURE,
+ "%s: short write on tape device", out.name);
+ /* NOTREACHED */
+
+ }
+ if ((out.dbcnt -= n) < out.dbsz)
+ break;
+ }
+
+ /* Reassemble the output block. */
+ if (out.dbcnt)
+ (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
+ out.dbp = out.db + out.dbcnt;
+
+ if (progress && (st.out_full + st.out_part) % progress == 0)
+ (void)write(STDERR_FILENO, ".", 1);
+}
+
+/*
+ * A protected against SIGINFO write
+ */
+ssize_t
+bwrite(IO *io, const void *buf, size_t len)
+{
+ sigset_t oset;
+ ssize_t rv;
+ int oerrno;
+
+ (void)sigprocmask(SIG_BLOCK, &infoset, &oset);
+ rv = io->ops->op_write(io->fd, buf, len);
+ oerrno = errno;
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+ errno = oerrno;
+ return (rv);
+}
diff --git a/toolbox/dd.h b/toolbox/upstream-netbsd/bin/dd/dd.h
similarity index 74%
rename from toolbox/dd.h
rename to toolbox/upstream-netbsd/bin/dd/dd.h
index 89f2833..b01c7b3 100644
--- a/toolbox/dd.h
+++ b/toolbox/upstream-netbsd/bin/dd/dd.h
@@ -1,4 +1,4 @@
-/* $NetBSD: dd.h,v 1.12 2004/01/17 20:48:57 dbj Exp $ */
+/* $NetBSD: dd.h,v 1.15 2011/02/04 19:42:12 pooka Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
@@ -35,7 +35,40 @@
* @(#)dd.h 8.3 (Berkeley) 4/2/94
*/
-#include <stdint.h>
+#include <sys/stat.h>
+
+struct ddfops {
+ int (*op_init)(void);
+
+ int (*op_open)(const char *, int, ...);
+ int (*op_close)(int);
+
+ int (*op_fcntl)(int, int, ...);
+#ifdef __ANDROID__
+ int (*op_ioctl)(int, int, ...);
+#else
+ int (*op_ioctl)(int, unsigned long, ...);
+#endif
+
+ int (*op_fstat)(int, struct stat *);
+ int (*op_fsync)(int);
+ int (*op_ftruncate)(int, off_t);
+
+ off_t (*op_lseek)(int, off_t, int);
+
+ ssize_t (*op_read)(int, void *, size_t);
+ ssize_t (*op_write)(int, const void *, size_t);
+};
+
+#define ddop_open(dir, a1, a2, ...) dir.ops->op_open(a1, a2, __VA_ARGS__)
+#define ddop_close(dir, a1) dir.ops->op_close(a1)
+#define ddop_fcntl(dir, a1, a2, ...) dir.ops->op_fcntl(a1, a2, __VA_ARGS__)
+#define ddop_ioctl(dir, a1, a2, ...) dir.ops->op_ioctl(a1, a2, __VA_ARGS__)
+#define ddop_fsync(dir, a1) dir.ops->op_fsync(a1)
+#define ddop_ftruncate(dir, a1, a2) dir.ops->op_ftruncate(a1, a2)
+#define ddop_lseek(dir, a1, a2, a3) dir.ops->op_lseek(a1, a2, a3)
+#define ddop_read(dir, a1, a2, a3) dir.ops->op_read(a1, a2, a3)
+#define ddop_write(dir, a1, a2, a3) dir.ops->op_write(a1, a2, a3)
/* Input/output stream state. */
typedef struct {
@@ -54,6 +87,7 @@
const char *name; /* name */
int fd; /* file descriptor */
uint64_t offset; /* # of blocks to skip */
+ struct ddfops const *ops; /* ops to use with fd */
} IO;
typedef struct {
@@ -91,4 +125,3 @@
#define C_UNBLOCK 0x80000
#define C_OSYNC 0x100000
#define C_SPARSE 0x200000
-#define C_FDATASYNC 0x400000
diff --git a/toolbox/upstream-netbsd/bin/dd/dd_hostops.c b/toolbox/upstream-netbsd/bin/dd/dd_hostops.c
new file mode 100644
index 0000000..d6e7a89
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/dd/dd_hostops.c
@@ -0,0 +1,53 @@
+/* $NetBSD: dd_hostops.c,v 1.1 2011/02/04 19:42:12 pooka Exp $ */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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
+__RCSID("$NetBSD: dd_hostops.c,v 1.1 2011/02/04 19:42:12 pooka Exp $");
+#endif /* !lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "dd.h"
+
+const struct ddfops ddfops_prog = {
+ .op_open = open,
+ .op_close = close,
+ .op_fcntl = fcntl,
+ .op_ioctl = ioctl,
+ .op_fstat = fstat,
+ .op_fsync = fsync,
+ .op_ftruncate = ftruncate,
+ .op_lseek = lseek,
+ .op_read = read,
+ .op_write = write,
+};
diff --git a/toolbox/upstream-netbsd/bin/dd/extern.h b/toolbox/upstream-netbsd/bin/dd/extern.h
new file mode 100644
index 0000000..9c59021
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/dd/extern.h
@@ -0,0 +1,82 @@
+/* $NetBSD: extern.h,v 1.22 2011/11/07 22:24:23 jym Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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.3 (Berkeley) 4/2/94
+ */
+
+#include <sys/cdefs.h>
+
+#ifdef NO_CONV
+__dead void block(void);
+__dead void block_close(void);
+__dead void unblock(void);
+__dead void unblock_close(void);
+#else
+void block(void);
+void block_close(void);
+void unblock(void);
+void unblock_close(void);
+#endif
+
+#ifndef NO_MSGFMT
+int dd_write_msg(const char *, int);
+#endif
+
+void dd_out(int);
+void def(void);
+void def_close(void);
+void jcl(char **);
+void pos_in(void);
+void pos_out(void);
+void summary(void);
+void summaryx(int);
+__dead void terminate(int);
+void unblock(void);
+void unblock_close(void);
+ssize_t bwrite(IO *, const void *, size_t);
+
+extern IO in, out;
+extern STAT st;
+extern void (*cfunc)(void);
+extern uint64_t cpy_cnt;
+extern uint64_t cbsz;
+extern u_int ddflags;
+extern u_int files_cnt;
+extern uint64_t progress;
+extern const u_char *ctab;
+extern const u_char a2e_32V[], a2e_POSIX[];
+extern const u_char e2a_32V[], e2a_POSIX[];
+extern const u_char a2ibm_32V[], a2ibm_POSIX[];
+extern u_char casetab[];
+extern const char *msgfmt;
diff --git a/toolbox/upstream-netbsd/bin/dd/misc.c b/toolbox/upstream-netbsd/bin/dd/misc.c
new file mode 100644
index 0000000..0fac98b
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/dd/misc.c
@@ -0,0 +1,342 @@
+/* $NetBSD: misc.c,v 1.23 2011/11/07 22:24:23 jym Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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[] = "@(#)misc.c 8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: misc.c,v 1.23 2011/11/07 22:24:23 jym Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <util.h>
+#include <inttypes.h>
+
+#include "dd.h"
+#include "extern.h"
+
+#define tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000)
+
+static void posix_summary(void);
+#ifndef NO_MSGFMT
+static void custom_summary(void);
+static void human_summary(void);
+static void quiet_summary(void);
+
+static void buffer_write(const char *, size_t, int);
+#endif /* NO_MSGFMT */
+
+void
+summary(void)
+{
+
+ if (progress)
+ (void)write(STDERR_FILENO, "\n", 1);
+
+#ifdef NO_MSGFMT
+ return posix_summary();
+#else /* NO_MSGFMT */
+ if (strncmp(msgfmt, "human", sizeof("human")) == 0)
+ return human_summary();
+
+ if (strncmp(msgfmt, "posix", sizeof("posix")) == 0)
+ return posix_summary();
+
+ if (strncmp(msgfmt, "quiet", sizeof("quiet")) == 0)
+ return quiet_summary();
+
+ return custom_summary();
+#endif /* NO_MSGFMT */
+}
+
+static void
+posix_summary(void)
+{
+ char buf[100];
+ int64_t mS;
+ struct timeval tv;
+
+ if (progress)
+ (void)write(STDERR_FILENO, "\n", 1);
+
+ (void)gettimeofday(&tv, NULL);
+ mS = tv2mS(tv) - tv2mS(st.start);
+ if (mS == 0)
+ mS = 1;
+
+ /* Use snprintf(3) so that we don't reenter stdio(3). */
+ (void)snprintf(buf, sizeof(buf),
+ "%llu+%llu records in\n%llu+%llu records out\n",
+ (unsigned long long)st.in_full, (unsigned long long)st.in_part,
+ (unsigned long long)st.out_full, (unsigned long long)st.out_part);
+ (void)write(STDERR_FILENO, buf, strlen(buf));
+ if (st.swab) {
+ (void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n",
+ (unsigned long long)st.swab,
+ (st.swab == 1) ? "block" : "blocks");
+ (void)write(STDERR_FILENO, buf, strlen(buf));
+ }
+ if (st.trunc) {
+ (void)snprintf(buf, sizeof(buf), "%llu truncated %s\n",
+ (unsigned long long)st.trunc,
+ (st.trunc == 1) ? "block" : "blocks");
+ (void)write(STDERR_FILENO, buf, strlen(buf));
+ }
+ if (st.sparse) {
+ (void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n",
+ (unsigned long long)st.sparse,
+ (st.sparse == 1) ? "block" : "blocks");
+ (void)write(STDERR_FILENO, buf, strlen(buf));
+ }
+ (void)snprintf(buf, sizeof(buf),
+ "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n",
+ (unsigned long long) st.bytes,
+ (long) (mS / 1000),
+ (int) (mS % 1000),
+ (unsigned long long) (st.bytes * 1000LL / mS));
+ (void)write(STDERR_FILENO, buf, strlen(buf));
+}
+
+/* ARGSUSED */
+void
+summaryx(int notused)
+{
+
+ summary();
+}
+
+/* ARGSUSED */
+void
+terminate(int signo)
+{
+
+ summary();
+ (void)raise_default_signal(signo);
+ _exit(127);
+}
+
+#ifndef NO_MSGFMT
+/*
+ * Buffer write(2) calls
+ */
+static void
+buffer_write(const char *str, size_t size, int flush)
+{
+ static char wbuf[128];
+ static size_t cnt = 0; /* Internal counter to allow wbuf to wrap */
+
+ unsigned int i;
+
+ for (i = 0; i < size; i++) {
+ if (str != NULL) {
+ wbuf[cnt++] = str[i];
+ }
+ if (cnt >= sizeof(wbuf)) {
+ (void)write(STDERR_FILENO, wbuf, cnt);
+ cnt = 0;
+ }
+ }
+
+ if (flush != 0) {
+ (void)write(STDERR_FILENO, wbuf, cnt);
+ cnt = 0;
+ }
+}
+
+/*
+ * Write summary to stderr according to format 'fmt'. If 'enable' is 0, it
+ * will not attempt to write anything. Can be used to validate the
+ * correctness of the 'fmt' string.
+ */
+int
+dd_write_msg(const char *fmt, int enable)
+{
+ char hbuf[7], nbuf[32];
+ const char *ptr;
+ int64_t mS;
+ struct timeval tv;
+
+ (void)gettimeofday(&tv, NULL);
+ mS = tv2mS(tv) - tv2mS(st.start);
+ if (mS == 0)
+ mS = 1;
+
+#define ADDC(c) do { if (enable != 0) buffer_write(&c, 1, 0); } \
+ while (/*CONSTCOND*/0)
+#define ADDS(p) do { if (enable != 0) buffer_write(p, strlen(p), 0); } \
+ while (/*CONSTCOND*/0)
+
+ for (ptr = fmt; *ptr; ptr++) {
+ if (*ptr != '%') {
+ ADDC(*ptr);
+ continue;
+ }
+
+ switch (*++ptr) {
+ case 'b':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.bytes);
+ ADDS(nbuf);
+ break;
+ case 'B':
+ if (humanize_number(hbuf, sizeof(hbuf),
+ st.bytes, "B",
+ HN_AUTOSCALE, HN_DECIMAL) == -1)
+ warnx("humanize_number (bytes transferred)");
+ ADDS(hbuf);
+ break;
+ case 'e':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long) (st.bytes * 1000LL / mS));
+ ADDS(nbuf);
+ break;
+ case 'E':
+ if (humanize_number(hbuf, sizeof(hbuf),
+ st.bytes * 1000LL / mS, "B",
+ HN_AUTOSCALE, HN_DECIMAL) == -1)
+ warnx("humanize_number (bytes per second)");
+ ADDS(hbuf); ADDS("/sec");
+ break;
+ case 'i':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.in_part);
+ ADDS(nbuf);
+ break;
+ case 'I':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.in_full);
+ ADDS(nbuf);
+ break;
+ case 'o':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.out_part);
+ ADDS(nbuf);
+ break;
+ case 'O':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.out_full);
+ ADDS(nbuf);
+ break;
+ case 's':
+ (void)snprintf(nbuf, sizeof(nbuf), "%li.%03d",
+ (long) (mS / 1000), (int) (mS % 1000));
+ ADDS(nbuf);
+ break;
+ case 'p':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.sparse);
+ ADDS(nbuf);
+ break;
+ case 't':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.trunc);
+ ADDS(nbuf);
+ break;
+ case 'w':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.swab);
+ ADDS(nbuf);
+ break;
+ case 'P':
+ ADDS("block");
+ if (st.sparse != 1) ADDS("s");
+ break;
+ case 'T':
+ ADDS("block");
+ if (st.trunc != 1) ADDS("s");
+ break;
+ case 'W':
+ ADDS("block");
+ if (st.swab != 1) ADDS("s");
+ break;
+ case '%':
+ ADDC(*ptr);
+ break;
+ default:
+ if (*ptr == '\0')
+ goto done;
+ errx(EXIT_FAILURE, "unknown specifier '%c' in "
+ "msgfmt string", *ptr);
+ /* NOTREACHED */
+ }
+ }
+
+done:
+ /* flush buffer */
+ buffer_write(NULL, 0, 1);
+ return 0;
+}
+
+static void
+custom_summary(void)
+{
+
+ dd_write_msg(msgfmt, 1);
+}
+
+static void
+human_summary(void)
+{
+ (void)dd_write_msg("%I+%i records in\n%O+%o records out\n", 1);
+ if (st.swab) {
+ (void)dd_write_msg("%w odd length swab %W\n", 1);
+ }
+ if (st.trunc) {
+ (void)dd_write_msg("%t truncated %T\n", 1);
+ }
+ if (st.sparse) {
+ (void)dd_write_msg("%p sparse output %P\n", 1);
+ }
+ (void)dd_write_msg("%b bytes (%B) transferred in %s secs "
+ "(%e bytes/sec - %E)\n", 1);
+}
+
+static void
+quiet_summary(void)
+{
+
+ /* stay quiet */
+}
+#endif /* NO_MSGFMT */
diff --git a/toolbox/upstream-netbsd/bin/dd/position.c b/toolbox/upstream-netbsd/bin/dd/position.c
new file mode 100644
index 0000000..36dd580
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/dd/position.c
@@ -0,0 +1,185 @@
+/* $NetBSD: position.c,v 1.18 2010/11/22 21:04:28 pooka Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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[] = "@(#)position.c 8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: position.c,v 1.18 2010/11/22 21:04:28 pooka Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "dd.h"
+#include "extern.h"
+
+/*
+ * Position input/output data streams before starting the copy. Device type
+ * dependent. Seekable devices use lseek, and the rest position by reading.
+ * Seeking past the end of file can cause null blocks to be written to the
+ * output.
+ */
+void
+pos_in(void)
+{
+ int bcnt, cnt, nr, warned;
+
+ /* If not a pipe or tape device, try to seek on it. */
+ if (!(in.flags & (ISPIPE|ISTAPE))) {
+ if (ddop_lseek(in, in.fd,
+ (off_t)in.offset * (off_t)in.dbsz, SEEK_CUR) == -1) {
+ err(EXIT_FAILURE, "%s", in.name);
+ /* NOTREACHED */
+ }
+ return;
+ /* NOTREACHED */
+ }
+
+ /*
+ * Read the data. If a pipe, read until satisfy the number of bytes
+ * being skipped. No differentiation for reading complete and partial
+ * blocks for other devices.
+ */
+ for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) {
+ if ((nr = ddop_read(in, in.fd, in.db, bcnt)) > 0) {
+ if (in.flags & ISPIPE) {
+ if (!(bcnt -= nr)) {
+ bcnt = in.dbsz;
+ --cnt;
+ }
+ } else
+ --cnt;
+ continue;
+ }
+
+ if (nr == 0) {
+ if (files_cnt > 1) {
+ --files_cnt;
+ continue;
+ }
+ errx(EXIT_FAILURE, "skip reached end of input");
+ /* NOTREACHED */
+ }
+
+ /*
+ * Input error -- either EOF with no more files, or I/O error.
+ * If noerror not set die. POSIX requires that the warning
+ * message be followed by an I/O display.
+ */
+ if (ddflags & C_NOERROR) {
+ if (!warned) {
+
+ warn("%s", in.name);
+ warned = 1;
+ summary();
+ }
+ continue;
+ }
+ err(EXIT_FAILURE, "%s", in.name);
+ /* NOTREACHED */
+ }
+}
+
+void
+pos_out(void)
+{
+ struct mtop t_op;
+ int n;
+ uint64_t cnt;
+
+ /*
+ * If not a tape, try seeking on the file. Seeking on a pipe is
+ * going to fail, but don't protect the user -- they shouldn't
+ * have specified the seek operand.
+ */
+ if (!(out.flags & ISTAPE)) {
+ if (ddop_lseek(out, out.fd,
+ (off_t)out.offset * (off_t)out.dbsz, SEEK_SET) == -1)
+ err(EXIT_FAILURE, "%s", out.name);
+ /* NOTREACHED */
+ return;
+ }
+
+ /* If no read access, try using mtio. */
+ if (out.flags & NOREAD) {
+ t_op.mt_op = MTFSR;
+ t_op.mt_count = out.offset;
+
+ if (ddop_ioctl(out, out.fd, MTIOCTOP, &t_op) < 0)
+ err(EXIT_FAILURE, "%s", out.name);
+ /* NOTREACHED */
+ return;
+ }
+
+ /* Read it. */
+ for (cnt = 0; cnt < out.offset; ++cnt) {
+ if ((n = ddop_read(out, out.fd, out.db, out.dbsz)) > 0)
+ continue;
+
+ if (n < 0)
+ err(EXIT_FAILURE, "%s", out.name);
+ /* NOTREACHED */
+
+ /*
+ * If reach EOF, fill with NUL characters; first, back up over
+ * the EOF mark. Note, cnt has not yet been incremented, so
+ * the EOF read does not count as a seek'd block.
+ */
+ t_op.mt_op = MTBSR;
+ t_op.mt_count = 1;
+ if (ddop_ioctl(out, out.fd, MTIOCTOP, &t_op) == -1)
+ err(EXIT_FAILURE, "%s", out.name);
+ /* NOTREACHED */
+
+ while (cnt++ < out.offset)
+ if ((uint64_t)(n = bwrite(&out,
+ out.db, out.dbsz)) != out.dbsz)
+ err(EXIT_FAILURE, "%s", out.name);
+ /* NOTREACHED */
+ break;
+ }
+}
diff --git a/toolbox/upstream-netbsd/bin/ln/ln.c b/toolbox/upstream-netbsd/bin/ln/ln.c
new file mode 100644
index 0000000..9127477
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/ln/ln.c
@@ -0,0 +1,230 @@
+/* $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
new file mode 100644
index 0000000..4be6c30
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/mv/mv.c
@@ -0,0 +1,396 @@
+/* $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/cp/extern.h b/toolbox/upstream-netbsd/bin/mv/pathnames.h
similarity index 63%
copy from toolbox/cp/extern.h
copy to toolbox/upstream-netbsd/bin/mv/pathnames.h
index ffbadf7..7838946 100644
--- a/toolbox/cp/extern.h
+++ b/toolbox/upstream-netbsd/bin/mv/pathnames.h
@@ -1,7 +1,7 @@
-/* $NetBSD: extern.h,v 1.17 2012/01/04 15:58:37 christos Exp $ */
+/* $NetBSD: pathnames.h,v 1.8 2004/08/19 22:26:07 christos Exp $ */
-/*-
- * Copyright (c) 1991, 1993, 1994
+/*
+ * 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
@@ -28,34 +28,18 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)extern.h 8.2 (Berkeley) 4/1/94
+ * @(#)pathnames.h 8.1 (Berkeley) 5/31/93
*/
-#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 cp_usage(void) __attribute__((__noreturn__));
-__END_DECLS
-
-#endif /* !_EXTERN_H_ */
+#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
new file mode 100644
index 0000000..f183810
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/rm/rm.c
@@ -0,0 +1,625 @@
+/* $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
new file mode 100644
index 0000000..03261ce
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/rmdir/rmdir.c
@@ -0,0 +1,121 @@
+/* $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/include/namespace.h b/toolbox/upstream-netbsd/include/namespace.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/toolbox/upstream-netbsd/include/namespace.h
diff --git a/toolbox/upstream-netbsd/include/sys/extattr.h b/toolbox/upstream-netbsd/include/sys/extattr.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/toolbox/upstream-netbsd/include/sys/extattr.h
diff --git a/toolbox/upstream-netbsd/include/sys/mtio.h b/toolbox/upstream-netbsd/include/sys/mtio.h
new file mode 100644
index 0000000..8fb5655
--- /dev/null
+++ b/toolbox/upstream-netbsd/include/sys/mtio.h
@@ -0,0 +1 @@
+#include <linux/mtio.h>
diff --git a/toolbox/upstream-netbsd/lib/libc/gen/getbsize.c b/toolbox/upstream-netbsd/lib/libc/gen/getbsize.c
new file mode 100644
index 0000000..a9ce2c1
--- /dev/null
+++ b/toolbox/upstream-netbsd/lib/libc/gen/getbsize.c
@@ -0,0 +1,118 @@
+/* $NetBSD: getbsize.c,v 1.17 2012/06/25 22:32:43 abs Exp $ */
+
+/*-
+ * Copyright (c) 1991, 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>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)getbsize.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: getbsize.c,v 1.17 2012/06/25 22:32:43 abs Exp $");
+#endif
+#endif /* not lint */
+
+#include "namespace.h"
+
+#include <assert.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __weak_alias
+__weak_alias(getbsize,_getbsize)
+#endif
+
+char *
+getbsize(int *headerlenp, long *blocksizep)
+{
+ static char header[20];
+ long n, max, mul, blocksize;
+ char *ep, *p;
+ const char *form;
+
+#define KB (1024L)
+#define MB (1024L * 1024L)
+#define GB (1024L * 1024L * 1024L)
+#define MAXB GB /* No tera, peta, nor exa. */
+ form = "";
+ if ((p = getenv("BLOCKSIZE")) != NULL && *p != '\0') {
+ if ((n = strtol(p, &ep, 10)) < 0)
+ goto underflow;
+ if (n == 0)
+ n = 1;
+ if (*ep && ep[1])
+ goto fmterr;
+ switch (*ep) {
+ case 'G': case 'g':
+ form = "G";
+ max = MAXB / GB;
+ mul = GB;
+ break;
+ case 'K': case 'k':
+ form = "K";
+ max = MAXB / KB;
+ mul = KB;
+ break;
+ case 'M': case 'm':
+ form = "M";
+ max = MAXB / MB;
+ mul = MB;
+ break;
+ case '\0':
+ max = MAXB;
+ mul = 1;
+ break;
+ default:
+fmterr: warnx("%s: unknown blocksize", p);
+ n = 512;
+ mul = 1;
+ max = 0;
+ break;
+ }
+ if (n > max) {
+ warnx("maximum blocksize is %ldG", MAXB / GB);
+ n = max;
+ }
+ if ((blocksize = n * mul) < 512) {
+underflow: warnx("%s: minimum blocksize is 512", p);
+ form = "";
+ blocksize = n = 512;
+ }
+ } else
+ blocksize = n = 512;
+
+ if (headerlenp)
+ *headerlenp =
+ snprintf(header, sizeof(header), "%ld%s-blocks", n, form);
+ if (blocksizep)
+ *blocksizep = blocksize;
+ return (header);
+}
diff --git a/toolbox/upstream-netbsd/lib/libc/gen/humanize_number.c b/toolbox/upstream-netbsd/lib/libc/gen/humanize_number.c
new file mode 100644
index 0000000..533560f
--- /dev/null
+++ b/toolbox/upstream-netbsd/lib/libc/gen/humanize_number.c
@@ -0,0 +1,161 @@
+/* $NetBSD: humanize_number.c,v 1.16 2012/03/17 20:01:14 christos Exp $ */
+
+/*
+ * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: humanize_number.c,v 1.16 2012/03/17 20:01:14 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+
+int
+humanize_number(char *buf, size_t len, int64_t bytes,
+ const char *suffix, int scale, int flags)
+{
+ const char *prefixes, *sep;
+ int b, r, s1, s2, sign;
+ int64_t divisor, max, post = 1;
+ size_t i, baselen, maxscale;
+
+ _DIAGASSERT(buf != NULL);
+ _DIAGASSERT(suffix != NULL);
+ _DIAGASSERT(scale >= 0);
+
+ if (flags & HN_DIVISOR_1000) {
+ /* SI for decimal multiplies */
+ divisor = 1000;
+ if (flags & HN_B)
+ prefixes = "B\0k\0M\0G\0T\0P\0E";
+ else
+ prefixes = "\0\0k\0M\0G\0T\0P\0E";
+ } else {
+ /*
+ * binary multiplies
+ * XXX IEC 60027-2 recommends Ki, Mi, Gi...
+ */
+ divisor = 1024;
+ if (flags & HN_B)
+ prefixes = "B\0K\0M\0G\0T\0P\0E";
+ else
+ prefixes = "\0\0K\0M\0G\0T\0P\0E";
+ }
+
+#define SCALE2PREFIX(scale) (&prefixes[(scale) << 1])
+ maxscale = 7;
+
+ if ((size_t)scale >= maxscale &&
+ (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0)
+ return (-1);
+
+ if (buf == NULL || suffix == NULL)
+ return (-1);
+
+ if (len > 0)
+ buf[0] = '\0';
+ if (bytes < 0) {
+ sign = -1;
+ baselen = 3; /* sign, digit, prefix */
+ if (-bytes < INT64_MAX / 100)
+ bytes *= -100;
+ else {
+ bytes = -bytes;
+ post = 100;
+ baselen += 2;
+ }
+ } else {
+ sign = 1;
+ baselen = 2; /* digit, prefix */
+ if (bytes < INT64_MAX / 100)
+ bytes *= 100;
+ else {
+ post = 100;
+ baselen += 2;
+ }
+ }
+ if (flags & HN_NOSPACE)
+ sep = "";
+ else {
+ sep = " ";
+ baselen++;
+ }
+ baselen += strlen(suffix);
+
+ /* Check if enough room for `x y' + suffix + `\0' */
+ if (len < baselen + 1)
+ return (-1);
+
+ if (scale & (HN_AUTOSCALE | HN_GETSCALE)) {
+ /* See if there is additional columns can be used. */
+ for (max = 100, i = len - baselen; i-- > 0;)
+ max *= 10;
+
+ /*
+ * Divide the number until it fits the given column.
+ * If there will be an overflow by the rounding below,
+ * divide once more.
+ */
+ for (i = 0; bytes >= max - 50 && i < maxscale; i++)
+ bytes /= divisor;
+
+ if (scale & HN_GETSCALE) {
+ _DIAGASSERT(__type_fit(int, i));
+ return (int)i;
+ }
+ } else
+ for (i = 0; i < (size_t)scale && i < maxscale; i++)
+ bytes /= divisor;
+ bytes *= post;
+
+ /* If a value <= 9.9 after rounding and ... */
+ if (bytes < 995 && i > 0 && flags & HN_DECIMAL) {
+ /* baselen + \0 + .N */
+ if (len < baselen + 1 + 2)
+ return (-1);
+ b = ((int)bytes + 5) / 10;
+ s1 = b / 10;
+ s2 = b % 10;
+ r = snprintf(buf, len, "%d%s%d%s%s%s",
+ sign * s1, localeconv()->decimal_point, s2,
+ sep, SCALE2PREFIX(i), suffix);
+ } else
+ r = snprintf(buf, len, "%" PRId64 "%s%s%s",
+ sign * ((bytes + 50) / 100),
+ sep, SCALE2PREFIX(i), suffix);
+
+ return (r);
+}
diff --git a/toolbox/upstream-netbsd/lib/libc/stdlib/strsuftoll.c b/toolbox/upstream-netbsd/lib/libc/stdlib/strsuftoll.c
new file mode 100644
index 0000000..80fc52f
--- /dev/null
+++ b/toolbox/upstream-netbsd/lib/libc/stdlib/strsuftoll.c
@@ -0,0 +1,249 @@
+/* $NetBSD: strsuftoll.c,v 1.9 2011/10/22 22:08:47 christos Exp $ */
+/*-
+ * Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: strsuftoll.c,v 1.9 2011/10/22 22:08:47 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef _LIBC
+#include "namespace.h"
+#endif
+
+#if !HAVE_STRSUFTOLL
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _LIBC
+# ifdef __weak_alias
+__weak_alias(strsuftoll, _strsuftoll)
+__weak_alias(strsuftollx, _strsuftollx)
+# endif
+#endif /* LIBC */
+
+/*
+ * Convert an expression of the following forms to a (u)int64_t.
+ * 1) A positive decimal number.
+ * 2) A positive decimal number followed by a b (mult by 512).
+ * 3) A positive decimal number followed by a k (mult by 1024).
+ * 4) A positive decimal number followed by a m (mult by 1048576).
+ * 5) A positive decimal number followed by a g (mult by 1073741824).
+ * 6) A positive decimal number followed by a t (mult by 1099511627776).
+ * 7) A positive decimal number followed by a w (mult by sizeof int)
+ * 8) Two or more positive decimal numbers (with/without k,b or w).
+ * separated by x (also * for backwards compatibility), specifying
+ * the product of the indicated values.
+ * Returns the result upon successful conversion, or exits with an
+ * appropriate error.
+ *
+ */
+/* LONGLONG */
+long long
+strsuftoll(const char *desc, const char *val,
+ long long min, long long max)
+{
+ long long result;
+ char errbuf[100];
+
+ result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
+ if (*errbuf != '\0')
+ errx(EXIT_FAILURE, "%s", errbuf);
+ return result;
+}
+
+/*
+ * As strsuftoll(), but returns the error message into the provided buffer
+ * rather than exiting with it.
+ */
+/* LONGLONG */
+static long long
+__strsuftollx(const char *desc, const char *val,
+ long long min, long long max, char *ebuf, size_t ebuflen, size_t depth)
+{
+ long long num, t;
+ char *expr;
+
+ _DIAGASSERT(desc != NULL);
+ _DIAGASSERT(val != NULL);
+ _DIAGASSERT(ebuf != NULL);
+
+ if (depth > 16) {
+ snprintf(ebuf, ebuflen, "%s: Recursion limit exceeded", desc);
+ return 0;
+ }
+
+ while (isspace((unsigned char)*val)) /* Skip leading space */
+ val++;
+
+ errno = 0;
+ num = strtoll(val, &expr, 10);
+ if (errno == ERANGE)
+ goto erange; /* Overflow */
+
+ if (expr == val) /* No digits */
+ goto badnum;
+
+ switch (*expr) {
+ case 'b':
+ t = num;
+ num *= 512; /* 1 block */
+ if (t > num)
+ goto erange;
+ ++expr;
+ break;
+ case 'k':
+ t = num;
+ num *= 1024; /* 1 kibibyte */
+ if (t > num)
+ goto erange;
+ ++expr;
+ break;
+ case 'm':
+ t = num;
+ num *= 1048576; /* 1 mebibyte */
+ if (t > num)
+ goto erange;
+ ++expr;
+ break;
+ case 'g':
+ t = num;
+ num *= 1073741824; /* 1 gibibyte */
+ if (t > num)
+ goto erange;
+ ++expr;
+ break;
+ case 't':
+ t = num;
+ num *= 1099511627776LL; /* 1 tebibyte */
+ if (t > num)
+ goto erange;
+ ++expr;
+ break;
+ case 'w':
+ t = num;
+ num *= sizeof(int); /* 1 word */
+ if (t > num)
+ goto erange;
+ ++expr;
+ break;
+ }
+
+ switch (*expr) {
+ case '\0':
+ break;
+ case '*': /* Backward compatible */
+ case 'x':
+ t = num;
+ num *= __strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen,
+ depth + 1);
+ if (*ebuf != '\0')
+ return 0;
+ if (t > num) {
+ erange:
+ errno = ERANGE;
+ snprintf(ebuf, ebuflen, "%s: %s", desc, strerror(errno));
+ return 0;
+ }
+ break;
+ default:
+ badnum:
+ snprintf(ebuf, ebuflen, "%s `%s': illegal number", desc, val);
+ return 0;
+ }
+ if (num < min) {
+ /* LONGLONG */
+ snprintf(ebuf, ebuflen, "%s %lld is less than %lld.",
+ desc, (long long)num, (long long)min);
+ return 0;
+ }
+ if (num > max) {
+ /* LONGLONG */
+ snprintf(ebuf, ebuflen, "%s %lld is greater than %lld.",
+ desc, (long long)num, (long long)max);
+ return 0;
+ }
+ *ebuf = '\0';
+ return num;
+}
+
+long long
+strsuftollx(const char *desc, const char *val,
+ long long min, long long max, char *ebuf, size_t ebuflen)
+{
+ return __strsuftollx(desc, val, min, max, ebuf, ebuflen, 0);
+}
+#endif /* !HAVE_STRSUFTOLL */
diff --git a/toolbox/cp/extern.h b/toolbox/upstream-netbsd/lib/libc/string/swab.c
similarity index 61%
copy from toolbox/cp/extern.h
copy to toolbox/upstream-netbsd/lib/libc/string/swab.c
index ffbadf7..392b186 100644
--- a/toolbox/cp/extern.h
+++ b/toolbox/upstream-netbsd/lib/libc/string/swab.c
@@ -1,9 +1,12 @@
-/* $NetBSD: extern.h,v 1.17 2012/01/04 15:58:37 christos Exp $ */
+/* $NetBSD: swab.c,v 1.18 2011/01/04 17:14:07 martin Exp $ */
-/*-
- * Copyright (c) 1991, 1993, 1994
+/*
+ * Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
+ * This code is derived from software contributed to Berkeley by
+ * Jeffrey Mogul.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -27,35 +30,51 @@
* 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>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)swab.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: swab.c,v 1.18 2011/01/04 17:14:07 martin Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
-__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 cp_usage(void) __attribute__((__noreturn__));
-__END_DECLS
+#include <assert.h>
+#include <unistd.h>
-#endif /* !_EXTERN_H_ */
+void
+swab(const void * __restrict from, void * __restrict to, ssize_t len)
+{
+ char temp;
+ const char *fp;
+ char *tp;
+
+ if (len <= 1)
+ return;
+
+ _DIAGASSERT(from != NULL);
+ _DIAGASSERT(to != NULL);
+
+ len /= 2;
+ fp = (const char *)from;
+ tp = (char *)to;
+#define STEP temp = *fp++,*tp++ = *fp++,*tp++ = temp
+
+ if (__predict_false(len == 1)) {
+ STEP;
+ return;
+ }
+
+ /* round to multiple of 8 */
+ while ((--len % 8) != 0)
+ STEP;
+ len /= 8;
+ if (len == 0)
+ return;
+ while (len-- != 0) {
+ STEP; STEP; STEP; STEP;
+ STEP; STEP; STEP; STEP;
+ }
+}
diff --git a/toolbox/upstream-netbsd/lib/libutil/raise_default_signal.c b/toolbox/upstream-netbsd/lib/libutil/raise_default_signal.c
new file mode 100644
index 0000000..50cffd4
--- /dev/null
+++ b/toolbox/upstream-netbsd/lib/libutil/raise_default_signal.c
@@ -0,0 +1,117 @@
+/* $NetBSD: raise_default_signal.c,v 1.3 2008/04/28 20:23:03 martin Exp $ */
+
+/*-
+ * Copyright (c) 2007 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: raise_default_signal.c,v 1.3 2008/04/28 20:23:03 martin Exp $");
+#endif
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <util.h>
+
+#if ! HAVE_RAISE_DEFAULT_SIGNAL
+/*
+ * raise_default_signal sig
+ * Raise the default signal handler for sig, by
+ * - block all signals
+ * - set the signal handler to SIG_DFL
+ * - raise the signal
+ * - unblock the signal to deliver it
+ *
+ * The original signal mask and signal handler is restored on exit
+ * (whether successful or not).
+ *
+ * Returns 0 on success, or -1 on failure with errno set to
+ * on of the values for sigemptyset(), sigaddset(), sigprocmask(),
+ * sigaction(), or raise().
+ */
+int
+raise_default_signal(int sig)
+{
+ struct sigaction origact, act;
+ sigset_t origmask, fullmask, mask;
+ int retval, oerrno;
+
+ retval = -1;
+
+ /* Setup data structures */
+ /* XXX memset(3) isn't async-safe according to signal(7) */
+ (void)memset(&act, 0, sizeof(act));
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = 0;
+ if ((sigemptyset(&act.sa_mask) == -1) ||
+ (sigfillset(&fullmask) == -1) ||
+ (sigemptyset(&mask) == -1) ||
+ (sigaddset(&mask, sig) == -1))
+ goto restore_none;
+
+ /* Block all signals */
+ if (sigprocmask(SIG_BLOCK, &fullmask, &origmask) == -1)
+ goto restore_none;
+ /* (use 'goto restore_mask' to restore state) */
+
+ /* Enable the SIG_DFL handler */
+ if (sigaction(sig, &act, &origact) == -1)
+ goto restore_mask;
+ /* (use 'goto restore_act' to restore state) */
+
+ /* Raise the signal, and unblock the signal to deliver it */
+ if ((raise(sig) == -1) ||
+ (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1))
+ goto restore_act;
+
+ /* Flag successful raise() */
+ retval = 0;
+
+ /* Restore the original handler */
+ restore_act:
+ oerrno = errno;
+ (void)sigaction(sig, &origact, NULL);
+ errno = oerrno;
+
+ /* Restore the original mask */
+ restore_mask:
+ oerrno = errno;
+ (void)sigprocmask(SIG_SETMASK, &origmask, NULL);
+ errno = oerrno;
+
+ restore_none:
+ return retval;
+}
+
+#endif /* ! HAVE_RAISE_DEFAULT_SIGNAL */
diff --git a/toolbox/chown.c b/toolbox/upstream-netbsd/sbin/chown/chown.c
similarity index 99%
rename from toolbox/chown.c
rename to toolbox/upstream-netbsd/sbin/chown/chown.c
index 6ac2233..ee46eee 100644
--- a/toolbox/chown.c
+++ b/toolbox/upstream-netbsd/sbin/chown/chown.c
@@ -78,7 +78,7 @@
};
int
-chown_main(int argc, char **argv)
+main(int argc, char **argv)
{
FTS *ftsp;
FTSENT *p;
diff --git a/toolbox/du.c b/toolbox/upstream-netbsd/usr.bin/du/du.c
similarity index 81%
rename from toolbox/du.c
rename to toolbox/upstream-netbsd/usr.bin/du/du.c
index fc7c943..086ac4a 100644
--- a/toolbox/du.c
+++ b/toolbox/upstream-netbsd/usr.bin/du/du.c
@@ -1,4 +1,4 @@
-/* $NetBSD: du.c,v 1.33 2008/07/30 22:03:40 dsl Exp $ */
+/* $NetBSD: du.c,v 1.36 2012/03/11 11:23:20 shattered Exp $ */
/*
* Copyright (c) 1989, 1993, 1994
@@ -42,10 +42,11 @@
#if 0
static char sccsid[] = "@(#)du.c 8.5 (Berkeley) 5/4/95";
#else
-__RCSID("$NetBSD: du.c,v 1.33 2008/07/30 22:03:40 dsl Exp $");
+__RCSID("$NetBSD: du.c,v 1.36 2012/03/11 11:23:20 shattered Exp $");
#endif
#endif /* not lint */
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -53,6 +54,7 @@
#include <err.h>
#include <errno.h>
#include <fts.h>
+#include <inttypes.h>
#include <util.h>
#include <stdio.h>
#include <stdlib.h>
@@ -60,16 +62,18 @@
#include <unistd.h>
#include <limits.h>
-int linkchk(dev_t, ino_t);
-void prstat(const char *, int64_t);
-static void usage(void);
+/* Count inodes or file size */
+#define COUNT (iflag ? 1 : p->fts_statp->st_blocks)
-long blocksize;
+static int linkchk(dev_t, ino_t);
+static void prstat(const char *, int64_t);
+__dead static void usage(void);
-#define howmany(x, y) (((x)+((y)-1))/(y))
+static int hflag, iflag;
+static long blocksize;
int
-du_main(int argc, char *argv[])
+main(int argc, char *argv[])
{
FTS *fts;
FTSENT *p;
@@ -79,11 +83,11 @@
int Hflag, Lflag, aflag, ch, cflag, dflag, gkmflag, nflag, rval, sflag;
const char *noargv[2];
- Hflag = Lflag = aflag = cflag = dflag = gkmflag = sflag = 0;
+ Hflag = Lflag = aflag = cflag = dflag = gkmflag = nflag = sflag = 0;
totalblocks = 0;
ftsoptions = FTS_PHYSICAL;
depth = INT_MAX;
- while ((ch = getopt(argc, argv, "HLPacd:ghkmnrsx")) != -1)
+ while ((ch = getopt(argc, argv, "HLPacd:ghikmnrsx")) != -1)
switch (ch) {
case 'H':
Hflag = 1;
@@ -115,6 +119,12 @@
blocksize = 1024 * 1024 * 1024;
gkmflag = 1;
break;
+ case 'h':
+ hflag = 1;
+ break;
+ case 'i':
+ iflag = 1;
+ break;
case 'k':
blocksize = 1024;
gkmflag = 1;
@@ -123,6 +133,9 @@
blocksize = 1024 * 1024;
gkmflag = 1;
break;
+ case 'n':
+ nflag = 1;
+ break;
case 'r':
break;
case 's':
@@ -175,21 +188,36 @@
}
if (!gkmflag)
- blocksize = 512;
+ (void)getbsize(NULL, &blocksize);
blocksize /= 512;
if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
err(1, "fts_open `%s'", *argv);
for (rval = 0; (p = fts_read(fts)) != NULL;) {
+#ifndef __ANDROID__
+ if (nflag) {
+ switch (p->fts_info) {
+ case FTS_NS:
+ case FTS_SLNONE:
+ /* nothing */
+ break;
+ default:
+ if (p->fts_statp->st_flags & UF_NODUMP) {
+ fts_set(fts, p, FTS_SKIP);
+ continue;
+ }
+ }
+ }
+#endif
switch (p->fts_info) {
case FTS_D: /* Ignore. */
break;
case FTS_DP:
p->fts_parent->fts_number +=
- p->fts_number += p->fts_statp->st_blocks;
+ p->fts_number += COUNT;
if (cflag)
- totalblocks += p->fts_statp->st_blocks;
+ totalblocks += COUNT;
/*
* If listing each directory, or not listing files
* or directories and this is post-order of the
@@ -216,10 +244,10 @@
* the root of a traversal, display the total.
*/
if (listfiles || !p->fts_level)
- prstat(p->fts_path, p->fts_statp->st_blocks);
- p->fts_parent->fts_number += p->fts_statp->st_blocks;
+ prstat(p->fts_path, COUNT);
+ p->fts_parent->fts_number += COUNT;
if (cflag)
- totalblocks += p->fts_statp->st_blocks;
+ totalblocks += COUNT;
}
}
if (errno)
@@ -229,15 +257,29 @@
exit(rval);
}
-void
+static void
prstat(const char *fname, int64_t blocks)
{
- (void)printf("%lld\t%s\n",
- (long long)howmany(blocks, (int64_t)blocksize),
- fname);
+ if (iflag) {
+ (void)printf("%" PRId64 "\t%s\n", blocks, fname);
+ return;
+ }
+
+ if (hflag) {
+ char buf[5];
+ int64_t sz = blocks * 512;
+
+ humanize_number(buf, sizeof(buf), sz, "", HN_AUTOSCALE,
+ HN_B | HN_NOSPACE | HN_DECIMAL);
+
+ (void)printf("%s\t%s\n", buf, fname);
+ } else
+ (void)printf("%" PRId64 "\t%s\n",
+ howmany(blocks, (int64_t)blocksize),
+ fname);
}
-int
+static int
linkchk(dev_t dev, ino_t ino)
{
static struct entry {
@@ -317,6 +359,6 @@
{
(void)fprintf(stderr,
- "usage: du [-H | -L | -P] [-a | -d depth | -s] [-cgkmrx] [file ...]\n");
+ "usage: du [-H | -L | -P] [-a | -d depth | -s] [-cghikmnrx] [file ...]\n");
exit(1);
}
diff --git a/toolbox/grep/fastgrep.c b/toolbox/upstream-netbsd/usr.bin/grep/fastgrep.c
similarity index 100%
rename from toolbox/grep/fastgrep.c
rename to toolbox/upstream-netbsd/usr.bin/grep/fastgrep.c
diff --git a/toolbox/grep/file.c b/toolbox/upstream-netbsd/usr.bin/grep/file.c
similarity index 97%
rename from toolbox/grep/file.c
rename to toolbox/upstream-netbsd/usr.bin/grep/file.c
index 86b7658..da03d71 100644
--- a/toolbox/grep/file.c
+++ b/toolbox/upstream-netbsd/usr.bin/grep/file.c
@@ -41,7 +41,7 @@
#include <sys/types.h>
#include <sys/stat.h>
-#ifndef ANDROID
+#ifndef __ANDROID__
#include <bzlib.h>
#endif
#include <err.h>
@@ -53,7 +53,7 @@
#include <unistd.h>
#include <wchar.h>
#include <wctype.h>
-#ifndef ANDROID
+#ifndef __ANDROID__
#include <zlib.h>
#endif
@@ -62,7 +62,7 @@
#define MAXBUFSIZ (32 * 1024)
#define LNBUFBUMP 80
-#ifndef ANDROID
+#ifndef __ANDROID__
static gzFile gzbufdesc;
static BZFILE* bzbufdesc;
#endif
@@ -83,7 +83,7 @@
bufpos = buffer;
bufrem = 0;
-#ifndef ANDROID
+#ifndef __ANDROID__
if (filebehave == FILE_GZIP)
nr = gzread(gzbufdesc, buffer, MAXBUFSIZ);
else if (filebehave == FILE_BZIP && bzbufdesc != NULL) {
@@ -202,7 +202,7 @@
grep_file_init(struct file *f)
{
-#ifndef ANDROID
+#ifndef __ANDROID__
if (filebehave == FILE_GZIP &&
(gzbufdesc = gzdopen(f->fd, "r")) == NULL)
goto error;
diff --git a/toolbox/grep/grep.c b/toolbox/upstream-netbsd/usr.bin/grep/grep.c
similarity index 98%
rename from toolbox/grep/grep.c
rename to toolbox/upstream-netbsd/usr.bin/grep/grep.c
index 5a4fa0c..1ea6ed3 100644
--- a/toolbox/grep/grep.c
+++ b/toolbox/upstream-netbsd/usr.bin/grep/grep.c
@@ -1,4 +1,4 @@
-/* $NetBSD: grep.c,v 1.11 2012/05/06 22:27:00 joerg Exp $ */
+/* $NetBSD: grep.c,v 1.12 2014/07/11 16:30:45 christos Exp $ */
/* $FreeBSD: head/usr.bin/grep/grep.c 211519 2010-08-19 22:55:17Z delphij $ */
/* $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $ */
@@ -34,7 +34,7 @@
#endif
#include <sys/cdefs.h>
-__RCSID("$NetBSD: grep.c,v 1.11 2012/05/06 22:27:00 joerg Exp $");
+__RCSID("$NetBSD: grep.c,v 1.12 2014/07/11 16:30:45 christos Exp $");
#include <sys/stat.h>
#include <sys/types.h>
@@ -159,7 +159,6 @@
{
fprintf(stderr, getstr(4), __progname);
fprintf(stderr, "%s", getstr(5));
- fprintf(stderr, "%s", getstr(5));
fprintf(stderr, "%s", getstr(6));
fprintf(stderr, "%s", getstr(7));
exit(2);
@@ -312,7 +311,7 @@
}
int
-grep_main(int argc, char *argv[])
+main(int argc, char *argv[])
{
char **aargv, **eargv, *eopts;
char *ep;
diff --git a/toolbox/grep/grep.h b/toolbox/upstream-netbsd/usr.bin/grep/grep.h
similarity index 97%
rename from toolbox/grep/grep.h
rename to toolbox/upstream-netbsd/usr.bin/grep/grep.h
index 6454f93..fa2a3e3 100644
--- a/toolbox/grep/grep.h
+++ b/toolbox/upstream-netbsd/usr.bin/grep/grep.h
@@ -29,18 +29,14 @@
* SUCH DAMAGE.
*/
-#ifdef ANDROID
-#define WITHOUT_NLS
-#endif
-
-#ifndef ANDROID
+#ifndef __ANDROID__
#include <bzlib.h>
#endif
#include <limits.h>
#include <regex.h>
#include <stdbool.h>
#include <stdio.h>
-#ifndef ANDROID
+#ifndef __ANDROID__
#include <zlib.h>
#endif
diff --git a/toolbox/grep/queue.c b/toolbox/upstream-netbsd/usr.bin/grep/queue.c
similarity index 100%
rename from toolbox/grep/queue.c
rename to toolbox/upstream-netbsd/usr.bin/grep/queue.c
diff --git a/toolbox/grep/util.c b/toolbox/upstream-netbsd/usr.bin/grep/util.c
similarity index 96%
rename from toolbox/grep/util.c
rename to toolbox/upstream-netbsd/usr.bin/grep/util.c
index 497db06..ecd948d 100644
--- a/toolbox/grep/util.c
+++ b/toolbox/upstream-netbsd/usr.bin/grep/util.c
@@ -1,4 +1,4 @@
-/* $NetBSD: util.c,v 1.16 2012/05/06 22:32:05 joerg Exp $ */
+/* $NetBSD: util.c,v 1.17 2013/01/21 03:24:43 msaitoh Exp $ */
/* $FreeBSD: head/usr.bin/grep/util.c 211496 2010-08-19 09:28:59Z des $ */
/* $OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $ */
@@ -34,7 +34,7 @@
#endif
#include <sys/cdefs.h>
-__RCSID("$NetBSD: util.c,v 1.16 2012/05/06 22:32:05 joerg Exp $");
+__RCSID("$NetBSD: util.c,v 1.17 2013/01/21 03:24:43 msaitoh Exp $");
#include <sys/stat.h>
#include <sys/types.h>
@@ -74,9 +74,10 @@
for (i = 0; i < fpatterns; ++i) {
if (fnmatch(fpattern[i].pat, fname, 0) == 0 ||
fnmatch(fpattern[i].pat, fname_base, 0) == 0) {
- if (fpattern[i].mode == EXCL_PAT)
+ if (fpattern[i].mode == EXCL_PAT) {
+ free(fname_copy);
return (false);
- else
+ } else
ret = true;
}
}
@@ -128,7 +129,7 @@
break;
default:
fts_flags = FTS_LOGICAL;
-
+
}
fts_flags |= FTS_NOSTAT | FTS_NOCHDIR;
@@ -323,7 +324,7 @@
continue;
/* Check for whole word match */
if (fg_pattern[i].word && pmatch.rm_so != 0) {
- wint_t wbegin, wend;
+ wchar_t wbegin, wend;
wbegin = wend = L' ';
if (pmatch.rm_so != 0 &&
@@ -474,13 +475,13 @@
if (!oflag)
fwrite(line->dat + a, matches[i].rm_so - a, 1,
stdout);
- if (color)
+ if (color)
fprintf(stdout, "\33[%sm\33[K", color);
- fwrite(line->dat + matches[i].rm_so,
+ fwrite(line->dat + matches[i].rm_so,
matches[i].rm_eo - matches[i].rm_so, 1,
stdout);
- if (color)
+ if (color)
fprintf(stdout, "\33[m\33[K");
a = matches[i].rm_eo;
if (oflag)
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 bf82882..0d05aba 100644
--- a/toolbox/watchprops.c
+++ b/toolbox/watchprops.c
@@ -6,8 +6,6 @@
#include <cutils/properties.h>
#include <cutils/hashmap.h>
-#include <sys/atomics.h>
-
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
@@ -23,9 +21,9 @@
static void announce(char *name, char *value)
{
- char *x;
+ unsigned char *x;
- for(x = value; *x; x++) {
+ for(x = (unsigned char *)value; *x; x++) {
if((*x < 32) || (*x > 127)) *x = '.';
}
@@ -77,9 +75,7 @@
int watchprops_main(int argc, char *argv[])
{
- unsigned serial = 0;
- unsigned count = 0;
- unsigned n;
+ unsigned serial;
Hashmap *watchlist = hashmapCreate(1024, str_hash, str_equals);
if (!watchlist)
@@ -87,7 +83,7 @@
__system_property_foreach(populate_watchlist, watchlist);
- for(;;) {
+ for(serial = 0;;) {
serial = __system_property_wait_any(serial);
__system_property_foreach(update_watchlist, watchlist);
}