aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--adb/adb.c4
-rw-r--r--adb/file_sync_client.c6
-rw-r--r--adb/usb_vendors.c27
-rw-r--r--debuggerd/crasher.c124
-rw-r--r--fs_mgr/fs_mgr_priv.h2
-rw-r--r--include/corkscrew/map_info.h4
-rw-r--r--init/builtins.c3
-rw-r--r--init/devices.c11
-rwxr-xr-xinit/init.c80
-rw-r--r--init/init.h2
-rw-r--r--init/init_parser.c16
-rw-r--r--init/keychords.c7
-rwxr-xr-xinit/property_service.c107
-rw-r--r--init/property_service.h19
-rw-r--r--init/signal_handler.c10
-rwxr-xr-xinit/util.c19
-rw-r--r--libcorkscrew/Android.mk19
-rwxr-xr-xlibcorkscrew/arch-x86/backtrace-x86.c19
-rw-r--r--libcorkscrew/backtrace.c30
-rw-r--r--libcorkscrew/demangle.c6
-rw-r--r--libcorkscrew/map_info.c97
-rw-r--r--libcorkscrew/ptrace.c11
-rw-r--r--libcorkscrew/symbol_table.c10
-rw-r--r--libcorkscrew/test.cpp (renamed from libcorkscrew/test.c)36
-rw-r--r--libcutils/Android.mk4
-rw-r--r--libcutils/arch-mips/android_memset.c31
-rw-r--r--libcutils/properties.c29
-rw-r--r--libnetutils/dhcp_utils.c3
-rw-r--r--libsparse/output_file.c3
-rw-r--r--libsysutils/src/SocketClient.cpp9
-rw-r--r--rootdir/init.rc18
-rw-r--r--toolbox/dd.c8
-rw-r--r--toolbox/dmesg.c27
-rw-r--r--toolbox/ls.c80
-rw-r--r--toolbox/mount.c7
-rw-r--r--toolbox/netstat.c4
-rw-r--r--toolbox/watchprops.c103
37 files changed, 637 insertions, 358 deletions
diff --git a/adb/adb.c b/adb/adb.c
index d2a2d27e..ec74b49d 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -401,6 +401,10 @@ static char *connection_state_name(atransport *t)
return "bootloader";
case CS_DEVICE:
return "device";
+ case CS_RECOVERY:
+ return "recovery";
+ case CS_SIDELOAD:
+ return "sideload";
case CS_OFFLINE:
return "offline";
case CS_UNAUTHORIZED:
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index 64e393cc..354d0fb3 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -32,7 +32,7 @@
#include "file_sync_service.h"
-static unsigned total_bytes;
+static unsigned long long total_bytes;
static long long start_time;
static long long NOW()
@@ -58,8 +58,8 @@ static void END()
t = 1000000;
fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n",
- ((((long long) total_bytes) * 1000000LL) / t) / 1024LL,
- (long long) total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
+ ((total_bytes * 1000000LL) / t) / 1024LL,
+ total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
}
void sync_quit(int fd)
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index df9b1d1a..68bb2328 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -137,6 +137,24 @@
#define VENDOR_ID_HARRIS 0x19A5
// OPPO's USB Vendor ID
#define VENDOR_ID_OPPO 0x22D9
+// Xiaomi's USB Vendor ID
+#define VENDOR_ID_XIAOMI 0x2717
+// BYD's USB Vendor ID
+#define VENDOR_ID_BYD 0x19D1
+// OUYA's USB Vendor ID
+#define VENDOR_ID_OUYA 0x2836
+// Haier's USB Vendor ID
+#define VENDOR_ID_HAIER 0x201E
+// Hisense's USB Vendor ID
+#define VENDOR_ID_HISENSE 0x109b
+// MTK's USB Vendor ID
+#define VENDOR_ID_MTK 0x0e8d
+// B&N Nook's USB Vendor ID
+#define VENDOR_ID_NOOK 0x2080
+// Qisda's USB Vendor ID
+#define VENDOR_ID_QISDA 0x1D45
+// ECS's USB Vendor ID
+#define VENDOR_ID_ECS 0x03fc
/** built-in vendor list */
@@ -192,6 +210,15 @@ int builtInVendorIds[] = {
VENDOR_ID_ANYDATA,
VENDOR_ID_HARRIS,
VENDOR_ID_OPPO,
+ VENDOR_ID_XIAOMI,
+ VENDOR_ID_BYD,
+ VENDOR_ID_OUYA,
+ VENDOR_ID_HAIER,
+ VENDOR_ID_HISENSE,
+ VENDOR_ID_MTK,
+ VENDOR_ID_NOOK,
+ VENDOR_ID_QISDA,
+ VENDOR_ID_ECS,
};
#define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c
index 630d9801..5ecb1a55 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.c
@@ -17,10 +17,11 @@
#include <cutils/sockets.h>
+extern const char* __progname;
+
void crash1(void);
void crashnostack(void);
-void maybeabort(void);
-int do_action(const char* arg);
+static int do_action(const char* arg);
static void debuggerd_connect()
{
@@ -28,42 +29,46 @@ static void debuggerd_connect()
int s;
sprintf(tmp, "%d", gettid());
s = socket_local_client("android:debuggerd",
- ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+ ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
if(s >= 0) {
read(s, tmp, 1);
close(s);
}
}
-int smash_stack(int i) {
+static void maybeabort() {
+ if(time(0) != 42) {
+ abort();
+ }
+}
+
+static int smash_stack(int i) {
printf("crasher: deliberately corrupting stack...\n");
// Unless there's a "big enough" buffer on the stack, gcc
// doesn't bother inserting checks.
char buf[8];
- // If we don't write something relatively unpredicatable
+ // If we don't write something relatively unpredictable
// into the buffer and then do something with it, gcc
// optimizes everything away and just returns a constant.
*(int*)(&buf[7]) = (uintptr_t) &buf[0];
return *(int*)(&buf[0]);
}
-void test_call1()
-{
- *((int*) 32) = 1;
+static void* global = 0; // So GCC doesn't optimize the tail recursion out of overflow_stack.
+
+__attribute__((noinline)) static void overflow_stack(void* p) {
+ void* buf[1];
+ buf[0] = p;
+ global = buf;
+ overflow_stack(&buf);
}
-void *test_thread(void *x)
+static void test_call1()
{
- printf("crasher: thread pid=%d tid=%d\n", getpid(), gettid());
-
- sleep(1);
- test_call1();
- printf("goodbye\n");
-
- return 0;
+ *((int*) 32) = 1;
}
-void *noisy(void *x)
+static void *noisy(void *x)
{
char c = (unsigned) x;
for(;;) {
@@ -74,7 +79,7 @@ void *noisy(void *x)
return 0;
}
-int ctest()
+static int ctest()
{
pthread_t thr;
pthread_attr_t attr;
@@ -92,7 +97,7 @@ static void* thread_callback(void* raw_arg)
return (void*) do_action((const char*) raw_arg);
}
-int do_action_on_thread(const char* arg)
+static int do_action_on_thread(const char* arg)
{
pthread_t t;
pthread_create(&t, NULL, thread_callback, (void*) arg);
@@ -101,58 +106,75 @@ int do_action_on_thread(const char* arg)
return (int) result;
}
-__attribute__((noinline)) int crash3(int a) {
- *((int*) 0xdead) = a;
- return a*4;
+__attribute__((noinline)) static int crash3(int a) {
+ *((int*) 0xdead) = a;
+ return a*4;
+}
+
+__attribute__((noinline)) static int crash2(int a) {
+ a = crash3(a) + 2;
+ return a*3;
}
-__attribute__((noinline)) int crash2(int a) {
- a = crash3(a) + 2;
- return a*3;
+__attribute__((noinline)) static int crash(int a) {
+ a = crash2(a) + 1;
+ return a*2;
}
-__attribute__((noinline)) int crash(int a) {
- a = crash2(a) + 1;
- return a*2;
+static void abuse_heap() {
+ char buf[16];
+ free((void*) buf); // GCC is smart enough to warn about this, but we're doing it deliberately.
}
-int do_action(const char* arg)
+static int do_action(const char* arg)
{
- if(!strncmp(arg, "thread-", strlen("thread-"))) {
+ 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,"smash-stack")) {
+ return smash_stack(42);
+ } else if (!strcmp(arg,"stack-overflow")) {
+ overflow_stack(NULL);
+ } else if (!strcmp(arg,"nostack")) {
+ crashnostack();
+ } else if (!strcmp(arg,"ctest")) {
+ return ctest();
+ } else if (!strcmp(arg,"exit")) {
+ exit(1);
+ } else if (!strcmp(arg,"crash")) {
+ return crash(42);
+ } else if (!strcmp(arg,"abort")) {
+ maybeabort();
+ } else if (!strcmp(arg, "heap-usage")) {
+ abuse_heap();
}
- if(!strcmp(arg,"smash-stack")) return smash_stack(42);
- if(!strcmp(arg,"nostack")) crashnostack();
- if(!strcmp(arg,"ctest")) return ctest();
- if(!strcmp(arg,"exit")) exit(1);
- if(!strcmp(arg,"crash")) return crash(42);
- if(!strcmp(arg,"abort")) maybeabort();
-
- pthread_t thr;
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_create(&thr, &attr, test_thread, 0);
- while(1) sleep(1);
+ fprintf(stderr, "%s OP\n", __progname);
+ fprintf(stderr, "where OP is:\n");
+ fprintf(stderr, " smash-stack overwrite a stack-guard canary\n");
+ fprintf(stderr, " stack-overflow recurse until the stack overflows\n");
+ fprintf(stderr, " heap-corruption cause a libc abort by corrupting the heap\n");
+ fprintf(stderr, " heap-usage cause a libc abort by abusing a heap function\n");
+ fprintf(stderr, " nostack crash with a NULL stack pointer\n");
+ fprintf(stderr, " ctest (obsoleted by thread-crash?)\n");
+ fprintf(stderr, " exit call exit(1)\n");
+ fprintf(stderr, " crash cause a SIGSEGV\n");
+ fprintf(stderr, " abort call abort()\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;
}
int main(int argc, char **argv)
{
fprintf(stderr,"crasher: built at " __TIME__ "!@\n");
- fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid());
if(argc > 1) {
return do_action(argv[1]);
} else {
crash1();
-// *((int*) 0) = 42;
}
-
- return 0;
-}
-void maybeabort()
-{
- if(time(0) != 42) abort();
+ return 0;
}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 75dad498..f961b390 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -25,7 +25,7 @@
#define CRYPTO_TMPFS_OPTIONS "size=128m,mode=0771,uid=1000,gid=1000"
-#define WAIT_TIMEOUT 5
+#define WAIT_TIMEOUT 20
/* fstab has the following format:
*
diff --git a/include/corkscrew/map_info.h b/include/corkscrew/map_info.h
index c9b241d3..14bfad67 100644
--- a/include/corkscrew/map_info.h
+++ b/include/corkscrew/map_info.h
@@ -63,6 +63,10 @@ map_info_t* acquire_my_map_info_list();
* previous acquired using acquire_my_map_info_list(). */
void release_my_map_info_list(map_info_t* milist);
+/* Flushes the cached memory map so the next call to
+ * acquire_my_map_info_list() gets fresh data. */
+void flush_my_map_info_list();
+
#ifdef __cplusplus
}
#endif
diff --git a/init/builtins.c b/init/builtins.c
index 0f9f1313..576f0d92 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -593,8 +593,7 @@ int do_restart(int nargs, char **args)
struct service *svc;
svc = service_find_by_name(args[1]);
if (svc) {
- service_stop(svc);
- service_start(svc, NULL);
+ service_restart(svc);
}
return 0;
}
diff --git a/init/devices.c b/init/devices.c
index cc350efd..18936420 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -127,6 +127,7 @@ void fixup_sys_perms(const char *upath)
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...
@@ -148,6 +149,14 @@ void fixup_sys_perms(const char *upath)
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);
+ }
+ }
}
}
@@ -442,6 +451,8 @@ static char **parse_platform_block_device(struct uevent *uevent)
if (uevent->partition_name) {
p = strdup(uevent->partition_name);
sanitize(p);
+ if (strcmp(uevent->partition_name, p))
+ NOTICE("Linking partition '%s' as '%s'\n", uevent->partition_name, p);
if (asprintf(&links[link_num], "%s/by-name/%s", link_path, p) > 0)
link_num++;
else
diff --git a/init/init.c b/init/init.c
index 93b59974..28d2863a 100755
--- a/init/init.c
+++ b/init/init.c
@@ -90,7 +90,7 @@ void notify_service_state(const char *name, const char *state)
}
static int have_console;
-static char *console_name = "/dev/console";
+static char console_name[PROP_VALUE_MAX] = "/dev/console";
static time_t process_needs_restart;
static const char *ENV[32];
@@ -164,7 +164,7 @@ void service_start(struct service *svc, const char *dynamic_args)
* state and immediately takes it out of the restarting
* state if it was in there
*/
- svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET));
+ svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART));
svc->time_started = 0;
/* running processes require no additional work -- if
@@ -359,15 +359,14 @@ void service_start(struct service *svc, const char *dynamic_args)
notify_service_state(svc->name, "running");
}
-/* The how field should be either SVC_DISABLED or SVC_RESET */
+/* The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART */
static void service_stop_or_reset(struct service *svc, int how)
{
- /* we are no longer running, nor should we
- * attempt to restart
- */
- svc->flags &= (~(SVC_RUNNING|SVC_RESTARTING));
+ /* The service is still SVC_RUNNING until its process exits, but if it has
+ * already exited it shoudn't attempt a restart yet. */
+ svc->flags &= (~SVC_RESTARTING);
- if ((how != SVC_DISABLED) && (how != SVC_RESET)) {
+ if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) {
/* Hrm, an illegal flag. Default to SVC_DISABLED */
how = SVC_DISABLED;
}
@@ -399,6 +398,17 @@ void service_stop(struct service *svc)
service_stop_or_reset(svc, SVC_DISABLED);
}
+void service_restart(struct service *svc)
+{
+ if (svc->flags & SVC_RUNNING) {
+ /* Stop, wait, then start the service. */
+ service_stop_or_reset(svc, SVC_RESTART);
+ } else if (!(svc->flags & SVC_RESTARTING)) {
+ /* Just start the service since it's not running. */
+ service_start(svc, NULL);
+ } /* else: Service is restarting anyways. */
+}
+
void property_changed(const char *name, const char *value)
{
if (property_triggers_enabled)
@@ -430,7 +440,7 @@ static void restart_processes()
static void msg_start(const char *name)
{
- struct service *svc;
+ struct service *svc = NULL;
char *tmp = NULL;
char *args = NULL;
@@ -438,11 +448,13 @@ static void msg_start(const char *name)
svc = service_find_by_name(name);
else {
tmp = strdup(name);
- args = strchr(tmp, ':');
- *args = '\0';
- args++;
+ if (tmp) {
+ args = strchr(tmp, ':');
+ *args = '\0';
+ args++;
- svc = service_find_by_name(tmp);
+ svc = service_find_by_name(tmp);
+ }
}
if (svc) {
@@ -465,6 +477,17 @@ static void msg_stop(const char *name)
}
}
+static void msg_restart(const char *name)
+{
+ struct service *svc = service_find_by_name(name);
+
+ if (svc) {
+ service_restart(svc);
+ } else {
+ ERROR("no such service '%s'\n", name);
+ }
+}
+
void handle_control_message(const char *msg, const char *arg)
{
if (!strcmp(msg,"start")) {
@@ -472,8 +495,7 @@ void handle_control_message(const char *msg, const char *arg)
} else if (!strcmp(msg,"stop")) {
msg_stop(arg);
} else if (!strcmp(msg,"restart")) {
- msg_stop(arg);
- msg_start(arg);
+ msg_restart(arg);
} else {
ERROR("unknown control msg '%s'\n", msg);
}
@@ -547,11 +569,9 @@ static int keychord_init_action(int nargs, char **args)
static int console_init_action(int nargs, char **args)
{
int fd;
- char tmp[PROP_VALUE_MAX];
if (console[0]) {
- snprintf(tmp, sizeof(tmp), "/dev/%s", console);
- console_name = strdup(tmp);
+ snprintf(console_name, sizeof(console_name), "/dev/%s", console);
}
fd = open(console_name, O_RDWR);
@@ -625,7 +645,7 @@ static void import_kernel_nv(char *name, int for_emulator)
static void export_kernel_boot_props(void)
{
char tmp[PROP_VALUE_MAX];
- const char *pval;
+ int ret;
unsigned i;
struct {
const char *src_prop;
@@ -639,22 +659,26 @@ static void export_kernel_boot_props(void)
};
for (i = 0; i < ARRAY_SIZE(prop_map); i++) {
- pval = property_get(prop_map[i].src_prop);
- property_set(prop_map[i].dest_prop, pval ?: prop_map[i].def_val);
+ ret = property_get(prop_map[i].src_prop, tmp);
+ if (ret > 0)
+ property_set(prop_map[i].dest_prop, tmp);
+ else
+ property_set(prop_map[i].dest_prop, prop_map[i].def_val);
}
- pval = property_get("ro.boot.console");
- if (pval)
- strlcpy(console, pval, sizeof(console));
+ ret = property_get("ro.boot.console", tmp);
+ if (ret)
+ strlcpy(console, tmp, sizeof(console));
/* save a copy for init's usage during boot */
- strlcpy(bootmode, property_get("ro.bootmode"), sizeof(bootmode));
+ property_get("ro.bootmode", tmp);
+ strlcpy(bootmode, tmp, sizeof(bootmode));
/* if this was given on kernel command line, override what we read
* before (e.g. from /proc/cpuinfo), if anything */
- pval = property_get("ro.boot.hardware");
- if (pval)
- strlcpy(hardware, pval, sizeof(hardware));
+ ret = property_get("ro.boot.hardware", tmp);
+ if (ret)
+ strlcpy(hardware, tmp, sizeof(hardware));
property_set("ro.hardware", hardware);
snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
diff --git a/init/init.h b/init/init.h
index 955e1f04..aa6a4ab0 100644
--- a/init/init.h
+++ b/init/init.h
@@ -72,6 +72,7 @@ struct svcenvinfo {
#define SVC_RESET 0x40 /* Use when stopping a process, but not disabling
so it can be restarted with its class */
#define SVC_RC_DISABLED 0x80 /* Remember if the disabled flag was set in the rc script */
+#define SVC_RESTART 0x100 /* Use to safely restart (stop, wait, start) a service */
#define NR_SVC_SUPP_GIDS 12 /* twelve supplementary groups */
@@ -127,6 +128,7 @@ void service_for_each_flags(unsigned matchflags,
void (*func)(struct service *svc));
void service_stop(struct service *svc);
void service_reset(struct service *svc);
+void service_restart(struct service *svc);
void service_start(struct service *svc, const char *dynamic_args);
void property_changed(const char *name, const char *value);
diff --git a/init/init_parser.c b/init/init_parser.c
index 686640ed..cce10938 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -206,8 +206,9 @@ int expand_props(char *dst, const char *src, int dst_size)
while (*src_ptr && left > 0) {
char *c;
char prop[PROP_NAME_MAX + 1];
- const char *prop_val;
+ char prop_val[PROP_VALUE_MAX];
int prop_len = 0;
+ int prop_val_len;
c = strchr(src_ptr, '$');
if (!c) {
@@ -265,14 +266,14 @@ int expand_props(char *dst, const char *src, int dst_size)
goto err;
}
- prop_val = property_get(prop);
- if (!prop_val) {
+ prop_val_len = property_get(prop, prop_val);
+ if (!prop_val_len) {
ERROR("property '%s' doesn't exist while expanding '%s'\n",
prop, src);
goto err;
}
- ret = push_chars(&dst_ptr, &left, prop_val, strlen(prop_val));
+ ret = push_chars(&dst_ptr, &left, prop_val, prop_val_len);
if (ret < 0)
goto err_nospace;
src_ptr = c;
@@ -543,7 +544,7 @@ void queue_all_property_triggers()
const char* equals = strchr(name, '=');
if (equals) {
char prop_name[PROP_NAME_MAX + 1];
- const char* value;
+ char value[PROP_VALUE_MAX];
int length = equals - name;
if (length > PROP_NAME_MAX) {
ERROR("property name too long in trigger %s", act->name);
@@ -552,9 +553,8 @@ void queue_all_property_triggers()
prop_name[length] = 0;
/* does the property exist, and match the trigger value? */
- value = property_get(prop_name);
- if (value && (!strcmp(equals + 1, value) ||
- !strcmp(equals + 1, "*"))) {
+ property_get(prop_name, value);
+ if (!strcmp(equals + 1, value) ||!strcmp(equals + 1, "*")) {
action_add_queue_tail(act);
}
}
diff --git a/init/keychords.c b/init/keychords.c
index 061d1570..4a640426 100644
--- a/init/keychords.c
+++ b/init/keychords.c
@@ -95,20 +95,19 @@ void keychord_init()
void handle_keychord()
{
struct service *svc;
- const char* debuggable;
- const char* adb_enabled;
+ char adb_enabled[PROP_VALUE_MAX];
int ret;
__u16 id;
// Only handle keychords if adb is enabled.
- adb_enabled = property_get("init.svc.adbd");
+ property_get("init.svc.adbd", adb_enabled);
ret = read(keychord_fd, &id, sizeof(id));
if (ret != sizeof(id)) {
ERROR("could not read keychord id\n");
return;
}
- if ((adb_enabled && !strcmp(adb_enabled, "running"))) {
+ if (!strcmp(adb_enabled, "running")) {
svc = service_find_by_keychord(id);
if (svc) {
INFO("starting service %s from keychord\n", svc->name);
diff --git a/init/property_service.c b/init/property_service.c
index 64f6b403..6c71807a 100755
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -111,7 +111,6 @@ struct {
};
typedef struct {
- void *data;
size_t size;
int fd;
} workspace;
@@ -119,83 +118,34 @@ typedef struct {
static int init_workspace(workspace *w, size_t size)
{
void *data;
- int fd;
-
- /* dev is a tmpfs that we can use to carve a shared workspace
- * out of, so let's do that...
- */
- fd = open(PROP_FILENAME, O_RDWR | O_CREAT | O_NOFOLLOW, 0644);
- if (fd < 0)
- return -1;
-
- if (ftruncate(fd, size) < 0)
- goto out;
-
- data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if(data == MAP_FAILED)
- goto out;
-
- close(fd);
-
- fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW);
+ int fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW);
if (fd < 0)
return -1;
- w->data = data;
w->size = size;
w->fd = fd;
return 0;
-
-out:
- close(fd);
- return -1;
}
-/* (8 header words + 372 toc words) = 1520 bytes */
-/* 1536 bytes header and toc + 372 prop_infos @ 128 bytes = 49152 bytes */
-
-#define PA_COUNT_MAX 372
-#define PA_INFO_START 1536
-#define PA_SIZE 49152
-
static workspace pa_workspace;
-static prop_info *pa_info_array;
-
-extern prop_area *__system_property_area__;
static int init_property_area(void)
{
- prop_area *pa;
+ if (property_area_inited)
+ return -1;
- if(pa_info_array)
+ if(__system_property_area_init())
return -1;
- if(init_workspace(&pa_workspace, PA_SIZE))
+ if(init_workspace(&pa_workspace, 0))
return -1;
fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
- pa_info_array = (void*) (((char*) pa_workspace.data) + PA_INFO_START);
-
- pa = pa_workspace.data;
- memset(pa, 0, PA_SIZE);
- pa->magic = PROP_AREA_MAGIC;
- pa->version = PROP_AREA_VERSION;
-
- /* plug into the lib property services */
- __system_property_area__ = pa;
property_area_inited = 1;
return 0;
}
-static void update_prop_info(prop_info *pi, const char *value, unsigned len)
-{
- pi->serial = pi->serial | 1;
- memcpy(pi->value, value, len + 1);
- pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);
- __futex_wake(&pi->serial, INT32_MAX);
-}
-
static int check_mac_perms(const char *name, char *sctx)
{
if (is_selinux_enabled() <= 0)
@@ -298,19 +248,9 @@ static int check_perms(const char *name, unsigned int uid, unsigned int gid, cha
return 0;
}
-const char* property_get(const char *name)
+int __property_get(const char *name, char *value)
{
- prop_info *pi;
-
- if(strlen(name) >= PROP_NAME_MAX) return 0;
-
- pi = (prop_info*) __system_property_find(name);
-
- if(pi != 0) {
- return pi->value;
- } else {
- return 0;
- }
+ return __system_property_get(name, value);
}
static void write_persistent_property(const char *name, const char *value)
@@ -337,8 +277,8 @@ static void write_persistent_property(const char *name, const char *value)
int property_set(const char *name, const char *value)
{
- prop_area *pa;
prop_info *pi;
+ int ret;
size_t namelen = strlen(name);
size_t valuelen = strlen(value);
@@ -353,25 +293,13 @@ int property_set(const char *name, const char *value)
/* ro.* properties may NEVER be modified once set */
if(!strncmp(name, "ro.", 3)) return -1;
- pa = __system_property_area__;
- update_prop_info(pi, value, valuelen);
- pa->serial++;
- __futex_wake(&pa->serial, INT32_MAX);
+ __system_property_update(pi, value, valuelen);
} else {
- pa = __system_property_area__;
- if(pa->count == PA_COUNT_MAX) return -1;
-
- pi = pa_info_array + pa->count;
- pi->serial = (valuelen << 24);
- memcpy(pi->name, name, namelen + 1);
- memcpy(pi->value, value, valuelen + 1);
-
- pa->toc[pa->count] =
- (namelen << 24) | (((unsigned) pi) - ((unsigned) pa));
-
- pa->count++;
- pa->serial++;
- __futex_wake(&pa->serial, INT32_MAX);
+ ret = __system_property_add(name, namelen, value, valuelen);
+ if (ret < 0) {
+ ERROR("Failed to set '%s'='%s'", name, value);
+ return ret;
+ }
}
/* If name starts with "net." treat as a DNS property. */
if (strncmp("net.", name, strlen("net.")) == 0) {
@@ -593,8 +521,11 @@ int properties_inited(void)
static void load_override_properties() {
#ifdef ALLOW_LOCAL_PROP_OVERRIDE
- const char *debuggable = property_get("ro.debuggable");
- if (debuggable && (strcmp(debuggable, "1") == 0)) {
+ char debuggable[PROP_VALUE_MAX];
+ int ret;
+
+ ret = property_get("ro.debuggable", debuggable);
+ if (ret && (strcmp(debuggable, "1") == 0)) {
load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
}
#endif /* ALLOW_LOCAL_PROP_OVERRIDE */
diff --git a/init/property_service.h b/init/property_service.h
index b9d1bf61..46cbd8ff 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -18,6 +18,7 @@
#define _INIT_PROPERTY_H
#include <stdbool.h>
+#include <sys/system_properties.h>
extern void handle_property_set_fd(void);
extern void property_init(void);
@@ -25,9 +26,25 @@ extern void property_load_boot_defaults(void);
extern void load_persist_props(void);
extern void start_property_service(void);
void get_property_workspace(int *fd, int *sz);
-extern const char* property_get(const char *name);
+extern int __property_get(const char *name, char *value);
extern int property_set(const char *name, const char *value);
extern int properties_inited();
int get_property_set_fd(void);
+extern void __property_get_size_error()
+ __attribute__((__error__("property_get called with too small buffer")));
+
+static inline
+__attribute__ ((always_inline))
+__attribute__ ((gnu_inline))
+__attribute__ ((artificial))
+int property_get(const char *name, char *value)
+{
+ size_t value_len = __builtin_object_size(value, 0);
+ if (value_len != PROP_VALUE_MAX)
+ __property_get_size_error();
+
+ return __property_get(name, value);
+}
+
#endif /* _INIT_PROPERTY_H */
diff --git a/init/signal_handler.c b/init/signal_handler.c
index abccb406..d31ad63c 100644
--- a/init/signal_handler.c
+++ b/init/signal_handler.c
@@ -63,7 +63,7 @@ static int wait_for_one_process(int block)
NOTICE("process '%s', pid %d exited\n", svc->name, pid);
- if (!(svc->flags & SVC_ONESHOT)) {
+ if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {
kill(-pid, SIGKILL);
NOTICE("process '%s' killing any children in process group\n", svc->name);
}
@@ -78,8 +78,9 @@ static int wait_for_one_process(int block)
svc->pid = 0;
svc->flags &= (~SVC_RUNNING);
- /* oneshot processes go into the disabled state on exit */
- if (svc->flags & SVC_ONESHOT) {
+ /* oneshot processes go into the disabled state on exit,
+ * except when manually restarted. */
+ if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {
svc->flags |= SVC_DISABLED;
}
@@ -90,7 +91,7 @@ static int wait_for_one_process(int block)
}
now = gettime();
- if (svc->flags & SVC_CRITICAL) {
+ if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) {
if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
ERROR("critical process '%s' exited %d times in %d minutes; "
@@ -105,6 +106,7 @@ static int wait_for_one_process(int block)
}
}
+ svc->flags &= (~SVC_RESTART);
svc->flags |= SVC_RESTARTING;
/* Execute all onrestart commands for this service. */
diff --git a/init/util.c b/init/util.c
index 918bc057..76af9e57 100755
--- a/init/util.c
+++ b/init/util.c
@@ -305,14 +305,27 @@ int mkdir_recursive(const char *pathname, mode_t mode)
return 0;
}
+/*
+ * replaces any unacceptable characters with '_', the
+ * length of the resulting string is equal to the input string
+ */
void sanitize(char *s)
{
+ const char* accept =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789"
+ "_-.";
+
if (!s)
return;
- while (isalnum(*s))
- s++;
- *s = 0;
+
+ for (; *s; s++) {
+ s += strspn(s, accept);
+ if (*s) *s = '_';
+ }
}
+
void make_link(const char *oldpath, const char *newpath)
{
int ret;
diff --git a/libcorkscrew/Android.mk b/libcorkscrew/Android.mk
index 83707893..d62c2d5a 100644
--- a/libcorkscrew/Android.mk
+++ b/libcorkscrew/Android.mk
@@ -59,23 +59,28 @@ include $(BUILD_SHARED_LIBRARY)
# Build test.
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := test.c
-LOCAL_CFLAGS += -std=gnu99 -Werror -fno-inline-small-functions
+LOCAL_SRC_FILES := test.cpp
+LOCAL_CFLAGS += -Werror -fno-inline-small-functions
LOCAL_SHARED_LIBRARIES := libcorkscrew
LOCAL_MODULE := libcorkscrew_test
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
+# TODO: reenable darwin-x86
+# ifeq ($(HOST_ARCH),x86)
ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
# Build libcorkscrew.
include $(CLEAR_VARS)
LOCAL_SRC_FILES += $(generic_src_files) $(x86_src_files)
LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
-LOCAL_SHARED_LIBRARIES += libgccdemangle
LOCAL_STATIC_LIBRARIES += libcutils liblog
-LOCAL_LDLIBS += -ldl -lrt
+LOCAL_LDLIBS += -ldl
+ifeq ($(HOST_OS),linux)
+ LOCAL_SHARED_LIBRARIES += libgccdemangle # TODO: is this even needed on Linux?
+ LOCAL_LDLIBS += -lrt
+endif
LOCAL_CFLAGS += -std=gnu99 -Werror
LOCAL_MODULE := libcorkscrew
LOCAL_MODULE_TAGS := optional
@@ -83,11 +88,11 @@ include $(BUILD_HOST_SHARED_LIBRARY)
# Build test.
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := test.c
-LOCAL_CFLAGS += -std=gnu99 -Werror -fno-inline-small-functions
+LOCAL_SRC_FILES := test.cpp
+LOCAL_CFLAGS += -Werror
LOCAL_SHARED_LIBRARIES := libcorkscrew
LOCAL_MODULE := libcorkscrew_test
LOCAL_MODULE_TAGS := optional
include $(BUILD_HOST_EXECUTABLE)
-endif # linux-x86
+endif # HOST_ARCH == x86
diff --git a/libcorkscrew/arch-x86/backtrace-x86.c b/libcorkscrew/arch-x86/backtrace-x86.c
index 29159edc..e133ab6f 100755
--- a/libcorkscrew/arch-x86/backtrace-x86.c
+++ b/libcorkscrew/arch-x86/backtrace-x86.c
@@ -75,13 +75,18 @@ typedef struct ucontext {
#endif /* __BIONIC_HAVE_UCONTEXT_T */
-#else /* __BIONIC__ */
+#elif defined(__APPLE__)
+
+#define _XOPEN_SOURCE
+#include <ucontext.h>
+
+#else
// glibc has its own renaming of the Linux kernel's structures.
#define __USE_GNU // For REG_EBP, REG_ESP, and REG_EIP.
#include <ucontext.h>
-#endif /* __ BIONIC__ */
+#endif
/* Unwind state. */
typedef struct {
@@ -819,9 +824,15 @@ ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo __attribute__((unused)),
const ucontext_t* uc = (const ucontext_t*)sigcontext;
unwind_state_t state;
+#if defined(__APPLE__)
+ state.reg[DWARF_EBP] = uc->uc_mcontext->__ss.__ebp;
+ state.reg[DWARF_ESP] = uc->uc_mcontext->__ss.__esp;
+ state.reg[DWARF_EIP] = uc->uc_mcontext->__ss.__eip;
+#else
state.reg[DWARF_EBP] = uc->uc_mcontext.gregs[REG_EBP];
state.reg[DWARF_ESP] = uc->uc_mcontext.gregs[REG_ESP];
state.reg[DWARF_EIP] = uc->uc_mcontext.gregs[REG_EIP];
+#endif
memory_t memory;
init_memory(&memory, map_info_list);
@@ -831,6 +842,9 @@ ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo __attribute__((unused)),
ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
+#if defined(__APPLE__)
+ return -1;
+#else
pt_regs_x86_t regs;
if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
return -1;
@@ -845,4 +859,5 @@ ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
init_memory_ptrace(&memory, tid);
return unwind_backtrace_common(&memory, context->map_info_list,
&state, backtrace, ignore_depth, max_depth);
+#endif
}
diff --git a/libcorkscrew/backtrace.c b/libcorkscrew/backtrace.c
index 03dbd53c..b365e5bd 100644
--- a/libcorkscrew/backtrace.c
+++ b/libcorkscrew/backtrace.c
@@ -33,7 +33,6 @@
#include <unwind.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
-#include <elf.h>
#define __USE_GNU // For dladdr(3) in glibc.
#include <dlfcn.h>
@@ -43,6 +42,15 @@
// Bionic implements and exports gettid but only implements tgkill.
extern int tgkill(int tgid, int tid, int sig);
+#elif defined(__APPLE__)
+
+#include <sys/syscall.h>
+
+// Mac OS >= 10.6 has a system call equivalent to Linux's gettid().
+static pid_t gettid() {
+ return syscall(SYS_thread_selfid);
+}
+
#else
// glibc doesn't implement or export either gettid or tgkill.
@@ -97,7 +105,7 @@ ssize_t unwind_backtrace(backtrace_frame_t* backtrace, size_t ignore_depth, size
state.returned_frames = 0;
init_memory(&state.memory, milist);
- _Unwind_Reason_Code rc =_Unwind_Backtrace(unwind_backtrace_callback, &state);
+ _Unwind_Reason_Code rc = _Unwind_Backtrace(unwind_backtrace_callback, &state);
release_my_map_info_list(milist);
@@ -146,7 +154,9 @@ ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace,
ALOGV("Unwinding thread %d from thread %d.", tid, gettid());
-#ifdef CORKSCREW_HAVE_ARCH
+ // TODO: there's no tgkill(2) on Mac OS, so we'd either need the
+ // mach_port_t or the pthread_t rather than the tid.
+#if defined(CORKSCREW_HAVE_ARCH) && !defined(__APPLE__)
struct sigaction act;
struct sigaction oact;
memset(&act, 0, sizeof(act));
@@ -305,20 +315,20 @@ void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t* frame
const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize) {
const char* mapName = symbol->map_name ? symbol->map_name : "<unknown>";
const char* symbolName = symbol->demangled_name ? symbol->demangled_name : symbol->symbol_name;
- size_t fieldWidth = (bufferSize - 80) / 2;
+ int fieldWidth = (bufferSize - 80) / 2;
if (symbolName) {
uint32_t pc_offset = symbol->relative_pc - symbol->relative_symbol_addr;
if (pc_offset) {
- snprintf(buffer, bufferSize, "#%02d pc %08x %.*s (%.*s+%u)",
- frameNumber, symbol->relative_pc, fieldWidth, mapName,
+ snprintf(buffer, bufferSize, "#%02u pc %p %.*s (%.*s+%u)",
+ frameNumber, (void*) symbol->relative_pc, fieldWidth, mapName,
fieldWidth, symbolName, pc_offset);
} else {
- snprintf(buffer, bufferSize, "#%02d pc %08x %.*s (%.*s)",
- frameNumber, symbol->relative_pc, fieldWidth, mapName,
+ snprintf(buffer, bufferSize, "#%02u pc %p %.*s (%.*s)",
+ frameNumber, (void*) symbol->relative_pc, fieldWidth, mapName,
fieldWidth, symbolName);
}
} else {
- snprintf(buffer, bufferSize, "#%02d pc %08x %.*s",
- frameNumber, symbol->relative_pc, fieldWidth, mapName);
+ snprintf(buffer, bufferSize, "#%02u pc %p %.*s",
+ frameNumber, (void*) symbol->relative_pc, fieldWidth, mapName);
}
}
diff --git a/libcorkscrew/demangle.c b/libcorkscrew/demangle.c
index 54247cbf..30ab1b09 100644
--- a/libcorkscrew/demangle.c
+++ b/libcorkscrew/demangle.c
@@ -25,6 +25,12 @@ extern char *__cxa_demangle (const char *mangled, char *buf, size_t *len,
int *status);
char* demangle_symbol_name(const char* name) {
+#if defined(__APPLE__)
+ // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
+ if (name != NULL && name[0] != '_') {
+ return NULL;
+ }
+#endif
// __cxa_demangle handles NULL by returning NULL
return __cxa_demangle(name, 0, 0, 0);
}
diff --git a/libcorkscrew/map_info.c b/libcorkscrew/map_info.c
index 6a27664d..93dffbf7 100644
--- a/libcorkscrew/map_info.c
+++ b/libcorkscrew/map_info.c
@@ -29,6 +29,67 @@
#include <cutils/log.h>
#include <sys/time.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 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);
+
+ map_info_t* mi = calloc(1, sizeof(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';
+ mi->data = NULL;
+ 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;
+}
+
+map_info_t* load_map_info_list(pid_t pid) {
+ char cmd[1024];
+ 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];
+ map_info_t* milist = NULL;
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ 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
@@ -63,9 +124,9 @@ static map_info_t* parse_maps_line(const char* line)
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);
+ "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;
}
@@ -91,6 +152,8 @@ map_info_t* load_map_info_list(pid_t tid) {
return milist;
}
+#endif
+
void free_map_info_list(map_info_t* milist) {
while (milist) {
map_info_t* next = milist->next;
@@ -132,11 +195,17 @@ typedef struct {
int64_t timestamp;
} my_map_info_data_t;
-static int64_t now() {
+static int64_t now_ns() {
+#if defined(HAVE_POSIX_CLOCKS)
struct timespec t;
t.tv_sec = t.tv_nsec = 0;
clock_gettime(CLOCK_MONOTONIC, &t);
return t.tv_sec * 1000000000LL + t.tv_nsec;
+#else
+ struct timeval t;
+ gettimeofday(&t, NULL);
+ return t.tv_sec * 1000000000LL + t.tv_usec * 1000LL;
+#endif
}
static void dec_ref(map_info_t* milist, my_map_info_data_t* data) {
@@ -150,8 +219,8 @@ static void dec_ref(map_info_t* milist, my_map_info_data_t* data) {
map_info_t* acquire_my_map_info_list() {
pthread_mutex_lock(&g_my_map_info_list_mutex);
- int64_t time = now();
- if (g_my_map_info_list) {
+ int64_t time = now_ns();
+ if (g_my_map_info_list != NULL) {
my_map_info_data_t* data = (my_map_info_data_t*)g_my_map_info_list->data;
int64_t age = time - data->timestamp;
if (age >= MAX_CACHE_AGE) {
@@ -163,10 +232,10 @@ map_info_t* acquire_my_map_info_list() {
}
}
- if (!g_my_map_info_list) {
+ if (g_my_map_info_list == NULL) {
my_map_info_data_t* data = (my_map_info_data_t*)malloc(sizeof(my_map_info_data_t));
g_my_map_info_list = load_map_info_list(getpid());
- if (g_my_map_info_list) {
+ if (g_my_map_info_list != NULL) {
ALOGV("Loaded my_map_info_list %p.", g_my_map_info_list);
g_my_map_info_list->data = data;
data->refs = 1;
@@ -196,3 +265,15 @@ void release_my_map_info_list(map_info_t* milist) {
pthread_mutex_unlock(&g_my_map_info_list_mutex);
}
}
+
+void flush_my_map_info_list() {
+ pthread_mutex_lock(&g_my_map_info_list_mutex);
+
+ if (g_my_map_info_list != NULL) {
+ my_map_info_data_t* data = (my_map_info_data_t*) g_my_map_info_list->data;
+ dec_ref(g_my_map_info_list, data);
+ g_my_map_info_list = NULL;
+ }
+
+ pthread_mutex_unlock(&g_my_map_info_list_mutex);
+}
diff --git a/libcorkscrew/ptrace.c b/libcorkscrew/ptrace.c
index 776ef69f..be58f7f9 100644
--- a/libcorkscrew/ptrace.c
+++ b/libcorkscrew/ptrace.c
@@ -46,21 +46,25 @@ void init_memory_ptrace(memory_t* memory, pid_t tid) {
}
bool try_get_word(const memory_t* memory, uintptr_t ptr, uint32_t* out_value) {
- ALOGV("try_get_word: reading word at 0x%08x", ptr);
+ ALOGV("try_get_word: reading word at %p", (void*) ptr);
if (ptr & 3) {
- ALOGV("try_get_word: invalid pointer 0x%08x", ptr);
+ ALOGV("try_get_word: invalid pointer %p", (void*) ptr);
*out_value = 0xffffffffL;
return false;
}
if (memory->tid < 0) {
if (!is_readable_map(memory->map_info_list, ptr)) {
- ALOGV("try_get_word: pointer 0x%08x not in a readable map", ptr);
+ ALOGV("try_get_word: pointer %p not in a readable map", (void*) ptr);
*out_value = 0xffffffffL;
return false;
}
*out_value = *(uint32_t*)ptr;
return true;
} else {
+#if defined(__APPLE__)
+ ALOGV("no ptrace on Mac OS");
+ return false;
+#else
// ptrace() returns -1 and sets errno when the operation fails.
// To disambiguate -1 from a valid result, we clear errno beforehand.
errno = 0;
@@ -71,6 +75,7 @@ bool try_get_word(const memory_t* memory, uintptr_t ptr, uint32_t* out_value) {
return false;
}
return true;
+#endif
}
}
diff --git a/libcorkscrew/symbol_table.c b/libcorkscrew/symbol_table.c
index 29e4a79f..982ccc8e 100644
--- a/libcorkscrew/symbol_table.c
+++ b/libcorkscrew/symbol_table.c
@@ -21,13 +21,17 @@
#include <stdbool.h>
#include <stdlib.h>
-#include <elf.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <cutils/log.h>
+#if defined(__APPLE__)
+#else
+
+#include <elf.h>
+
static bool is_elf(Elf32_Ehdr* e) {
return (e->e_ident[EI_MAG0] == ELFMAG0 &&
e->e_ident[EI_MAG1] == ELFMAG1 &&
@@ -35,6 +39,8 @@ static bool is_elf(Elf32_Ehdr* e) {
e->e_ident[EI_MAG3] == ELFMAG3);
}
+#endif
+
// Compare function for qsort
static int qcompar(const void *a, const void *b) {
const symbol_t* asym = (const symbol_t*)a;
@@ -55,6 +61,7 @@ static int bcompar(const void *key, const void *element) {
symbol_table_t* load_symbol_table(const char *filename) {
symbol_table_t* table = NULL;
+#if !defined(__APPLE__)
ALOGV("Loading symbol table from '%s'.", filename);
int fd = open(filename, O_RDONLY);
@@ -197,6 +204,7 @@ out_unmap:
out_close:
close(fd);
+#endif
out:
return table;
diff --git a/libcorkscrew/test.c b/libcorkscrew/test.cpp
index af34c032..22dfa7d4 100644
--- a/libcorkscrew/test.c
+++ b/libcorkscrew/test.cpp
@@ -3,11 +3,14 @@
#include <stdio.h>
#include <stdlib.h>
-void do_backtrace() {
+int do_backtrace(float /* just to test demangling */) {
const size_t MAX_DEPTH = 32;
backtrace_frame_t* frames = (backtrace_frame_t*) malloc(sizeof(backtrace_frame_t) * MAX_DEPTH);
ssize_t frame_count = unwind_backtrace(frames, 0, MAX_DEPTH);
fprintf(stderr, "frame_count=%d\n", (int) frame_count);
+ if (frame_count <= 0) {
+ return frame_count;
+ }
backtrace_symbol_t* backtrace_symbols = (backtrace_symbol_t*) malloc(sizeof(backtrace_symbol_t) * frame_count);
get_backtrace_symbols(frames, frame_count, backtrace_symbols);
@@ -31,7 +34,7 @@ void do_backtrace() {
symbol = find_symbol(symbols, frames[i].absolute_pc);
}
if (symbol != NULL) {
- uintptr_t offset = frames[i].absolute_pc - symbol->start;
+ int offset = frames[i].absolute_pc - symbol->start;
fprintf(stderr, " %s (%s%+d)\n", line, symbol->name, offset);
} else {
fprintf(stderr, " %s (\?\?\?)\n", line);
@@ -43,22 +46,31 @@ void do_backtrace() {
free_backtrace_symbols(backtrace_symbols, frame_count);
free(backtrace_symbols);
free(frames);
+ return frame_count;
}
-__attribute__ ((noinline)) void g() {
- fprintf(stderr, "g()\n");
- do_backtrace();
-}
+struct C {
+ int g(int i);
+};
-__attribute__ ((noinline)) int f(int i) {
- fprintf(stderr, "f(%i)\n", i);
+__attribute__ ((noinline)) int C::g(int i) {
if (i == 0) {
- g();
- return 0;
+ return do_backtrace(0.1);
}
- return f(i - 1);
+ return g(i - 1);
+}
+
+extern "C" __attribute__ ((noinline)) int f() {
+ C c;
+ return c.g(5);
}
int main() {
- return f(5);
+ flush_my_map_info_list();
+ f();
+
+ flush_my_map_info_list();
+ f();
+
+ return 0;
}
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 4056e8af..50377056 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -131,7 +131,11 @@ ifeq ($(TARGET_ARCH_VARIANT),x86-atom)
LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32
LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c
else # !x86-atom
+ifeq ($(TARGET_ARCH),mips)
+LOCAL_SRC_FILES += arch-mips/android_memset.c
+else # !mips
LOCAL_SRC_FILES += memory.c
+endif # !mips
endif # !x86-atom
endif # !arm
diff --git a/libcutils/arch-mips/android_memset.c b/libcutils/arch-mips/android_memset.c
new file mode 100644
index 00000000..bbc99fed
--- /dev/null
+++ b/libcutils/arch-mips/android_memset.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/memory.h>
+
+/* Use mips-assembler versions supplied by bionic/libc/arch-mips/string/memset.S: */
+void _memset16(uint16_t* dst, uint16_t value, size_t size);
+void _memset32(uint32_t* dst, uint32_t value, size_t size);
+
+void android_memset16(uint16_t* dst, uint16_t value, size_t size)
+{
+ _memset16(dst, value, size);
+}
+
+void android_memset32(uint32_t* dst, uint32_t value, size_t size)
+{
+ _memset32(dst, value, size);
+}
diff --git a/libcutils/properties.c b/libcutils/properties.c
index f732ec06..28d8b2f5 100644
--- a/libcutils/properties.c
+++ b/libcutils/properties.c
@@ -52,19 +52,28 @@ int property_get(const char *key, char *value, const char *default_value)
return len;
}
-int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
- void *cookie)
+struct property_list_callback_data
+{
+ void (*propfn)(const char *key, const char *value, void *cookie);
+ void *cookie;
+};
+
+static void property_list_callback(const prop_info *pi, void *cookie)
{
char name[PROP_NAME_MAX];
char value[PROP_VALUE_MAX];
- const prop_info *pi;
- unsigned n;
-
- for(n = 0; (pi = __system_property_find_nth(n)); n++) {
- __system_property_read(pi, name, value);
- propfn(name, value, cookie);
- }
- return 0;
+ struct property_list_callback_data *data = cookie;
+
+ __system_property_read(pi, name, value);
+ data->propfn(name, value, data->cookie);
+}
+
+int property_list(
+ void (*propfn)(const char *key, const char *value, void *cookie),
+ void *cookie)
+{
+ struct property_list_callback_data data = { propfn, cookie };
+ return __system_property_foreach(property_list_callback, &data);
}
#elif defined(HAVE_SYSTEM_PROPERTY_SERVER)
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index bd48eff3..da00f743 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -365,9 +365,8 @@ int dhcp_do_request_renew(const char *interface,
return -1;
}
if (strcmp(prop_value, "ok") == 0) {
- fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
+ return fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
server, lease, vendorInfo, domain);
- return 0;
} else {
snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value);
return -1;
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index b5ae4191..5014e4a8 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -675,6 +675,9 @@ struct output_file *output_file_open_fd(int fd, unsigned int block_size, int64_t
} else {
out = output_file_new_normal();
}
+ if (!out) {
+ return NULL;
+ }
out->ops->open(out, fd);
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index 3d4984d3..ae0e0770 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -112,6 +112,12 @@ char *SocketClient::quoteArg(const char *arg) {
char *result = (char *)malloc(len * 2 + 3);
char *current = result;
const char *end = arg + len;
+ char *oldresult;
+
+ if(result == NULL) {
+ SLOGW("malloc error (%s)", strerror(errno));
+ return NULL;
+ }
*(current++) = '"';
while (arg < end) {
@@ -125,8 +131,9 @@ char *SocketClient::quoteArg(const char *arg) {
}
*(current++) = '"';
*(current++) = '\0';
+ oldresult = result; // save pointer in case realloc fails
result = (char *)realloc(result, current-result);
- return result;
+ return result ? result : oldresult;
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1e6ad670..a7057c87 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -37,7 +37,7 @@ loglevel 3
export ANDROID_STORAGE /storage
export ASEC_MOUNTPOINT /mnt/asec
export LOOP_MOUNTPOINT /mnt/obb
- export BOOTCLASSPATH /system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar
+ export BOOTCLASSPATH /system/framework/core.jar:/system/framework/conscrypt.jar:/system/framework/okhttp.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar
# Backward compatibility
symlink /system/etc /etc
@@ -131,14 +131,6 @@ loglevel 3
# This is needed by any process that uses socket tagging.
chmod 0644 /dev/xt_qtaguid
-on fs
-# mount mtd partitions
- # Mount /system rw first to give the filesystem a chance to save a checkpoint
- mount yaffs2 mtd@system /system
- mount yaffs2 mtd@system /system ro remount
- mount yaffs2 mtd@userdata /data nosuid nodev
- mount yaffs2 mtd@cache /cache nosuid nodev
-
on post-fs
# once everything is setup, no need to modify /
mount rootfs rootfs / ro remount
@@ -252,7 +244,7 @@ on post-fs-data
symlink /data/data/com.android.shell/files/bugreports /data/bugreports
# Separate location for storing security policy files on data
- mkdir /data/security 0700 system system
+ mkdir /data/security 0711 system system
# If there is no fs-post-data action in the init.<device>.rc file, you
# must uncomment this line, otherwise encrypted filesystems
@@ -337,12 +329,6 @@ on boot
chown system system /sys/class/leds/red/device/grpfreq
chown system system /sys/class/leds/red/device/grppwm
chown system system /sys/class/leds/red/device/blink
- chown system system /sys/class/leds/red/brightness
- chown system system /sys/class/leds/green/brightness
- chown system system /sys/class/leds/blue/brightness
- chown system system /sys/class/leds/red/device/grpfreq
- chown system system /sys/class/leds/red/device/grppwm
- chown system system /sys/class/leds/red/device/blink
chown system system /sys/class/timed_output/vibrator/enable
chown system system /sys/module/sco/parameters/disable_esco
chown system system /sys/kernel/ipv4/tcp_wmem_min
diff --git a/toolbox/dd.c b/toolbox/dd.c
index 350f1d2d..a8c12d28 100644
--- a/toolbox/dd.c
+++ b/toolbox/dd.c
@@ -590,8 +590,8 @@ pos_in(void)
/* If not a pipe or tape device, try to seek on it. */
if (!(in.flags & (ISPIPE|ISTAPE))) {
- if (lseek(in.fd,
- (off_t)in.offset * (off_t)in.dbsz, SEEK_CUR) == -1) {
+ 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);
@@ -661,8 +661,8 @@ pos_out(void)
* have specified the seek operand.
*/
if (!(out.flags & ISTAPE)) {
- if (lseek(out.fd,
- (off_t)out.offset * (off_t)out.dbsz, SEEK_SET) == -1) {
+ 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);
diff --git a/toolbox/dmesg.c b/toolbox/dmesg.c
index e57f6077..9c73b00c 100644
--- a/toolbox/dmesg.c
+++ b/toolbox/dmesg.c
@@ -5,15 +5,30 @@
#include <sys/klog.h>
#include <string.h>
-#define KLOG_BUF_SHIFT 17 /* CONFIG_LOG_BUF_SHIFT from our kernel */
-#define KLOG_BUF_LEN (1 << KLOG_BUF_SHIFT)
+#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[KLOG_BUF_LEN + 1];
- char *p = buffer;
+ char *buffer;
+ char *p;
ssize_t ret;
- int n, op;
+ 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;
@@ -21,7 +36,7 @@ int dmesg_main(int argc, char **argv)
op = KLOG_READ_ALL;
}
- n = klogctl(op, buffer, KLOG_BUF_LEN);
+ n = klogctl(op, buffer, klog_buf_len);
if (n < 0) {
perror("klogctl");
return EXIT_FAILURE;
diff --git a/toolbox/ls.c b/toolbox/ls.c
index e5305212..53245111 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -28,6 +28,7 @@
#define LIST_LONG_NUMERIC (1 << 5)
#define LIST_CLASSIFY (1 << 6)
#define LIST_MACLABEL (1 << 7)
+#define LIST_INODE (1 << 8)
// fwd
static int listpath(const char *name, int flags);
@@ -127,22 +128,20 @@ static int show_total_size(const char *dirname, DIR *d, int flags)
return 0;
}
-static int listfile_size(const char *path, const char *filename, int flags)
+static int listfile_size(const char *path, const char *filename, struct stat *s,
+ int flags)
{
- struct stat s;
-
- if (lstat(path, &s) < 0) {
- fprintf(stderr, "lstat '%s' failed: %s\n", path, strerror(errno));
+ if(!s || !path) {
return -1;
}
/* blocks are 512 bytes, we want output to be KB */
if ((flags & LIST_SIZE) != 0) {
- printf("%lld ", s.st_blocks / 2);
+ printf("%lld ", s->st_blocks / 2);
}
if ((flags & LIST_CLASSIFY) != 0) {
- char filetype = mode2kind(s.st_mode);
+ char filetype = mode2kind(s->st_mode);
if (filetype != 'l') {
printf("%c ", filetype);
} else {
@@ -161,15 +160,18 @@ static int listfile_size(const char *path, const char *filename, int flags)
return 0;
}
-static int listfile_long(const char *path, int flags)
+static int listfile_long(const char *path, struct stat *s, int flags)
{
- struct stat s;
char date[32];
char mode[16];
char user[16];
char group[16];
const char *name;
+ if(!s || !path) {
+ return -1;
+ }
+
/* name is anything after the final '/', or the whole path if none*/
name = strrchr(path, '/');
if(name == 0) {
@@ -178,36 +180,32 @@ static int listfile_long(const char *path, int flags)
name++;
}
- if(lstat(path, &s) < 0) {
- return -1;
- }
-
- mode2str(s.st_mode, mode);
+ mode2str(s->st_mode, mode);
if (flags & LIST_LONG_NUMERIC) {
- sprintf(user, "%ld", s.st_uid);
- sprintf(group, "%ld", s.st_gid);
+ sprintf(user, "%ld", s->st_uid);
+ sprintf(group, "%ld", s->st_gid);
} else {
- user2str(s.st_uid, user);
- group2str(s.st_gid, group);
+ user2str(s->st_uid, user);
+ group2str(s->st_gid, group);
}
- strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s.st_mtime));
+ strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s->st_mtime));
date[31] = 0;
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
// MMMMMMMM UUUUUUUU GGGGGGGGG XXXXXXXX YYYY-MM-DD HH:MM NAME (->LINK)
- switch(s.st_mode & S_IFMT) {
+ switch(s->st_mode & S_IFMT) {
case S_IFBLK:
case S_IFCHR:
printf("%s %-8s %-8s %3d, %3d %s %s\n",
mode, user, group,
- (int) MAJOR(s.st_rdev), (int) MINOR(s.st_rdev),
+ (int) MAJOR(s->st_rdev), (int) MINOR(s->st_rdev),
date, name);
break;
case S_IFREG:
printf("%s %-8s %-8s %8lld %s %s\n",
- mode, user, group, s.st_size, date, name);
+ mode, user, group, s->st_size, date, name);
break;
case S_IFLNK: {
char linkto[256];
@@ -237,15 +235,18 @@ static int listfile_long(const char *path, int flags)
return 0;
}
-static int listfile_maclabel(const char *path, int flags)
+static int listfile_maclabel(const char *path, struct stat *s, int flags)
{
- struct stat s;
char mode[16];
char user[16];
char group[16];
char *maclabel = NULL;
const char *name;
+ if(!s || !path) {
+ return -1;
+ }
+
/* name is anything after the final '/', or the whole path if none*/
name = strrchr(path, '/');
if(name == 0) {
@@ -254,20 +255,16 @@ static int listfile_maclabel(const char *path, int flags)
name++;
}
- if(lstat(path, &s) < 0) {
- return -1;
- }
-
lgetfilecon(path, &maclabel);
if (!maclabel) {
return -1;
}
- mode2str(s.st_mode, mode);
- user2str(s.st_uid, user);
- group2str(s.st_gid, group);
+ mode2str(s->st_mode, mode);
+ user2str(s->st_uid, user);
+ group2str(s->st_gid, group);
- switch(s.st_mode & S_IFMT) {
+ switch(s->st_mode & S_IFMT) {
case S_IFLNK: {
char linkto[256];
ssize_t len;
@@ -301,7 +298,9 @@ static int listfile_maclabel(const char *path, int flags)
static int listfile(const char *dirname, const char *filename, int flags)
{
- if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_MACLABEL)) == 0) {
+ struct stat s;
+
+ if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_MACLABEL | LIST_INODE)) == 0) {
printf("%s\n", filename);
return 0;
}
@@ -316,12 +315,20 @@ static int listfile(const char *dirname, const char *filename, int flags)
pathname = filename;
}
+ if(lstat(pathname, &s) < 0) {
+ return -1;
+ }
+
+ if(flags & LIST_INODE) {
+ printf("%8llu ", s.st_ino);
+ }
+
if ((flags & LIST_MACLABEL) != 0) {
- return listfile_maclabel(pathname, flags);
+ return listfile_maclabel(pathname, &s, flags);
} else if ((flags & LIST_LONG) != 0) {
- return listfile_long(pathname, flags);
+ return listfile_long(pathname, &s, flags);
} else /*((flags & LIST_SIZE) != 0)*/ {
- return listfile_size(pathname, filename, flags);
+ return listfile_size(pathname, filename, &s, flags);
}
}
@@ -456,6 +463,7 @@ int ls_main(int argc, char **argv)
case 'Z': flags |= LIST_MACLABEL; break;
case 'a': flags |= LIST_ALL; break;
case 'F': flags |= LIST_CLASSIFY; break;
+ case 'i': flags |= LIST_INODE; break;
default:
fprintf(stderr, "%s: Unknown option '-%c'. Aborting.\n", "ls", arg[0]);
exit(1);
diff --git a/toolbox/mount.c b/toolbox/mount.c
index b7adce2d..bcda2a28 100644
--- a/toolbox/mount.c
+++ b/toolbox/mount.c
@@ -19,7 +19,7 @@
#define LOOPDEV_MAXLEN 64
struct mount_opts {
- const char str[8];
+ const char str[16];
unsigned long rwmask;
unsigned long rwset;
unsigned long rwnoset;
@@ -65,10 +65,11 @@ static const struct mount_opts options[] = {
static void add_extra_option(struct extra_opts *extra, char *s)
{
int len = strlen(s);
- int newlen = extra->used_size + len;
+ int newlen;
if (extra->str)
len++; /* +1 for ',' */
+ newlen = extra->used_size + len;
if (newlen >= extra->alloc_size) {
char *new;
@@ -79,7 +80,7 @@ static void add_extra_option(struct extra_opts *extra, char *s)
extra->str = new;
extra->end = extra->str + extra->used_size;
- extra->alloc_size = newlen;
+ extra->alloc_size = newlen + 1;
}
if (extra->used_size) {
diff --git a/toolbox/netstat.c b/toolbox/netstat.c
index 5768599a..05dc6400 100644
--- a/toolbox/netstat.c
+++ b/toolbox/netstat.c
@@ -108,7 +108,7 @@ static void ipv4(const char *filename, const char *label) {
addr2str(AF_INET, &raddr, rport, rip);
printf("%4s %6d %6d %-22s %-22s %s\n",
- label, txq, rxq, lip, rip,
+ label, rxq, txq, lip, rip,
state2str(state));
}
}
@@ -136,7 +136,7 @@ static void ipv6(const char *filename, const char *label) {
addr2str(AF_INET6, &raddr6, rport, rip);
printf("%4s %6d %6d %-22s %-22s %s\n",
- label, txq, rxq, lip, rip,
+ label, rxq, txq, lip, rip,
state2str(state));
}
}
diff --git a/toolbox/watchprops.c b/toolbox/watchprops.c
index d3119924..bf82882f 100644
--- a/toolbox/watchprops.c
+++ b/toolbox/watchprops.c
@@ -1,35 +1,30 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
+#include <errno.h>
#include <cutils/properties.h>
+#include <cutils/hashmap.h>
#include <sys/atomics.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
-
-extern prop_area *__system_property_area__;
-
-typedef struct pwatch pwatch;
-
-struct pwatch
+static int str_hash(void *key)
{
- const prop_info *pi;
- unsigned serial;
-};
+ return hashmapHash(key, strlen(key));
+}
-static pwatch watchlist[1024];
+static bool str_equals(void *keyA, void *keyB)
+{
+ return strcmp(keyA, keyB) == 0;
+}
-static void announce(const prop_info *pi)
+static void announce(char *name, char *value)
{
- char name[PROP_NAME_MAX];
- char value[PROP_VALUE_MAX];
char *x;
- __system_property_read(pi, name, value);
-
for(x = value; *x; x++) {
if((*x < 32) || (*x > 127)) *x = '.';
}
@@ -37,40 +32,64 @@ static void announce(const prop_info *pi)
fprintf(stderr,"%10d %s = '%s'\n", (int) time(0), name, value);
}
+static void add_to_watchlist(Hashmap *watchlist, const char *name,
+ const prop_info *pi)
+{
+ char *key = strdup(name);
+ unsigned *value = malloc(sizeof(unsigned));
+ if (!key || !value)
+ exit(1);
+
+ *value = __system_property_serial(pi);
+ hashmapPut(watchlist, key, value);
+}
+
+static void populate_watchlist(const prop_info *pi, void *cookie)
+{
+ Hashmap *watchlist = cookie;
+ char name[PROP_NAME_MAX];
+ char value_unused[PROP_VALUE_MAX];
+
+ __system_property_read(pi, name, value_unused);
+ add_to_watchlist(watchlist, name, pi);
+}
+
+static void update_watchlist(const prop_info *pi, void *cookie)
+{
+ Hashmap *watchlist = cookie;
+ char name[PROP_NAME_MAX];
+ char value[PROP_VALUE_MAX];
+ unsigned *serial;
+
+ __system_property_read(pi, name, value);
+ serial = hashmapGet(watchlist, name);
+ if (!serial) {
+ add_to_watchlist(watchlist, name, pi);
+ announce(name, value);
+ } else {
+ unsigned tmp = __system_property_serial(pi);
+ if (*serial != tmp) {
+ *serial = tmp;
+ announce(name, value);
+ }
+ }
+}
+
int watchprops_main(int argc, char *argv[])
{
- prop_area *pa = __system_property_area__;
- unsigned serial = pa->serial;
- unsigned count = pa->count;
+ unsigned serial = 0;
+ unsigned count = 0;
unsigned n;
- if(count >= 1024) exit(1);
+ Hashmap *watchlist = hashmapCreate(1024, str_hash, str_equals);
+ if (!watchlist)
+ exit(1);
- for(n = 0; n < count; n++) {
- watchlist[n].pi = __system_property_find_nth(n);
- watchlist[n].serial = watchlist[n].pi->serial;
- }
+ __system_property_foreach(populate_watchlist, watchlist);
for(;;) {
- do {
- __futex_wait(&pa->serial, serial, 0);
- } while(pa->serial == serial);
-
- while(count < pa->count){
- watchlist[count].pi = __system_property_find_nth(count);
- watchlist[count].serial = watchlist[n].pi->serial;
- announce(watchlist[count].pi);
- count++;
- if(count == 1024) exit(1);
- }
-
- for(n = 0; n < count; n++){
- unsigned tmp = watchlist[n].pi->serial;
- if(watchlist[n].serial != tmp) {
- announce(watchlist[n].pi);
- watchlist[n].serial = tmp;
- }
- }
+ serial = __system_property_wait_any(serial);
+ __system_property_foreach(update_watchlist, watchlist);
}
return 0;
}