Merge "libnetutils: Clean all IPs assigned to the interface on cleaning"
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 752c953..6cfe79b 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -29,7 +29,7 @@
LOCAL_SRC_FILES += $(TARGET_ARCH)/crashglue.S
LOCAL_MODULE := crasher
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_TAGS := optional
#LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_SHARED_LIBRARIES := libcutils libc
include $(BUILD_EXECUTABLE)
@@ -45,7 +45,7 @@
LOCAL_SRC_FILES := vfp-crasher.c vfp.S
LOCAL_MODULE := vfp-crasher
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := libcutils libc
include $(BUILD_EXECUTABLE)
endif # ARCH_ARM_HAVE_VFP == true
diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c
index 5fa4442..7a3e781 100644
--- a/debuggerd/debuggerd.c
+++ b/debuggerd/debuggerd.c
@@ -642,7 +642,7 @@
goto done;
}
- sprintf(buf,"/proc/%d/task/%d", cr.pid, tid);
+ snprintf(buf, sizeof buf, "/proc/%d/task/%d", cr.pid, tid);
if(stat(buf, &s)) {
LOG("tid %d does not exist in pid %d. ignoring debug request\n",
tid, cr.pid);
@@ -652,7 +652,19 @@
XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n", cr.pid, cr.uid, cr.gid, tid);
+ /* Note that at this point, the target thread's signal handler
+ * is blocked in a read() call. This gives us the time to PTRACE_ATTACH
+ * to it before it has a chance to really fault.
+ *
+ * After the attach, the thread is stopped, and we write to the file
+ * descriptor to ensure that it will run as soon as we call PTRACE_CONT
+ * below. See details in bionic/libc/linker/debugger.c, in function
+ * debugger_signal_handler().
+ */
tid_attach_status = ptrace(PTRACE_ATTACH, tid, 0, 0);
+
+ TEMP_FAILURE_RETRY(write(fd, &tid, 1));
+
if(tid_attach_status < 0) {
LOG("ptrace attach failed: %s\n", strerror(errno));
goto done;
diff --git a/gpttool/Android.mk b/gpttool/Android.mk
new file mode 100644
index 0000000..a9fffe9
--- /dev/null
+++ b/gpttool/Android.mk
@@ -0,0 +1,14 @@
+ifeq ($(HOST_OS),linux)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := gpttool.c
+LOCAL_STATIC_LIBRARIES := libz
+
+LOCAL_MODULE := gpttool
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_HOST_EXECUTABLE)
+
+endif
diff --git a/gpttool/gpttool.c b/gpttool/gpttool.c
new file mode 100644
index 0000000..05d5177
--- /dev/null
+++ b/gpttool/gpttool.c
@@ -0,0 +1,376 @@
+/* system/core/gpttool/gpttool.c
+**
+** Copyright 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <zlib.h>
+
+#include <linux/fs.h>
+
+#include <sys/stat.h>
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+typedef unsigned long long u64;
+
+const u8 partition_type_uuid[16] = {
+ 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
+ 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7,
+};
+
+
+#define EFI_VERSION 0x00010000
+#define EFI_MAGIC "EFI PART"
+#define EFI_ENTRIES 128
+#define EFI_NAMELEN 36
+
+struct efi_header {
+ u8 magic[8];
+
+ u32 version;
+ u32 header_sz;
+
+ u32 crc32;
+ u32 reserved;
+
+ u64 header_lba;
+ u64 backup_lba;
+ u64 first_lba;
+ u64 last_lba;
+
+ u8 volume_uuid[16];
+
+ u64 entries_lba;
+
+ u32 entries_count;
+ u32 entries_size;
+ u32 entries_crc32;
+} __attribute__((packed));
+
+struct efi_entry {
+ u8 type_uuid[16];
+ u8 uniq_uuid[16];
+ u64 first_lba;
+ u64 last_lba;
+ u64 attr;
+ u16 name[EFI_NAMELEN];
+};
+
+struct ptable {
+ u8 mbr[512];
+ union {
+ struct efi_header header;
+ u8 block[512];
+ };
+ struct efi_entry entry[EFI_ENTRIES];
+};
+
+void get_uuid(u8 *uuid)
+{
+ int fd;
+ fd = open("/dev/urandom", O_RDONLY);
+ read(fd, uuid, 16);
+ close(fd);
+}
+
+void init_mbr(u8 *mbr, u32 blocks)
+{
+ mbr[0x1be] = 0x00; // nonbootable
+ mbr[0x1bf] = 0xFF; // bogus CHS
+ mbr[0x1c0] = 0xFF;
+ mbr[0x1c1] = 0xFF;
+
+ mbr[0x1c2] = 0xEE; // GPT partition
+ mbr[0x1c3] = 0xFF; // bogus CHS
+ mbr[0x1c4] = 0xFF;
+ mbr[0x1c5] = 0xFF;
+
+ mbr[0x1c6] = 0x01; // start
+ mbr[0x1c7] = 0x00;
+ mbr[0x1c8] = 0x00;
+ mbr[0x1c9] = 0x00;
+
+ memcpy(mbr + 0x1ca, &blocks, sizeof(u32));
+
+ mbr[0x1fe] = 0x55;
+ mbr[0x1ff] = 0xaa;
+}
+
+int add_ptn(struct ptable *ptbl, u64 first, u64 last, const char *name)
+{
+ struct efi_header *hdr = &ptbl->header;
+ struct efi_entry *entry = ptbl->entry;
+ unsigned n;
+
+ if (first < 34) {
+ fprintf(stderr,"partition '%s' overlaps partition table\n", name);
+ return -1;
+ }
+
+ if (last > hdr->last_lba) {
+ fprintf(stderr,"partition '%s' does not fit on disk\n", name);
+ return -1;
+ }
+ for (n = 0; n < EFI_ENTRIES; n++, entry++) {
+ if (entry->type_uuid[0])
+ continue;
+ memcpy(entry->type_uuid, partition_type_uuid, 16);
+ get_uuid(entry->uniq_uuid);
+ entry->first_lba = first;
+ entry->last_lba = last;
+ for (n = 0; (n < EFI_NAMELEN) && *name; n++)
+ entry->name[n] = *name++;
+ return 0;
+ }
+ fprintf(stderr,"out of partition table entries\n");
+ return -1;
+}
+
+int usage(void)
+{
+ fprintf(stderr,
+ "usage: gpttool write <disk> [ <partition> ]*\n"
+ " gpttool read <disk>\n"
+ " gpttool test [ <partition> ]*\n"
+ "\n"
+ "partition: [<name>]:<size>[kmg] | @<file-of-partitions>\n"
+ );
+ return 0;
+}
+
+void show(struct ptable *ptbl)
+{
+ struct efi_entry *entry = ptbl->entry;
+ unsigned n, m;
+ char name[EFI_NAMELEN];
+
+ fprintf(stderr,"ptn start block end block name\n");
+ fprintf(stderr,"---- ------------- ------------- --------------------\n");
+
+ for (n = 0; n < EFI_ENTRIES; n++, entry++) {
+ if (entry->type_uuid[0] == 0)
+ break;
+ for (m = 0; m < EFI_NAMELEN; m++) {
+ name[m] = entry->name[m] & 127;
+ }
+ name[m] = 0;
+ fprintf(stderr,"#%03d %13lld %13lld %s\n",
+ n + 1, entry->first_lba, entry->last_lba, name);
+ }
+}
+
+u64 find_next_lba(struct ptable *ptbl)
+{
+ struct efi_entry *entry = ptbl->entry;
+ unsigned n;
+ u64 a = 0;
+ for (n = 0; n < EFI_ENTRIES; n++, entry++) {
+ if ((entry->last_lba + 1) > a)
+ a = entry->last_lba + 1;
+ }
+ return a;
+}
+
+u64 next_lba = 0;
+
+u64 parse_size(char *sz)
+{
+ int l = strlen(sz);
+ u64 n = strtoull(sz, 0, 10);
+ if (l) {
+ switch(sz[l-1]){
+ case 'k':
+ case 'K':
+ n *= 1024;
+ break;
+ case 'm':
+ case 'M':
+ n *= (1024 * 1024);
+ break;
+ case 'g':
+ case 'G':
+ n *= (1024 * 1024 * 1024);
+ break;
+ }
+ }
+ return n;
+}
+
+int parse_ptn(struct ptable *ptbl, char *x)
+{
+ char *y = strchr(x, ':');
+ u64 sz;
+
+ if (!y) {
+ fprintf(stderr,"invalid partition entry: %s\n", x);
+ return -1;
+ }
+ *y++ = 0;
+
+ if (*y == 0) {
+ sz = ptbl->header.last_lba - next_lba;
+ } else {
+ sz = parse_size(y);
+ if (sz & 511) {
+ fprintf(stderr,"partition size must be multiple of 512\n");
+ return -1;
+ }
+ sz /= 512;
+ }
+
+ if (sz == 0) {
+ fprintf(stderr,"zero size partitions not allowed\n");
+ return -1;
+ }
+
+ if (x[0] && add_ptn(ptbl, next_lba, next_lba + sz - 1, x))
+ return -1;
+
+ next_lba = next_lba + sz;
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ struct ptable ptbl;
+ struct efi_entry *entry;
+ struct efi_header *hdr = &ptbl.header;
+ struct stat s;
+ u32 n;
+ u64 sz, blk;
+ int fd;
+ const char *device;
+ int real_disk = 0;
+
+ if (argc < 2)
+ return usage();
+
+ if (!strcmp(argv[1], "write")) {
+ if (argc < 3)
+ return usage();
+ device = argv[2];
+ argc -= 2;
+ argv += 2;
+ real_disk = 1;
+ } else if (!strcmp(argv[1], "test")) {
+ argc -= 1;
+ argv += 1;
+ real_disk = 0;
+ sz = 2097152 * 16;
+ fprintf(stderr,"< simulating 16GB disk >\n\n");
+ } else {
+ return usage();
+ }
+
+ if (real_disk) {
+ if (!strcmp(device, "/dev/sda") ||
+ !strcmp(device, "/dev/sdb")) {
+ fprintf(stderr,"error: refusing to partition sda or sdb\n");
+ return -1;
+ }
+
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr,"error: cannot open '%s'\n", device);
+ return -1;
+ }
+ if (ioctl(fd, BLKGETSIZE64, &sz)) {
+ fprintf(stderr,"error: cannot query block device size\n");
+ return -1;
+ }
+ sz /= 512;
+ fprintf(stderr,"blocks %lld\n", sz);
+ }
+
+ memset(&ptbl, 0, sizeof(ptbl));
+
+ init_mbr(ptbl.mbr, sz - 1);
+
+ memcpy(hdr->magic, EFI_MAGIC, sizeof(hdr->magic));
+ hdr->version = EFI_VERSION;
+ hdr->header_sz = sizeof(struct efi_header);
+ hdr->header_lba = 1;
+ hdr->backup_lba = sz - 1;
+ hdr->first_lba = 34;
+ hdr->last_lba = sz - 1;
+ get_uuid(hdr->volume_uuid);
+ hdr->entries_lba = 2;
+ hdr->entries_count = 128;
+ hdr->entries_size = sizeof(struct efi_entry);
+
+ while (argc > 1) {
+ if (argv[1][0] == '@') {
+ char line[256], *p;
+ FILE *f;
+ f = fopen(argv[1] + 1, "r");
+ if (!f) {
+ fprintf(stderr,"cannot read partitions from '%s\n", argv[1]);
+ return -1;
+ }
+ while (fgets(line, sizeof(line), f)) {
+ p = line + strlen(line);
+ while (p > line) {
+ p--;
+ if (*p > ' ')
+ break;
+ *p = 0;
+ }
+ p = line;
+ while (*p && (*p <= ' '))
+ p++;
+ if (*p == '#')
+ continue;
+ if (*p == 0)
+ continue;
+ if (parse_ptn(&ptbl, p))
+ return -1;
+ }
+ fclose(f);
+ } else {
+ if (parse_ptn(&ptbl, argv[1]))
+ return -1;
+ }
+ argc--;
+ argv++;
+ }
+
+ n = crc32(0, Z_NULL, 0);
+ n = crc32(n, (void*) ptbl.entry, sizeof(ptbl.entry));
+ hdr->entries_crc32 = n;
+
+ n = crc32(0, Z_NULL, 0);
+ n = crc32(n, (void*) &ptbl.header, sizeof(ptbl.header));
+ hdr->crc32 = n;
+
+ show(&ptbl);
+
+ if (real_disk) {
+ write(fd, &ptbl, sizeof(ptbl));
+ fsync(fd);
+
+ if (ioctl(fd, BLKRRPART, 0)) {
+ fprintf(stderr,"could not re-read partition table\n");
+ }
+ close(fd);
+ }
+ return 0;
+}
diff --git a/include/cutils/atomic-arm.h b/include/cutils/atomic-arm.h
index 004cc0c..16fe512 100644
--- a/include/cutils/atomic-arm.h
+++ b/include/cutils/atomic-arm.h
@@ -146,38 +146,6 @@
#if defined(__thumb__)
-extern int32_t android_atomic_swap(int32_t new_value,
- volatile int32_t *ptr);
-#elif defined(__ARM_HAVE_LDREX_STREX)
-extern inline int32_t android_atomic_swap(int32_t new_value,
- volatile int32_t *ptr)
-{
- int32_t prev, status;
- do {
- __asm__ __volatile__ ("ldrex %0, [%3]\n"
- "strex %1, %4, [%3]"
- : "=&r" (prev), "=&r" (status), "+m" (*ptr)
- : "r" (ptr), "r" (new_value)
- : "cc");
- } while (__builtin_expect(status != 0, 0));
- android_memory_barrier();
- return prev;
-}
-#else
-extern inline int32_t android_atomic_swap(int32_t new_value,
- volatile int32_t *ptr)
-{
- int32_t prev;
- __asm__ __volatile__ ("swp %0, %2, [%3]"
- : "=&r" (prev), "+m" (*ptr)
- : "r" (new_value), "r" (ptr)
- : "cc");
- android_memory_barrier();
- return prev;
-}
-#endif
-
-#if defined(__thumb__)
extern int32_t android_atomic_add(int32_t increment,
volatile int32_t *ptr);
#elif defined(__ARM_HAVE_LDREX_STREX)
diff --git a/include/cutils/atomic-x86.h b/include/cutils/atomic-x86.h
index bce23ad..438012e 100644
--- a/include/cutils/atomic-x86.h
+++ b/include/cutils/atomic-x86.h
@@ -98,17 +98,6 @@
return android_atomic_cas(old_value, new_value, ptr);
}
-extern inline int32_t android_atomic_swap(int32_t new_value,
- volatile int32_t *ptr)
-{
- __asm__ __volatile__ ("xchgl %1, %0"
- : "=r" (new_value)
- : "m" (*ptr), "0" (new_value)
- : "memory");
- /* new_value now holds the old value of *ptr */
- return new_value;
-}
-
extern inline int32_t android_atomic_add(int32_t increment,
volatile int32_t *ptr)
{
diff --git a/include/cutils/atomic.h b/include/cutils/atomic.h
index a50bf0f..ae42eb8 100644
--- a/include/cutils/atomic.h
+++ b/include/cutils/atomic.h
@@ -90,13 +90,6 @@
void android_atomic_release_store(int32_t value, volatile int32_t* addr);
/*
- * Unconditional swap operation with release ordering.
- *
- * Stores the new value at *addr, and returns the previous value.
- */
-int32_t android_atomic_swap(int32_t value, volatile int32_t* addr);
-
-/*
* Compare-and-set operation with "acquire" or "release" ordering.
*
* This returns zero if the new value was successfully stored, which will
diff --git a/include/netutils/dhcp.h b/include/netutils/dhcp.h
index 96798c5..bd16240 100644
--- a/include/netutils/dhcp.h
+++ b/include/netutils/dhcp.h
@@ -24,12 +24,12 @@
extern int do_dhcp(char *iname);
extern int dhcp_do_request(const char *ifname,
- in_addr_t *ipaddr,
- in_addr_t *gateway,
- in_addr_t *mask,
- in_addr_t *dns1,
- in_addr_t *dns2,
- in_addr_t *server,
+ char *ipaddr,
+ char *gateway,
+ uint32_t *prefixLength,
+ char *dns1,
+ char *dns2,
+ char *server,
uint32_t *lease);
extern int dhcp_stop(const char *ifname);
extern int dhcp_release_lease(const char *ifname);
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index e446fc9..0f05a1b 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -53,7 +53,7 @@
#define AID_KEYSTORE 1017 /* keystore subsystem */
#define AID_USB 1018 /* USB devices */
#define AID_DRM 1019 /* DRM server */
-#define AID_DRMIO 1020 /* DRM IO server */
+#define AID_AVAILABLE 1020 /* available for use */
#define AID_GPS 1021 /* GPS daemon */
#define AID_NFC 1022 /* nfc subsystem */
#define AID_MEDIA_RW 1023 /* internal media storage write access */
@@ -100,7 +100,7 @@
{ "install", AID_INSTALL, },
{ "media", AID_MEDIA, },
{ "drm", AID_DRM, },
- { "drmio", AID_DRMIO, },
+ { "available", AID_AVAILABLE, },
{ "nfc", AID_NFC, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
diff --git a/include/sysutils/SocketListener.h b/include/sysutils/SocketListener.h
index c7edfeb..6592b01 100644
--- a/include/sysutils/SocketListener.h
+++ b/include/sysutils/SocketListener.h
@@ -30,7 +30,7 @@
pthread_t mThread;
public:
- SocketListener(const char *socketNames, bool listen);
+ SocketListener(const char *socketName, bool listen);
SocketListener(int socketFd, bool listen);
virtual ~SocketListener();
diff --git a/include/usbhost/usbhost.h b/include/usbhost/usbhost.h
index 7ef7ace..41e2ddc 100644
--- a/include/usbhost/usbhost.h
+++ b/include/usbhost/usbhost.h
@@ -177,6 +177,13 @@
/* Releases the specified interface of a USB device */
int usb_device_release_interface(struct usb_device *device, unsigned int interface);
+/* Requests the kernel to connect or disconnect its driver for the specified interface.
+ * This can be used to ask the kernel to disconnect its driver for a device
+ * so usb_device_claim_interface can claim it instead.
+ */
+int usb_device_connect_kernel_driver(struct usb_device *device,
+ unsigned int interface, int connect);
+
/* Creates a new usb_request. */
struct usb_request *usb_request_new(struct usb_device *dev,
const struct usb_endpoint_descriptor *ep_desc);
diff --git a/init/builtins.c b/init/builtins.c
index 915c5aa..490ad48 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -485,6 +485,16 @@
return symlink(args[1], args[2]);
}
+int do_rm(int nargs, char **args)
+{
+ return unlink(args[1]);
+}
+
+int do_rmdir(int nargs, char **args)
+{
+ return rmdir(args[1]);
+}
+
int do_sysclktz(int nargs, char **args)
{
struct timezone tz;
diff --git a/init/init_parser.c b/init/init_parser.c
index 00e6b9e..0898ae8 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -125,6 +125,8 @@
break;
case 'r':
if (!strcmp(s, "estart")) return K_restart;
+ if (!strcmp(s, "mdir")) return K_rmdir;
+ if (!strcmp(s, "m")) return K_rm;
break;
case 's':
if (!strcmp(s, "ervice")) return K_service;
diff --git a/init/keywords.h b/init/keywords.h
index d15ad49..c977fd7 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -15,6 +15,8 @@
int do_mkdir(int nargs, char **args);
int do_mount(int nargs, char **args);
int do_restart(int nargs, char **args);
+int do_rm(int nargs, char **args);
+int do_rmdir(int nargs, char **args);
int do_setkey(int nargs, char **args);
int do_setprop(int nargs, char **args);
int do_setrlimit(int nargs, char **args);
@@ -59,6 +61,8 @@
KEYWORD(oneshot, OPTION, 0, 0)
KEYWORD(onrestart, OPTION, 0, 0)
KEYWORD(restart, COMMAND, 1, do_restart)
+ KEYWORD(rm, COMMAND, 1, do_rm)
+ KEYWORD(rmdir, COMMAND, 1, do_rmdir)
KEYWORD(service, SECTION, 0, 0)
KEYWORD(setenv, OPTION, 2, 0)
KEYWORD(setkey, COMMAND, 0, do_setkey)
diff --git a/libcutils/atomic-android-sh.c b/libcutils/atomic-android-sh.c
index f8f1f57..8bac68a 100644
--- a/libcutils/atomic-android-sh.c
+++ b/libcutils/atomic-android-sh.c
@@ -113,18 +113,6 @@
return oldValue;
}
-int32_t android_atomic_acquire_swap(int32_t value, volatile int32_t* addr) {
- return android_atomic_release_swap(value, addr);
-}
-
-int32_t android_atomic_release_swap(int32_t value, volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, value, addr));
- return oldValue;
-}
-
int android_atomic_acquire_cmpxchg(int32_t oldvalue, int32_t newvalue,
volatile int32_t* addr) {
return android_atomic_release_cmpxchg(oldValue, newValue, addr);
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index 1802688..030e677 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -60,60 +60,60 @@
return -1; /* failure */
}
-static void fill_ip_info(const char *interface,
- in_addr_t *ipaddr,
- in_addr_t *gateway,
- in_addr_t *mask,
- in_addr_t *dns1,
- in_addr_t *dns2,
- in_addr_t *server,
+static int fill_ip_info(const char *interface,
+ char *ipaddr,
+ char *gateway,
+ uint32_t *prefixLength,
+ char *dns1,
+ char *dns2,
+ char *server,
uint32_t *lease)
{
char prop_name[PROPERTY_KEY_MAX];
char prop_value[PROPERTY_VALUE_MAX];
- struct in_addr addr;
- in_addr_t iaddr;
snprintf(prop_name, sizeof(prop_name), "%s.%s.ipaddress", DHCP_PROP_NAME_PREFIX, interface);
- if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
- *ipaddr = addr.s_addr;
- } else {
- *ipaddr = 0;
- }
+ property_get(prop_name, ipaddr, NULL);
+
snprintf(prop_name, sizeof(prop_name), "%s.%s.gateway", DHCP_PROP_NAME_PREFIX, interface);
- if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
- *gateway = addr.s_addr;
- } else {
- *gateway = 0;
- }
+ property_get(prop_name, gateway, NULL);
+
snprintf(prop_name, sizeof(prop_name), "%s.%s.mask", DHCP_PROP_NAME_PREFIX, interface);
- if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
- *mask = addr.s_addr;
- } else {
- *mask = 0;
+ if (property_get(prop_name, prop_value, NULL)) {
+ int p;
+ // this conversion is v4 only, but this dhcp client is v4 only anyway
+ in_addr_t mask = ntohl(inet_addr(prop_value));
+ // Check netmask is a valid IP address. ntohl gives NONE response (all 1's) for
+ // non 255.255.255.255 inputs. if we get that value check if it is legit..
+ if (mask == INADDR_NONE && strcmp(prop_value, "255.255.255.255") != 0) {
+ snprintf(errmsg, sizeof(errmsg), "DHCP gave invalid net mask %s", prop_value);
+ return -1;
+ }
+ for (p = 0; p < 32; p++) {
+ if (mask == 0) break;
+ // check for non-contiguous netmask, e.g., 255.254.255.0
+ if ((mask & 0x80000000) == 0) {
+ snprintf(errmsg, sizeof(errmsg), "DHCP gave invalid net mask %s", prop_value);
+ return -1;
+ }
+ mask = mask << 1;
+ }
+ *prefixLength = p;
}
snprintf(prop_name, sizeof(prop_name), "%s.%s.dns1", DHCP_PROP_NAME_PREFIX, interface);
- if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
- *dns1 = addr.s_addr;
- } else {
- *dns1 = 0;
- }
+ property_get(prop_name, dns1, NULL);
+
snprintf(prop_name, sizeof(prop_name), "%s.%s.dns2", DHCP_PROP_NAME_PREFIX, interface);
- if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
- *dns2 = addr.s_addr;
- } else {
- *dns2 = 0;
- }
+ property_get(prop_name, dns2, NULL);
+
snprintf(prop_name, sizeof(prop_name), "%s.%s.server", DHCP_PROP_NAME_PREFIX, interface);
- if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
- *server = addr.s_addr;
- } else {
- *server = 0;
- }
+ property_get(prop_name, server, NULL);
+
snprintf(prop_name, sizeof(prop_name), "%s.%s.leasetime", DHCP_PROP_NAME_PREFIX, interface);
if (property_get(prop_name, prop_value, NULL)) {
*lease = atol(prop_value);
}
+ return 0;
}
static const char *ipaddr_to_string(in_addr_t addr)
@@ -129,12 +129,12 @@
* configuring the interface.
*/
int dhcp_do_request(const char *interface,
- in_addr_t *ipaddr,
- in_addr_t *gateway,
- in_addr_t *mask,
- in_addr_t *dns1,
- in_addr_t *dns2,
- in_addr_t *server,
+ char *ipaddr,
+ char *gateway,
+ uint32_t *prefixLength,
+ char *dns1,
+ char *dns2,
+ char *server,
uint32_t *lease)
{
char result_prop_name[PROPERTY_KEY_MAX];
@@ -175,8 +175,13 @@
}
if (strcmp(prop_value, "ok") == 0) {
char dns_prop_name[PROPERTY_KEY_MAX];
- fill_ip_info(interface, ipaddr, gateway, mask, dns1, dns2, server, lease);
- /* copy the dhcp.XXX.dns properties to net.XXX.dns */
+ if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns1, dns2, server, lease)
+ == -1) {
+ return -1;
+ }
+
+ /* copy dns data to system properties - TODO - remove this after we have async
+ * notification of renewal's */
snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", interface);
property_set(dns_prop_name, *dns1 ? ipaddr_to_string(*dns1) : "");
snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", interface);
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
index dd2b32d..3b1f618 100644
--- a/libsysutils/Android.mk
+++ b/libsysutils/Android.mk
@@ -1,3 +1,4 @@
+ifneq ($(BUILD_TINY_ANDROID),true)
BUILD_LIBSYSUTILS := false
ifneq ($(TARGET_SIMULATOR),true)
BUILD_LIBSYSUTILS := true
@@ -33,3 +34,4 @@
include $(BUILD_SHARED_LIBRARY)
endif
+endif
diff --git a/libsysutils/src/FrameworkClient.cpp b/libsysutils/src/FrameworkClient.cpp
index 562dd67..2f37055 100644
--- a/libsysutils/src/FrameworkClient.cpp
+++ b/libsysutils/src/FrameworkClient.cpp
@@ -14,13 +14,15 @@
}
int FrameworkClient::sendMsg(const char *msg) {
+ int ret;
if (mSocket < 0) {
errno = EHOSTUNREACH;
return -1;
}
pthread_mutex_lock(&mWriteMutex);
- if (write(mSocket, msg, strlen(msg) +1) < 0) {
+ ret = TEMP_FAILURE_RETRY(write(mSocket, msg, strlen(msg) +1));
+ if (ret < 0) {
SLOGW("Unable to send msg '%s' (%s)", msg, strerror(errno));
}
pthread_mutex_unlock(&mWriteMutex);
@@ -28,13 +30,13 @@
}
int FrameworkClient::sendMsg(const char *msg, const char *data) {
- char *buffer = (char *) alloca(strlen(msg) + strlen(data) + 1);
+ size_t bufflen = strlen(msg) + strlen(data) + 1;
+ char *buffer = (char *) alloca(bufflen);
if (!buffer) {
errno = -ENOMEM;
return -1;
}
- strcpy(buffer, msg);
- strcat(buffer, data);
+ snprintf(buffer, bufflen, "%s%s", msg, data);
return sendMsg(buffer);
}
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index 4da8eb6..3416ceb 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -34,7 +34,8 @@
char buffer[255];
int len;
- if ((len = read(c->getSocket(), buffer, sizeof(buffer) -1)) < 0) {
+ len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
+ if (len < 0) {
SLOGE("read() failed (%s)", strerror(errno));
return false;
} else if (!len)
@@ -45,6 +46,7 @@
for (i = 0; i < len; i++) {
if (buffer[i] == '\0') {
+ /* IMPORTANT: dispatchCommand() expects a zero-terminated string */
dispatchCommand(c, buffer + offset);
offset = i + 1;
}
@@ -63,6 +65,7 @@
char tmp[255];
char *p = data;
char *q = tmp;
+ char *qlimit = tmp + sizeof(tmp) - 1;
bool esc = false;
bool quote = false;
int k;
@@ -72,6 +75,8 @@
while(*p) {
if (*p == '\\') {
if (esc) {
+ if (q >= qlimit)
+ goto overflow;
*q++ = '\\';
esc = false;
} else
@@ -79,11 +84,15 @@
p++;
continue;
} else if (esc) {
- if (*p == '"')
+ if (*p == '"') {
+ if (q >= qlimit)
+ goto overflow;
*q++ = '"';
- else if (*p == '\\')
+ } else if (*p == '\\') {
+ if (q >= qlimit)
+ goto overflow;
*q++ = '\\';
- else {
+ } else {
cli->sendMsg(500, "Unsupported escape sequence", false);
goto out;
}
@@ -101,9 +110,13 @@
continue;
}
+ if (q >= qlimit)
+ goto overflow;
*q = *p++;
if (!quote && *q == ' ') {
*q = '\0';
+ if (argc >= CMD_ARGS_MAX)
+ goto overflow;
argv[argc++] = strdup(tmp);
memset(tmp, 0, sizeof(tmp));
q = tmp;
@@ -112,6 +125,9 @@
q++;
}
+ *q = '\0';
+ if (argc >= CMD_ARGS_MAX)
+ goto overflow;
argv[argc++] = strdup(tmp);
#if 0
for (k = 0; k < argc; k++) {
@@ -123,7 +139,7 @@
cli->sendMsg(500, "Unclosed quotes error", false);
goto out;
}
-
+
for (i = mCommands->begin(); i != mCommands->end(); ++i) {
FrameworkCommand *c = *i;
@@ -141,4 +157,8 @@
for (j = 0; j < argc; j++)
free(argv[j]);
return;
+
+overflow:
+ cli->sendMsg(500, "Command too long", false);
+ goto out;
}
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 86c1f42..c8d3b1f 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -56,45 +56,76 @@
}
}
+/* If the string between 'str' and 'end' begins with 'prefixlen' characters
+ * from the 'prefix' array, then return 'str + prefixlen', otherwise return
+ * NULL.
+ */
+static const char*
+has_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen)
+{
+ if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen))
+ return str + prefixlen;
+ else
+ return NULL;
+}
+
+/* Same as strlen(x) for constant string literals ONLY */
+#define CONST_STRLEN(x) (sizeof(x)-1)
+
+/* Convenience macro to call has_prefix with a constant string literal */
+#define HAS_CONST_PREFIX(str,end,prefix) has_prefix((str),(end),prefix,CONST_STRLEN(prefix))
+
+
bool NetlinkEvent::decode(char *buffer, int size) {
- char *s = buffer;
- char *end;
+ const char *s = buffer;
+ const char *end;
int param_idx = 0;
int i;
int first = 1;
+ if (size == 0)
+ return false;
+
+ /* Ensure the buffer is zero-terminated, the code below depends on this */
+ buffer[size-1] = '\0';
+
end = s + size;
while (s < end) {
if (first) {
- char *p;
- for (p = s; *p != '@'; p++);
- p++;
- mPath = strdup(p);
+ const char *p;
+ /* buffer is 0-terminated, no need to check p < end */
+ for (p = s; *p != '@'; p++) {
+ if (!*p) { /* no '@', should not happen */
+ return false;
+ }
+ }
+ mPath = strdup(p+1);
first = 0;
} else {
- if (!strncmp(s, "ACTION=", strlen("ACTION="))) {
- char *a = s + strlen("ACTION=");
+ const char* a;
+ if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
if (!strcmp(a, "add"))
mAction = NlActionAdd;
else if (!strcmp(a, "remove"))
mAction = NlActionRemove;
else if (!strcmp(a, "change"))
mAction = NlActionChange;
- } else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM=")))
- mSeq = atoi(s + strlen("SEQNUM="));
- else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM=")))
- mSubsystem = strdup(s + strlen("SUBSYSTEM="));
- else
+ } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
+ mSeq = atoi(a);
+ } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
+ mSubsystem = strdup(a);
+ } else if (param_idx < NL_PARAMS_MAX) {
mParams[param_idx++] = strdup(s);
+ }
}
- s+= strlen(s) + 1;
+ s += strlen(s) + 1;
}
return true;
}
const char *NetlinkEvent::findParam(const char *paramName) {
size_t len = strlen(paramName);
- for (int i = 0; mParams[i] && i < NL_PARAMS_MAX; ++i) {
+ for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) {
const char *ptr = mParams[i] + len;
if (!strncmp(mParams[i], paramName, len) && *ptr == '=')
return ++ptr;
diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp
index e2a354e..a4f62c6 100644
--- a/libsysutils/src/NetlinkListener.cpp
+++ b/libsysutils/src/NetlinkListener.cpp
@@ -34,7 +34,8 @@
int socket = cli->getSocket();
int count;
- if ((count = recv(socket, mBuffer, sizeof(mBuffer), 0)) < 0) {
+ count = TEMP_FAILURE_RETRY(recv(socket, mBuffer, sizeof(mBuffer), 0));
+ if (count < 0) {
SLOGE("recv failed (%s)", strerror(errno));
return false;
}
diff --git a/libsysutils/src/ServiceManager.cpp b/libsysutils/src/ServiceManager.cpp
index 1ba6ef0..41ac1dd 100644
--- a/libsysutils/src/ServiceManager.cpp
+++ b/libsysutils/src/ServiceManager.cpp
@@ -10,7 +10,39 @@
ServiceManager::ServiceManager() {
}
+/* The service name should not exceed SERVICE_NAME_MAX to avoid
+ * some weird things. This is due to the fact that:
+ *
+ * - Starting a service is done by writing its name to the "ctl.start"
+ * system property. This triggers the init daemon to actually start
+ * the service for us.
+ *
+ * - Stopping the service is done by writing its name to "ctl.stop"
+ * in a similar way.
+ *
+ * - Reading the status of a service is done by reading the property
+ * named "init.svc.<name>"
+ *
+ * If strlen(<name>) > (PROPERTY_KEY_MAX-1)-9, then you can start/stop
+ * the service by writing to ctl.start/stop, but you won't be able to
+ * read its state due to the truncation of "init.svc.<name>" into a
+ * zero-terminated buffer of PROPERTY_KEY_MAX characters.
+ */
+#define SERVICE_NAME_MAX (PROPERTY_KEY_MAX-10)
+
+/* The maximum amount of time to wait for a service to start or stop,
+ * in micro-seconds (really an approximation) */
+#define SLEEP_MAX_USEC 2000000 /* 2 seconds */
+
+/* The minimal sleeping interval between checking for the service's state
+ * when looping for SLEEP_MAX_USEC */
+#define SLEEP_MIN_USEC 200000 /* 200 msec */
+
int ServiceManager::start(const char *name) {
+ if (strlen(name) > SERVICE_NAME_MAX) {
+ SLOGE("Service name '%s' is too long", name);
+ return 0;
+ }
if (isRunning(name)) {
SLOGW("Service '%s' is already running", name);
return 0;
@@ -19,13 +51,14 @@
SLOGD("Starting service '%s'", name);
property_set("ctl.start", name);
- int count = 200;
- while(count--) {
- sched_yield();
+ int count = SLEEP_MAX_USEC;
+ while(count > 0) {
+ usleep(SLEEP_MIN_USEC);
+ count -= SLEEP_MIN_USEC;
if (isRunning(name))
break;
}
- if (!count) {
+ if (count <= 0) {
SLOGW("Timed out waiting for service '%s' to start", name);
errno = ETIMEDOUT;
return -1;
@@ -35,6 +68,10 @@
}
int ServiceManager::stop(const char *name) {
+ if (strlen(name) > SERVICE_NAME_MAX) {
+ SLOGE("Service name '%s' is too long", name);
+ return 0;
+ }
if (!isRunning(name)) {
SLOGW("Service '%s' is already stopped", name);
return 0;
@@ -43,28 +80,33 @@
SLOGD("Stopping service '%s'", name);
property_set("ctl.stop", name);
- int count = 200;
- while(count--) {
- sched_yield();
+ int count = SLEEP_MAX_USEC;
+ while(count > 0) {
+ usleep(SLEEP_MIN_USEC);
+ count -= SLEEP_MIN_USEC;
if (!isRunning(name))
break;
}
- if (!count) {
+ if (count <= 0) {
SLOGW("Timed out waiting for service '%s' to stop", name);
errno = ETIMEDOUT;
return -1;
}
- SLOGD("Sucessfully stopped '%s'", name);
+ SLOGD("Successfully stopped '%s'", name);
return 0;
}
bool ServiceManager::isRunning(const char *name) {
char propVal[PROPERTY_VALUE_MAX];
- char propName[255];
+ char propName[PROPERTY_KEY_MAX];
+ int ret;
- snprintf(propName, sizeof(propVal), "init.svc.%s", name);
-
+ ret = snprintf(propName, sizeof(propName), "init.svc.%s", name);
+ if (ret > (int)sizeof(propName)-1) {
+ SLOGD("Service name '%s' is too long", name);
+ return false;
+ }
if (property_get(propName, propVal, NULL)) {
if (!strcmp(propVal, "running"))
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index c9c7417..a6aed26 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -32,14 +32,24 @@
int SocketClient::sendMsg(int code, const char *msg, bool addErrno) {
char *buf;
+ const char* arg;
+ const char* fmt;
+ char tmp[1];
+ int len;
if (addErrno) {
- buf = (char *) alloca(strlen(msg) + strlen(strerror(errno)) + 8);
- sprintf(buf, "%.3d %s (%s)", code, msg, strerror(errno));
+ fmt = "%.3d %s (%s)";
+ arg = strerror(errno);
} else {
- buf = (char *) alloca(strlen(msg) + strlen("XXX "));
- sprintf(buf, "%.3d %s", code, msg);
+ fmt = "%.3d %s";
+ arg = NULL;
}
+ /* Measure length of required buffer */
+ len = snprintf(tmp, sizeof tmp, fmt, code, msg, arg);
+ /* Allocate in the stack, then write to it */
+ buf = (char*)alloca(len+1);
+ snprintf(buf, len+1, fmt, code, msg, arg);
+ /* Send the zero-terminated message */
return sendMsg(buf);
}
@@ -68,18 +78,24 @@
pthread_mutex_lock(&mWriteMutex);
while (brtw > 0) {
- if ((rc = write(mSocket, p, brtw)) < 0) {
- SLOGW("write error (%s)", strerror(errno));
- pthread_mutex_unlock(&mWriteMutex);
- return -1;
- } else if (!rc) {
+ rc = write(mSocket, p, brtw);
+ if (rc > 0) {
+ p += rc;
+ brtw -= rc;
+ continue;
+ }
+
+ if (rc < 0 && errno == EINTR)
+ continue;
+
+ pthread_mutex_unlock(&mWriteMutex);
+ if (rc == 0) {
SLOGW("0 length write :(");
errno = EIO;
- pthread_mutex_unlock(&mWriteMutex);
- return -1;
+ } else {
+ SLOGW("write error (%s)", strerror(errno));
}
- p += rc;
- brtw -= rc;
+ return -1;
}
pthread_mutex_unlock(&mWriteMutex);
return 0;
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 1bc06db..611d5fe 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -54,7 +54,7 @@
close(mCtrlPipe[1]);
}
SocketClientCollection::iterator it;
- for (it = mClients->begin(); it != mClients->end(); ++it) {
+ for (it = mClients->begin(); it != mClients->end();) {
delete (*it);
it = mClients->erase(it);
}
@@ -96,8 +96,10 @@
int SocketListener::stopListener() {
char c = 0;
+ int rc;
- if (write(mCtrlPipe[1], &c, 1) != 1) {
+ rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1));
+ if (rc != 1) {
SLOGE("Error writing to control pipe (%s)", strerror(errno));
return -1;
}
@@ -118,7 +120,7 @@
}
SocketClientCollection::iterator it;
- for (it = mClients->begin(); it != mClients->end(); ++it) {
+ for (it = mClients->begin(); it != mClients->end();) {
delete (*it);
it = mClients->erase(it);
}
@@ -135,11 +137,13 @@
void SocketListener::runListener() {
+ SocketClientCollection *pendingList = new SocketClientCollection();
+
while(1) {
SocketClientCollection::iterator it;
fd_set read_fds;
int rc = 0;
- int max = 0;
+ int max = -1;
FD_ZERO(&read_fds);
@@ -154,13 +158,16 @@
pthread_mutex_lock(&mClientsLock);
for (it = mClients->begin(); it != mClients->end(); ++it) {
- FD_SET((*it)->getSocket(), &read_fds);
- if ((*it)->getSocket() > max)
- max = (*it)->getSocket();
+ int fd = (*it)->getSocket();
+ FD_SET(fd, &read_fds);
+ if (fd > max)
+ max = fd;
}
pthread_mutex_unlock(&mClientsLock);
if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
+ if (errno == EINTR)
+ continue;
SLOGE("select failed (%s)", strerror(errno));
sleep(1);
continue;
@@ -171,10 +178,14 @@
break;
if (mListen && FD_ISSET(mSock, &read_fds)) {
struct sockaddr addr;
- socklen_t alen = sizeof(addr);
+ socklen_t alen;
int c;
- if ((c = accept(mSock, &addr, &alen)) < 0) {
+ do {
+ alen = sizeof(addr);
+ c = accept(mSock, &addr, &alen);
+ } while (c < 0 && errno == EINTR);
+ if (c < 0) {
SLOGE("accept failed (%s)", strerror(errno));
sleep(1);
continue;
@@ -184,27 +195,42 @@
pthread_mutex_unlock(&mClientsLock);
}
- do {
- pthread_mutex_lock(&mClientsLock);
- for (it = mClients->begin(); it != mClients->end(); ++it) {
- int fd = (*it)->getSocket();
- if (FD_ISSET(fd, &read_fds)) {
- pthread_mutex_unlock(&mClientsLock);
- if (!onDataAvailable(*it)) {
- close(fd);
- pthread_mutex_lock(&mClientsLock);
- delete *it;
- it = mClients->erase(it);
- pthread_mutex_unlock(&mClientsLock);
- }
- FD_CLR(fd, &read_fds);
- pthread_mutex_lock(&mClientsLock);
- continue;
- }
+ /* Add all active clients to the pending list first */
+ pendingList->clear();
+ pthread_mutex_lock(&mClientsLock);
+ for (it = mClients->begin(); it != mClients->end(); ++it) {
+ int fd = (*it)->getSocket();
+ if (FD_ISSET(fd, &read_fds)) {
+ pendingList->push_back(*it);
}
- pthread_mutex_unlock(&mClientsLock);
- } while (0);
+ }
+ pthread_mutex_unlock(&mClientsLock);
+
+ /* Process the pending list, since it is owned by the thread,
+ * there is no need to lock it */
+ while (!pendingList->empty()) {
+ /* Pop the first item from the list */
+ it = pendingList->begin();
+ SocketClient* c = *it;
+ pendingList->erase(it);
+ /* Process it, if false is returned, remove and destroy it */
+ if (!onDataAvailable(c)) {
+ /* Remove the client from our array */
+ pthread_mutex_lock(&mClientsLock);
+ for (it = mClients->begin(); it != mClients->end(); ++it) {
+ if (*it == c) {
+ mClients->erase(it);
+ break;
+ }
+ }
+ pthread_mutex_unlock(&mClientsLock);
+ /* Destroy the client */
+ close(c->getSocket());
+ delete c;
+ }
+ }
}
+ delete pendingList;
}
void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index d6736d3..89a7f0a 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -60,7 +60,7 @@
struct usb_device {
char dev_name[64];
- unsigned char desc[256];
+ unsigned char desc[4096];
int desc_length;
int fd;
int writeable;
@@ -204,6 +204,8 @@
{
int fd, did_retry = 0, writeable = 1;
+ D("usb_device_open %s\n", dev_name);
+
retry:
fd = open(dev_name, O_RDWR);
if (fd < 0) {
@@ -240,10 +242,12 @@
struct usb_device *device = calloc(1, sizeof(struct usb_device));
int length;
+ D("usb_device_new %s fd: %d\n", dev_name, fd);
+
if (lseek(fd, 0, SEEK_SET) != 0)
goto failed;
length = read(fd, device->desc, sizeof(device->desc));
- D("usb_device_new read returned %d errno %d\n", fd, errno);
+ D("usb_device_new read returned %d errno %d\n", length, errno);
if (length < 0)
goto failed;
@@ -452,6 +456,17 @@
return ioctl(device->fd, USBDEVFS_RELEASEINTERFACE, &interface);
}
+int usb_device_connect_kernel_driver(struct usb_device *device,
+ unsigned int interface, int connect)
+{
+ struct usbdevfs_ioctl ctl;
+
+ ctl.ifno = interface;
+ ctl.ioctl_code = (connect ? USBDEVFS_CONNECT : USBDEVFS_DISCONNECT);
+ ctl.data = NULL;
+ return ioctl(device->fd, USBDEVFS_IOCTL, &ctl);
+}
+
struct usb_request *usb_request_new(struct usb_device *dev,
const struct usb_endpoint_descriptor *ep_desc)
{
diff --git a/logcat/event.logtags b/logcat/event.logtags
index eee08c6..2e814ff 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -63,47 +63,7 @@
# ZygoteInit class preloading ends:
3030 boot_progress_preload_end (time|2|3)
-# dvm_gc_info: LIST (LONG, LONG, LONG)
-#
-# First LONG:
-#
-# [63] 1
-# [62-24] ASCII process identifier
-# [23-12] GC time in ms
-# [11- 0] Bytes freed
-#
-# Second LONG (aggregated heap info):
-#
-# [63-62] 10
-# [61-60] Reserved; must be zero
-# [59-48] Objects freed
-# [47-36] Actual size (current footprint)
-# [35-24] Allowed size (current hard max)
-# [23-12] Objects allocated
-# [11- 0] Bytes allocated
-#
-# Third LONG (zygote heap info):
-#
-# [63-62] 11
-# [61-60] Reserved; must be zero
-# [59-48] Soft limit
-# [47-36] Actual size (current footprint)
-# [35-24] Allowed size (current hard max)
-# [23-12] Objects allocated
-# [11- 0] Bytes allocated
-#
-# Fourth LONG:
-#
-# [63-48] Reserved; must be zero
-# [47-36] dlmallocFootprint
-# [35-24] mallinfo: total allocated space
-# [23-12] External byte limit
-# [11- 0] External bytes allocated
-#
-# See HeapDebug.c
-#
-20001 dvm_gc_info (custom|2),(custom|2),(custom|2),(custom|2)
-20002 dvm_gc_madvise_info (total|1|2),(zygote|1|2)
+# Dalvik VM
20003 dvm_lock_sample (process|3),(main|1|5),(thread|3),(time|1|3),(file|3),(line|1|5),(ownerfile|3),(ownerline|1|5),(sample_percent|1|6)
75000 sqlite_mem_alarm_current (current|1|2)
diff --git a/rootdir/etc/init.goldfish.rc b/rootdir/etc/init.goldfish.rc
index fa70c2e..7cc028f 100644
--- a/rootdir/etc/init.goldfish.rc
+++ b/rootdir/etc/init.goldfish.rc
@@ -6,6 +6,7 @@
on boot
setprop ARGH ARGH
+ setprop net.eth0.gw 10.0.2.2
setprop net.eth0.dns1 10.0.2.3
setprop net.gprs.local-ip 10.0.2.15
setprop ro.radio.use-ppp no
@@ -27,6 +28,12 @@
start goldfish-logcat
start goldfish-setup
+ # This is a workaround for another bug in init and init.rc
+ # where the late_start class of services is never started
+ # properly when running an unencrypted /data partition.
+ #
+ start ril-daemon
+
setprop ro.setupwizard.mode EMULATOR
# enable Google-specific location features,
diff --git a/rootdir/etc/init.goldfish.sh b/rootdir/etc/init.goldfish.sh
index c18c032..1156dd7 100755
--- a/rootdir/etc/init.goldfish.sh
+++ b/rootdir/etc/init.goldfish.sh
@@ -1,8 +1,26 @@
#!/system/bin/sh
+# Setup networking when boot starts
ifconfig eth0 10.0.2.15 netmask 255.255.255.0 up
route add default gw 10.0.2.2 dev eth0
+# ro.kernel.android.qemud is normally set when we
+# want the RIL (radio interface layer) to talk to
+# the emulated modem through qemud.
+#
+# However, this will be undefined in two cases:
+#
+# - When we want the RIL to talk directly to a guest
+# serial device that is connected to a host serial
+# device by the emulator.
+#
+# - We don't want to use the RIL but the VM-based
+# modem emulation that runs inside the guest system
+# instead.
+#
+# The following detects the latter case and sets up the
+# system for it.
+#
qemud=`getprop ro.kernel.android.qemud`
case "$qemud" in
"")
@@ -18,17 +36,18 @@
;;
esac
+# Setup additionnal DNS servers if needed
num_dns=`getprop ro.kernel.ndns`
case "$num_dns" in
2) setprop net.eth0.dns2 10.0.2.4
- ;;
+ ;;
3) setprop net.eth0.dns2 10.0.2.4
- setprop net.eth0.dns3 10.0.2.5
- ;;
+ setprop net.eth0.dns3 10.0.2.5
+ ;;
4) setprop net.eth0.dns2 10.0.2.4
- setprop net.eth0.dns3 10.0.2.5
- setprop net.eth0.dns4 10.0.2.6
- ;;
+ setprop net.eth0.dns3 10.0.2.5
+ setprop net.eth0.dns4 10.0.2.6
+ ;;
esac
# disable boot animation for a faster boot sequence when needed
@@ -42,10 +61,6 @@
#
/system/bin/qemu-props
-# this line doesn't really do anything useful. however without it the
-# previous setprop doesn't seem to apply for some really odd reason
-#setprop ro.qemu.init.completed 1
-
# set up the second interface (for inter-emulator connections)
# if required
my_ip=`getprop net.shared_net_ip`
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 9a8ea0f..f6c1162 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -19,7 +19,7 @@
export ANDROID_DATA /data
export ASEC_MOUNTPOINT /mnt/asec
export LOOP_MOUNTPOINT /mnt/obb
- export BOOTCLASSPATH /system/framework/core.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/core-junit.jar
+ export BOOTCLASSPATH /system/framework/core.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/core-junit.jar
# Backward compatibility
symlink /system/etc /etc
@@ -296,6 +296,9 @@
on property:vold.decrypt=trigger_post_fs_data
trigger post-fs-data
+on property:vold.decrypt=trigger_restart_min_framework
+ class_start main
+
on property:vold.decrypt=trigger_restart_framework
class_start main
class_start late_start
@@ -357,7 +360,7 @@
class main
service ril-daemon /system/bin/rild
- class core
+ class late_start
socket rild stream 660 root radio
socket rild-debug stream 660 radio system
user root
@@ -376,11 +379,6 @@
user drm
group inet
-service drmio /system/bin/drmioserver
- class main
- user drmio
- group drmio
-
service media /system/bin/mediaserver
class main
user media
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 21a44ce..0b8f656 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -95,6 +95,12 @@
__u32 namelen;
char *name;
+ /* If non-null, this is the real name of the file in the underlying storage.
+ * This may differ from the field "name" only by case.
+ * strlen(actual_name) will always equal strlen(name), so it is safe to use
+ * namelen for both fields.
+ */
+ char *actual_name;
};
struct fuse {
@@ -109,21 +115,24 @@
char rootpath[1024];
};
-/* true if file names should be squashed to lower case */
-static int force_lower_case = 0;
static unsigned uid = -1;
static unsigned gid = -1;
#define PATH_BUFFER_SIZE 1024
+#define NO_CASE_SENSITIVE_MATCH 0
+#define CASE_SENSITIVE_MATCH 1
+
/*
* Get the real-life absolute path to a node.
* node: start at this node
* buf: storage for returned string
* name: append this string to path if set
*/
-char *node_get_path(struct node *node, char *buf, const char *name)
+char *do_node_get_path(struct node *node, char *buf, const char *name, int match_case_insensitive)
{
+ struct node *in_node = node;
+ const char *in_name = name;
char *out = buf + PATH_BUFFER_SIZE - 1;
int len;
out[0] = 0;
@@ -134,7 +143,7 @@
}
while (node) {
- name = node->name;
+ name = (node->actual_name ? node->actual_name : node->name);
len = node->namelen;
node = node->parent;
start:
@@ -142,11 +151,45 @@
return 0;
out -= len;
memcpy(out, name, len);
- out --;
- out[0] = '/';
+ /* avoid double slash at beginning of path */
+ if (out[0] != '/') {
+ out --;
+ out[0] = '/';
+ }
}
- return out;
+ /* If we are searching for a file within node (rather than computing node's path)
+ * and fail, then we need to look for a case insensitive match.
+ */
+ if (in_name && match_case_insensitive && access(out, F_OK) != 0) {
+ char *path, buffer[PATH_BUFFER_SIZE];
+ DIR* dir;
+ struct dirent* entry;
+ path = do_node_get_path(in_node, buffer, NULL, NO_CASE_SENSITIVE_MATCH);
+ dir = opendir(path);
+ if (!dir) {
+ ERROR("opendir %s failed: %s", path, strerror(errno));
+ return out;
+ }
+
+ while ((entry = readdir(dir))) {
+ if (!strcasecmp(entry->d_name, in_name)) {
+ /* we have a match - replace the name */
+ len = strlen(in_name);
+ memcpy(buf + PATH_BUFFER_SIZE - len - 1, entry->d_name, len);
+ break;
+ }
+ }
+ closedir(dir);
+ }
+
+ return out;
+}
+
+char *node_get_path(struct node *node, char *buf, const char *name)
+{
+ /* We look for case insensitive matches by default */
+ return do_node_get_path(node, buf, name, CASE_SENSITIVE_MATCH);
}
void attr_from_stat(struct fuse_attr *attr, struct stat *s)
@@ -204,6 +247,41 @@
parent->refcount++;
}
+/* Check to see if our parent directory already has a file with a name
+ * that differs only by case. If we find one, store it in the actual_name
+ * field so node_get_path will map it to this file in the underlying storage.
+ */
+static void node_find_actual_name(struct node *node)
+{
+ char *path, buffer[PATH_BUFFER_SIZE];
+ const char *node_name = node->name;
+ DIR* dir;
+ struct dirent* entry;
+
+ if (!node->parent) return;
+
+ path = node_get_path(node->parent, buffer, 0);
+ dir = opendir(path);
+ if (!dir) {
+ ERROR("opendir %s failed: %s", path, strerror(errno));
+ return;
+ }
+
+ while ((entry = readdir(dir))) {
+ const char *test_name = entry->d_name;
+ if (strcmp(test_name, node_name) && !strcasecmp(test_name, node_name)) {
+ /* we have a match - differs but only by case */
+ node->actual_name = strdup(test_name);
+ if (!node->actual_name) {
+ ERROR("strdup failed - out of memory\n");
+ exit(1);
+ }
+ break;
+ }
+ }
+ closedir(dir);
+}
+
struct node *node_create(struct node *parent, const char *name, __u64 nid, __u64 gen)
{
struct node *node;
@@ -224,7 +302,7 @@
add_node_to_parent(node, parent);
memcpy(node->name, name, namelen + 1);
node->namelen = namelen;
-
+ node_find_actual_name(node);
return node;
}
@@ -236,6 +314,7 @@
return 0;
node->name = newname;
memcpy(node->name, name, node->namelen + 1);
+ node_find_actual_name(node);
return node->name;
}
@@ -387,6 +466,7 @@
/* TODO: remove debugging - poison memory */
memset(node->name, 0xef, node->namelen);
free(node->name);
+ free(node->actual_name);
memset(node, 0xfc, sizeof(*node));
free(node);
}
@@ -448,84 +528,6 @@
fuse_reply(fuse, unique, &out, sizeof(out));
}
-static int name_needs_normalizing(const char* name) {
- char ch;
- while ((ch = *name++) != 0) {
- if (ch != tolower(ch))
- return 1;
- }
- return 0;
-}
-
-static void normalize_name(char *name)
-{
- if (force_lower_case) {
- char ch;
- while ((ch = *name) != 0)
- *name++ = tolower(ch);
- }
-}
-
-static void recursive_fix_files(const char* path) {
- DIR* dir;
- struct dirent* entry;
- char pathbuf[PATH_MAX];
- char oldpath[PATH_MAX];
- int pathLength = strlen(path);
- int pathRemaining;
- char* fileSpot;
-
- if (pathLength >= sizeof(pathbuf) - 1) {
- ERROR("path too long: %s\n", path);
- return;
- }
- strcpy(pathbuf, path);
- if (pathbuf[pathLength - 1] != '/') {
- pathbuf[pathLength++] = '/';
- }
- fileSpot = pathbuf + pathLength;
- pathRemaining = sizeof(pathbuf) - pathLength - 1;
-
- dir = opendir(path);
- if (!dir) {
- ERROR("opendir %s failed: %s", path, strerror(errno));
- return;
- }
-
- while ((entry = readdir(dir))) {
- const char* name = entry->d_name;
- int nameLength;
-
- // ignore "." and ".."
- if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
- continue;
- }
-
- nameLength = strlen(name);
- if (nameLength > pathRemaining) {
- ERROR("path %s/%s too long\n", path, name);
- continue;
- }
- strcpy(fileSpot, name);
-
- // make sure owner and group are correct
- chown(pathbuf, uid, gid);
-
- if (name_needs_normalizing(name)) {
- /* rename file to lower case file name */
- strlcpy(oldpath, pathbuf, sizeof(oldpath));
- normalize_name(pathbuf);
- rename(oldpath, pathbuf);
- }
-
- if (entry->d_type == DT_DIR) {
- /* recurse to subdirectories */
- recursive_fix_files(pathbuf);
- }
- }
- closedir(dir);
-}
-
void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *data, unsigned len)
{
struct node *node;
@@ -549,7 +551,6 @@
switch (hdr->opcode) {
case FUSE_LOOKUP: { /* bytez[] -> entry_out */
- normalize_name((char*) data);
TRACE("LOOKUP %llx %s\n", hdr->nodeid, (char*) data);
lookup_entry(fuse, node, (char*) data, hdr->unique);
return;
@@ -609,8 +610,6 @@
char *name = ((char*) data) + sizeof(*req);
int res;
- normalize_name(name);
-
TRACE("MKNOD %s @ %llx\n", name, hdr->nodeid);
path = node_get_path(node, buffer, name);
@@ -630,8 +629,6 @@
char *name = ((char*) data) + sizeof(*req);
int res;
- normalize_name(name);
-
TRACE("MKDIR %s @ %llx 0%o\n", name, hdr->nodeid, req->mode);
path = node_get_path(node, buffer, name);
@@ -647,7 +644,6 @@
case FUSE_UNLINK: { /* bytez[] -> */
char *path, buffer[PATH_BUFFER_SIZE];
int res;
- normalize_name((char*) data);
TRACE("UNLINK %s @ %llx\n", (char*) data, hdr->nodeid);
path = node_get_path(node, buffer, (char*) data);
res = unlink(path);
@@ -657,7 +653,6 @@
case FUSE_RMDIR: { /* bytez[] -> */
char *path, buffer[PATH_BUFFER_SIZE];
int res;
- normalize_name((char*) data);
TRACE("RMDIR %s @ %llx\n", (char*) data, hdr->nodeid);
path = node_get_path(node, buffer, (char*) data);
res = rmdir(path);
@@ -674,9 +669,6 @@
struct node *newparent;
int res;
- normalize_name(oldname);
- normalize_name(newname);
-
TRACE("RENAME %s->%s @ %llx\n", oldname, newname, hdr->nodeid);
target = lookup_child_by_name(node, oldname);
@@ -691,7 +683,16 @@
fuse_status(fuse, hdr->unique, -ENOENT);
return;
}
- newpath = node_get_path(newparent, newbuffer, newname);
+ if (newparent == node) {
+ /* Special case for renaming a file where destination
+ * is same path differing only by case.
+ * In this case we don't want to look for a case insensitive match.
+ * This allows commands like "mv foo FOO" to work as expected.
+ */
+ newpath = do_node_get_path(newparent, newbuffer, newname, NO_CASE_SENSITIVE_MATCH);
+ } else {
+ newpath = node_get_path(newparent, newbuffer, newname);
+ }
if (!remove_child(node, target->nid)) {
ERROR("RENAME remove_child not found");
@@ -723,7 +724,6 @@
return;
}
- normalize_name(buffer);
path = node_get_path(node, buffer, 0);
TRACE("OPEN %llx '%s' 0%o fh=%p\n", hdr->nodeid, path, req->flags, h);
h->fd = open(path, req->flags);
@@ -825,7 +825,6 @@
return;
}
- normalize_name(buffer);
path = node_get_path(node, buffer, 0);
TRACE("OPENDIR %llx '%s'\n", hdr->nodeid, path);
h->d = opendir(path);
@@ -846,13 +845,19 @@
struct dirent *de;
struct dirhandle *h = id_to_ptr(req->fh);
TRACE("READDIR %p\n", h);
+ if (req->offset == 0) {
+ /* rewinddir() might have been called above us, so rewind here too */
+ TRACE("calling rewinddir()\n");
+ rewinddir(h->d);
+ }
de = readdir(h->d);
if (!de) {
fuse_status(fuse, hdr->unique, 0);
return;
}
fde->ino = FUSE_UNKNOWN_INO;
- fde->off = 0;
+ /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
+ fde->off = req->offset + 1;
fde->type = de->d_type;
fde->namelen = strlen(de->d_name);
memcpy(fde->name, de->d_name, fde->namelen + 1);
@@ -933,30 +938,19 @@
int fd;
int res;
const char *path = NULL;
- int fix_files = 0;
int i;
for (i = 1; i < argc; i++) {
char* arg = argv[i];
- if (arg[0] == '-') {
- if (!strcmp(arg, "-l")) {
- force_lower_case = 1;
- } else if (!strcmp(arg, "-f")) {
- fix_files = 1;
- } else {
- return usage();
- }
- } else {
- if (!path)
- path = arg;
- else if (uid == -1)
- uid = strtoul(arg, 0, 10);
- else if (gid == -1)
- gid = strtoul(arg, 0, 10);
- else {
- ERROR("too many arguments\n");
- return usage();
- }
+ if (!path)
+ path = arg;
+ else if (uid == -1)
+ uid = strtoul(arg, 0, 10);
+ else if (gid == -1)
+ gid = strtoul(arg, 0, 10);
+ else {
+ ERROR("too many arguments\n");
+ return usage();
}
}
@@ -987,9 +981,6 @@
return -1;
}
- if (fix_files)
- recursive_fix_files(path);
-
if (setgid(gid) < 0) {
ERROR("cannot setgid!\n");
return -1;
diff --git a/toolbox/r.c b/toolbox/r.c
index 5a82e20..eb8ea0b 100644
--- a/toolbox/r.c
+++ b/toolbox/r.c
@@ -13,8 +13,10 @@
int r_main(int argc, char *argv[])
{
int width = 4, set = 0, fd;
- unsigned addr, value;
+ unsigned addr, value, endaddr = 0;
+ unsigned long mmap_start, mmap_size;
void *page;
+ char *end;
if(argc < 2) return usage();
@@ -31,6 +33,18 @@
if(argc < 2) return usage();
addr = strtoul(argv[1], 0, 16);
+ end = strchr(argv[1], '-');
+ if (end)
+ endaddr = strtoul(end + 1, 0, 16);
+
+ if (!endaddr)
+ endaddr = addr + width - 1;
+
+ if (endaddr <= addr) {
+ fprintf(stderr, "invalid end address\n");
+ return -1;
+ }
+
if(argc > 2) {
set = 1;
value = strtoul(argv[2], 0, 16);
@@ -42,33 +56,40 @@
return -1;
}
- page = mmap(0, 8192, PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, addr & (~4095));
+ mmap_start = addr & ~(PAGE_SIZE - 1);
+ mmap_size = endaddr - mmap_start + 1;
+ mmap_size = (mmap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+
+ page = mmap(0, mmap_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, mmap_start);
if(page == MAP_FAILED){
fprintf(stderr,"cannot mmap region\n");
return -1;
}
- switch(width){
- case 4: {
- unsigned *x = (unsigned*) (((unsigned) page) + (addr & 4095));
- if(set) *x = value;
- fprintf(stderr,"%08x: %08x\n", addr, *x);
- break;
+ while (addr <= endaddr) {
+ switch(width){
+ case 4: {
+ unsigned *x = (unsigned*) (((unsigned) page) + (addr & 4095));
+ if(set) *x = value;
+ fprintf(stderr,"%08x: %08x\n", addr, *x);
+ break;
+ }
+ case 2: {
+ unsigned short *x = (unsigned short*) (((unsigned) page) + (addr & 4095));
+ if(set) *x = value;
+ fprintf(stderr,"%08x: %04x\n", addr, *x);
+ break;
+ }
+ case 1: {
+ unsigned char *x = (unsigned char*) (((unsigned) page) + (addr & 4095));
+ if(set) *x = value;
+ fprintf(stderr,"%08x: %02x\n", addr, *x);
+ break;
+ }
+ }
+ addr += width;
}
- case 2: {
- unsigned short *x = (unsigned short*) (((unsigned) page) + (addr & 4095));
- if(set) *x = value;
- fprintf(stderr,"%08x: %04x\n", addr, *x);
- break;
- }
- case 1: {
- unsigned char *x = (unsigned char*) (((unsigned) page) + (addr & 4095));
- if(set) *x = value;
- fprintf(stderr,"%08x: %02x\n", addr, *x);
- break;
- }
- }
return 0;
}