am e382cc99: Merge "debuggerd: Reorganize to facilitate IA commit"
* commit 'e382cc999e48b3faabea7743ec8cec303b6005ba':
debuggerd: Reorganize to facilitate IA commit
diff --git a/ThirdPartyProject.prop b/ThirdPartyProject.prop
new file mode 100644
index 0000000..18b0594
--- /dev/null
+++ b/ThirdPartyProject.prop
@@ -0,0 +1,10 @@
+# Copyright 2010 Google Inc. All Rights Reserved.
+#Fri Jul 16 10:03:09 PDT 2010
+currentVersion=2.6.32
+version=2.6.32
+isNative=true
+feedurl=http\://kernel.org/pub/linux/kernel/v2.6/
+name=linux
+keywords=linux
+onDevice=true
+homepage=http\://kernel.org
diff --git a/adb/adb.c b/adb/adb.c
index ee78688..0da7218 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -893,7 +893,9 @@
struct __user_cap_header_struct header;
struct __user_cap_data_struct cap;
- prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+ if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
+ exit(1);
+ }
/* add extra groups:
** AID_ADB to access the USB driver
@@ -907,11 +909,17 @@
*/
gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_RW, AID_MOUNT };
- setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+ if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
+ exit(1);
+ }
/* then switch user and group to "shell" */
- setgid(AID_SHELL);
- setuid(AID_SHELL);
+ if (setgid(AID_SHELL) != 0) {
+ exit(1);
+ }
+ if (setuid(AID_SHELL) != 0) {
+ exit(1);
+ }
/* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */
header.version = _LINUX_CAPABILITY_VERSION;
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index efeb2a0..accca5b 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -77,6 +77,14 @@
#define VENDOR_ID_PMC 0x04DA
// Toshiba's USB Vendor ID
#define VENDOR_ID_TOSHIBA 0x0930
+// SK Telesys's USB Vendor ID
+#define VENDOR_ID_SK_TELESYS 0x1F53
+// KT Tech's USB Vendor ID
+#define VENDOR_ID_KT_TECH 0x2116
+// Asus's USB Vendor ID
+#define VENDOR_ID_ASUS 0x0b05
+// Philips's USB Vendor ID
+#define VENDOR_ID_PHILIPS 0x0471
/** built-in vendor list */
@@ -102,6 +110,10 @@
VENDOR_ID_NEC,
VENDOR_ID_PMC,
VENDOR_ID_TOSHIBA,
+ VENDOR_ID_SK_TELESYS,
+ VENDOR_ID_KT_TECH,
+ VENDOR_ID_ASUS,
+ VENDOR_ID_PHILIPS,
};
#define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c
index eda43cc..374a9a5 100644
--- a/debuggerd/debuggerd.c
+++ b/debuggerd/debuggerd.c
@@ -114,6 +114,50 @@
}
}
+const char *get_sigcode(int signo, int code)
+{
+ switch (signo) {
+ case SIGILL:
+ switch (code) {
+ case ILL_ILLOPC: return "ILL_ILLOPC";
+ case ILL_ILLOPN: return "ILL_ILLOPN";
+ case ILL_ILLADR: return "ILL_ILLADR";
+ case ILL_ILLTRP: return "ILL_ILLTRP";
+ case ILL_PRVOPC: return "ILL_PRVOPC";
+ case ILL_PRVREG: return "ILL_PRVREG";
+ case ILL_COPROC: return "ILL_COPROC";
+ case ILL_BADSTK: return "ILL_BADSTK";
+ }
+ break;
+ case SIGBUS:
+ switch (code) {
+ case BUS_ADRALN: return "BUS_ADRALN";
+ case BUS_ADRERR: return "BUS_ADRERR";
+ case BUS_OBJERR: return "BUS_OBJERR";
+ }
+ break;
+ case SIGFPE:
+ switch (code) {
+ case FPE_INTDIV: return "FPE_INTDIV";
+ case FPE_INTOVF: return "FPE_INTOVF";
+ case FPE_FLTDIV: return "FPE_FLTDIV";
+ case FPE_FLTOVF: return "FPE_FLTOVF";
+ case FPE_FLTUND: return "FPE_FLTUND";
+ case FPE_FLTRES: return "FPE_FLTRES";
+ case FPE_FLTINV: return "FPE_FLTINV";
+ case FPE_FLTSUB: return "FPE_FLTSUB";
+ }
+ break;
+ case SIGSEGV:
+ switch (code) {
+ case SEGV_MAPERR: return "SEGV_MAPERR";
+ case SEGV_ACCERR: return "SEGV_ACCERR";
+ }
+ break;
+ }
+ return "?";
+}
+
void dump_fault_addr(int tfd, int pid, int sig)
{
siginfo_t si;
@@ -122,8 +166,10 @@
if(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)){
_LOG(tfd, false, "cannot get siginfo: %s\n", strerror(errno));
} else {
- _LOG(tfd, false, "signal %d (%s), fault addr %08x\n",
- sig, get_signame(sig), si.si_addr);
+ _LOG(tfd, false, "signal %d (%s), code %d (%s), fault addr %08x\n",
+ sig, get_signame(sig),
+ si.si_code, get_sigcode(sig, si.si_code),
+ si.si_addr);
}
}
@@ -170,7 +216,7 @@
ptr = (Elf32_Phdr *) (mi->start + ehdr.e_phoff);
for (i = 0; i < ehdr.e_phnum; i++) {
/* Parse the program header */
- get_remote_struct(pid, (char *) ptr+i, &phdr,
+ get_remote_struct(pid, (char *) (ptr+i), &phdr,
sizeof(Elf32_Phdr));
#ifdef __arm__
/* Found a EXIDX segment? */
diff --git a/fastboot/engine.c b/fastboot/engine.c
index dc74417..48073ee 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.c
@@ -291,7 +291,8 @@
a->start = now();
if (start < 0) start = a->start;
if (a->msg) {
- fprintf(stderr,"%30s... ",a->msg);
+ // fprintf(stderr,"%30s... ",a->msg);
+ fprintf(stderr,"%s...\n",a->msg);
}
if (a->op == OP_DOWNLOAD) {
status = fb_download_data(usb, a->data, a->size);
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index bed30b2..f3bfbeba 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -150,6 +150,8 @@
(info->dev_vendor != 0x18d1) && // Google
(info->dev_vendor != 0x0451) &&
(info->dev_vendor != 0x0502) &&
+ (info->dev_vendor != 0x0fce) && // Sony Ericsson
+ (info->dev_vendor != 0x05c6) && // Qualcomm
(info->dev_vendor != 0x22b8) && // Motorola
(info->dev_vendor != 0x0955) && // Nvidia
(info->dev_vendor != 0x413c) && // DELL
diff --git a/fastboot/protocol.c b/fastboot/protocol.c
index c788a12..3948363 100644
--- a/fastboot/protocol.c
+++ b/fastboot/protocol.c
@@ -62,7 +62,7 @@
}
if(!memcmp(status, "INFO", 4)) {
- fprintf(stderr,"%s\n", status);
+ fprintf(stderr,"(bootloader) %s\n", status + 4);
continue;
}
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c
index 2ce53eb..78b7b98 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.c
@@ -137,6 +137,7 @@
ctrl.wIndex = 0;
ctrl.wLength = sizeof(buffer);
ctrl.data = buffer;
+ ctrl.timeout = 50;
result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
if (result > 0) {
diff --git a/fastboot/usb_osx.c b/fastboot/usb_osx.c
index 0b0512d..9488687 100644
--- a/fastboot/usb_osx.c
+++ b/fastboot/usb_osx.c
@@ -64,7 +64,7 @@
/** Try out all the interfaces and see if there's a match. Returns 0 on
* success, -1 on failure. */
-static int try_interfaces(IOUSBDeviceInterface **dev, usb_handle *handle) {
+static int try_interfaces(IOUSBDeviceInterface182 **dev, usb_handle *handle) {
IOReturn kr;
IOUSBFindInterfaceRequest request;
io_iterator_t iterator;
@@ -515,8 +515,29 @@
return -1;
}
+#if 0
result = (*h->interface)->WritePipe(
h->interface, h->bulkOut, (void *)data, len);
+#else
+ /* Attempt to work around crashes in the USB driver that may be caused
+ * by trying to write too much data at once. The kernel IOCopyMapper
+ * panics if a single iovmAlloc needs more than half of its mapper pages.
+ */
+ const int maxLenToSend = 1048576; // 1 MiB
+ int lenRemaining = len;
+ result = 0;
+ while (lenRemaining > 0) {
+ int lenToSend = lenRemaining > maxLenToSend
+ ? maxLenToSend : lenRemaining;
+
+ result = (*h->interface)->WritePipe(
+ h->interface, h->bulkOut, (void *)data, lenToSend);
+ if (result != 0) break;
+
+ lenRemaining -= lenToSend;
+ data = (const char*)data + lenToSend;
+ }
+#endif
#if 0
if ((result == 0) && (h->zero_mask)) {
diff --git a/include/arch/darwin-x86/AndroidConfig.h b/include/arch/darwin-x86/AndroidConfig.h
index 3aa0cd1..2bb44c6 100644
--- a/include/arch/darwin-x86/AndroidConfig.h
+++ b/include/arch/darwin-x86/AndroidConfig.h
@@ -285,4 +285,19 @@
*/
#define HAVE_SCHED_H 1
+/*
+ * Define if pread() exists
+ */
+#define HAVE_PREAD 1
+
+/*
+ * Define if we have st_mtim in struct stat
+ */
+#define HAVE_STAT_ST_MTIM 1
+
+/*
+ * Define if printf() supports %zd for size_t arguments
+ */
+#define HAVE_PRINTF_ZD 1
+
#endif /*_ANDROID_CONFIG_H*/
diff --git a/include/arch/freebsd-x86/AndroidConfig.h b/include/arch/freebsd-x86/AndroidConfig.h
index 57d5024..992b689 100644
--- a/include/arch/freebsd-x86/AndroidConfig.h
+++ b/include/arch/freebsd-x86/AndroidConfig.h
@@ -344,4 +344,18 @@
*/
#define HAVE_SCHED_H 1
+/*
+ * Define if pread() exists
+ */
+#define HAVE_PREAD 1
+/*
+ * Define if we have st_mtim in struct stat
+ */
+#define HAVE_STAT_ST_MTIM 1
+
+/*
+ * Define if printf() supports %zd for size_t arguments
+ */
+#define HAVE_PRINTF_ZD 1
+
#endif /*_ANDROID_CONFIG_H*/
diff --git a/include/arch/linux-arm/AndroidConfig.h b/include/arch/linux-arm/AndroidConfig.h
index f51ddb1..5b7ccee 100644
--- a/include/arch/linux-arm/AndroidConfig.h
+++ b/include/arch/linux-arm/AndroidConfig.h
@@ -42,9 +42,16 @@
#define HAVE_PTHREADS
/*
+ * Do we have pthread_setname_np()?
+ *
+ * (HAVE_PTHREAD_SETNAME_NP is used by WebKit to enable a function with
+ * the same name but different parameters, so we can't use that here.)
+ */
+#define HAVE_ANDROID_PTHREAD_SETNAME_NP
+
+/*
* Do we have the futex syscall?
*/
-
#define HAVE_FUTEX
/*
@@ -332,4 +339,19 @@
*/
#define HAVE_SCHED_H 1
+/*
+ * Define if pread() exists
+ */
+#define HAVE_PREAD 1
+
+/*
+ * Define if we have st_mtim in struct stat
+ */
+#define HAVE_STAT_ST_MTIM 1
+
+/*
+ * Define if printf() supports %zd for size_t arguments
+ */
+#define HAVE_PRINTF_ZD 1
+
#endif /* _ANDROID_CONFIG_H */
diff --git a/include/arch/linux-sh/AndroidConfig.h b/include/arch/linux-sh/AndroidConfig.h
index 5e93990..0dd7b3b 100644
--- a/include/arch/linux-sh/AndroidConfig.h
+++ b/include/arch/linux-sh/AndroidConfig.h
@@ -42,9 +42,16 @@
#define HAVE_PTHREADS
/*
+ * Do we have pthread_setname_np()?
+ *
+ * (HAVE_PTHREAD_SETNAME_NP is used by WebKit to enable a function with
+ * the same name but different parameters, so we can't use that here.)
+ */
+#define HAVE_ANDROID_PTHREAD_SETNAME_NP
+
+/*
* Do we have the futex syscall?
*/
-
#define HAVE_FUTEX
/*
@@ -339,4 +346,19 @@
*/
#define HAVE_UNWIND_CONTEXT_STRUCT
+/*
+ * Define if pread() exists
+ */
+#define HAVE_PREAD 1
+
+/*
+ * Define if we have st_mtim in struct stat
+ */
+#define HAVE_STAT_ST_MTIM 1
+
+/*
+ * Define if printf() supports %zd for size_t arguments
+ */
+#define HAVE_PRINTF_ZD 1
+
#endif /* _ANDROID_CONFIG_H */
diff --git a/include/arch/linux-x86/AndroidConfig.h b/include/arch/linux-x86/AndroidConfig.h
index b0fe90a..24f6ccc 100644
--- a/include/arch/linux-x86/AndroidConfig.h
+++ b/include/arch/linux-x86/AndroidConfig.h
@@ -313,4 +313,19 @@
*/
#define HAVE_SCHED_H 1
+/*
+ * Define if pread() exists
+ */
+#define HAVE_PREAD 1
+
+/*
+ * Define if we have st_mtim in struct stat
+ */
+#define HAVE_STAT_ST_MTIM 1
+
+/*
+ * Define if printf() supports %zd for size_t arguments
+ */
+#define HAVE_PRINTF_ZD 1
+
#endif /*_ANDROID_CONFIG_H*/
diff --git a/include/arch/target_linux-x86/AndroidConfig.h b/include/arch/target_linux-x86/AndroidConfig.h
index c7434ca..d6ce3f2 100644
--- a/include/arch/target_linux-x86/AndroidConfig.h
+++ b/include/arch/target_linux-x86/AndroidConfig.h
@@ -28,9 +28,16 @@
#define HAVE_PTHREADS
/*
+ * Do we have pthread_setname_np()?
+ *
+ * (HAVE_PTHREAD_SETNAME_NP is used by WebKit to enable a function with
+ * the same name but different parameters, so we can't use that here.)
+ */
+#define HAVE_ANDROID_PTHREAD_SETNAME_NP
+
+/*
* Do we have the futex syscall?
*/
-
#define HAVE_FUTEX
/*
@@ -323,4 +330,19 @@
*/
#define HAVE_SCHED_H 1
+/*
+ * Define if pread() exists
+ */
+#define HAVE_PREAD 1
+
+/*
+ * Define if we have st_mtim in struct stat
+ */
+#define HAVE_STAT_ST_MTIM 1
+
+/*
+ * Define if printf() supports %zd for size_t arguments
+ */
+#define HAVE_PRINTF_ZD 1
+
#endif /* _ANDROID_CONFIG_H */
diff --git a/include/arch/windows/AndroidConfig.h b/include/arch/windows/AndroidConfig.h
index bb8e5ef..f0bf56f 100644
--- a/include/arch/windows/AndroidConfig.h
+++ b/include/arch/windows/AndroidConfig.h
@@ -318,4 +318,19 @@
*/
/* #define HAVE_SCHED_H */
+/*
+ * Define if pread() exists
+ */
+/* #define HAVE_PREAD 1 */
+
+/*
+ * Define if we have st_mtim in struct stat
+ */
+/* #define HAVE_STAT_ST_MTIM 1 */
+
+/*
+ * Define if printf() supports %zd for size_t arguments
+ */
+/* #define HAVE_PRINTF_ZD 1 */
+
#endif /*_ANDROID_CONFIG_H*/
diff --git a/include/cutils/ashmem.h b/include/cutils/ashmem.h
index fd56dbe..25b233e 100644
--- a/include/cutils/ashmem.h
+++ b/include/cutils/ashmem.h
@@ -10,7 +10,7 @@
#ifndef _CUTILS_ASHMEM_H
#define _CUTILS_ASHMEM_H
-#include <stdint.h>
+#include <stddef.h>
#ifdef __cplusplus
extern "C" {
diff --git a/include/cutils/atomic-arm.h b/include/cutils/atomic-arm.h
new file mode 100644
index 0000000..93633c4
--- /dev/null
+++ b/include/cutils/atomic-arm.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_CUTILS_ATOMIC_ARM_H
+#define ANDROID_CUTILS_ATOMIC_ARM_H
+
+#include <stdint.h>
+#include <machine/cpu-features.h>
+
+extern inline void android_compiler_barrier(void)
+{
+ __asm__ __volatile__ ("" : : : "memory");
+}
+
+#if ANDROID_SMP == 0
+extern inline void android_memory_barrier(void)
+{
+ android_compiler_barrier();
+}
+#elif defined(__ARM_HAVE_DMB)
+extern inline void android_memory_barrier(void)
+{
+ __asm__ __volatile__ ("dmb" : : : "memory");
+}
+#elif defined(__ARM_HAVE_LDREX_STREX)
+extern inline void android_memory_barrier(void)
+{
+ __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5"
+ : : "r" (0) : "memory");
+}
+#else
+extern inline void android_memory_barrier(void)
+{
+ typedef void (kuser_memory_barrier)(void);
+ (*(kuser_memory_barrier *)0xffff0fa0)();
+}
+#endif
+
+extern inline int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
+{
+ int32_t value = *ptr;
+ android_memory_barrier();
+ return value;
+}
+
+extern inline int32_t android_atomic_release_load(volatile const int32_t *ptr)
+{
+ android_memory_barrier();
+ return *ptr;
+}
+
+extern inline void android_atomic_acquire_store(int32_t value,
+ volatile int32_t *ptr)
+{
+ *ptr = value;
+ android_memory_barrier();
+}
+
+extern inline void android_atomic_release_store(int32_t value,
+ volatile int32_t *ptr)
+{
+ android_memory_barrier();
+ *ptr = value;
+}
+
+#if defined(__thumb__)
+extern int android_atomic_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr);
+#elif defined(__ARM_HAVE_LDREX_STREX)
+extern inline int android_atomic_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ do {
+ __asm__ __volatile__ ("ldrex %0, [%3]\n"
+ "mov %1, #0\n"
+ "teq %0, %4\n"
+ "strexeq %1, %5, [%3]"
+ : "=&r" (prev), "=&r" (status), "+m"(*ptr)
+ : "r" (ptr), "Ir" (old_value), "r" (new_value)
+ : "cc");
+ } while (__builtin_expect(status != 0, 0));
+ return prev != old_value;
+}
+#else
+extern inline int android_atomic_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ typedef int (kuser_cmpxchg)(int32_t, int32_t, volatile int32_t *);
+ int32_t prev, status;
+ prev = *ptr;
+ do {
+ status = (*(kuser_cmpxchg *)0xffff0fc0)(old_value, new_value, ptr);
+ if (__builtin_expect(status == 0, 1))
+ return 0;
+ prev = *ptr;
+ } while (prev == old_value);
+ return 1;
+}
+#endif
+
+extern inline int android_atomic_acquire_cas(int32_t old_value,
+ int32_t new_value,
+ volatile int32_t *ptr)
+{
+ int status = android_atomic_cas(old_value, new_value, ptr);
+ android_memory_barrier();
+ return status;
+}
+
+extern inline int android_atomic_release_cas(int32_t old_value,
+ int32_t new_value,
+ volatile int32_t *ptr)
+{
+ android_memory_barrier();
+ return android_atomic_cas(old_value, new_value, ptr);
+}
+
+
+#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)
+extern inline int32_t android_atomic_add(int32_t increment,
+ volatile int32_t *ptr)
+{
+ int32_t prev, tmp, status;
+ android_memory_barrier();
+ do {
+ __asm__ __volatile__ ("ldrex %0, [%4]\n"
+ "add %1, %0, %5\n"
+ "strex %2, %1, [%4]"
+ : "=&r" (prev), "=&r" (tmp),
+ "=&r" (status), "+m" (*ptr)
+ : "r" (ptr), "Ir" (increment)
+ : "cc");
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+#else
+extern inline int32_t android_atomic_add(int32_t increment,
+ volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ android_memory_barrier();
+ do {
+ prev = *ptr;
+ status = android_atomic_cas(prev, prev + increment, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+#endif
+
+extern inline int32_t android_atomic_inc(volatile int32_t *addr)
+{
+ return android_atomic_add(1, addr);
+}
+
+extern inline int32_t android_atomic_dec(volatile int32_t *addr)
+{
+ return android_atomic_add(-1, addr);
+}
+
+#if defined(__thumb__)
+extern int32_t android_atomic_and(int32_t value, volatile int32_t *ptr);
+#elif defined(__ARM_HAVE_LDREX_STREX)
+extern inline int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, tmp, status;
+ android_memory_barrier();
+ do {
+ __asm__ __volatile__ ("ldrex %0, [%4]\n"
+ "and %1, %0, %5\n"
+ "strex %2, %1, [%4]"
+ : "=&r" (prev), "=&r" (tmp),
+ "=&r" (status), "+m" (*ptr)
+ : "r" (ptr), "Ir" (value)
+ : "cc");
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+#else
+extern inline int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ android_memory_barrier();
+ do {
+ prev = *ptr;
+ status = android_atomic_cas(prev, prev & value, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+#endif
+
+#if defined(__thumb__)
+extern int32_t android_atomic_or(int32_t value, volatile int32_t *ptr);
+#elif defined(__ARM_HAVE_LDREX_STREX)
+extern inline int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, tmp, status;
+ android_memory_barrier();
+ do {
+ __asm__ __volatile__ ("ldrex %0, [%4]\n"
+ "orr %1, %0, %5\n"
+ "strex %2, %1, [%4]"
+ : "=&r" (prev), "=&r" (tmp),
+ "=&r" (status), "+m" (*ptr)
+ : "r" (ptr), "Ir" (value)
+ : "cc");
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+#else
+extern inline int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ android_memory_barrier();
+ do {
+ prev = *ptr;
+ status = android_atomic_cas(prev, prev | value, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+#endif
+
+#endif /* ANDROID_CUTILS_ATOMIC_ARM_H */
diff --git a/include/cutils/atomic-inline.h b/include/cutils/atomic-inline.h
new file mode 100644
index 0000000..715e0aa
--- /dev/null
+++ b/include/cutils/atomic-inline.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_CUTILS_ATOMIC_INLINE_H
+#define ANDROID_CUTILS_ATOMIC_INLINE_H
+
+/*
+ * Inline declarations and macros for some special-purpose atomic
+ * operations. These are intended for rare circumstances where a
+ * memory barrier needs to be issued inline rather than as a function
+ * call.
+ *
+ * Most code should not use these.
+ *
+ * Anything that does include this file must set ANDROID_SMP to either
+ * 0 or 1, indicating compilation for UP or SMP, respectively.
+ *
+ * Macros defined in this header:
+ *
+ * void ANDROID_MEMBAR_FULL(void)
+ * Full memory barrier. Provides a compiler reordering barrier, and
+ * on SMP systems emits an appropriate instruction.
+ */
+
+#if !defined(ANDROID_SMP)
+# error "Must define ANDROID_SMP before including atomic-inline.h"
+#endif
+
+#if defined(__arm__)
+#include <cutils/atomic-arm.h>
+#elif defined(__i386__) || defined(__x86_64__)
+#include <cutils/atomic-x86.h>
+#elif defined(__sh__)
+/* implementation is in atomic-android-sh.c */
+#else
+#error atomic operations are unsupported
+#endif
+
+#if ANDROID_SMP == 0
+#define ANDROID_MEMBAR_FULL android_compiler_barrier
+#else
+#define ANDROID_MEMBAR_FULL android_memory_barrier
+#endif
+
+#endif /* ANDROID_CUTILS_ATOMIC_INLINE_H */
diff --git a/include/cutils/atomic-x86.h b/include/cutils/atomic-x86.h
new file mode 100644
index 0000000..12a1985
--- /dev/null
+++ b/include/cutils/atomic-x86.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_CUTILS_ATOMIC_X86_H
+#define ANDROID_CUTILS_ATOMIC_X86_H
+
+#include <stdint.h>
+
+extern inline void android_compiler_barrier(void)
+{
+ __asm__ __volatile__ ("" : : : "memory");
+}
+
+#if ANDROID_SMP == 0
+extern inline void android_memory_barrier(void)
+{
+ android_compiler_barrier();
+}
+#else
+extern inline void android_memory_barrier(void)
+{
+ __asm__ __volatile__ ("mfence" : : : "memory");
+}
+#endif
+
+extern inline int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
+{
+ int32_t value = *ptr;
+ android_compiler_barrier();
+ return value;
+}
+
+extern inline int32_t android_atomic_release_load(volatile const int32_t *ptr)
+{
+ android_memory_barrier();
+ return *ptr;
+}
+
+extern inline void android_atomic_acquire_store(int32_t value,
+ volatile int32_t *ptr)
+{
+ *ptr = value;
+ android_memory_barrier();
+}
+
+extern inline void android_atomic_release_store(int32_t value,
+ volatile int32_t *ptr)
+{
+ android_compiler_barrier();
+ *ptr = value;
+}
+
+extern inline int android_atomic_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ int32_t prev;
+ __asm__ __volatile__ ("lock; cmpxchgl %1, %2"
+ : "=a" (prev)
+ : "q" (new_value), "m" (*ptr), "0" (old_value)
+ : "memory");
+ return prev != old_value;
+}
+
+extern inline int android_atomic_acquire_cas(int32_t old_value,
+ int32_t new_value,
+ volatile int32_t *ptr)
+{
+ /* Loads are not reordered with other loads. */
+ return android_atomic_cas(old_value, new_value, ptr);
+}
+
+extern inline int android_atomic_release_cas(int32_t old_value,
+ int32_t new_value,
+ volatile int32_t *ptr)
+{
+ /* Stores are not reordered with other stores. */
+ return android_atomic_cas(old_value, new_value, ptr);
+}
+
+extern 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)
+{
+ __asm__ __volatile__ ("lock; xaddl %0, %1"
+ : "+r" (increment), "+m" (*ptr)
+ : : "memory");
+ /* increment now holds the old value of *ptr */
+ return increment;
+}
+
+extern inline int32_t android_atomic_inc(volatile int32_t *addr)
+{
+ return android_atomic_add(1, addr);
+}
+
+extern inline int32_t android_atomic_dec(volatile int32_t *addr)
+{
+ return android_atomic_add(-1, addr);
+}
+
+extern inline int32_t android_atomic_and(int32_t value,
+ volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ do {
+ prev = *ptr;
+ status = android_atomic_cas(prev, prev & value, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+extern inline int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ do {
+ prev = *ptr;
+ status = android_atomic_cas(prev, prev | value, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+#endif /* ANDROID_CUTILS_ATOMIC_X86_H */
diff --git a/include/cutils/atomic.h b/include/cutils/atomic.h
index 5694d66..a50bf0f 100644
--- a/include/cutils/atomic.h
+++ b/include/cutils/atomic.h
@@ -25,53 +25,102 @@
#endif
/*
- * NOTE: memory shared between threads is synchronized by all atomic operations
- * below, this means that no explicit memory barrier is required: all reads or
- * writes issued before android_atomic_* operations are guaranteed to complete
- * before the atomic operation takes place.
+ * A handful of basic atomic operations. The appropriate pthread
+ * functions should be used instead of these whenever possible.
+ *
+ * The "acquire" and "release" terms can be defined intuitively in terms
+ * of the placement of memory barriers in a simple lock implementation:
+ * - wait until compare-and-swap(lock-is-free --> lock-is-held) succeeds
+ * - barrier
+ * - [do work]
+ * - barrier
+ * - store(lock-is-free)
+ * In very crude terms, the initial (acquire) barrier prevents any of the
+ * "work" from happening before the lock is held, and the later (release)
+ * barrier ensures that all of the work happens before the lock is released.
+ * (Think of cached writes, cache read-ahead, and instruction reordering
+ * around the CAS and store instructions.)
+ *
+ * The barriers must apply to both the compiler and the CPU. Note it is
+ * legal for instructions that occur before an "acquire" barrier to be
+ * moved down below it, and for instructions that occur after a "release"
+ * barrier to be moved up above it.
+ *
+ * The ARM-driven implementation we use here is short on subtlety,
+ * and actually requests a full barrier from the compiler and the CPU.
+ * The only difference between acquire and release is in whether they
+ * are issued before or after the atomic operation with which they
+ * are associated. To ease the transition to C/C++ atomic intrinsics,
+ * you should not rely on this, and instead assume that only the minimal
+ * acquire/release protection is provided.
+ *
+ * NOTE: all int32_t* values are expected to be aligned on 32-bit boundaries.
+ * If they are not, atomicity is not guaranteed.
*/
-void android_atomic_write(int32_t value, volatile int32_t* addr);
-
/*
- * all these atomic operations return the previous value
+ * Basic arithmetic and bitwise operations. These all provide a
+ * barrier with "release" ordering, and return the previous value.
+ *
+ * These have the same characteristics (e.g. what happens on overflow)
+ * as the equivalent non-atomic C operations.
*/
-
-
int32_t android_atomic_inc(volatile int32_t* addr);
int32_t android_atomic_dec(volatile int32_t* addr);
-
int32_t android_atomic_add(int32_t value, volatile int32_t* addr);
int32_t android_atomic_and(int32_t value, volatile int32_t* addr);
int32_t android_atomic_or(int32_t value, volatile int32_t* addr);
+/*
+ * Perform an atomic load with "acquire" or "release" ordering.
+ *
+ * This is only necessary if you need the memory barrier. A 32-bit read
+ * from a 32-bit aligned address is atomic on all supported platforms.
+ */
+int32_t android_atomic_acquire_load(volatile const int32_t* addr);
+int32_t android_atomic_release_load(volatile const int32_t* addr);
+
+/*
+ * Perform an atomic store with "acquire" or "release" ordering.
+ *
+ * This is only necessary if you need the memory barrier. A 32-bit write
+ * to a 32-bit aligned address is atomic on all supported platforms.
+ */
+void android_atomic_acquire_store(int32_t value, volatile int32_t* addr);
+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);
/*
- * NOTE: Two "quasiatomic" operations on the exact same memory address
- * are guaranteed to operate atomically with respect to each other,
- * but no guarantees are made about quasiatomic operations mixed with
- * non-quasiatomic operations on the same address, nor about
- * quasiatomic operations that are performed on partially-overlapping
- * memory.
+ * Compare-and-set operation with "acquire" or "release" ordering.
+ *
+ * This returns zero if the new value was successfully stored, which will
+ * only happen when *addr == oldvalue.
+ *
+ * (The return value is inverted from implementations on other platforms,
+ * but matches the ARM ldrex/strex result.)
+ *
+ * Implementations that use the release CAS in a loop may be less efficient
+ * than possible, because we re-issue the memory barrier on each iteration.
*/
-
-int64_t android_quasiatomic_swap_64(int64_t value, volatile int64_t* addr);
-int64_t android_quasiatomic_read_64(volatile int64_t* addr);
-
-/*
- * cmpxchg return a non zero value if the exchange was NOT performed,
- * in other words if oldvalue != *addr
- */
-
-int android_atomic_cmpxchg(int32_t oldvalue, int32_t newvalue,
+int android_atomic_acquire_cas(int32_t oldvalue, int32_t newvalue,
+ volatile int32_t* addr);
+int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue,
volatile int32_t* addr);
-int android_quasiatomic_cmpxchg_64(int64_t oldvalue, int64_t newvalue,
- volatile int64_t* addr);
+/*
+ * Aliases for code using an older version of this header. These are now
+ * deprecated and should not be used. The definitions will be removed
+ * in a future release.
+ */
+#define android_atomic_write android_atomic_release_store
+#define android_atomic_cmpxchg android_atomic_release_cas
-
-
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/include/cutils/mspace.h b/include/cutils/mspace.h
index e6e4047..93fe48e 100644
--- a/include/cutils/mspace.h
+++ b/include/cutils/mspace.h
@@ -87,6 +87,11 @@
size_t max_capacity, int locked, void *base);
size_t destroy_contiguous_mspace(mspace msp);
+
+/*
+ Returns the position of the "break" within the given mspace.
+*/
+void *contiguous_mspace_sbrk0(mspace msp);
#endif
/*
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index b6fea03..9c35aa4 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -54,6 +54,8 @@
#define AID_USB 1018 /* USB devices */
#define AID_DRM 1019 /* DRM server */
#define AID_DRMIO 1020 /* DRM IO server */
+#define AID_GPS 1021 /* GPS daemon */
+#define AID_NFC 1022 /* nfc subsystem */
#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
@@ -78,7 +80,7 @@
unsigned aid;
};
-static struct android_id_info android_ids[] = {
+static const struct android_id_info android_ids[] = {
{ "root", AID_ROOT, },
{ "system", AID_SYSTEM, },
{ "radio", AID_RADIO, },
@@ -97,6 +99,7 @@
{ "media", AID_MEDIA, },
{ "drm", AID_DRM, },
{ "drmio", AID_DRMIO, },
+ { "nfc", AID_NFC, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
{ "diag", AID_DIAG, },
@@ -106,6 +109,7 @@
{ "vpn", AID_VPN, },
{ "keystore", AID_KEYSTORE, },
{ "usb", AID_USB, },
+ { "gps", AID_GPS, },
{ "inet", AID_INET, },
{ "net_raw", AID_NET_RAW, },
{ "net_admin", AID_NET_ADMIN, },
@@ -142,6 +146,7 @@
{ 00771, AID_SYSTEM, AID_SYSTEM, "data" },
{ 00750, AID_ROOT, AID_SHELL, "sbin" },
{ 00755, AID_ROOT, AID_SHELL, "system/bin" },
+ { 00755, AID_ROOT, AID_SHELL, "system/vendor" },
{ 00755, AID_ROOT, AID_SHELL, "system/xbin" },
{ 00755, AID_ROOT, AID_ROOT, "system/etc/ppp" },
{ 00777, AID_ROOT, AID_ROOT, "sdcard" },
@@ -190,6 +195,7 @@
{ 06750, AID_ROOT, AID_SHELL, "system/bin/run-as" },
{ 00755, AID_ROOT, AID_SHELL, "system/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, "system/xbin/*" },
+ { 00755, AID_ROOT, AID_SHELL, "system/vendor/bin/*" },
{ 00750, AID_ROOT, AID_SHELL, "sbin/*" },
{ 00755, AID_ROOT, AID_ROOT, "bin/*" },
{ 00750, AID_ROOT, AID_SHELL, "init*" },
diff --git a/include/sysutils/SocketClient.h b/include/sysutils/SocketClient.h
index 469dd9d..e7fb177 100644
--- a/include/sysutils/SocketClient.h
+++ b/include/sysutils/SocketClient.h
@@ -4,16 +4,29 @@
#include "../../../frameworks/base/include/utils/List.h"
#include <pthread.h>
+#include <sys/types.h>
class SocketClient {
int mSocket;
pthread_mutex_t mWriteMutex;
+ /* Peer process ID */
+ pid_t mPid;
+
+ /* Peer user ID */
+ uid_t mUid;
+
+ /* Peer group ID */
+ gid_t mGid;
+
public:
SocketClient(int sock);
virtual ~SocketClient() {}
int getSocket() { return mSocket; }
+ pid_t getPid() const { return mPid; }
+ uid_t getUid() const { return mUid; }
+ gid_t getGid() const { return mGid; }
int sendMsg(int code, const char *msg, bool addErrno);
int sendMsg(const char *msg);
diff --git a/init/Android.mk b/init/Android.mk
index d3766d4..162c226 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -10,7 +10,12 @@
property_service.c \
util.c \
parser.c \
- logo.c
+ logo.c \
+ keychords.c \
+ signal_handler.c \
+ init_parser.c \
+ ueventd.c \
+ ueventd_parser.c
ifeq ($(strip $(INIT_BOOTCHART)),true)
LOCAL_SRC_FILES += bootchart.c
@@ -25,9 +30,20 @@
LOCAL_STATIC_LIBRARIES := libcutils libc
-#LOCAL_STATIC_LIBRARIES := libcutils libc libminui libpixelflinger_static
-#LOCAL_STATIC_LIBRARIES += libminzip libunz libamend libmtdutils libmincrypt
-#LOCAL_STATIC_LIBRARIES += libstdc++_static
-
include $(BUILD_EXECUTABLE)
+# Make a symlink from /sbin/ueventd to /init
+SYMLINKS := $(TARGET_ROOT_OUT)/sbin/ueventd
+$(SYMLINKS): INIT_BINARY := $(LOCAL_MODULE)
+$(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk
+ @echo "Symlink: $@ -> ../$(INIT_BINARY)"
+ @mkdir -p $(dir $@)
+ @rm -rf $@
+ $(hide) ln -sf ../$(INIT_BINARY) $@
+
+ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS)
+
+# We need this so that the installed files could be picked up based on the
+# local module name
+ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \
+ $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(SYMLINKS)
diff --git a/init/builtins.c b/init/builtins.c
index 44faf17..e0ccf9f 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -35,6 +35,9 @@
#include "keywords.h"
#include "property_service.h"
#include "devices.h"
+#include "init_parser.h"
+#include "util.h"
+#include "log.h"
#include <private/android_filesystem_config.h>
@@ -218,7 +221,7 @@
int do_import(int nargs, char **args)
{
- return parse_config_file(args[1]);
+ return init_parse_config_file(args[1]);
}
int do_mkdir(int nargs, char **args)
@@ -275,6 +278,7 @@
char *options = NULL;
unsigned flags = 0;
int n, i;
+ int wait = 0;
for (n = 4; n < nargs; n++) {
for (i = 0; mount_flags[i].name; i++) {
@@ -284,9 +288,13 @@
}
}
- /* if our last argument isn't a flag, wolf it up as an option string */
- if (n + 1 == nargs && !mount_flags[i].name)
- options = args[n];
+ if (!mount_flags[i].name) {
+ if (!strcmp(args[n], "wait"))
+ wait = 1;
+ /* if our last argument isn't a flag, wolf it up as an option string */
+ else if (n + 1 == nargs)
+ options = args[n];
+ }
}
system = args[1];
@@ -301,6 +309,8 @@
sprintf(tmp, "/dev/block/mtdblock%d", n);
+ if (wait)
+ wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);
if (mount(tmp, target, system, flags, options) < 0) {
return -1;
}
@@ -347,6 +357,8 @@
ERROR("out of loopback devices");
return -1;
} else {
+ if (wait)
+ wait_for_file(source, COMMAND_RETRY_TIMEOUT);
if (mount(source, target, system, flags, options) < 0) {
return -1;
}
@@ -414,7 +426,6 @@
int do_trigger(int nargs, char **args)
{
action_for_each_trigger(args[1], action_add_queue_tail);
- drain_action_queue();
return 0;
}
@@ -547,29 +558,10 @@
return -1;
}
-int do_device(int nargs, char **args) {
- int len;
- char tmp[64];
- char *source = args[1];
- int prefix = 0;
-
- if (nargs != 5)
- return -1;
- /* Check for wildcard '*' at the end which indicates a prefix. */
- len = strlen(args[1]) - 1;
- if (args[1][len] == '*') {
- args[1][len] = '\0';
- prefix = 1;
+int do_wait(int nargs, char **args)
+{
+ if (nargs == 2) {
+ return wait_for_file(args[1], COMMAND_RETRY_TIMEOUT);
}
- /* If path starts with mtd@ lookup the mount number. */
- if (!strncmp(source, "mtd@", 4)) {
- int n = mtd_name_to_number(source + 4);
- if (n >= 0) {
- snprintf(tmp, sizeof(tmp), "/dev/mtd/mtd%d", n);
- source = tmp;
- }
- }
- add_devperms_partners(source, get_mode(args[2]), decode_uid(args[3]),
- decode_uid(args[4]), prefix);
- return 0;
+ return -1;
}
diff --git a/init/devices.c b/init/devices.c
index 8789b89..e73efdf 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -31,20 +31,26 @@
#include <private/android_filesystem_config.h>
#include <sys/time.h>
#include <asm/page.h>
+#include <sys/wait.h>
-#include "init.h"
#include "devices.h"
+#include "util.h"
+#include "log.h"
+#include "list.h"
-#define CMDLINE_PREFIX "/dev"
#define SYSFS_PREFIX "/sys"
-#define FIRMWARE_DIR "/etc/firmware"
-#define MAX_QEMU_PERM 6
+#define FIRMWARE_DIR1 "/etc/firmware"
+#define FIRMWARE_DIR2 "/vendor/firmware"
+
+static int device_fd = -1;
struct uevent {
const char *action;
const char *path;
const char *subsystem;
const char *firmware;
+ const char *partition_name;
+ int partition_num;
int major;
int minor;
};
@@ -53,6 +59,7 @@
{
struct sockaddr_nl addr;
int sz = 64*1024; // XXX larger? udev uses 16MB!
+ int on = 1;
int s;
memset(&addr, 0, sizeof(addr));
@@ -65,6 +72,7 @@
return -1;
setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
+ setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(s);
@@ -76,238 +84,122 @@
struct perms_ {
char *name;
+ char *attr;
mode_t perm;
unsigned int uid;
unsigned int gid;
unsigned short prefix;
};
-static struct perms_ devperms[] = {
- { "/dev/null", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/zero", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/full", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/ptmx", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/tty", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/random", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/urandom", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/ashmem", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/binder", 0666, AID_ROOT, AID_ROOT, 0 },
- /* logger should be world writable (for logging) but not readable */
- { "/dev/log/", 0662, AID_ROOT, AID_LOG, 1 },
-
- /* the msm hw3d client device node is world writable/readable. */
- { "/dev/msm_hw3dc", 0666, AID_ROOT, AID_ROOT, 0 },
-
- /* gpu driver for adreno200 is globally accessible */
- { "/dev/kgsl", 0666, AID_ROOT, AID_ROOT, 0 },
-
- /* these should not be world writable */
- { "/dev/diag", 0660, AID_RADIO, AID_RADIO, 0 },
- { "/dev/diag_arm9", 0660, AID_RADIO, AID_RADIO, 0 },
- { "/dev/android_adb", 0660, AID_ADB, AID_ADB, 0 },
- { "/dev/android_adb_enable", 0660, AID_ADB, AID_ADB, 0 },
- { "/dev/ttyMSM0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 },
- { "/dev/ttyHS0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 },
- { "/dev/uinput", 0660, AID_SYSTEM, AID_BLUETOOTH, 0 },
- { "/dev/alarm", 0664, AID_SYSTEM, AID_RADIO, 0 },
- { "/dev/tty0", 0660, AID_ROOT, AID_SYSTEM, 0 },
- { "/dev/graphics/", 0660, AID_ROOT, AID_GRAPHICS, 1 },
- { "/dev/msm_hw3dm", 0660, AID_SYSTEM, AID_GRAPHICS, 0 },
- { "/dev/input/", 0660, AID_ROOT, AID_INPUT, 1 },
- { "/dev/eac", 0660, AID_ROOT, AID_AUDIO, 0 },
- { "/dev/cam", 0660, AID_ROOT, AID_CAMERA, 0 },
- { "/dev/pmem", 0660, AID_SYSTEM, AID_GRAPHICS, 0 },
- { "/dev/pmem_adsp", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/pmem_camera", 0660, AID_SYSTEM, AID_CAMERA, 1 },
- { "/dev/oncrpc/", 0660, AID_ROOT, AID_SYSTEM, 1 },
- { "/dev/adsp/", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/snd/", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/mt9t013", 0660, AID_SYSTEM, AID_SYSTEM, 0 },
- { "/dev/msm_camera/", 0660, AID_SYSTEM, AID_SYSTEM, 1 },
- { "/dev/akm8976_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 },
- { "/dev/akm8976_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 },
- { "/dev/akm8973_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 },
- { "/dev/akm8973_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 },
- { "/dev/bma150", 0640, AID_COMPASS, AID_SYSTEM, 0 },
- { "/dev/cm3602", 0640, AID_COMPASS, AID_SYSTEM, 0 },
- { "/dev/akm8976_pffd", 0640, AID_COMPASS, AID_SYSTEM, 0 },
- { "/dev/lightsensor", 0640, AID_SYSTEM, AID_SYSTEM, 0 },
- { "/dev/msm_pcm_out", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/msm_pcm_in", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/msm_pcm_ctl", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/msm_snd", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/msm_mp3", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/audience_a1026", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/tpa2018d1", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/msm_audpre", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/msm_audio_ctl", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/htc-acoustic", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/vdec", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/q6venc", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/snd/dsp", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/snd/dsp1", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/snd/mixer", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/smd0", 0640, AID_RADIO, AID_RADIO, 0 },
- { "/dev/qemu_trace", 0666, AID_SYSTEM, AID_SYSTEM, 0 },
- { "/dev/qmi", 0640, AID_RADIO, AID_RADIO, 0 },
- { "/dev/qmi0", 0640, AID_RADIO, AID_RADIO, 0 },
- { "/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 },
- { "/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 },
- /* CDMA radio interface MUX */
- { "/dev/ts0710mux", 0640, AID_RADIO, AID_RADIO, 1 },
- { "/dev/ppp", 0660, AID_RADIO, AID_VPN, 0 },
- { "/dev/tun", 0640, AID_VPN, AID_VPN, 0 },
- { "/dev/bus/usb/", 0660, AID_ROOT, AID_USB, 1 },
- { NULL, 0, 0, 0, 0 },
-};
-
-/* devperms_partners list and perm_node are for hardware specific /dev entries */
struct perm_node {
struct perms_ dp;
struct listnode plist;
};
-list_declare(devperms_partners);
-/*
- * Permission override when in emulator mode, must be parsed before
- * system properties is initalized.
- */
-static int qemu_perm_count;
-static struct perms_ qemu_perms[MAX_QEMU_PERM + 1];
+static list_declare(sys_perms);
+static list_declare(dev_perms);
-int add_devperms_partners(const char *name, mode_t perm, unsigned int uid,
- unsigned int gid, unsigned short prefix) {
- int size;
- struct perm_node *node = malloc(sizeof (struct perm_node));
+int add_dev_perms(const char *name, const char *attr,
+ mode_t perm, unsigned int uid, unsigned int gid,
+ unsigned short prefix) {
+ struct perm_node *node = calloc(1, sizeof(*node));
if (!node)
return -ENOMEM;
- size = strlen(name) + 1;
- if ((node->dp.name = malloc(size)) == NULL)
+ node->dp.name = strdup(name);
+ if (!node->dp.name)
return -ENOMEM;
- memcpy(node->dp.name, name, size);
+ if (attr) {
+ node->dp.attr = strdup(attr);
+ if (!node->dp.attr)
+ return -ENOMEM;
+ }
+
node->dp.perm = perm;
node->dp.uid = uid;
node->dp.gid = gid;
node->dp.prefix = prefix;
- list_add_tail(&devperms_partners, &node->plist);
+ if (attr)
+ list_add_tail(&sys_perms, &node->plist);
+ else
+ list_add_tail(&dev_perms, &node->plist);
+
return 0;
}
-void qemu_init(void) {
- qemu_perm_count = 0;
- memset(&qemu_perms, 0, sizeof(qemu_perms));
-}
-
-static int qemu_perm(const char* name, mode_t perm, unsigned int uid,
- unsigned int gid, unsigned short prefix)
+void fixup_sys_perms(const char *upath)
{
- char *buf;
- if (qemu_perm_count == MAX_QEMU_PERM)
- return -ENOSPC;
+ char buf[512];
+ struct listnode *node;
+ struct perms_ *dp;
- buf = malloc(strlen(name) + 1);
- if (!buf)
- return -errno;
-
- strlcpy(buf, name, strlen(name) + 1);
- qemu_perms[qemu_perm_count].name = buf;
- qemu_perms[qemu_perm_count].perm = perm;
- qemu_perms[qemu_perm_count].uid = uid;
- qemu_perms[qemu_perm_count].gid = gid;
- qemu_perms[qemu_perm_count].prefix = prefix;
-
- qemu_perm_count++;
- return 0;
-}
-
-/* Permission overrides for emulator that are parsed from /proc/cmdline. */
-void qemu_cmdline(const char* name, const char *value)
-{
- char *buf;
- if (!strcmp(name, "android.ril")) {
- /* cmd line params currently assume /dev/ prefix */
- if (asprintf(&buf, CMDLINE_PREFIX"/%s", value) == -1) {
- return;
- }
- INFO("nani- buf:: %s\n", buf);
- qemu_perm(buf, 0660, AID_RADIO, AID_ROOT, 0);
- }
-}
-
-static int get_device_perm_inner(struct perms_ *perms, const char *path,
- unsigned *uid, unsigned *gid, mode_t *perm)
-{
- int i;
- for(i = 0; perms[i].name; i++) {
-
- if(perms[i].prefix) {
- if(strncmp(path, perms[i].name, strlen(perms[i].name)))
+ /* upaths omit the "/sys" that paths in this list
+ * contain, so we add 4 when comparing...
+ */
+ list_for_each(node, &sys_perms) {
+ dp = &(node_to_item(node, struct perm_node, plist))->dp;
+ if (dp->prefix) {
+ if (strncmp(upath, dp->name + 4, strlen(dp->name + 4)))
continue;
} else {
- if(strcmp(path, perms[i].name))
+ if (strcmp(upath, dp->name + 4))
continue;
}
- *uid = perms[i].uid;
- *gid = perms[i].gid;
- *perm = perms[i].perm;
- return 0;
+
+ if ((strlen(upath) + strlen(dp->attr) + 6) > sizeof(buf))
+ return;
+
+ sprintf(buf,"/sys%s/%s", upath, dp->attr);
+ INFO("fixup %s %d %d 0%o\n", buf, dp->uid, dp->gid, dp->perm);
+ chown(buf, dp->uid, dp->gid);
+ chmod(buf, dp->perm);
}
- return -1;
}
-/* First checks for emulator specific permissions specified in /proc/cmdline. */
static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid)
{
mode_t perm;
+ struct listnode *node;
+ struct perm_node *perm_node;
+ struct perms_ *dp;
- if (get_device_perm_inner(qemu_perms, path, uid, gid, &perm) == 0) {
- return perm;
- } else if (get_device_perm_inner(devperms, path, uid, gid, &perm) == 0) {
- return perm;
- } else {
- struct listnode *node;
- struct perm_node *perm_node;
- struct perms_ *dp;
+ /* search the perms list in reverse so that ueventd.$hardware can
+ * override ueventd.rc
+ */
+ list_for_each_reverse(node, &dev_perms) {
+ perm_node = node_to_item(node, struct perm_node, plist);
+ dp = &perm_node->dp;
- /* Check partners list. */
- list_for_each(node, &devperms_partners) {
- perm_node = node_to_item(node, struct perm_node, plist);
- dp = &perm_node->dp;
-
- if (dp->prefix) {
- if (strncmp(path, dp->name, strlen(dp->name)))
- continue;
- } else {
- if (strcmp(path, dp->name))
- continue;
- }
- /* Found perm in partner list. */
- *uid = dp->uid;
- *gid = dp->gid;
- return dp->perm;
+ if (dp->prefix) {
+ if (strncmp(path, dp->name, strlen(dp->name)))
+ continue;
+ } else {
+ if (strcmp(path, dp->name))
+ continue;
}
- /* Default if nothing found. */
- *uid = 0;
- *gid = 0;
- return 0600;
+ *uid = dp->uid;
+ *gid = dp->gid;
+ return dp->perm;
}
+ /* Default if nothing found. */
+ *uid = 0;
+ *gid = 0;
+ return 0600;
}
-static void make_device(const char *path, int block, int major, int minor)
+static void make_device(const char *path,
+ const char *upath,
+ int block, int major, int minor)
{
unsigned uid;
unsigned gid;
mode_t mode;
dev_t dev;
- if(major > 255 || minor > 255)
- return;
-
mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
- dev = (major << 8) | minor;
+ dev = makedev(major, minor);
/* Temporarily change egid to avoid race condition setting the gid of the
* device node. Unforunately changing the euid would prevent creation of
* some device nodes, so the uid has to be set with chown() and is still
@@ -345,6 +237,8 @@
uevent->firmware = "";
uevent->major = -1;
uevent->minor = -1;
+ uevent->partition_name = NULL;
+ uevent->partition_num = -1;
/* currently ignoring SEQNUM */
while(*msg) {
@@ -366,6 +260,12 @@
} else if(!strncmp(msg, "MINOR=", 6)) {
msg += 6;
uevent->minor = atoi(msg);
+ } else if(!strncmp(msg, "PARTN=", 6)) {
+ msg += 6;
+ uevent->partition_num = atoi(msg);
+ } else if(!strncmp(msg, "PARTNAME=", 9)) {
+ msg += 9;
+ uevent->partition_name = msg;
}
/* advance to after the next \0 */
@@ -378,14 +278,82 @@
uevent->firmware, uevent->major, uevent->minor);
}
+static char **parse_platform_block_device(struct uevent *uevent)
+{
+ const char *driver;
+ const char *path;
+ char *slash;
+ int width;
+ char buf[256];
+ char link_path[256];
+ int fd;
+ int link_num = 0;
+ int ret;
+ char *p;
+ unsigned int size;
+ struct stat info;
+
+ char **links = malloc(sizeof(char *) * 4);
+ if (!links)
+ return NULL;
+ memset(links, 0, sizeof(char *) * 4);
+
+ /* Drop "/devices/platform/" */
+ path = uevent->path;
+ driver = path + 18;
+ slash = strchr(driver, '/');
+ if (!slash)
+ goto err;
+ width = slash - driver;
+ if (width <= 0)
+ goto err;
+
+ snprintf(link_path, sizeof(link_path), "/dev/block/platform/%.*s",
+ width, driver);
+
+ if (uevent->partition_name) {
+ p = strdup(uevent->partition_name);
+ sanitize(p);
+ if (asprintf(&links[link_num], "%s/by-name/%s", link_path, p) > 0)
+ link_num++;
+ else
+ links[link_num] = NULL;
+ free(p);
+ }
+
+ if (uevent->partition_num >= 0) {
+ if (asprintf(&links[link_num], "%s/by-num/p%d", link_path, uevent->partition_num) > 0)
+ link_num++;
+ else
+ links[link_num] = NULL;
+ }
+
+ slash = strrchr(path, '/');
+ if (asprintf(&links[link_num], "%s/%s", link_path, slash + 1) > 0)
+ link_num++;
+ else
+ links[link_num] = NULL;
+
+ return links;
+
+err:
+ free(links);
+ return NULL;
+}
+
static void handle_device_event(struct uevent *uevent)
{
char devpath[96];
int devpath_ready = 0;
char *base, *name;
+ char **links = NULL;
int block;
+ int i;
- /* if it's not a /dev device, nothing to do */
+ if (!strcmp(uevent->action,"add"))
+ fixup_sys_perms(uevent->path);
+
+ /* if it's not a /dev device, nothing else to do */
if((uevent->major < 0) || (uevent->minor < 0))
return;
@@ -404,6 +372,8 @@
block = 1;
base = "/dev/block/";
mkdir(base, 0755);
+ if (!strncmp(uevent->path, "/devices/platform/", 18))
+ links = parse_platform_block_device(uevent);
} else {
block = 0;
/* this should probably be configurable somehow */
@@ -460,13 +430,25 @@
snprintf(devpath, sizeof(devpath), "%s%s", base, name);
if(!strcmp(uevent->action, "add")) {
- make_device(devpath, block, uevent->major, uevent->minor);
- return;
+ make_device(devpath, uevent->path, block, uevent->major, uevent->minor);
+ if (links) {
+ for (i = 0; links[i]; i++)
+ make_link(devpath, links[i]);
+ }
}
if(!strcmp(uevent->action, "remove")) {
+ if (links) {
+ for (i = 0; links[i]; i++)
+ remove_link(devpath, links[i]);
+ }
unlink(devpath);
- return;
+ }
+
+ if (links) {
+ for (i = 0; links[i]; i++)
+ free(links[i]);
+ free(links);
}
}
@@ -518,7 +500,7 @@
static void process_firmware_event(struct uevent *uevent)
{
- char *root, *loading, *data, *file;
+ char *root, *loading, *data, *file1 = NULL, *file2 = NULL;
int l, loading_fd, data_fd, fw_fd;
log_event_print("firmware event { '%s', '%s' }\n",
@@ -536,7 +518,11 @@
if (l == -1)
goto loading_free_out;
- l = asprintf(&file, FIRMWARE_DIR"/%s", uevent->firmware);
+ l = asprintf(&file1, FIRMWARE_DIR1"/%s", uevent->firmware);
+ if (l == -1)
+ goto data_free_out;
+
+ l = asprintf(&file2, FIRMWARE_DIR2"/%s", uevent->firmware);
if (l == -1)
goto data_free_out;
@@ -548,14 +534,17 @@
if(data_fd < 0)
goto loading_close_out;
- fw_fd = open(file, O_RDONLY);
- if(fw_fd < 0)
- goto data_close_out;
+ fw_fd = open(file1, O_RDONLY);
+ if(fw_fd < 0) {
+ fw_fd = open(file2, O_RDONLY);
+ if(fw_fd < 0)
+ goto data_close_out;
+ }
if(!load_firmware(fw_fd, loading_fd, data_fd))
- log_event_print("firmware copy success { '%s', '%s' }\n", root, file);
+ log_event_print("firmware copy success { '%s', '%s' }\n", root, uevent->firmware);
else
- log_event_print("firmware copy failure { '%s', '%s' }\n", root, file);
+ log_event_print("firmware copy failure { '%s', '%s' }\n", root, uevent->firmware);
close(fw_fd);
data_close_out:
@@ -563,7 +552,8 @@
loading_close_out:
close(loading_fd);
file_free_out:
- free(file);
+ free(file1);
+ free(file2);
data_free_out:
free(data);
loading_free_out:
@@ -575,6 +565,8 @@
static void handle_firmware_event(struct uevent *uevent)
{
pid_t pid;
+ int status;
+ int ret;
if(strcmp(uevent->subsystem, "firmware"))
return;
@@ -587,24 +579,52 @@
if (!pid) {
process_firmware_event(uevent);
exit(EXIT_SUCCESS);
+ } else {
+ do {
+ ret = waitpid(pid, &status, 0);
+ } while (ret == -1 && errno == EINTR);
}
}
#define UEVENT_MSG_LEN 1024
-void handle_device_fd(int fd)
+void handle_device_fd()
{
- char msg[UEVENT_MSG_LEN+2];
- int n;
+ for(;;) {
+ char msg[UEVENT_MSG_LEN+2];
+ char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+ struct iovec iov = {msg, sizeof(msg)};
+ struct sockaddr_nl snl;
+ struct msghdr hdr = {&snl, sizeof(snl), &iov, 1, cred_msg, sizeof(cred_msg), 0};
- while((n = recv(fd, msg, UEVENT_MSG_LEN, 0)) > 0) {
- struct uevent uevent;
+ ssize_t n = recvmsg(device_fd, &hdr, 0);
+ if (n <= 0) {
+ break;
+ }
- if(n == UEVENT_MSG_LEN) /* overflow -- discard */
+ if ((snl.nl_groups != 1) || (snl.nl_pid != 0)) {
+ /* ignoring non-kernel netlink multicast message */
+ continue;
+ }
+
+ struct cmsghdr * cmsg = CMSG_FIRSTHDR(&hdr);
+ if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
+ /* no sender credentials received, ignore message */
+ continue;
+ }
+
+ struct ucred * cred = (struct ucred *)CMSG_DATA(cmsg);
+ if (cred->uid != 0) {
+ /* message from non-root user, ignore */
+ continue;
+ }
+
+ if(n >= UEVENT_MSG_LEN) /* overflow -- discard */
continue;
msg[n] = '\0';
msg[n+1] = '\0';
+ struct uevent uevent;
parse_event(msg, &uevent);
handle_device_event(&uevent);
@@ -621,7 +641,7 @@
** socket's buffer.
*/
-static void do_coldboot(int event_fd, DIR *d)
+static void do_coldboot(DIR *d)
{
struct dirent *de;
int dfd, fd;
@@ -632,7 +652,7 @@
if(fd >= 0) {
write(fd, "add\n", 4);
close(fd);
- handle_device_fd(event_fd);
+ handle_device_fd();
}
while((de = readdir(d))) {
@@ -649,40 +669,49 @@
if(d2 == 0)
close(fd);
else {
- do_coldboot(event_fd, d2);
+ do_coldboot(d2);
closedir(d2);
}
}
}
-static void coldboot(int event_fd, const char *path)
+static void coldboot(const char *path)
{
DIR *d = opendir(path);
if(d) {
- do_coldboot(event_fd, d);
+ do_coldboot(d);
closedir(d);
}
}
-int device_init(void)
+void device_init(void)
{
suseconds_t t0, t1;
+ struct stat info;
int fd;
- fd = open_uevent_socket();
- if(fd < 0)
- return -1;
+ device_fd = open_uevent_socket();
+ if(device_fd < 0)
+ return;
- fcntl(fd, F_SETFD, FD_CLOEXEC);
- fcntl(fd, F_SETFL, O_NONBLOCK);
+ fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+ fcntl(device_fd, F_SETFL, O_NONBLOCK);
- t0 = get_usecs();
- coldboot(fd, "/sys/class");
- coldboot(fd, "/sys/block");
- coldboot(fd, "/sys/devices");
- t1 = get_usecs();
+ if (stat(coldboot_done, &info) < 0) {
+ t0 = get_usecs();
+ coldboot("/sys/class");
+ coldboot("/sys/block");
+ coldboot("/sys/devices");
+ t1 = get_usecs();
+ fd = open(coldboot_done, O_WRONLY|O_CREAT, 0000);
+ close(fd);
+ log_event_print("coldboot %ld uS\n", ((long) (t1 - t0)));
+ } else {
+ log_event_print("skipping coldboot, already done\n");
+ }
+}
- log_event_print("coldboot %ld uS\n", ((long) (t1 - t0)));
-
- return fd;
+int get_device_fd()
+{
+ return device_fd;
}
diff --git a/init/devices.h b/init/devices.h
index b484da4..a84fa58 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -17,11 +17,12 @@
#ifndef _INIT_DEVICES_H
#define _INIT_DEVICES_H
-extern void handle_device_fd(int fd);
-extern int device_init(void);
-extern void qemu_init(void);
-extern void qemu_cmdline(const char* name, const char *value);
-extern int add_devperms_partners(const char *name, mode_t perm, unsigned int uid,
- unsigned int gid, unsigned short prefix);
+#include <sys/stat.h>
+extern void handle_device_fd();
+extern void device_init(void);
+extern int add_dev_perms(const char *name, const char *attr,
+ mode_t perm, unsigned int uid,
+ unsigned int gid, unsigned short prefix);
+int get_device_fd();
#endif /* _INIT_DEVICES_H */
diff --git a/init/init.c b/init/init.c
index 0667593..75ffb5c 100755
--- a/init/init.c
+++ b/init/init.c
@@ -25,27 +25,32 @@
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/poll.h>
-#include <time.h>
#include <errno.h>
#include <stdarg.h>
#include <mtd/mtd-user.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <sys/reboot.h>
+#include <libgen.h>
#include <cutils/sockets.h>
#include <cutils/iosched_policy.h>
+#include <private/android_filesystem_config.h>
#include <termios.h>
-#include <linux/kd.h>
-#include <linux/keychord.h>
#include <sys/system_properties.h>
#include "devices.h"
#include "init.h"
+#include "list.h"
+#include "log.h"
#include "property_service.h"
#include "bootchart.h"
+#include "signal_handler.h"
+#include "keychords.h"
+#include "init_parser.h"
+#include "util.h"
+#include "ueventd.h"
static int property_triggers_enabled = 0;
@@ -62,11 +67,12 @@
static char hardware[32];
static unsigned revision = 0;
static char qemu[32];
-static struct input_keychord *keychords = 0;
-static int keychords_count = 0;
-static int keychords_length = 0;
-static void notify_service_state(const char *name, const char *state)
+static struct action *cur_action = NULL;
+static struct command *cur_command = NULL;
+static struct listnode *command_queue = NULL;
+
+void notify_service_state(const char *name, const char *state)
{
char pname[PROP_NAME_MAX];
int len = strlen(name);
@@ -122,24 +128,6 @@
close(fd);
}
-/*
- * gettime() - returns the time in seconds of the system's monotonic clock or
- * zero on error.
- */
-static time_t gettime(void)
-{
- struct timespec ts;
- int ret;
-
- ret = clock_gettime(CLOCK_MONOTONIC, &ts);
- if (ret < 0) {
- ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
- return 0;
- }
-
- return ts.tv_sec;
-}
-
static void publish_socket(const char *name, int fd)
{
char key[64] = ANDROID_SOCKET_ENV_PREFIX;
@@ -208,17 +196,20 @@
char tmp[32];
int fd, sz;
- get_property_workspace(&fd, &sz);
- sprintf(tmp, "%d,%d", dup(fd), sz);
- add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
+ if (properties_inited()) {
+ get_property_workspace(&fd, &sz);
+ sprintf(tmp, "%d,%d", dup(fd), sz);
+ add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
+ }
for (ei = svc->envvars; ei; ei = ei->next)
add_environment(ei->name, ei->value);
for (si = svc->sockets; si; si = si->next) {
- int s = create_socket(si->name,
- !strcmp(si->type, "dgram") ?
- SOCK_DGRAM : SOCK_STREAM,
+ int socket_type = (
+ !strcmp(si->type, "stream") ? SOCK_STREAM :
+ (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
+ int s = create_socket(si->name, socket_type,
si->perm, si->uid, si->gid);
if (s >= 0) {
publish_socket(si->name, s);
@@ -266,7 +257,7 @@
ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
}
} else {
- char *arg_ptrs[SVC_MAXARGS+1];
+ char *arg_ptrs[INIT_PARSER_MAXARGS+1];
int arg_idx = svc->nargs;
char *tmp = strdup(dynamic_args);
char *next = tmp;
@@ -277,7 +268,7 @@
while((bword = strsep(&next, " "))) {
arg_ptrs[arg_idx++] = bword;
- if (arg_idx == SVC_MAXARGS)
+ if (arg_idx == INIT_PARSER_MAXARGS)
break;
}
arg_ptrs[arg_idx] = '\0';
@@ -296,7 +287,8 @@
svc->pid = pid;
svc->flags |= SVC_RUNNING;
- notify_service_state(svc->name, "running");
+ if (properties_inited())
+ notify_service_state(svc->name, "running");
}
void service_stop(struct service *svc)
@@ -322,90 +314,8 @@
void property_changed(const char *name, const char *value)
{
- if (property_triggers_enabled) {
+ if (property_triggers_enabled)
queue_property_triggers(name, value);
- drain_action_queue();
- }
-}
-
-#define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */
-#define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery*/
-
-static int wait_for_one_process(int block)
-{
- pid_t pid;
- int status;
- struct service *svc;
- struct socketinfo *si;
- time_t now;
- struct listnode *node;
- struct command *cmd;
-
- while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );
- if (pid <= 0) return -1;
- INFO("waitpid returned pid %d, status = %08x\n", pid, status);
-
- svc = service_find_by_pid(pid);
- if (!svc) {
- ERROR("untracked pid %d exited\n", pid);
- return 0;
- }
-
- NOTICE("process '%s', pid %d exited\n", svc->name, pid);
-
- if (!(svc->flags & SVC_ONESHOT)) {
- kill(-pid, SIGKILL);
- NOTICE("process '%s' killing any children in process group\n", svc->name);
- }
-
- /* remove any sockets we may have created */
- for (si = svc->sockets; si; si = si->next) {
- char tmp[128];
- snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
- unlink(tmp);
- }
-
- svc->pid = 0;
- svc->flags &= (~SVC_RUNNING);
-
- /* oneshot processes go into the disabled state on exit */
- if (svc->flags & SVC_ONESHOT) {
- svc->flags |= SVC_DISABLED;
- }
-
- /* disabled processes do not get restarted automatically */
- if (svc->flags & SVC_DISABLED) {
- notify_service_state(svc->name, "stopped");
- return 0;
- }
-
- now = gettime();
- if (svc->flags & SVC_CRITICAL) {
- if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
- if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
- ERROR("critical process '%s' exited %d times in %d minutes; "
- "rebooting into recovery mode\n", svc->name,
- CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
- sync();
- __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
- LINUX_REBOOT_CMD_RESTART2, "recovery");
- return 0;
- }
- } else {
- svc->time_crashed = now;
- svc->nr_crashed = 1;
- }
- }
-
- svc->flags |= SVC_RESTARTING;
-
- /* Execute all onrestart commands for this service. */
- list_for_each(node, &svc->onrestart.commands) {
- cmd = node_to_item(node, struct command, clist);
- cmd->func(cmd->nargs, cmd->args);
- }
- notify_service_state(svc->name, "restarting");
- return 0;
}
static void restart_service_if_needed(struct service *svc)
@@ -431,13 +341,6 @@
restart_service_if_needed);
}
-static int signal_fd = -1;
-
-static void sigchld_handler(int s)
-{
- write(signal_fd, &s, 1);
-}
-
static void msg_start(const char *name)
{
struct service *svc;
@@ -486,78 +389,6 @@
}
}
-#define MAX_MTD_PARTITIONS 16
-
-static struct {
- char name[16];
- int number;
-} mtd_part_map[MAX_MTD_PARTITIONS];
-
-static int mtd_part_count = -1;
-
-static void find_mtd_partitions(void)
-{
- int fd;
- char buf[1024];
- char *pmtdbufp;
- ssize_t pmtdsize;
- int r;
-
- fd = open("/proc/mtd", O_RDONLY);
- if (fd < 0)
- return;
-
- buf[sizeof(buf) - 1] = '\0';
- pmtdsize = read(fd, buf, sizeof(buf) - 1);
- pmtdbufp = buf;
- while (pmtdsize > 0) {
- int mtdnum, mtdsize, mtderasesize;
- char mtdname[16];
- mtdname[0] = '\0';
- mtdnum = -1;
- r = sscanf(pmtdbufp, "mtd%d: %x %x %15s",
- &mtdnum, &mtdsize, &mtderasesize, mtdname);
- if ((r == 4) && (mtdname[0] == '"')) {
- char *x = strchr(mtdname + 1, '"');
- if (x) {
- *x = 0;
- }
- INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1);
- if (mtd_part_count < MAX_MTD_PARTITIONS) {
- strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1);
- mtd_part_map[mtd_part_count].number = mtdnum;
- mtd_part_count++;
- } else {
- ERROR("too many mtd partitions\n");
- }
- }
- while (pmtdsize > 0 && *pmtdbufp != '\n') {
- pmtdbufp++;
- pmtdsize--;
- }
- if (pmtdsize > 0) {
- pmtdbufp++;
- pmtdsize--;
- }
- }
- close(fd);
-}
-
-int mtd_name_to_number(const char *name)
-{
- int n;
- if (mtd_part_count < 0) {
- mtd_part_count = 0;
- find_mtd_partitions();
- }
- for (n = 0; n < mtd_part_count; n++) {
- if (!strcmp(name, mtd_part_map[n].name)) {
- return mtd_part_map[n].number;
- }
- }
- return -1;
-}
-
static void import_kernel_nv(char *name, int in_qemu)
{
char *value = strchr(name, '=');
@@ -585,8 +416,6 @@
strlcpy(bootloader, value, sizeof(bootloader));
} else if (!strcmp(name,"androidboot.hardware")) {
strlcpy(hardware, value, sizeof(hardware));
- } else {
- qemu_cmdline(name, value);
}
} else {
/* in the emulator, export any kernel option with the
@@ -631,199 +460,208 @@
chmod("/proc/cmdline", 0440);
}
-static void get_hardware_name(void)
-{
- char data[1024];
- int fd, n;
- char *x, *hw, *rev;
-
- /* Hardware string was provided on kernel command line */
- if (hardware[0])
- return;
-
- fd = open("/proc/cpuinfo", O_RDONLY);
- if (fd < 0) return;
-
- n = read(fd, data, 1023);
- close(fd);
- if (n < 0) return;
-
- data[n] = 0;
- hw = strstr(data, "\nHardware");
- rev = strstr(data, "\nRevision");
-
- if (hw) {
- x = strstr(hw, ": ");
- if (x) {
- x += 2;
- n = 0;
- while (*x && *x != '\n') {
- if (!isspace(*x))
- hardware[n++] = tolower(*x);
- x++;
- if (n == 31) break;
- }
- hardware[n] = 0;
- }
- }
-
- if (rev) {
- x = strstr(rev, ": ");
- if (x) {
- revision = strtoul(x + 2, 0, 16);
- }
- }
-}
-
-void drain_action_queue(void)
+static struct command *get_first_command(struct action *act)
{
struct listnode *node;
- struct command *cmd;
- struct action *act;
- int ret;
+ node = list_head(&act->commands);
+ if (!node)
+ return NULL;
- while ((act = action_remove_queue_head())) {
- INFO("processing action %p (%s)\n", act, act->name);
- list_for_each(node, &act->commands) {
- cmd = node_to_item(node, struct command, clist);
- ret = cmd->func(cmd->nargs, cmd->args);
- INFO("command '%s' r=%d\n", cmd->args[0], ret);
- }
- }
+ return node_to_item(node, struct command, clist);
}
-void open_devnull_stdio(void)
+static struct command *get_next_command(struct action *act, struct command *cmd)
+{
+ struct listnode *node;
+ node = cmd->clist.next;
+ if (!node)
+ return NULL;
+ if (node == &act->commands)
+ return NULL;
+
+ return node_to_item(node, struct command, clist);
+}
+
+static int is_last_command(struct action *act, struct command *cmd)
+{
+ return (list_tail(&act->commands) == &cmd->clist);
+}
+
+void execute_one_command(void)
+{
+ int ret;
+
+ if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
+ cur_action = action_remove_queue_head();
+ cur_command = NULL;
+ if (!cur_action)
+ return;
+ INFO("processing action %p (%s)\n", cur_action, cur_action->name);
+ cur_command = get_first_command(cur_action);
+ } else {
+ cur_command = get_next_command(cur_action, cur_command);
+ }
+
+ if (!cur_command)
+ return;
+
+ ret = cur_command->func(cur_command->nargs, cur_command->args);
+ INFO("command '%s' r=%d\n", cur_command->args[0], ret);
+}
+
+static int wait_for_coldboot_done_action(int nargs, char **args)
+{
+ int ret;
+ INFO("wait for %s\n", coldboot_done);
+ ret = wait_for_file(coldboot_done, COMMAND_RETRY_TIMEOUT);
+ if (ret)
+ ERROR("Timed out waiting for %s\n", coldboot_done);
+ return ret;
+}
+
+static int property_init_action(int nargs, char **args)
+{
+ INFO("property init\n");
+ property_init();
+ return 0;
+}
+
+static int keychord_init_action(int nargs, char **args)
+{
+ keychord_init();
+ return 0;
+}
+
+static int console_init_action(int nargs, char **args)
{
int fd;
- static const char *name = "/dev/__null__";
- if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
- fd = open(name, O_RDWR);
- unlink(name);
+ char tmp[PROP_VALUE_MAX];
+
+ if (console[0]) {
+ snprintf(tmp, sizeof(tmp), "/dev/%s", console);
+ console_name = strdup(tmp);
+ }
+
+ fd = open(console_name, O_RDWR);
+ if (fd >= 0)
+ have_console = 1;
+ close(fd);
+
+ if( load_565rle_image(INIT_IMAGE_FILE) ) {
+ fd = open("/dev/tty0", O_WRONLY);
if (fd >= 0) {
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
- if (fd > 2) {
- close(fd);
- }
- return;
+ const char *msg;
+ msg = "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n" // console is 40 cols x 30 lines
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ " A N D R O I D ";
+ write(fd, msg, strlen(msg));
+ close(fd);
}
}
-
- exit(1);
+ return 0;
}
-void add_service_keycodes(struct service *svc)
+static int set_init_properties_action(int nargs, char **args)
{
- struct input_keychord *keychord;
- int i, size;
+ char tmp[PROP_VALUE_MAX];
- if (svc->keycodes) {
- /* add a new keychord to the list */
- size = sizeof(*keychord) + svc->nkeycodes * sizeof(keychord->keycodes[0]);
- keychords = realloc(keychords, keychords_length + size);
- if (!keychords) {
- ERROR("could not allocate keychords\n");
- keychords_length = 0;
- keychords_count = 0;
- return;
- }
+ if (qemu[0])
+ import_kernel_cmdline(1);
- keychord = (struct input_keychord *)((char *)keychords + keychords_length);
- keychord->version = KEYCHORD_VERSION;
- keychord->id = keychords_count + 1;
- keychord->count = svc->nkeycodes;
- svc->keychord_id = keychord->id;
+ if (!strcmp(bootmode,"factory"))
+ property_set("ro.factorytest", "1");
+ else if (!strcmp(bootmode,"factory2"))
+ property_set("ro.factorytest", "2");
+ else
+ property_set("ro.factorytest", "0");
- for (i = 0; i < svc->nkeycodes; i++) {
- keychord->keycodes[i] = svc->keycodes[i];
- }
- keychords_count++;
- keychords_length += size;
- }
+ property_set("ro.serialno", serialno[0] ? serialno : "");
+ property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown");
+ property_set("ro.baseband", baseband[0] ? baseband : "unknown");
+ property_set("ro.carrier", carrier[0] ? carrier : "unknown");
+ property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown");
+
+ property_set("ro.hardware", hardware);
+ snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
+ property_set("ro.revision", tmp);
+ return 0;
}
-int open_keychord()
+static int property_service_init_action(int nargs, char **args)
{
- int fd, ret;
-
- service_for_each(add_service_keycodes);
-
- /* nothing to do if no services require keychords */
- if (!keychords)
- return -1;
-
- fd = open("/dev/keychord", O_RDWR);
- if (fd < 0) {
- ERROR("could not open /dev/keychord\n");
- return fd;
- }
- fcntl(fd, F_SETFD, FD_CLOEXEC);
-
- ret = write(fd, keychords, keychords_length);
- if (ret != keychords_length) {
- ERROR("could not configure /dev/keychord %d (%d)\n", ret, errno);
- close(fd);
- fd = -1;
- }
-
- free(keychords);
- keychords = 0;
-
- return fd;
+ /* read any property files on system or data and
+ * fire up the property service. This must happen
+ * after the ro.foo properties are set above so
+ * that /data/local.prop cannot interfere with them.
+ */
+ start_property_service();
+ return 0;
}
-void handle_keychord(int fd)
+static int signal_init_action(int nargs, char **args)
{
- struct service *svc;
- char* debuggable;
- char* adb_enabled;
- int ret;
- __u16 id;
+ signal_init();
+ return 0;
+}
- // only handle keychords if ro.debuggable is set or adb is enabled.
- // the logic here is that bugreports should be enabled in userdebug or eng builds
- // and on user builds for users that are developers.
- debuggable = property_get("ro.debuggable");
- adb_enabled = property_get("init.svc.adbd");
- if ((debuggable && !strcmp(debuggable, "1")) ||
- (adb_enabled && !strcmp(adb_enabled, "running"))) {
- ret = read(fd, &id, sizeof(id));
- if (ret != sizeof(id)) {
- ERROR("could not read keychord id\n");
- return;
- }
+static int check_startup_action(int nargs, char **args)
+{
+ /* make sure we actually have all the pieces we need */
+ if ((get_property_set_fd() < 0) ||
+ (get_signal_fd() < 0)) {
+ ERROR("init startup failure\n");
+ exit(1);
+ }
+ return 0;
+}
- svc = service_find_by_keychord(id);
- if (svc) {
- INFO("starting service %s from keychord\n", svc->name);
- service_start(svc, NULL);
- } else {
- ERROR("service for keychord %d not found\n", id);
- }
+static int queue_property_triggers_action(int nargs, char **args)
+{
+ queue_all_property_triggers();
+ /* enable property triggers */
+ property_triggers_enabled = 1;
+ return 0;
+}
+
+#if BOOTCHART
+static int bootchart_init_action(int nargs, char **args)
+{
+ bootchart_count = bootchart_init();
+ if (bootchart_count < 0) {
+ ERROR("bootcharting init failure\n");
+ } else if (bootchart_count > 0) {
+ NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS);
+ } else {
+ NOTICE("bootcharting ignored\n");
}
}
+#endif
int main(int argc, char **argv)
{
- int device_fd = -1;
- int property_set_fd = -1;
- int signal_recv_fd = -1;
- int keychord_fd = -1;
- int fd_count;
- int s[2];
- int fd;
- struct sigaction act;
- char tmp[PROP_VALUE_MAX];
+ int fd_count = 0;
struct pollfd ufds[4];
char *tmpdev;
char* debuggable;
+ char tmp[32];
+ int property_set_fd_init = 0;
+ int signal_fd_init = 0;
+ int keychord_fd_init = 0;
- act.sa_handler = sigchld_handler;
- act.sa_flags = SA_NOCLDSTOP;
- act.sa_mask = 0;
- act.sa_restorer = NULL;
- sigaction(SIGCHLD, &act, 0);
+ if (!strcmp(basename(argv[0]), "ueventd"))
+ return ueventd_main(argc, argv);
/* clear the umask */
umask(0);
@@ -853,165 +691,82 @@
log_init();
INFO("reading config file\n");
- parse_config_file("/init.rc");
+ init_parse_config_file("/init.rc");
/* pull the kernel commandline and ramdisk properties file in */
- qemu_init();
import_kernel_cmdline(0);
- get_hardware_name();
+ get_hardware_name(hardware, &revision);
snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
- parse_config_file(tmp);
+ init_parse_config_file(tmp);
action_for_each_trigger("early-init", action_add_queue_tail);
- drain_action_queue();
- INFO("device init\n");
- device_fd = device_init();
-
- property_init();
-
- // only listen for keychords if ro.debuggable is true
- keychord_fd = open_keychord();
-
- if (console[0]) {
- snprintf(tmp, sizeof(tmp), "/dev/%s", console);
- console_name = strdup(tmp);
- }
-
- fd = open(console_name, O_RDWR);
- if (fd >= 0)
- have_console = 1;
- close(fd);
-
- if( load_565rle_image(INIT_IMAGE_FILE) ) {
- fd = open("/dev/tty0", O_WRONLY);
- if (fd >= 0) {
- const char *msg;
- msg = "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n" // console is 40 cols x 30 lines
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- " A N D R O I D ";
- write(fd, msg, strlen(msg));
- close(fd);
- }
- }
-
- if (qemu[0])
- import_kernel_cmdline(1);
-
- if (!strcmp(bootmode,"factory"))
- property_set("ro.factorytest", "1");
- else if (!strcmp(bootmode,"factory2"))
- property_set("ro.factorytest", "2");
- else
- property_set("ro.factorytest", "0");
-
- property_set("ro.serialno", serialno[0] ? serialno : "");
- property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown");
- property_set("ro.baseband", baseband[0] ? baseband : "unknown");
- property_set("ro.carrier", carrier[0] ? carrier : "unknown");
- property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown");
-
- property_set("ro.hardware", hardware);
- snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
- property_set("ro.revision", tmp);
+ queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
+ queue_builtin_action(property_init_action, "property_init");
+ queue_builtin_action(keychord_init_action, "keychord_init");
+ queue_builtin_action(console_init_action, "console_init");
+ queue_builtin_action(set_init_properties_action, "set_init_properties");
/* execute all the boot actions to get us started */
action_for_each_trigger("init", action_add_queue_tail);
- drain_action_queue();
+ action_for_each_trigger("early-fs", action_add_queue_tail);
+ action_for_each_trigger("fs", action_add_queue_tail);
+ action_for_each_trigger("post-fs", action_add_queue_tail);
- /* read any property files on system or data and
- * fire up the property service. This must happen
- * after the ro.foo properties are set above so
- * that /data/local.prop cannot interfere with them.
- */
- property_set_fd = start_property_service();
-
- /* create a signalling mechanism for the sigchld handler */
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
- signal_fd = s[0];
- signal_recv_fd = s[1];
- fcntl(s[0], F_SETFD, FD_CLOEXEC);
- fcntl(s[0], F_SETFL, O_NONBLOCK);
- fcntl(s[1], F_SETFD, FD_CLOEXEC);
- fcntl(s[1], F_SETFL, O_NONBLOCK);
- }
-
- /* make sure we actually have all the pieces we need */
- if ((device_fd < 0) ||
- (property_set_fd < 0) ||
- (signal_recv_fd < 0)) {
- ERROR("init startup failure\n");
- return 1;
- }
+ queue_builtin_action(property_service_init_action, "property_service_init");
+ queue_builtin_action(signal_init_action, "signal_init");
+ queue_builtin_action(check_startup_action, "check_startup");
/* execute all the boot actions to get us started */
action_for_each_trigger("early-boot", action_add_queue_tail);
action_for_each_trigger("boot", action_add_queue_tail);
- drain_action_queue();
/* run all property triggers based on current state of the properties */
- queue_all_property_triggers();
- drain_action_queue();
+ queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");
- /* enable property triggers */
- property_triggers_enabled = 1;
-
- ufds[0].fd = device_fd;
- ufds[0].events = POLLIN;
- ufds[1].fd = property_set_fd;
- ufds[1].events = POLLIN;
- ufds[2].fd = signal_recv_fd;
- ufds[2].events = POLLIN;
- fd_count = 3;
-
- if (keychord_fd > 0) {
- ufds[3].fd = keychord_fd;
- ufds[3].events = POLLIN;
- fd_count++;
- } else {
- ufds[3].events = 0;
- ufds[3].revents = 0;
- }
#if BOOTCHART
- bootchart_count = bootchart_init();
- if (bootchart_count < 0) {
- ERROR("bootcharting init failure\n");
- } else if (bootchart_count > 0) {
- NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS);
- } else {
- NOTICE("bootcharting ignored\n");
- }
+ queue_builtin_action(bootchart_init_action, "bootchart_init");
#endif
for(;;) {
int nr, i, timeout = -1;
- for (i = 0; i < fd_count; i++)
- ufds[i].revents = 0;
-
- drain_action_queue();
+ execute_one_command();
restart_processes();
+ if (!property_set_fd_init && get_property_set_fd() > 0) {
+ ufds[fd_count].fd = get_property_set_fd();
+ ufds[fd_count].events = POLLIN;
+ ufds[fd_count].revents = 0;
+ fd_count++;
+ property_set_fd_init = 1;
+ }
+ if (!signal_fd_init && get_signal_fd() > 0) {
+ ufds[fd_count].fd = get_signal_fd();
+ ufds[fd_count].events = POLLIN;
+ ufds[fd_count].revents = 0;
+ fd_count++;
+ signal_fd_init = 1;
+ }
+ if (!keychord_fd_init && get_keychord_fd() > 0) {
+ ufds[fd_count].fd = get_keychord_fd();
+ ufds[fd_count].events = POLLIN;
+ ufds[fd_count].revents = 0;
+ fd_count++;
+ keychord_fd_init = 1;
+ }
+
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}
+ if (!action_queue_empty() || cur_action)
+ timeout = 0;
+
#if BOOTCHART
if (bootchart_count > 0) {
if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
@@ -1022,25 +777,21 @@
}
}
#endif
+
nr = poll(ufds, fd_count, timeout);
if (nr <= 0)
continue;
- if (ufds[2].revents == POLLIN) {
- /* we got a SIGCHLD - reap and restart as needed */
- read(signal_recv_fd, tmp, sizeof(tmp));
- while (!wait_for_one_process(0))
- ;
- continue;
+ for (i = 0; i < fd_count; i++) {
+ if (ufds[i].revents == POLLIN) {
+ if (ufds[i].fd == get_property_set_fd())
+ handle_property_set_fd();
+ else if (ufds[i].fd == get_keychord_fd())
+ handle_keychord();
+ else if (ufds[i].fd == get_signal_fd())
+ handle_signal();
+ }
}
-
- if (ufds[0].revents == POLLIN)
- handle_device_fd(device_fd);
-
- if (ufds[1].revents == POLLIN)
- handle_property_set_fd(property_set_fd);
- if (ufds[3].revents == POLLIN)
- handle_keychord(keychord_fd);
}
return 0;
diff --git a/init/init.h b/init/init.h
index f92a4d7..8691335 100644
--- a/init/init.h
+++ b/init/init.h
@@ -17,56 +17,12 @@
#ifndef _INIT_INIT_H
#define _INIT_INIT_H
-int mtd_name_to_number(const char *name);
+#include "list.h"
+
+#include <sys/stat.h>
void handle_control_message(const char *msg, const char *arg);
-int create_socket(const char *name, int type, mode_t perm,
- uid_t uid, gid_t gid);
-
-void *read_file(const char *fn, unsigned *_sz);
-
-void log_init(void);
-void log_set_level(int level);
-void log_close(void);
-void log_write(int level, const char *fmt, ...)
- __attribute__ ((format(printf, 2, 3)));
-
-#define ERROR(x...) log_write(3, "<3>init: " x)
-#define NOTICE(x...) log_write(5, "<5>init: " x)
-#define INFO(x...) log_write(6, "<6>init: " x)
-
-#define LOG_DEFAULT_LEVEL 3 /* messages <= this level are logged */
-#define LOG_UEVENTS 0 /* log uevent messages if 1. verbose */
-
-unsigned int decode_uid(const char *s);
-
-struct listnode
-{
- struct listnode *next;
- struct listnode *prev;
-};
-
-#define node_to_item(node, container, member) \
- (container *) (((char*) (node)) - offsetof(container, member))
-
-#define list_declare(name) \
- struct listnode name = { \
- .next = &name, \
- .prev = &name, \
- }
-
-#define list_for_each(node, list) \
- for (node = (list)->next; node != (list); node = node->next)
-
-void list_init(struct listnode *list);
-void list_add_tail(struct listnode *list, struct listnode *item);
-void list_remove(struct listnode *item);
-
-#define list_empty(list) ((list) == (list)->next)
-#define list_head(list) ((list)->next)
-#define list_tail(list) ((list)->prev)
-
struct command
{
/* list of commands in an action */
@@ -116,7 +72,7 @@
#define NR_SVC_SUPP_GIDS 12 /* twelve supplementary groups */
-#define SVC_MAXARGS 64
+#define COMMAND_RETRY_TIMEOUT 5
struct service {
/* list of all services */
@@ -154,7 +110,7 @@
char *args[1];
}; /* ^-------'args' MUST be at the end of this struct! */
-int parse_config_file(const char *fn);
+void notify_service_state(const char *name, const char *state);
struct service *service_find_by_name(const char *name);
struct service *service_find_by_pid(pid_t pid);
@@ -168,14 +124,6 @@
void service_start(struct service *svc, const char *dynamic_args);
void property_changed(const char *name, const char *value);
-void drain_action_queue(void);
-struct action *action_remove_queue_head(void);
-void action_add_queue_tail(struct action *act);
-void action_for_each_trigger(const char *trigger,
- void (*func)(struct action *act));
-void queue_property_triggers(const char *name, const char *value);
-void queue_all_property_triggers();
-
#define INIT_IMAGE_FILE "/initlogo.rle"
int load_565rle_image( char *file_name );
diff --git a/init/init_parser.c b/init/init_parser.c
new file mode 100644
index 0000000..d136c28
--- /dev/null
+++ b/init/init_parser.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stddef.h>
+#include <ctype.h>
+
+#include "init.h"
+#include "parser.h"
+#include "init_parser.h"
+#include "log.h"
+#include "list.h"
+#include "property_service.h"
+#include "util.h"
+
+#include <cutils/iosched_policy.h>
+
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
+static list_declare(service_list);
+static list_declare(action_list);
+static list_declare(action_queue);
+
+static void *parse_service(struct parse_state *state, int nargs, char **args);
+static void parse_line_service(struct parse_state *state, int nargs, char **args);
+
+static void *parse_action(struct parse_state *state, int nargs, char **args);
+static void parse_line_action(struct parse_state *state, int nargs, char **args);
+
+#define SECTION 0x01
+#define COMMAND 0x02
+#define OPTION 0x04
+
+#include "keywords.h"
+
+#define KEYWORD(symbol, flags, nargs, func) \
+ [ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
+
+struct {
+ const char *name;
+ int (*func)(int nargs, char **args);
+ unsigned char nargs;
+ unsigned char flags;
+} keyword_info[KEYWORD_COUNT] = {
+ [ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
+#include "keywords.h"
+};
+#undef KEYWORD
+
+#define kw_is(kw, type) (keyword_info[kw].flags & (type))
+#define kw_name(kw) (keyword_info[kw].name)
+#define kw_func(kw) (keyword_info[kw].func)
+#define kw_nargs(kw) (keyword_info[kw].nargs)
+
+int lookup_keyword(const char *s)
+{
+ switch (*s++) {
+ case 'c':
+ if (!strcmp(s, "opy")) return K_copy;
+ if (!strcmp(s, "apability")) return K_capability;
+ if (!strcmp(s, "hdir")) return K_chdir;
+ if (!strcmp(s, "hroot")) return K_chroot;
+ if (!strcmp(s, "lass")) return K_class;
+ if (!strcmp(s, "lass_start")) return K_class_start;
+ if (!strcmp(s, "lass_stop")) return K_class_stop;
+ if (!strcmp(s, "onsole")) return K_console;
+ if (!strcmp(s, "hown")) return K_chown;
+ if (!strcmp(s, "hmod")) return K_chmod;
+ if (!strcmp(s, "ritical")) return K_critical;
+ break;
+ case 'd':
+ if (!strcmp(s, "isabled")) return K_disabled;
+ if (!strcmp(s, "omainname")) return K_domainname;
+ break;
+ case 'e':
+ if (!strcmp(s, "xec")) return K_exec;
+ if (!strcmp(s, "xport")) return K_export;
+ break;
+ case 'g':
+ if (!strcmp(s, "roup")) return K_group;
+ break;
+ case 'h':
+ if (!strcmp(s, "ostname")) return K_hostname;
+ break;
+ case 'i':
+ if (!strcmp(s, "oprio")) return K_ioprio;
+ if (!strcmp(s, "fup")) return K_ifup;
+ if (!strcmp(s, "nsmod")) return K_insmod;
+ if (!strcmp(s, "mport")) return K_import;
+ break;
+ case 'k':
+ if (!strcmp(s, "eycodes")) return K_keycodes;
+ break;
+ case 'l':
+ if (!strcmp(s, "oglevel")) return K_loglevel;
+ break;
+ case 'm':
+ if (!strcmp(s, "kdir")) return K_mkdir;
+ if (!strcmp(s, "ount")) return K_mount;
+ break;
+ case 'o':
+ if (!strcmp(s, "n")) return K_on;
+ if (!strcmp(s, "neshot")) return K_oneshot;
+ if (!strcmp(s, "nrestart")) return K_onrestart;
+ break;
+ case 'r':
+ if (!strcmp(s, "estart")) return K_restart;
+ break;
+ case 's':
+ if (!strcmp(s, "ervice")) return K_service;
+ if (!strcmp(s, "etenv")) return K_setenv;
+ if (!strcmp(s, "etkey")) return K_setkey;
+ if (!strcmp(s, "etprop")) return K_setprop;
+ if (!strcmp(s, "etrlimit")) return K_setrlimit;
+ if (!strcmp(s, "ocket")) return K_socket;
+ if (!strcmp(s, "tart")) return K_start;
+ if (!strcmp(s, "top")) return K_stop;
+ if (!strcmp(s, "ymlink")) return K_symlink;
+ if (!strcmp(s, "ysclktz")) return K_sysclktz;
+ break;
+ case 't':
+ if (!strcmp(s, "rigger")) return K_trigger;
+ break;
+ case 'u':
+ if (!strcmp(s, "ser")) return K_user;
+ break;
+ case 'w':
+ if (!strcmp(s, "rite")) return K_write;
+ if (!strcmp(s, "ait")) return K_wait;
+ break;
+ }
+ return K_UNKNOWN;
+}
+
+void parse_line_no_op(struct parse_state *state, int nargs, char **args)
+{
+}
+
+void parse_new_section(struct parse_state *state, int kw,
+ int nargs, char **args)
+{
+ printf("[ %s %s ]\n", args[0],
+ nargs > 1 ? args[1] : "");
+ switch(kw) {
+ case K_service:
+ state->context = parse_service(state, nargs, args);
+ if (state->context) {
+ state->parse_line = parse_line_service;
+ return;
+ }
+ break;
+ case K_on:
+ state->context = parse_action(state, nargs, args);
+ if (state->context) {
+ state->parse_line = parse_line_action;
+ return;
+ }
+ break;
+ }
+ state->parse_line = parse_line_no_op;
+}
+
+static void parse_config(const char *fn, char *s)
+{
+ struct parse_state state;
+ char *args[INIT_PARSER_MAXARGS];
+ int nargs;
+
+ nargs = 0;
+ state.filename = fn;
+ state.line = 1;
+ state.ptr = s;
+ state.nexttoken = 0;
+ state.parse_line = parse_line_no_op;
+ for (;;) {
+ switch (next_token(&state)) {
+ case T_EOF:
+ state.parse_line(&state, 0, 0);
+ return;
+ case T_NEWLINE:
+ if (nargs) {
+ int kw = lookup_keyword(args[0]);
+ if (kw_is(kw, SECTION)) {
+ state.parse_line(&state, 0, 0);
+ parse_new_section(&state, kw, nargs, args);
+ } else {
+ state.parse_line(&state, nargs, args);
+ }
+ nargs = 0;
+ }
+ break;
+ case T_TEXT:
+ if (nargs < INIT_PARSER_MAXARGS) {
+ args[nargs++] = state.text;
+ }
+ break;
+ }
+ }
+}
+
+int init_parse_config_file(const char *fn)
+{
+ char *data;
+ data = read_file(fn, 0);
+ if (!data) return -1;
+
+ parse_config(fn, data);
+ DUMP();
+ return 0;
+}
+
+static int valid_name(const char *name)
+{
+ if (strlen(name) > 16) {
+ return 0;
+ }
+ while (*name) {
+ if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
+ return 0;
+ }
+ name++;
+ }
+ return 1;
+}
+
+struct service *service_find_by_name(const char *name)
+{
+ struct listnode *node;
+ struct service *svc;
+ list_for_each(node, &service_list) {
+ svc = node_to_item(node, struct service, slist);
+ if (!strcmp(svc->name, name)) {
+ return svc;
+ }
+ }
+ return 0;
+}
+
+struct service *service_find_by_pid(pid_t pid)
+{
+ struct listnode *node;
+ struct service *svc;
+ list_for_each(node, &service_list) {
+ svc = node_to_item(node, struct service, slist);
+ if (svc->pid == pid) {
+ return svc;
+ }
+ }
+ return 0;
+}
+
+struct service *service_find_by_keychord(int keychord_id)
+{
+ struct listnode *node;
+ struct service *svc;
+ list_for_each(node, &service_list) {
+ svc = node_to_item(node, struct service, slist);
+ if (svc->keychord_id == keychord_id) {
+ return svc;
+ }
+ }
+ return 0;
+}
+
+void service_for_each(void (*func)(struct service *svc))
+{
+ struct listnode *node;
+ struct service *svc;
+ list_for_each(node, &service_list) {
+ svc = node_to_item(node, struct service, slist);
+ func(svc);
+ }
+}
+
+void service_for_each_class(const char *classname,
+ void (*func)(struct service *svc))
+{
+ struct listnode *node;
+ struct service *svc;
+ list_for_each(node, &service_list) {
+ svc = node_to_item(node, struct service, slist);
+ if (!strcmp(svc->classname, classname)) {
+ func(svc);
+ }
+ }
+}
+
+void service_for_each_flags(unsigned matchflags,
+ void (*func)(struct service *svc))
+{
+ struct listnode *node;
+ struct service *svc;
+ list_for_each(node, &service_list) {
+ svc = node_to_item(node, struct service, slist);
+ if (svc->flags & matchflags) {
+ func(svc);
+ }
+ }
+}
+
+void action_for_each_trigger(const char *trigger,
+ void (*func)(struct action *act))
+{
+ struct listnode *node;
+ struct action *act;
+ list_for_each(node, &action_list) {
+ act = node_to_item(node, struct action, alist);
+ if (!strcmp(act->name, trigger)) {
+ func(act);
+ }
+ }
+}
+
+void queue_property_triggers(const char *name, const char *value)
+{
+ struct listnode *node;
+ struct action *act;
+ list_for_each(node, &action_list) {
+ act = node_to_item(node, struct action, alist);
+ if (!strncmp(act->name, "property:", strlen("property:"))) {
+ const char *test = act->name + strlen("property:");
+ int name_length = strlen(name);
+
+ if (!strncmp(name, test, name_length) &&
+ test[name_length] == '=' &&
+ !strcmp(test + name_length + 1, value)) {
+ action_add_queue_tail(act);
+ }
+ }
+ }
+}
+
+void queue_all_property_triggers()
+{
+ struct listnode *node;
+ struct action *act;
+ list_for_each(node, &action_list) {
+ act = node_to_item(node, struct action, alist);
+ if (!strncmp(act->name, "property:", strlen("property:"))) {
+ /* parse property name and value
+ syntax is property:<name>=<value> */
+ const char* name = act->name + strlen("property:");
+ const char* equals = strchr(name, '=');
+ if (equals) {
+ char prop_name[PROP_NAME_MAX + 1];
+ const char* value;
+ int length = equals - name;
+ if (length > PROP_NAME_MAX) {
+ ERROR("property name too long in trigger %s", act->name);
+ } else {
+ memcpy(prop_name, name, length);
+ prop_name[length] = 0;
+
+ /* does the property exist, and match the trigger value? */
+ value = property_get(prop_name);
+ if (value && !strcmp(equals + 1, value)) {
+ action_add_queue_tail(act);
+ }
+ }
+ }
+ }
+ }
+}
+
+void queue_builtin_action(int (*func)(int nargs, char **args), char *name)
+{
+ struct action *act;
+ struct command *cmd;
+
+ act = calloc(1, sizeof(*act));
+ act->name = name;
+ list_init(&act->commands);
+
+ cmd = calloc(1, sizeof(*cmd));
+ cmd->func = func;
+ cmd->args[0] = name;
+ list_add_tail(&act->commands, &cmd->clist);
+
+ list_add_tail(&action_list, &act->alist);
+ action_add_queue_tail(act);
+}
+
+void action_add_queue_tail(struct action *act)
+{
+ list_add_tail(&action_queue, &act->qlist);
+}
+
+struct action *action_remove_queue_head(void)
+{
+ if (list_empty(&action_queue)) {
+ return 0;
+ } else {
+ struct listnode *node = list_head(&action_queue);
+ struct action *act = node_to_item(node, struct action, qlist);
+ list_remove(node);
+ return act;
+ }
+}
+
+int action_queue_empty()
+{
+ return list_empty(&action_queue);
+}
+
+static void *parse_service(struct parse_state *state, int nargs, char **args)
+{
+ struct service *svc;
+ if (nargs < 3) {
+ parse_error(state, "services must have a name and a program\n");
+ return 0;
+ }
+ if (!valid_name(args[1])) {
+ parse_error(state, "invalid service name '%s'\n", args[1]);
+ return 0;
+ }
+
+ svc = service_find_by_name(args[1]);
+ if (svc) {
+ parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
+ return 0;
+ }
+
+ nargs -= 2;
+ svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
+ if (!svc) {
+ parse_error(state, "out of memory\n");
+ return 0;
+ }
+ svc->name = args[1];
+ svc->classname = "default";
+ memcpy(svc->args, args + 2, sizeof(char*) * nargs);
+ svc->args[nargs] = 0;
+ svc->nargs = nargs;
+ svc->onrestart.name = "onrestart";
+ list_init(&svc->onrestart.commands);
+ list_add_tail(&service_list, &svc->slist);
+ return svc;
+}
+
+static void parse_line_service(struct parse_state *state, int nargs, char **args)
+{
+ struct service *svc = state->context;
+ struct command *cmd;
+ int i, kw, kw_nargs;
+
+ if (nargs == 0) {
+ return;
+ }
+
+ svc->ioprio_class = IoSchedClass_NONE;
+
+ kw = lookup_keyword(args[0]);
+ switch (kw) {
+ case K_capability:
+ break;
+ case K_class:
+ if (nargs != 2) {
+ parse_error(state, "class option requires a classname\n");
+ } else {
+ svc->classname = args[1];
+ }
+ break;
+ case K_console:
+ svc->flags |= SVC_CONSOLE;
+ break;
+ case K_disabled:
+ svc->flags |= SVC_DISABLED;
+ break;
+ case K_ioprio:
+ if (nargs != 3) {
+ parse_error(state, "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n");
+ } else {
+ svc->ioprio_pri = strtoul(args[2], 0, 8);
+
+ if (svc->ioprio_pri < 0 || svc->ioprio_pri > 7) {
+ parse_error(state, "priority value must be range 0 - 7\n");
+ break;
+ }
+
+ if (!strcmp(args[1], "rt")) {
+ svc->ioprio_class = IoSchedClass_RT;
+ } else if (!strcmp(args[1], "be")) {
+ svc->ioprio_class = IoSchedClass_BE;
+ } else if (!strcmp(args[1], "idle")) {
+ svc->ioprio_class = IoSchedClass_IDLE;
+ } else {
+ parse_error(state, "ioprio option usage: ioprio <rt|be|idle> <0-7>\n");
+ }
+ }
+ break;
+ case K_group:
+ if (nargs < 2) {
+ parse_error(state, "group option requires a group id\n");
+ } else if (nargs > NR_SVC_SUPP_GIDS + 2) {
+ parse_error(state, "group option accepts at most %d supp. groups\n",
+ NR_SVC_SUPP_GIDS);
+ } else {
+ int n;
+ svc->gid = decode_uid(args[1]);
+ for (n = 2; n < nargs; n++) {
+ svc->supp_gids[n-2] = decode_uid(args[n]);
+ }
+ svc->nr_supp_gids = n - 2;
+ }
+ break;
+ case K_keycodes:
+ if (nargs < 2) {
+ parse_error(state, "keycodes option requires atleast one keycode\n");
+ } else {
+ svc->keycodes = malloc((nargs - 1) * sizeof(svc->keycodes[0]));
+ if (!svc->keycodes) {
+ parse_error(state, "could not allocate keycodes\n");
+ } else {
+ svc->nkeycodes = nargs - 1;
+ for (i = 1; i < nargs; i++) {
+ svc->keycodes[i - 1] = atoi(args[i]);
+ }
+ }
+ }
+ break;
+ case K_oneshot:
+ svc->flags |= SVC_ONESHOT;
+ break;
+ case K_onrestart:
+ nargs--;
+ args++;
+ kw = lookup_keyword(args[0]);
+ if (!kw_is(kw, COMMAND)) {
+ parse_error(state, "invalid command '%s'\n", args[0]);
+ break;
+ }
+ kw_nargs = kw_nargs(kw);
+ if (nargs < kw_nargs) {
+ parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
+ kw_nargs > 2 ? "arguments" : "argument");
+ break;
+ }
+
+ cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
+ cmd->func = kw_func(kw);
+ cmd->nargs = nargs;
+ memcpy(cmd->args, args, sizeof(char*) * nargs);
+ list_add_tail(&svc->onrestart.commands, &cmd->clist);
+ break;
+ case K_critical:
+ svc->flags |= SVC_CRITICAL;
+ break;
+ case K_setenv: { /* name value */
+ struct svcenvinfo *ei;
+ if (nargs < 2) {
+ parse_error(state, "setenv option requires name and value arguments\n");
+ break;
+ }
+ ei = calloc(1, sizeof(*ei));
+ if (!ei) {
+ parse_error(state, "out of memory\n");
+ break;
+ }
+ ei->name = args[1];
+ ei->value = args[2];
+ ei->next = svc->envvars;
+ svc->envvars = ei;
+ break;
+ }
+ case K_socket: {/* name type perm [ uid gid ] */
+ struct socketinfo *si;
+ if (nargs < 4) {
+ parse_error(state, "socket option requires name, type, perm arguments\n");
+ break;
+ }
+ if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")
+ && strcmp(args[2],"seqpacket")) {
+ parse_error(state, "socket type must be 'dgram', 'stream' or 'seqpacket'\n");
+ break;
+ }
+ si = calloc(1, sizeof(*si));
+ if (!si) {
+ parse_error(state, "out of memory\n");
+ break;
+ }
+ si->name = args[1];
+ si->type = args[2];
+ si->perm = strtoul(args[3], 0, 8);
+ if (nargs > 4)
+ si->uid = decode_uid(args[4]);
+ if (nargs > 5)
+ si->gid = decode_uid(args[5]);
+ si->next = svc->sockets;
+ svc->sockets = si;
+ break;
+ }
+ case K_user:
+ if (nargs != 2) {
+ parse_error(state, "user option requires a user id\n");
+ } else {
+ svc->uid = decode_uid(args[1]);
+ }
+ break;
+ default:
+ parse_error(state, "invalid option '%s'\n", args[0]);
+ }
+}
+
+static void *parse_action(struct parse_state *state, int nargs, char **args)
+{
+ struct action *act;
+ if (nargs < 2) {
+ parse_error(state, "actions must have a trigger\n");
+ return 0;
+ }
+ if (nargs > 2) {
+ parse_error(state, "actions may not have extra parameters\n");
+ return 0;
+ }
+ act = calloc(1, sizeof(*act));
+ act->name = args[1];
+ list_init(&act->commands);
+ list_add_tail(&action_list, &act->alist);
+ /* XXX add to hash */
+ return act;
+}
+
+static void parse_line_action(struct parse_state* state, int nargs, char **args)
+{
+ struct command *cmd;
+ struct action *act = state->context;
+ int (*func)(int nargs, char **args);
+ int kw, n;
+
+ if (nargs == 0) {
+ return;
+ }
+
+ kw = lookup_keyword(args[0]);
+ if (!kw_is(kw, COMMAND)) {
+ parse_error(state, "invalid command '%s'\n", args[0]);
+ return;
+ }
+
+ n = kw_nargs(kw);
+ if (nargs < n) {
+ parse_error(state, "%s requires %d %s\n", args[0], n - 1,
+ n > 2 ? "arguments" : "argument");
+ return;
+ }
+ cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
+ cmd->func = kw_func(kw);
+ cmd->nargs = nargs;
+ memcpy(cmd->args, args, sizeof(char*) * nargs);
+ list_add_tail(&act->commands, &cmd->clist);
+}
diff --git a/init/init_parser.h b/init/init_parser.h
new file mode 100644
index 0000000..ff13b04
--- /dev/null
+++ b/init/init_parser.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_INIT_PARSER_H_
+#define _INIT_INIT_PARSER_H_
+
+#define INIT_PARSER_MAXARGS 64
+
+struct action;
+
+struct action *action_remove_queue_head(void);
+void action_add_queue_tail(struct action *act);
+void action_for_each_trigger(const char *trigger,
+ void (*func)(struct action *act));
+int action_queue_empty(void);
+void queue_property_triggers(const char *name, const char *value);
+void queue_all_property_triggers();
+void queue_builtin_action(int (*func)(int nargs, char **args), char *name);
+
+int init_parse_config_file(const char *fn);
+
+#endif
diff --git a/init/keychords.c b/init/keychords.c
new file mode 100644
index 0000000..53ab391
--- /dev/null
+++ b/init/keychords.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <linux/keychord.h>
+
+#include "init.h"
+#include "log.h"
+#include "property_service.h"
+
+static struct input_keychord *keychords = 0;
+static int keychords_count = 0;
+static int keychords_length = 0;
+static int keychord_fd = -1;
+
+void add_service_keycodes(struct service *svc)
+{
+ struct input_keychord *keychord;
+ int i, size;
+
+ if (svc->keycodes) {
+ /* add a new keychord to the list */
+ size = sizeof(*keychord) + svc->nkeycodes * sizeof(keychord->keycodes[0]);
+ keychords = realloc(keychords, keychords_length + size);
+ if (!keychords) {
+ ERROR("could not allocate keychords\n");
+ keychords_length = 0;
+ keychords_count = 0;
+ return;
+ }
+
+ keychord = (struct input_keychord *)((char *)keychords + keychords_length);
+ keychord->version = KEYCHORD_VERSION;
+ keychord->id = keychords_count + 1;
+ keychord->count = svc->nkeycodes;
+ svc->keychord_id = keychord->id;
+
+ for (i = 0; i < svc->nkeycodes; i++) {
+ keychord->keycodes[i] = svc->keycodes[i];
+ }
+ keychords_count++;
+ keychords_length += size;
+ }
+}
+
+void keychord_init()
+{
+ int fd, ret;
+
+ service_for_each(add_service_keycodes);
+
+ /* nothing to do if no services require keychords */
+ if (!keychords)
+ return;
+
+ fd = open("/dev/keychord", O_RDWR);
+ if (fd < 0) {
+ ERROR("could not open /dev/keychord\n");
+ return;
+ }
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ ret = write(fd, keychords, keychords_length);
+ if (ret != keychords_length) {
+ ERROR("could not configure /dev/keychord %d (%d)\n", ret, errno);
+ close(fd);
+ fd = -1;
+ }
+
+ free(keychords);
+ keychords = 0;
+
+ keychord_fd = fd;
+}
+
+void handle_keychord()
+{
+ struct service *svc;
+ const char* debuggable;
+ const char* adb_enabled;
+ int ret;
+ __u16 id;
+
+ // only handle keychords if ro.debuggable is set or adb is enabled.
+ // the logic here is that bugreports should be enabled in userdebug or eng builds
+ // and on user builds for users that are developers.
+ debuggable = property_get("ro.debuggable");
+ adb_enabled = property_get("init.svc.adbd");
+ if ((debuggable && !strcmp(debuggable, "1")) ||
+ (adb_enabled && !strcmp(adb_enabled, "running"))) {
+ ret = read(keychord_fd, &id, sizeof(id));
+ if (ret != sizeof(id)) {
+ ERROR("could not read keychord id\n");
+ return;
+ }
+
+ svc = service_find_by_keychord(id);
+ if (svc) {
+ INFO("starting service %s from keychord\n", svc->name);
+ service_start(svc, NULL);
+ } else {
+ ERROR("service for keychord %d not found\n", id);
+ }
+ }
+}
+
+int get_keychord_fd()
+{
+ return keychord_fd;
+}
diff --git a/init/keychords.h b/init/keychords.h
new file mode 100644
index 0000000..070b858
--- /dev/null
+++ b/init/keychords.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_KEYCHORDS_H_
+#define _INIT_KEYCHORDS_H_
+
+struct service;
+
+void add_service_keycodes(struct service *svc);
+void keychord_init(void);
+void handle_keychord(void);
+int get_keychord_fd(void);
+
+#endif
diff --git a/init/keywords.h b/init/keywords.h
index 254c785..25315d8 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -27,7 +27,7 @@
int do_chown(int nargs, char **args);
int do_chmod(int nargs, char **args);
int do_loglevel(int nargs, char **args);
-int do_device(int nargs, char **args);
+int do_wait(int nargs, char **args);
#define __MAKE_KEYWORD_ENUM__
#define KEYWORD(symbol, flags, nargs, func) K_##symbol,
enum {
@@ -69,12 +69,12 @@
KEYWORD(symlink, COMMAND, 1, do_symlink)
KEYWORD(sysclktz, COMMAND, 1, do_sysclktz)
KEYWORD(user, OPTION, 0, 0)
+ KEYWORD(wait, COMMAND, 1, do_wait)
KEYWORD(write, COMMAND, 2, do_write)
KEYWORD(copy, COMMAND, 2, do_copy)
KEYWORD(chown, COMMAND, 2, do_chown)
KEYWORD(chmod, COMMAND, 2, do_chmod)
KEYWORD(loglevel, COMMAND, 1, do_loglevel)
- KEYWORD(device, COMMAND, 4, do_device)
KEYWORD(ioprio, OPTION, 0, 0)
#ifdef __MAKE_KEYWORD_ENUM__
KEYWORD_COUNT,
diff --git a/init/list.h b/init/list.h
new file mode 100644
index 0000000..0a7b28c
--- /dev/null
+++ b/init/list.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_LIST_H_
+#define _INIT_LIST_H_
+
+struct listnode
+{
+ struct listnode *next;
+ struct listnode *prev;
+};
+
+#define node_to_item(node, container, member) \
+ (container *) (((char*) (node)) - offsetof(container, member))
+
+#define list_declare(name) \
+ struct listnode name = { \
+ .next = &name, \
+ .prev = &name, \
+ }
+
+#define list_for_each(node, list) \
+ for (node = (list)->next; node != (list); node = node->next)
+
+#define list_for_each_reverse(node, list) \
+ for (node = (list)->prev; node != (list); node = node->prev)
+
+void list_init(struct listnode *list);
+void list_add_tail(struct listnode *list, struct listnode *item);
+void list_remove(struct listnode *item);
+
+#define list_empty(list) ((list) == (list)->next)
+#define list_head(list) ((list)->next)
+#define list_tail(list) ((list)->prev)
+
+#endif
diff --git a/init/log.h b/init/log.h
new file mode 100644
index 0000000..3d93965
--- /dev/null
+++ b/init/log.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_LOG_H_
+#define _INIT_LOG_H_
+
+void log_init(void);
+void log_set_level(int level);
+void log_close(void);
+void log_write(int level, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+
+#define ERROR(x...) log_write(3, "<3>init: " x)
+#define NOTICE(x...) log_write(5, "<5>init: " x)
+#define INFO(x...) log_write(6, "<6>init: " x)
+
+#define LOG_DEFAULT_LEVEL 3 /* messages <= this level are logged */
+#define LOG_UEVENTS 0 /* log uevent messages if 1. verbose */
+
+#endif
diff --git a/init/logo.c b/init/logo.c
index 6a740bf..614224c 100644
--- a/init/logo.c
+++ b/init/logo.c
@@ -25,7 +25,7 @@
#include <linux/fb.h>
#include <linux/kd.h>
-#include "init.h"
+#include "log.h"
#ifdef ANDROID
#include <cutils/memory.h>
diff --git a/init/parser.c b/init/parser.c
index ca03da9..2f36ac7 100644
--- a/init/parser.c
+++ b/init/parser.c
@@ -1,23 +1,10 @@
#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
-#include <stddef.h>
-#include <ctype.h>
-#include "init.h"
-#include "property_service.h"
-
-#include <cutils/iosched_policy.h>
-
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
-static list_declare(service_list);
-static list_declare(action_list);
-static list_declare(action_queue);
+#include "parser.h"
+#include "list.h"
+#include "log.h"
#define RAW(x...) log_write(6, x)
@@ -62,27 +49,6 @@
#endif
}
-#define T_EOF 0
-#define T_TEXT 1
-#define T_NEWLINE 2
-
-struct parse_state
-{
- char *ptr;
- char *text;
- int line;
- int nexttoken;
- void *context;
- void (*parse_line)(struct parse_state *state, int nargs, char **args);
- const char *filename;
-};
-
-static void *parse_service(struct parse_state *state, int nargs, char **args);
-static void parse_line_service(struct parse_state *state, int nargs, char **args);
-
-static void *parse_action(struct parse_state *state, int nargs, char **args);
-static void parse_line_action(struct parse_state *state, int nargs, char **args);
-
void parse_error(struct parse_state *state, const char *fmt, ...)
{
va_list ap;
@@ -100,115 +66,6 @@
ERROR("%s", buf);
}
-#define SECTION 0x01
-#define COMMAND 0x02
-#define OPTION 0x04
-
-#include "keywords.h"
-
-#define KEYWORD(symbol, flags, nargs, func) \
- [ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
-
-struct {
- const char *name;
- int (*func)(int nargs, char **args);
- unsigned char nargs;
- unsigned char flags;
-} keyword_info[KEYWORD_COUNT] = {
- [ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
-#include "keywords.h"
-};
-#undef KEYWORD
-
-#define kw_is(kw, type) (keyword_info[kw].flags & (type))
-#define kw_name(kw) (keyword_info[kw].name)
-#define kw_func(kw) (keyword_info[kw].func)
-#define kw_nargs(kw) (keyword_info[kw].nargs)
-
-int lookup_keyword(const char *s)
-{
- switch (*s++) {
- case 'c':
- if (!strcmp(s, "opy")) return K_copy;
- if (!strcmp(s, "apability")) return K_capability;
- if (!strcmp(s, "hdir")) return K_chdir;
- if (!strcmp(s, "hroot")) return K_chroot;
- if (!strcmp(s, "lass")) return K_class;
- if (!strcmp(s, "lass_start")) return K_class_start;
- if (!strcmp(s, "lass_stop")) return K_class_stop;
- if (!strcmp(s, "onsole")) return K_console;
- if (!strcmp(s, "hown")) return K_chown;
- if (!strcmp(s, "hmod")) return K_chmod;
- if (!strcmp(s, "ritical")) return K_critical;
- break;
- case 'd':
- if (!strcmp(s, "isabled")) return K_disabled;
- if (!strcmp(s, "omainname")) return K_domainname;
- if (!strcmp(s, "evice")) return K_device;
- break;
- case 'e':
- if (!strcmp(s, "xec")) return K_exec;
- if (!strcmp(s, "xport")) return K_export;
- break;
- case 'g':
- if (!strcmp(s, "roup")) return K_group;
- break;
- case 'h':
- if (!strcmp(s, "ostname")) return K_hostname;
- break;
- case 'i':
- if (!strcmp(s, "oprio")) return K_ioprio;
- if (!strcmp(s, "fup")) return K_ifup;
- if (!strcmp(s, "nsmod")) return K_insmod;
- if (!strcmp(s, "mport")) return K_import;
- break;
- case 'k':
- if (!strcmp(s, "eycodes")) return K_keycodes;
- break;
- case 'l':
- if (!strcmp(s, "oglevel")) return K_loglevel;
- break;
- case 'm':
- if (!strcmp(s, "kdir")) return K_mkdir;
- if (!strcmp(s, "ount")) return K_mount;
- break;
- case 'o':
- if (!strcmp(s, "n")) return K_on;
- if (!strcmp(s, "neshot")) return K_oneshot;
- if (!strcmp(s, "nrestart")) return K_onrestart;
- break;
- case 'r':
- if (!strcmp(s, "estart")) return K_restart;
- break;
- case 's':
- if (!strcmp(s, "ervice")) return K_service;
- if (!strcmp(s, "etenv")) return K_setenv;
- if (!strcmp(s, "etkey")) return K_setkey;
- if (!strcmp(s, "etprop")) return K_setprop;
- if (!strcmp(s, "etrlimit")) return K_setrlimit;
- if (!strcmp(s, "ocket")) return K_socket;
- if (!strcmp(s, "tart")) return K_start;
- if (!strcmp(s, "top")) return K_stop;
- if (!strcmp(s, "ymlink")) return K_symlink;
- if (!strcmp(s, "ysclktz")) return K_sysclktz;
- break;
- case 't':
- if (!strcmp(s, "rigger")) return K_trigger;
- break;
- case 'u':
- if (!strcmp(s, "ser")) return K_user;
- break;
- case 'w':
- if (!strcmp(s, "rite")) return K_write;
- break;
- }
- return K_UNKNOWN;
-}
-
-void parse_line_no_op(struct parse_state *state, int nargs, char **args)
-{
-}
-
int next_token(struct parse_state *state)
{
char *x = state->ptr;
@@ -322,512 +179,3 @@
}
return T_EOF;
}
-
-void parse_line(int nargs, char **args)
-{
- int n;
- int id = lookup_keyword(args[0]);
- printf("%s(%d)", args[0], id);
- for (n = 1; n < nargs; n++) {
- printf(" '%s'", args[n]);
- }
- printf("\n");
-}
-
-void parse_new_section(struct parse_state *state, int kw,
- int nargs, char **args)
-{
- printf("[ %s %s ]\n", args[0],
- nargs > 1 ? args[1] : "");
- switch(kw) {
- case K_service:
- state->context = parse_service(state, nargs, args);
- if (state->context) {
- state->parse_line = parse_line_service;
- return;
- }
- break;
- case K_on:
- state->context = parse_action(state, nargs, args);
- if (state->context) {
- state->parse_line = parse_line_action;
- return;
- }
- break;
- }
- state->parse_line = parse_line_no_op;
-}
-
-static void parse_config(const char *fn, char *s)
-{
- struct parse_state state;
- char *args[SVC_MAXARGS];
- int nargs;
-
- nargs = 0;
- state.filename = fn;
- state.line = 1;
- state.ptr = s;
- state.nexttoken = 0;
- state.parse_line = parse_line_no_op;
- for (;;) {
- switch (next_token(&state)) {
- case T_EOF:
- state.parse_line(&state, 0, 0);
- return;
- case T_NEWLINE:
- if (nargs) {
- int kw = lookup_keyword(args[0]);
- if (kw_is(kw, SECTION)) {
- state.parse_line(&state, 0, 0);
- parse_new_section(&state, kw, nargs, args);
- } else {
- state.parse_line(&state, nargs, args);
- }
- nargs = 0;
- }
- break;
- case T_TEXT:
- if (nargs < SVC_MAXARGS) {
- args[nargs++] = state.text;
- }
- break;
- }
- }
-}
-
-int parse_config_file(const char *fn)
-{
- char *data;
- data = read_file(fn, 0);
- if (!data) return -1;
-
- parse_config(fn, data);
- DUMP();
- return 0;
-}
-
-static int valid_name(const char *name)
-{
- if (strlen(name) > 16) {
- return 0;
- }
- while (*name) {
- if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
- return 0;
- }
- name++;
- }
- return 1;
-}
-
-struct service *service_find_by_name(const char *name)
-{
- struct listnode *node;
- struct service *svc;
- list_for_each(node, &service_list) {
- svc = node_to_item(node, struct service, slist);
- if (!strcmp(svc->name, name)) {
- return svc;
- }
- }
- return 0;
-}
-
-struct service *service_find_by_pid(pid_t pid)
-{
- struct listnode *node;
- struct service *svc;
- list_for_each(node, &service_list) {
- svc = node_to_item(node, struct service, slist);
- if (svc->pid == pid) {
- return svc;
- }
- }
- return 0;
-}
-
-struct service *service_find_by_keychord(int keychord_id)
-{
- struct listnode *node;
- struct service *svc;
- list_for_each(node, &service_list) {
- svc = node_to_item(node, struct service, slist);
- if (svc->keychord_id == keychord_id) {
- return svc;
- }
- }
- return 0;
-}
-
-void service_for_each(void (*func)(struct service *svc))
-{
- struct listnode *node;
- struct service *svc;
- list_for_each(node, &service_list) {
- svc = node_to_item(node, struct service, slist);
- func(svc);
- }
-}
-
-void service_for_each_class(const char *classname,
- void (*func)(struct service *svc))
-{
- struct listnode *node;
- struct service *svc;
- list_for_each(node, &service_list) {
- svc = node_to_item(node, struct service, slist);
- if (!strcmp(svc->classname, classname)) {
- func(svc);
- }
- }
-}
-
-void service_for_each_flags(unsigned matchflags,
- void (*func)(struct service *svc))
-{
- struct listnode *node;
- struct service *svc;
- list_for_each(node, &service_list) {
- svc = node_to_item(node, struct service, slist);
- if (svc->flags & matchflags) {
- func(svc);
- }
- }
-}
-
-void action_for_each_trigger(const char *trigger,
- void (*func)(struct action *act))
-{
- struct listnode *node;
- struct action *act;
- list_for_each(node, &action_list) {
- act = node_to_item(node, struct action, alist);
- if (!strcmp(act->name, trigger)) {
- func(act);
- }
- }
-}
-
-void queue_property_triggers(const char *name, const char *value)
-{
- struct listnode *node;
- struct action *act;
- list_for_each(node, &action_list) {
- act = node_to_item(node, struct action, alist);
- if (!strncmp(act->name, "property:", strlen("property:"))) {
- const char *test = act->name + strlen("property:");
- int name_length = strlen(name);
-
- if (!strncmp(name, test, name_length) &&
- test[name_length] == '=' &&
- !strcmp(test + name_length + 1, value)) {
- action_add_queue_tail(act);
- }
- }
- }
-}
-
-void queue_all_property_triggers()
-{
- struct listnode *node;
- struct action *act;
- list_for_each(node, &action_list) {
- act = node_to_item(node, struct action, alist);
- if (!strncmp(act->name, "property:", strlen("property:"))) {
- /* parse property name and value
- syntax is property:<name>=<value> */
- const char* name = act->name + strlen("property:");
- const char* equals = strchr(name, '=');
- if (equals) {
- char prop_name[PROP_NAME_MAX + 1];
- const char* value;
- int length = equals - name;
- if (length > PROP_NAME_MAX) {
- ERROR("property name too long in trigger %s", act->name);
- } else {
- memcpy(prop_name, name, length);
- prop_name[length] = 0;
-
- /* does the property exist, and match the trigger value? */
- value = property_get(prop_name);
- if (value && !strcmp(equals + 1, value)) {
- action_add_queue_tail(act);
- }
- }
- }
- }
- }
-}
-
-void action_add_queue_tail(struct action *act)
-{
- list_add_tail(&action_queue, &act->qlist);
-}
-
-struct action *action_remove_queue_head(void)
-{
- if (list_empty(&action_queue)) {
- return 0;
- } else {
- struct listnode *node = list_head(&action_queue);
- struct action *act = node_to_item(node, struct action, qlist);
- list_remove(node);
- return act;
- }
-}
-
-static void *parse_service(struct parse_state *state, int nargs, char **args)
-{
- struct service *svc;
- if (nargs < 3) {
- parse_error(state, "services must have a name and a program\n");
- return 0;
- }
- if (!valid_name(args[1])) {
- parse_error(state, "invalid service name '%s'\n", args[1]);
- return 0;
- }
-
- svc = service_find_by_name(args[1]);
- if (svc) {
- parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
- return 0;
- }
-
- nargs -= 2;
- svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
- if (!svc) {
- parse_error(state, "out of memory\n");
- return 0;
- }
- svc->name = args[1];
- svc->classname = "default";
- memcpy(svc->args, args + 2, sizeof(char*) * nargs);
- svc->args[nargs] = 0;
- svc->nargs = nargs;
- svc->onrestart.name = "onrestart";
- list_init(&svc->onrestart.commands);
- list_add_tail(&service_list, &svc->slist);
- return svc;
-}
-
-static void parse_line_service(struct parse_state *state, int nargs, char **args)
-{
- struct service *svc = state->context;
- struct command *cmd;
- int i, kw, kw_nargs;
-
- if (nargs == 0) {
- return;
- }
-
- svc->ioprio_class = IoSchedClass_NONE;
-
- kw = lookup_keyword(args[0]);
- switch (kw) {
- case K_capability:
- break;
- case K_class:
- if (nargs != 2) {
- parse_error(state, "class option requires a classname\n");
- } else {
- svc->classname = args[1];
- }
- break;
- case K_console:
- svc->flags |= SVC_CONSOLE;
- break;
- case K_disabled:
- svc->flags |= SVC_DISABLED;
- break;
- case K_ioprio:
- if (nargs != 3) {
- parse_error(state, "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n");
- } else {
- svc->ioprio_pri = strtoul(args[2], 0, 8);
-
- if (svc->ioprio_pri < 0 || svc->ioprio_pri > 7) {
- parse_error(state, "priority value must be range 0 - 7\n");
- break;
- }
-
- if (!strcmp(args[1], "rt")) {
- svc->ioprio_class = IoSchedClass_RT;
- } else if (!strcmp(args[1], "be")) {
- svc->ioprio_class = IoSchedClass_BE;
- } else if (!strcmp(args[1], "idle")) {
- svc->ioprio_class = IoSchedClass_IDLE;
- } else {
- parse_error(state, "ioprio option usage: ioprio <rt|be|idle> <0-7>\n");
- }
- }
- break;
- case K_group:
- if (nargs < 2) {
- parse_error(state, "group option requires a group id\n");
- } else if (nargs > NR_SVC_SUPP_GIDS + 2) {
- parse_error(state, "group option accepts at most %d supp. groups\n",
- NR_SVC_SUPP_GIDS);
- } else {
- int n;
- svc->gid = decode_uid(args[1]);
- for (n = 2; n < nargs; n++) {
- svc->supp_gids[n-2] = decode_uid(args[n]);
- }
- svc->nr_supp_gids = n - 2;
- }
- break;
- case K_keycodes:
- if (nargs < 2) {
- parse_error(state, "keycodes option requires atleast one keycode\n");
- } else {
- svc->keycodes = malloc((nargs - 1) * sizeof(svc->keycodes[0]));
- if (!svc->keycodes) {
- parse_error(state, "could not allocate keycodes\n");
- } else {
- svc->nkeycodes = nargs - 1;
- for (i = 1; i < nargs; i++) {
- svc->keycodes[i - 1] = atoi(args[i]);
- }
- }
- }
- break;
- case K_oneshot:
- svc->flags |= SVC_ONESHOT;
- break;
- case K_onrestart:
- nargs--;
- args++;
- kw = lookup_keyword(args[0]);
- if (!kw_is(kw, COMMAND)) {
- parse_error(state, "invalid command '%s'\n", args[0]);
- break;
- }
- kw_nargs = kw_nargs(kw);
- if (nargs < kw_nargs) {
- parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
- kw_nargs > 2 ? "arguments" : "argument");
- break;
- }
-
- cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
- cmd->func = kw_func(kw);
- cmd->nargs = nargs;
- memcpy(cmd->args, args, sizeof(char*) * nargs);
- list_add_tail(&svc->onrestart.commands, &cmd->clist);
- break;
- case K_critical:
- svc->flags |= SVC_CRITICAL;
- break;
- case K_setenv: { /* name value */
- struct svcenvinfo *ei;
- if (nargs < 2) {
- parse_error(state, "setenv option requires name and value arguments\n");
- break;
- }
- ei = calloc(1, sizeof(*ei));
- if (!ei) {
- parse_error(state, "out of memory\n");
- break;
- }
- ei->name = args[1];
- ei->value = args[2];
- ei->next = svc->envvars;
- svc->envvars = ei;
- break;
- }
- case K_socket: {/* name type perm [ uid gid ] */
- struct socketinfo *si;
- if (nargs < 4) {
- parse_error(state, "socket option requires name, type, perm arguments\n");
- break;
- }
- if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")) {
- parse_error(state, "socket type must be 'dgram' or 'stream'\n");
- break;
- }
- si = calloc(1, sizeof(*si));
- if (!si) {
- parse_error(state, "out of memory\n");
- break;
- }
- si->name = args[1];
- si->type = args[2];
- si->perm = strtoul(args[3], 0, 8);
- if (nargs > 4)
- si->uid = decode_uid(args[4]);
- if (nargs > 5)
- si->gid = decode_uid(args[5]);
- si->next = svc->sockets;
- svc->sockets = si;
- break;
- }
- case K_user:
- if (nargs != 2) {
- parse_error(state, "user option requires a user id\n");
- } else {
- svc->uid = decode_uid(args[1]);
- }
- break;
- default:
- parse_error(state, "invalid option '%s'\n", args[0]);
- }
-}
-
-static void *parse_action(struct parse_state *state, int nargs, char **args)
-{
- struct action *act;
- if (nargs < 2) {
- parse_error(state, "actions must have a trigger\n");
- return 0;
- }
- if (nargs > 2) {
- parse_error(state, "actions may not have extra parameters\n");
- return 0;
- }
- act = calloc(1, sizeof(*act));
- act->name = args[1];
- list_init(&act->commands);
- list_add_tail(&action_list, &act->alist);
- /* XXX add to hash */
- return act;
-}
-
-static void parse_line_action(struct parse_state* state, int nargs, char **args)
-{
- struct command *cmd;
- struct action *act = state->context;
- int (*func)(int nargs, char **args);
- int kw, n;
- int alloc_size = 0;
-
- if (nargs == 0) {
- return;
- }
-
- kw = lookup_keyword(args[0]);
- if (!kw_is(kw, COMMAND)) {
- parse_error(state, "invalid command '%s'\n", args[0]);
- return;
- }
-
- n = kw_nargs(kw);
- if (nargs < n) {
- parse_error(state, "%s requires %d %s\n", args[0], n - 1,
- n > 2 ? "arguments" : "argument");
- return;
- }
- alloc_size = sizeof(*cmd) + sizeof(char*) * (nargs + 1);
- cmd = malloc(alloc_size);
- if (!cmd) {
- parse_error(state, "malloc failed\n");
- return;
- }
-
- memset((char *)cmd, 0, alloc_size);
- cmd->func = kw_func(kw);
- cmd->nargs = nargs;
- memcpy(cmd->args, args, sizeof(char*) * nargs);
- list_add_tail(&act->commands, &cmd->clist);
-}
diff --git a/init/parser.h b/init/parser.h
new file mode 100644
index 0000000..be93758
--- /dev/null
+++ b/init/parser.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PARSER_H_
+#define PARSER_H_
+
+#define T_EOF 0
+#define T_TEXT 1
+#define T_NEWLINE 2
+
+struct parse_state
+{
+ char *ptr;
+ char *text;
+ int line;
+ int nexttoken;
+ void *context;
+ void (*parse_line)(struct parse_state *state, int nargs, char **args);
+ const char *filename;
+};
+
+int lookup_keyword(const char *s);
+void DUMP(void);
+int next_token(struct parse_state *state);
+void parse_error(struct parse_state *state, const char *fmt, ...);
+
+#endif /* PARSER_H_ */
diff --git a/init/property_service.c b/init/property_service.c
index d2505dd..d8fea56 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -27,7 +27,6 @@
#include <cutils/misc.h>
#include <cutils/sockets.h>
-#include <cutils/ashmem.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
@@ -43,10 +42,15 @@
#include "property_service.h"
#include "init.h"
+#include "util.h"
+#include "log.h"
#define PERSISTENT_PROPERTY_DIR "/data/property"
static int persistent_properties_loaded = 0;
+static int property_area_inited = 0;
+
+static int property_set_fd = -1;
/* White list of permissions for setting property services. */
struct {
@@ -105,21 +109,31 @@
void *data;
int fd;
- fd = ashmem_create_region("system_properties", size);
- if(fd < 0)
+ /* dev is a tmpfs that we can use to carve a shared workspace
+ * out of, so let's do that...
+ */
+ fd = open("/dev/__properties__", O_RDWR | O_CREAT, 0600);
+ 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;
- /* allow the wolves we share with to do nothing but read */
- ashmem_set_prot_region(fd, PROT_READ);
+ close(fd);
+
+ fd = open("/dev/__properties__", O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ unlink("/dev/__properties__");
w->data = data;
w->size = size;
w->fd = fd;
-
return 0;
out:
@@ -160,7 +174,7 @@
/* plug into the lib property services */
__system_property_area__ = pa;
-
+ property_area_inited = 1;
return 0;
}
@@ -187,7 +201,7 @@
*
* Returns 1 if uid allowed, 0 otherwise.
*/
-static int check_control_perms(const char *name, int uid, int gid) {
+static int check_control_perms(const char *name, unsigned int uid, unsigned int gid) {
int i;
if (uid == AID_SYSTEM || uid == AID_ROOT)
return 1;
@@ -208,7 +222,7 @@
* Checks permissions for setting system properties.
* Returns 1 if uid allowed, 0 otherwise.
*/
-static int check_perms(const char *name, unsigned int uid, int gid)
+static int check_perms(const char *name, unsigned int uid, unsigned int gid)
{
int i;
if (uid == 0)
@@ -344,7 +358,7 @@
return 0;
}
-void handle_property_set_fd(int fd)
+void handle_property_set_fd()
{
prop_msg msg;
int s;
@@ -355,7 +369,7 @@
socklen_t addr_size = sizeof(addr);
socklen_t cr_size = sizeof(cr);
- if ((s = accept(fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
+ if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
return;
}
@@ -493,7 +507,12 @@
load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
}
-int start_property_service(void)
+int properties_inited(void)
+{
+ return property_area_inited;
+}
+
+void start_property_service(void)
{
int fd;
@@ -504,10 +523,15 @@
load_persistent_properties();
fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);
- if(fd < 0) return -1;
+ if(fd < 0) return;
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, O_NONBLOCK);
listen(fd, 8);
- return fd;
+ property_set_fd = fd;
+}
+
+int get_property_set_fd()
+{
+ return property_set_fd;
}
diff --git a/init/property_service.h b/init/property_service.h
index d12f1f3..045d20a 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -17,12 +17,13 @@
#ifndef _INIT_PROPERTY_H
#define _INIT_PROPERTY_H
-extern void handle_property_fd(int fd);
-extern void handle_property_set_fd(int fd);
+extern void handle_property_set_fd(void);
extern void property_init(void);
-extern int start_property_service(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_set(const char *name, const char *value);
+extern int properties_inited();
+int get_property_set_fd(void);
#endif /* _INIT_PROPERTY_H */
diff --git a/init/readme.txt b/init/readme.txt
index a185790..df524a6 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -72,7 +72,7 @@
socket <name> <type> <perm> [ <user> [ <group> ] ]
Create a unix domain socket named /dev/socket/<name> and pass
- its fd to the launched process. <type> must be "dgram" or "stream".
+ its fd to the launched process. <type> must be "dgram", "stream" or "seqpacket".
User and group default to 0.
user <username>
diff --git a/init/signal_handler.c b/init/signal_handler.c
new file mode 100644
index 0000000..3e5d136
--- /dev/null
+++ b/init/signal_handler.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <cutils/sockets.h>
+#include <sys/reboot.h>
+
+#include "init.h"
+#include "list.h"
+#include "util.h"
+#include "log.h"
+
+static int signal_fd = -1;
+static int signal_recv_fd = -1;
+
+static void sigchld_handler(int s)
+{
+ write(signal_fd, &s, 1);
+}
+
+#define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */
+#define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery*/
+
+static int wait_for_one_process(int block)
+{
+ pid_t pid;
+ int status;
+ struct service *svc;
+ struct socketinfo *si;
+ time_t now;
+ struct listnode *node;
+ struct command *cmd;
+
+ while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );
+ if (pid <= 0) return -1;
+ INFO("waitpid returned pid %d, status = %08x\n", pid, status);
+
+ svc = service_find_by_pid(pid);
+ if (!svc) {
+ ERROR("untracked pid %d exited\n", pid);
+ return 0;
+ }
+
+ NOTICE("process '%s', pid %d exited\n", svc->name, pid);
+
+ if (!(svc->flags & SVC_ONESHOT)) {
+ kill(-pid, SIGKILL);
+ NOTICE("process '%s' killing any children in process group\n", svc->name);
+ }
+
+ /* remove any sockets we may have created */
+ for (si = svc->sockets; si; si = si->next) {
+ char tmp[128];
+ snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
+ unlink(tmp);
+ }
+
+ svc->pid = 0;
+ svc->flags &= (~SVC_RUNNING);
+
+ /* oneshot processes go into the disabled state on exit */
+ if (svc->flags & SVC_ONESHOT) {
+ svc->flags |= SVC_DISABLED;
+ }
+
+ /* disabled processes do not get restarted automatically */
+ if (svc->flags & SVC_DISABLED) {
+ notify_service_state(svc->name, "stopped");
+ return 0;
+ }
+
+ now = gettime();
+ if (svc->flags & SVC_CRITICAL) {
+ if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
+ if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
+ ERROR("critical process '%s' exited %d times in %d minutes; "
+ "rebooting into recovery mode\n", svc->name,
+ CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
+ sync();
+ __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+ LINUX_REBOOT_CMD_RESTART2, "recovery");
+ return 0;
+ }
+ } else {
+ svc->time_crashed = now;
+ svc->nr_crashed = 1;
+ }
+ }
+
+ svc->flags |= SVC_RESTARTING;
+
+ /* Execute all onrestart commands for this service. */
+ list_for_each(node, &svc->onrestart.commands) {
+ cmd = node_to_item(node, struct command, clist);
+ cmd->func(cmd->nargs, cmd->args);
+ }
+ notify_service_state(svc->name, "restarting");
+ return 0;
+}
+
+void handle_signal(void)
+{
+ char tmp[32];
+
+ /* we got a SIGCHLD - reap and restart as needed */
+ read(signal_recv_fd, tmp, sizeof(tmp));
+ while (!wait_for_one_process(0))
+ ;
+}
+
+void signal_init(void)
+{
+ int s[2];
+
+ struct sigaction act;
+
+ act.sa_handler = sigchld_handler;
+ act.sa_flags = SA_NOCLDSTOP;
+ act.sa_mask = 0;
+ act.sa_restorer = NULL;
+ sigaction(SIGCHLD, &act, 0);
+
+ /* create a signalling mechanism for the sigchld handler */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
+ signal_fd = s[0];
+ signal_recv_fd = s[1];
+ fcntl(s[0], F_SETFD, FD_CLOEXEC);
+ fcntl(s[0], F_SETFL, O_NONBLOCK);
+ fcntl(s[1], F_SETFD, FD_CLOEXEC);
+ fcntl(s[1], F_SETFL, O_NONBLOCK);
+ }
+
+ handle_signal();
+}
+
+int get_signal_fd()
+{
+ return signal_recv_fd;
+}
diff --git a/init/signal_handler.h b/init/signal_handler.h
new file mode 100644
index 0000000..b092ccb
--- /dev/null
+++ b/init/signal_handler.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_SIGNAL_HANDLER_H_
+#define _INIT_SIGNAL_HANDLER_H_
+
+void signal_init(void);
+void handle_signal(void);
+int get_signal_fd(void);
+
+#endif
diff --git a/init/ueventd.c b/init/ueventd.c
new file mode 100644
index 0000000..0e97be7
--- /dev/null
+++ b/init/ueventd.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <poll.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <private/android_filesystem_config.h>
+
+#include "ueventd.h"
+#include "log.h"
+#include "util.h"
+#include "devices.h"
+#include "ueventd_parser.h"
+
+static char hardware[32];
+static unsigned revision = 0;
+
+int ueventd_main(int argc, char **argv)
+{
+ struct pollfd ufd;
+ int nr;
+ char tmp[32];
+
+ open_devnull_stdio();
+ log_init();
+
+ INFO("starting ueventd\n");
+
+ get_hardware_name(hardware, &revision);
+
+ ueventd_parse_config_file("/ueventd.rc");
+
+ snprintf(tmp, sizeof(tmp), "/ueventd.%s.rc", hardware);
+ ueventd_parse_config_file(tmp);
+
+ device_init();
+
+ ufd.events = POLLIN;
+ ufd.fd = get_device_fd();
+
+ while(1) {
+ ufd.revents = 0;
+ nr = poll(&ufd, 1, -1);
+ if (nr <= 0)
+ continue;
+ if (ufd.revents == POLLIN)
+ handle_device_fd();
+ }
+}
+
+static int get_android_id(const char *id)
+{
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(android_ids); i++)
+ if (!strcmp(id, android_ids[i].name))
+ return android_ids[i].aid;
+ return 0;
+}
+
+void set_device_permission(int nargs, char **args)
+{
+ char *name;
+ char *attr = 0;
+ mode_t perm;
+ uid_t uid;
+ gid_t gid;
+ int prefix = 0;
+ char *endptr;
+ int ret;
+ char *tmp = 0;
+
+ if (nargs == 0)
+ return;
+
+ if (args[0][0] == '#')
+ return;
+
+ name = args[0];
+
+ if (!strncmp(name,"/sys/", 5) && (nargs == 5)) {
+ INFO("/sys/ rule %s %s\n",args[0],args[1]);
+ attr = args[1];
+ args++;
+ nargs--;
+ }
+
+ if (nargs != 4) {
+ ERROR("invalid line ueventd.rc line for '%s'\n", args[0]);
+ return;
+ }
+
+ /* If path starts with mtd@ lookup the mount number. */
+ if (!strncmp(name, "mtd@", 4)) {
+ int n = mtd_name_to_number(name + 4);
+ if (n >= 0)
+ asprintf(&tmp, "/dev/mtd/mtd%d", n);
+ name = tmp;
+ } else {
+ int len = strlen(name);
+ if (name[len - 1] == '*') {
+ prefix = 1;
+ name[len - 1] = '\0';
+ }
+ }
+
+ perm = strtol(args[1], &endptr, 8);
+ if (!endptr || *endptr != '\0') {
+ ERROR("invalid mode '%s'\n", args[1]);
+ free(tmp);
+ return;
+ }
+
+ ret = get_android_id(args[2]);
+ if (ret < 0) {
+ ERROR("invalid uid '%s'\n", args[2]);
+ free(tmp);
+ return;
+ }
+ uid = ret;
+
+ ret = get_android_id(args[3]);
+ if (ret < 0) {
+ ERROR("invalid gid '%s'\n", args[3]);
+ free(tmp);
+ return;
+ }
+ gid = ret;
+
+ add_dev_perms(name, attr, perm, uid, gid, prefix);
+ free(tmp);
+}
diff --git a/init/ueventd.h b/init/ueventd.h
new file mode 100644
index 0000000..9066e47
--- /dev/null
+++ b/init/ueventd.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_UEVENTD_H_
+#define _INIT_UEVENTD_H_
+
+int ueventd_main(int argc, char **argv);
+
+#endif
diff --git a/init/ueventd_parser.c b/init/ueventd_parser.c
new file mode 100644
index 0000000..0dd8b4d
--- /dev/null
+++ b/init/ueventd_parser.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "ueventd_parser.h"
+#include "parser.h"
+#include "log.h"
+#include "list.h"
+#include "util.h"
+
+static void parse_line_device(struct parse_state *state, int nargs, char **args);
+
+static void parse_config(const char *fn, char *s)
+{
+ struct parse_state state;
+ char *args[UEVENTD_PARSER_MAXARGS];
+ int nargs;
+ nargs = 0;
+ state.filename = fn;
+ state.line = 1;
+ state.ptr = s;
+ state.nexttoken = 0;
+ state.parse_line = parse_line_device;
+ for (;;) {
+ int token = next_token(&state);
+ switch (token) {
+ case T_EOF:
+ state.parse_line(&state, 0, 0);
+ return;
+ case T_NEWLINE:
+ if (nargs) {
+ state.parse_line(&state, nargs, args);
+ nargs = 0;
+ }
+ break;
+ case T_TEXT:
+ if (nargs < UEVENTD_PARSER_MAXARGS) {
+ args[nargs++] = state.text;
+ }
+ break;
+ }
+ }
+}
+
+int ueventd_parse_config_file(const char *fn)
+{
+ char *data;
+ data = read_file(fn, 0);
+ if (!data) return -1;
+
+ parse_config(fn, data);
+ DUMP();
+ return 0;
+}
+
+static void parse_line_device(struct parse_state* state, int nargs, char **args)
+{
+ set_device_permission(nargs, args);
+}
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
new file mode 100644
index 0000000..3684285
--- /dev/null
+++ b/init/ueventd_parser.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_UEVENTD_PARSER_H_
+#define _INIT_UEVENTD_PARSER_H_
+
+#define UEVENTD_PARSER_MAXARGS 5
+
+int ueventd_parse_config_file(const char *fn);
+void set_device_permission(int nargs, char **args);
+
+#endif
diff --git a/init/util.c b/init/util.c
old mode 100644
new mode 100755
index 0b7667d..d8ec88e
--- a/init/util.c
+++ b/init/util.c
@@ -21,6 +21,7 @@
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
+#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -32,7 +33,9 @@
#include <private/android_filesystem_config.h>
-#include "init.h"
+#include "log.h"
+#include "list.h"
+#include "util.h"
static int log_fd = -1;
/* Inital log level before init.rc is parsed and this this is reset. */
@@ -209,3 +212,247 @@
item->prev->next = item->next;
}
+#define MAX_MTD_PARTITIONS 16
+
+static struct {
+ char name[16];
+ int number;
+} mtd_part_map[MAX_MTD_PARTITIONS];
+
+static int mtd_part_count = -1;
+
+static void find_mtd_partitions(void)
+{
+ int fd;
+ char buf[1024];
+ char *pmtdbufp;
+ ssize_t pmtdsize;
+ int r;
+
+ fd = open("/proc/mtd", O_RDONLY);
+ if (fd < 0)
+ return;
+
+ buf[sizeof(buf) - 1] = '\0';
+ pmtdsize = read(fd, buf, sizeof(buf) - 1);
+ pmtdbufp = buf;
+ while (pmtdsize > 0) {
+ int mtdnum, mtdsize, mtderasesize;
+ char mtdname[16];
+ mtdname[0] = '\0';
+ mtdnum = -1;
+ r = sscanf(pmtdbufp, "mtd%d: %x %x %15s",
+ &mtdnum, &mtdsize, &mtderasesize, mtdname);
+ if ((r == 4) && (mtdname[0] == '"')) {
+ char *x = strchr(mtdname + 1, '"');
+ if (x) {
+ *x = 0;
+ }
+ INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1);
+ if (mtd_part_count < MAX_MTD_PARTITIONS) {
+ strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1);
+ mtd_part_map[mtd_part_count].number = mtdnum;
+ mtd_part_count++;
+ } else {
+ ERROR("too many mtd partitions\n");
+ }
+ }
+ while (pmtdsize > 0 && *pmtdbufp != '\n') {
+ pmtdbufp++;
+ pmtdsize--;
+ }
+ if (pmtdsize > 0) {
+ pmtdbufp++;
+ pmtdsize--;
+ }
+ }
+ close(fd);
+}
+
+int mtd_name_to_number(const char *name)
+{
+ int n;
+ if (mtd_part_count < 0) {
+ mtd_part_count = 0;
+ find_mtd_partitions();
+ }
+ for (n = 0; n < mtd_part_count; n++) {
+ if (!strcmp(name, mtd_part_map[n].name)) {
+ return mtd_part_map[n].number;
+ }
+ }
+ return -1;
+}
+
+/*
+ * gettime() - returns the time in seconds of the system's monotonic clock or
+ * zero on error.
+ */
+time_t gettime(void)
+{
+ struct timespec ts;
+ int ret;
+
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (ret < 0) {
+ ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
+ return 0;
+ }
+
+ return ts.tv_sec;
+}
+
+int mkdir_recursive(const char *pathname, mode_t mode)
+{
+ char buf[128];
+ const char *slash;
+ const char *p = pathname;
+ int width;
+ int ret;
+ struct stat info;
+
+ while ((slash = strchr(p, '/')) != NULL) {
+ width = slash - pathname;
+ p = slash + 1;
+ if (width < 0)
+ break;
+ if (width == 0)
+ continue;
+ if ((unsigned int)width > sizeof(buf) - 1) {
+ ERROR("path too long for mkdir_recursive\n");
+ return -1;
+ }
+ memcpy(buf, pathname, width);
+ buf[width] = 0;
+ if (stat(buf, &info) != 0) {
+ ret = mkdir(buf, mode);
+ if (ret && errno != EEXIST)
+ return ret;
+ }
+ }
+ ret = mkdir(pathname, mode);
+ if (ret && errno != EEXIST)
+ return ret;
+ return 0;
+}
+
+void sanitize(char *s)
+{
+ if (!s)
+ return;
+ while (isalnum(*s))
+ s++;
+ *s = 0;
+}
+void make_link(const char *oldpath, const char *newpath)
+{
+ int ret;
+ char buf[256];
+ char *slash;
+ int width;
+
+ slash = strrchr(newpath, '/');
+ if (!slash)
+ return;
+ width = slash - newpath;
+ if (width <= 0 || width > (int)sizeof(buf) - 1)
+ return;
+ memcpy(buf, newpath, width);
+ buf[width] = 0;
+ ret = mkdir_recursive(buf, 0755);
+ if (ret)
+ ERROR("Failed to create directory %s: %s (%d)\n", buf, strerror(errno), errno);
+
+ ret = symlink(oldpath, newpath);
+ if (ret && errno != EEXIST)
+ ERROR("Failed to symlink %s to %s: %s (%d)\n", oldpath, newpath, strerror(errno), errno);
+}
+
+void remove_link(const char *oldpath, const char *newpath)
+{
+ char path[256];
+ ssize_t ret;
+ ret = readlink(newpath, path, sizeof(path) - 1);
+ if (ret <= 0)
+ return;
+ path[ret] = 0;
+ if (!strcmp(path, oldpath))
+ unlink(newpath);
+}
+
+int wait_for_file(const char *filename, int timeout)
+{
+ struct stat info;
+ time_t timeout_time = gettime() + timeout;
+ int ret = -1;
+
+ while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0))
+ usleep(10000);
+
+ return ret;
+}
+
+void open_devnull_stdio(void)
+{
+ int fd;
+ static const char *name = "/dev/__null__";
+ if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
+ fd = open(name, O_RDWR);
+ unlink(name);
+ if (fd >= 0) {
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ if (fd > 2) {
+ close(fd);
+ }
+ return;
+ }
+ }
+
+ exit(1);
+}
+
+void get_hardware_name(char *hardware, unsigned int *revision)
+{
+ char data[1024];
+ int fd, n;
+ char *x, *hw, *rev;
+
+ /* Hardware string was provided on kernel command line */
+ if (hardware[0])
+ return;
+
+ fd = open("/proc/cpuinfo", O_RDONLY);
+ if (fd < 0) return;
+
+ n = read(fd, data, 1023);
+ close(fd);
+ if (n < 0) return;
+
+ data[n] = 0;
+ hw = strstr(data, "\nHardware");
+ rev = strstr(data, "\nRevision");
+
+ if (hw) {
+ x = strstr(hw, ": ");
+ if (x) {
+ x += 2;
+ n = 0;
+ while (*x && *x != '\n') {
+ if (!isspace(*x))
+ hardware[n++] = tolower(*x);
+ x++;
+ if (n == 31) break;
+ }
+ hardware[n] = 0;
+ }
+ }
+
+ if (rev) {
+ x = strstr(rev, ": ");
+ if (x) {
+ *revision = strtoul(x + 2, 0, 16);
+ }
+ }
+}
diff --git a/init/util.h b/init/util.h
new file mode 100644
index 0000000..2e47369
--- /dev/null
+++ b/init/util.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_UTIL_H_
+#define _INIT_UTIL_H_
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+static const char *coldboot_done = "/dev/.coldboot_done";
+
+int mtd_name_to_number(const char *name);
+int create_socket(const char *name, int type, mode_t perm,
+ uid_t uid, gid_t gid);
+void *read_file(const char *fn, unsigned *_sz);
+time_t gettime(void);
+unsigned int decode_uid(const char *s);
+
+int mkdir_recursive(const char *pathname, mode_t mode);
+void sanitize(char *p);
+void make_link(const char *oldpath, const char *newpath);
+void remove_link(const char *oldpath, const char *newpath);
+int wait_for_file(const char *filename, int timeout);
+void open_devnull_stdio(void);
+void get_hardware_name(char *hardware, unsigned int *revision);
+#endif
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index 8f33b0b..6e13f9a 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -23,10 +23,11 @@
#include <cutils/hashmap.h>
-#if defined(__i386__)
#include <sys/mman.h>
-#endif
+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
#if defined(__arm__)
#define DEFAULT_ARM_CODEGEN
@@ -230,7 +231,7 @@
void release() {
if (pProgramBase != 0) {
- free(pProgramBase);
+ munmap(pProgramBase, mSize);
pProgramBase = 0;
}
}
@@ -263,7 +264,9 @@
virtual void init(int size) {
release();
mSize = size;
- pProgramBase = (char*) calloc(1, size);
+ pProgramBase = (char*) mmap(NULL, size,
+ PROT_EXEC | PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ind = pProgramBase;
}
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 4c45cc9..e8c7775 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -16,10 +16,17 @@
LOCAL_PATH := $(my-dir)
include $(CLEAR_VARS)
+ifeq ($(TARGET_CPU_SMP),true)
+ targetSmpFlag := -DANDROID_SMP=1
+else
+ targetSmpFlag := -DANDROID_SMP=0
+endif
+hostSmpFlag := -DANDROID_SMP=0
+
commonSources := \
array.c \
hashmap.c \
- atomic.c \
+ atomic.c.arm \
native_handle.c \
buffer.c \
socket_inaddr_any_server.c \
@@ -77,9 +84,10 @@
# Static library for host
# ========================================================
LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(commonSources) $(commonHostSources)
+LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c
LOCAL_LDLIBS := -lpthread
LOCAL_STATIC_LIBRARIES := liblog
+LOCAL_CFLAGS += $(hostSmpFlag)
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -92,6 +100,7 @@
LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) memory.c dlmalloc_stubs.c
LOCAL_LDLIBS := -lpthread
LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_CFLAGS += $(targetSmpFlag)
include $(BUILD_SHARED_LIBRARY)
else #!sim
@@ -103,7 +112,7 @@
LOCAL_SRC_FILES := $(commonSources) ashmem-dev.c mq.c
ifeq ($(TARGET_ARCH),arm)
-LOCAL_SRC_FILES += memset32.S atomic-android-arm.S
+LOCAL_SRC_FILES += memset32.S
else # !arm
ifeq ($(TARGET_ARCH),sh)
LOCAL_SRC_FILES += memory.c atomic-android-sh.c
@@ -114,12 +123,14 @@
LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
LOCAL_STATIC_LIBRARIES := liblog
+LOCAL_CFLAGS += $(targetSmpFlag)
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libcutils
LOCAL_WHOLE_STATIC_LIBRARIES := libcutils
LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_CFLAGS += $(targetSmpFlag)
include $(BUILD_SHARED_LIBRARY)
endif #!sim
diff --git a/libcutils/atomic-android-arm.S b/libcutils/atomic-android-arm.S
deleted file mode 100644
index 4d98451..0000000
--- a/libcutils/atomic-android-arm.S
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright (C) 2005 The Android Open 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 <machine/cpu-features.h>
-
-/*
- * NOTE: these atomic operations are SMP safe on all architectures.
- */
-
- .text
- .align
-
- .global android_atomic_write
- .type android_atomic_write, %function
-
- .global android_atomic_inc
- .type android_atomic_inc, %function
- .global android_atomic_dec
- .type android_atomic_dec, %function
-
- .global android_atomic_add
- .type android_atomic_add, %function
- .global android_atomic_and
- .type android_atomic_and, %function
- .global android_atomic_or
- .type android_atomic_or, %function
-
- .global android_atomic_swap
- .type android_atomic_swap, %function
-
- .global android_atomic_cmpxchg
- .type android_atomic_cmpxchg, %function
-
-/*
- * ----------------------------------------------------------------------------
- * int __kernel_cmpxchg(int oldval, int newval, int *ptr)
- * clobbered: r3, ip, flags
- * return 0 if a swap was made, non-zero otherwise.
- */
-
- .equ kernel_cmpxchg, 0xFFFF0FC0
- .equ kernel_atomic_base, 0xFFFF0FFF
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_write
- * input: r0=value, r1=address
- * output: void
- */
-
-android_atomic_write:
- str r0, [r1]
- bx lr;
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_inc
- * input: r0 = address
- * output: r0 = old value
- */
-
-android_atomic_inc:
- .fnstart
- .save {r4, lr}
- stmdb sp!, {r4, lr}
- mov r2, r0
-1: @ android_atomic_inc
- ldr r0, [r2]
- mov r3, #kernel_atomic_base
-#ifdef __ARM_HAVE_PC_INTERWORK
- add lr, pc, #4
- add r1, r0, #1
- add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
-#else
- add r1, r0, #1
- add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
- mov lr, pc
- bx r3
-#endif
- bcc 1b
- sub r0, r1, #1
- ldmia sp!, {r4, lr}
- bx lr
- .fnend
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_dec
- * input: r0=address
- * output: r0 = old value
- */
-
-android_atomic_dec:
- .fnstart
- .save {r4, lr}
- stmdb sp!, {r4, lr}
- mov r2, r0
-1: @ android_atomic_dec
- ldr r0, [r2]
- mov r3, #kernel_atomic_base
-#ifdef __ARM_HAVE_PC_INTERWORK
- add lr, pc, #4
- sub r1, r0, #1
- add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
-#else
- sub r1, r0, #1
- add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
- mov lr, pc
- bx r3
-#endif
- bcc 1b
- add r0, r1, #1
- ldmia sp!, {r4, lr}
- bx lr
- .fnend
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_add
- * input: r0=value, r1=address
- * output: r0 = old value
- */
-
-android_atomic_add:
- .fnstart
- .save {r4, lr}
- stmdb sp!, {r4, lr}
- mov r2, r1
- mov r4, r0
-1: @ android_atomic_add
- ldr r0, [r2]
- mov r3, #kernel_atomic_base
-#ifdef __ARM_HAVE_PC_INTERWORK
- add lr, pc, #4
- add r1, r0, r4
- add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
-#else
- add r1, r0, r4
- add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
- mov lr, pc
- bx r3
-#endif
- bcc 1b
- sub r0, r1, r4
- ldmia sp!, {r4, lr}
- bx lr
- .fnend
-
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_and
- * input: r0=value, r1=address
- * output: r0 = old value
- */
-
-android_atomic_and:
- .fnstart
- .save {r4, r5, lr}
- stmdb sp!, {r4, r5, lr}
- mov r2, r1 /* r2 = address */
- mov r4, r0 /* r4 = the value */
-1: @ android_atomic_and
- ldr r0, [r2] /* r0 = address[0] */
- mov r3, #kernel_atomic_base
-#ifdef __ARM_HAVE_PC_INTERWORK
- add lr, pc, #8
- mov r5, r0 /* r5 = save address[0] */
- and r1, r0, r4 /* r1 = new value */
- add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
-#else
- mov r5, r0 /* r5 = save address[0] */
- and r1, r0, r4 /* r1 = new value */
- add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
- mov lr, pc
- bx r3
-#endif
- bcc 1b
- mov r0, r5
- ldmia sp!, {r4, r5, lr}
- bx lr
- .fnend
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_or
- * input: r0=value, r1=address
- * output: r0 = old value
- */
-
-android_atomic_or:
- .fnstart
- .save {r4, r5, lr}
- stmdb sp!, {r4, r5, lr}
- mov r2, r1 /* r2 = address */
- mov r4, r0 /* r4 = the value */
-1: @ android_atomic_or
- ldr r0, [r2] /* r0 = address[0] */
- mov r3, #kernel_atomic_base
-#ifdef __ARM_HAVE_PC_INTERWORK
- add lr, pc, #8
- mov r5, r0 /* r5 = save address[0] */
- orr r1, r0, r4 /* r1 = new value */
- add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
-#else
- mov r5, r0 /* r5 = save address[0] */
- orr r1, r0, r4 /* r1 = new value */
- add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
- mov lr, pc
- bx r3
-#endif
- bcc 1b
- mov r0, r5
- ldmia sp!, {r4, r5, lr}
- bx lr
- .fnend
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_swap
- * input: r0=value, r1=address
- * output: r0 = old value
- */
-
-/* replaced swp instruction with ldrex/strex for ARMv6 & ARMv7 */
-android_atomic_swap:
-#if defined (__ARM_HAVE_LDREX_STREX)
-1: ldrex r2, [r1]
- strex r3, r0, [r1]
- teq r3, #0
- bne 1b
- mov r0, r2
- mcr p15, 0, r0, c7, c10, 5 /* or, use dmb */
-#else
- swp r0, r0, [r1]
-#endif
- bx lr
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_cmpxchg
- * input: r0=oldvalue, r1=newvalue, r2=address
- * output: r0 = 0 (xchg done) or non-zero (xchg not done)
- */
-
-android_atomic_cmpxchg:
- .fnstart
- .save {r4, lr}
- stmdb sp!, {r4, lr}
- mov r4, r0 /* r4 = save oldvalue */
-1: @ android_atomic_cmpxchg
- mov r3, #kernel_atomic_base
-#ifdef __ARM_HAVE_PC_INTERWORK
- add lr, pc, #4
- mov r0, r4 /* r0 = oldvalue */
- add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
-#else
- mov r0, r4 /* r0 = oldvalue */
- add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
- mov lr, pc
- bx r3
-#endif
- bcs 2f /* swap was made. we're good, return. */
- ldr r3, [r2] /* swap not made, see if it's because *ptr!=oldvalue */
- cmp r3, r4
- beq 1b
-2: @ android_atomic_cmpxchg
- ldmia sp!, {r4, lr}
- bx lr
- .fnend
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_cmpxchg_64
- * input: r0-r1=oldvalue, r2-r3=newvalue, arg4 (on stack)=address
- * output: r0 = 0 (xchg done) or non-zero (xchg not done)
- */
-/* TODO: NEED IMPLEMENTATION FOR THIS ARCHITECTURE */
diff --git a/libcutils/atomic-android-armv6.S b/libcutils/atomic-android-armv6.S
deleted file mode 100644
index 1574c9c..0000000
--- a/libcutils/atomic-android-armv6.S
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
- .text
- .align
-
- .global android_atomic_write
- .type android_atomic_write, %function
-
- .global android_atomic_inc
- .type android_atomic_inc, %function
- .global android_atomic_dec
- .type android_atomic_dec, %function
-
- .global android_atomic_add
- .type android_atomic_add, %function
- .global android_atomic_and
- .type android_atomic_and, %function
- .global android_atomic_or
- .type android_atomic_or, %function
-
- .global android_atomic_swap
- .type android_atomic_swap, %function
-
- .global android_atomic_cmpxchg
- .type android_atomic_cmpxchg, %function
-
-
-
-/* FIXME: On SMP systems memory barriers may be needed */
-#warning "this file is not safe with SMP systems"
-
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_write
- * input: r0=value, r1=address
- * output: void
- */
-
-android_atomic_write:
- str r0, [r1]
- bx lr;
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_inc
- * input: r0 = address
- * output: r0 = old value
- */
-
-android_atomic_inc:
- mov r12, r0
-1: ldrex r0, [r12]
- add r2, r0, #1
- strex r1, r2, [r12]
- cmp r1, #0
- bxeq lr
- b 1b
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_dec
- * input: r0=address
- * output: r0 = old value
- */
-
-android_atomic_dec:
- mov r12, r0
-1: ldrex r0, [r12]
- sub r2, r0, #1
- strex r1, r2, [r12]
- cmp r1, #0
- bxeq lr
- b 1b
-
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_add
- * input: r0=value, r1=address
- * output: r0 = old value
- */
-
-android_atomic_add:
- mov r12, r0
-1: ldrex r0, [r1]
- add r2, r0, r12
- strex r3, r2, [r1]
- cmp r3, #0
- bxeq lr
- b 1b
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_and
- * input: r0=value, r1=address
- * output: r0 = old value
- */
-
-android_atomic_and:
- mov r12, r0
-1: ldrex r0, [r1]
- and r2, r0, r12
- strex r3, r2, [r1]
- cmp r3, #0
- bxeq lr
- b 1b
-
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_or
- * input: r0=value, r1=address
- * output: r0 = old value
- */
-
-android_atomic_or:
- mov r12, r0
-1: ldrex r0, [r1]
- orr r2, r0, r12
- strex r3, r2, [r1]
- cmp r3, #0
- bxeq lr
- b 1b
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_swap
- * input: r0=value, r1=address
- * output: r0 = old value
- */
-
-android_atomic_swap:
- swp r0, r0, [r1]
- bx lr
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_cmpxchg
- * input: r0=oldvalue, r1=newvalue, r2=address
- * output: r0 = 0 (xchg done) or non-zero (xchg not done)
- */
-
-android_atomic_cmpxchg:
- mov r12, r1
- ldrex r3, [r2]
- eors r0, r0, r3
- strexeq r0, r12, [r2]
- bx lr
-
-
-
-/*
- * ----------------------------------------------------------------------------
- * android_atomic_cmpxchg_64
- * input: r0-r1=oldvalue, r2-r3=newvalue, arg4 (on stack)=address
- * output: r0 = 0 (xchg done) or non-zero (xchg not done)
- */
-/* TODO: NEED IMPLEMENTATION FOR THIS ARCHITECTURE */
diff --git a/libcutils/atomic-android-sh.c b/libcutils/atomic-android-sh.c
index acbea97..f8f1f57 100644
--- a/libcutils/atomic-android-sh.c
+++ b/libcutils/atomic-android-sh.c
@@ -35,6 +35,9 @@
* ARM implementation, in this file above.
* We follow the fact that the initializer for mutex is a simple zero
* value.
+ *
+ * (3) These operations are NOT safe for SMP, as there is no currently
+ * no definition for a memory barrier operation.
*/
#include <pthread.h>
@@ -46,18 +49,35 @@
&_swap_locks[((unsigned)(void*)(addr) >> 3U) % SWAP_LOCK_COUNT]
-void android_atomic_write(int32_t value, volatile int32_t* addr) {
+int32_t android_atomic_acquire_load(volatile const int32_t* addr)
+{
+ return *addr;
+}
+
+int32_t android_atomic_release_load(volatile const int32_t* addr)
+{
+ return *addr;
+}
+
+void android_atomic_acquire_store(int32_t value, volatile int32_t* addr) {
int32_t oldValue;
do {
oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, value, addr));
+ } while (android_atomic_release_cas(oldValue, value, addr));
+}
+
+void android_atomic_release_store(int32_t value, volatile int32_t* addr) {
+ int32_t oldValue;
+ do {
+ oldValue = *addr;
+ } while (android_atomic_release_cas(oldValue, value, addr));
}
int32_t android_atomic_inc(volatile int32_t* addr) {
int32_t oldValue;
do {
oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, oldValue+1, addr));
+ } while (android_atomic_release_cas(oldValue, oldValue+1, addr));
return oldValue;
}
@@ -65,7 +85,7 @@
int32_t oldValue;
do {
oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, oldValue-1, addr));
+ } while (android_atomic_release_cas(oldValue, oldValue-1, addr));
return oldValue;
}
@@ -73,7 +93,7 @@
int32_t oldValue;
do {
oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, oldValue+value, addr));
+ } while (android_atomic_release_cas(oldValue, oldValue+value, addr));
return oldValue;
}
@@ -81,7 +101,7 @@
int32_t oldValue;
do {
oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, oldValue&value, addr));
+ } while (android_atomic_release_cas(oldValue, oldValue&value, addr));
return oldValue;
}
@@ -89,11 +109,15 @@
int32_t oldValue;
do {
oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, oldValue|value, addr));
+ } while (android_atomic_release_cas(oldValue, oldValue|value, addr));
return oldValue;
}
-int32_t android_atomic_swap(int32_t value, volatile int32_t* addr) {
+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;
@@ -101,7 +125,12 @@
return oldValue;
}
-int android_atomic_cmpxchg(int32_t oldvalue, int32_t newvalue,
+int android_atomic_acquire_cmpxchg(int32_t oldvalue, int32_t newvalue,
+ volatile int32_t* addr) {
+ return android_atomic_release_cmpxchg(oldValue, newValue, addr);
+}
+
+int android_atomic_release_cmpxchg(int32_t oldvalue, int32_t newvalue,
volatile int32_t* addr) {
int result;
pthread_mutex_t* lock = SWAP_LOCK(addr);
@@ -118,42 +147,3 @@
return result;
}
-int64_t android_quasiatomic_swap_64(int64_t value, volatile int64_t* addr) {
- int64_t oldValue;
- pthread_mutex_t* lock = SWAP_LOCK(addr);
-
- pthread_mutex_lock(lock);
-
- oldValue = *addr;
- *addr = value;
-
- pthread_mutex_unlock(lock);
- return oldValue;
-}
-
-int android_quasiatomic_cmpxchg_64(int64_t oldvalue, int64_t newvalue,
- volatile int64_t* addr) {
- int result;
- pthread_mutex_t* lock = SWAP_LOCK(addr);
-
- pthread_mutex_lock(lock);
-
- if (*addr == oldvalue) {
- *addr = newvalue;
- result = 0;
- } else {
- result = 1;
- }
- pthread_mutex_unlock(lock);
- return result;
-}
-
-int64_t android_quasiatomic_read_64(volatile int64_t* addr) {
- int64_t result;
- pthread_mutex_t* lock = SWAP_LOCK(addr);
-
- pthread_mutex_lock(lock);
- result = *addr;
- pthread_mutex_unlock(lock);
- return result;
-}
diff --git a/libcutils/atomic.c b/libcutils/atomic.c
index 41faaa2..f6cd8b0 100644
--- a/libcutils/atomic.c
+++ b/libcutils/atomic.c
@@ -14,326 +14,6 @@
* limitations under the License.
*/
-#include <cutils/atomic.h>
-#ifdef HAVE_WIN32_THREADS
-#include <windows.h>
-#else
-#include <sched.h>
-#endif
+#define inline
-/*****************************************************************************/
-#if defined(HAVE_MACOSX_IPC)
-
-#include <libkern/OSAtomic.h>
-
-void android_atomic_write(int32_t value, volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (OSAtomicCompareAndSwap32Barrier(oldValue, value, (int32_t*)addr) == 0);
-}
-
-int32_t android_atomic_inc(volatile int32_t* addr) {
- return OSAtomicIncrement32Barrier((int32_t*)addr)-1;
-}
-
-int32_t android_atomic_dec(volatile int32_t* addr) {
- return OSAtomicDecrement32Barrier((int32_t*)addr)+1;
-}
-
-int32_t android_atomic_add(int32_t value, volatile int32_t* addr) {
- return OSAtomicAdd32Barrier(value, (int32_t*)addr)-value;
-}
-
-int32_t android_atomic_and(int32_t value, volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (OSAtomicCompareAndSwap32Barrier(oldValue, oldValue&value, (int32_t*)addr) == 0);
- return oldValue;
-}
-
-int32_t android_atomic_or(int32_t value, volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (OSAtomicCompareAndSwap32Barrier(oldValue, oldValue|value, (int32_t*)addr) == 0);
- return oldValue;
-}
-
-int32_t android_atomic_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_cmpxchg(int32_t oldvalue, int32_t newvalue, volatile int32_t* addr) {
- return OSAtomicCompareAndSwap32Barrier(oldvalue, newvalue, (int32_t*)addr) == 0;
-}
-
-#if defined(__ppc__) \
- || defined(__PPC__) \
- || defined(__powerpc__) \
- || defined(__powerpc) \
- || defined(__POWERPC__) \
- || defined(_M_PPC) \
- || defined(__PPC)
-#define NEED_QUASIATOMICS 1
-#else
-
-int android_quasiatomic_cmpxchg_64(int64_t oldvalue, int64_t newvalue,
- volatile int64_t* addr) {
- return OSAtomicCompareAndSwap64Barrier(oldvalue, newvalue,
- (int64_t*)addr) == 0;
-}
-
-int64_t android_quasiatomic_swap_64(int64_t value, volatile int64_t* addr) {
- int64_t oldValue;
- do {
- oldValue = *addr;
- } while (android_quasiatomic_cmpxchg_64(oldValue, value, addr));
- return oldValue;
-}
-
-int64_t android_quasiatomic_read_64(volatile int64_t* addr) {
- return OSAtomicAdd64Barrier(0, addr);
-}
-
-#endif
-
-
-/*****************************************************************************/
-#elif defined(__i386__) || defined(__x86_64__)
-
-void android_atomic_write(int32_t value, volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, value, addr));
-}
-
-int32_t android_atomic_inc(volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, oldValue+1, addr));
- return oldValue;
-}
-
-int32_t android_atomic_dec(volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, oldValue-1, addr));
- return oldValue;
-}
-
-int32_t android_atomic_add(int32_t value, volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, oldValue+value, addr));
- return oldValue;
-}
-
-int32_t android_atomic_and(int32_t value, volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, oldValue&value, addr));
- return oldValue;
-}
-
-int32_t android_atomic_or(int32_t value, volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, oldValue|value, addr));
- return oldValue;
-}
-
-int32_t android_atomic_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_cmpxchg(int32_t oldvalue, int32_t newvalue, volatile int32_t* addr) {
- int xchg;
- asm volatile
- (
- " lock; cmpxchg %%ecx, (%%edx);"
- " setne %%al;"
- " andl $1, %%eax"
- : "=a" (xchg)
- : "a" (oldvalue), "c" (newvalue), "d" (addr)
- );
- return xchg;
-}
-
-#define NEED_QUASIATOMICS 1
-
-/*****************************************************************************/
-#elif __arm__
-// Most of the implementation is in atomic-android-arm.s.
-
-// on the device, we implement the 64-bit atomic operations through
-// mutex locking. normally, this is bad because we must initialize
-// a pthread_mutex_t before being able to use it, and this means
-// having to do an initialization check on each function call, and
-// that's where really ugly things begin...
-//
-// BUT, as a special twist, we take advantage of the fact that in our
-// pthread library, a mutex is simply a volatile word whose value is always
-// initialized to 0. In other words, simply declaring a static mutex
-// object initializes it !
-//
-// another twist is that we use a small array of mutexes to dispatch
-// the contention locks from different memory addresses
-//
-
-#include <pthread.h>
-
-#define SWAP_LOCK_COUNT 32U
-static pthread_mutex_t _swap_locks[SWAP_LOCK_COUNT];
-
-#define SWAP_LOCK(addr) \
- &_swap_locks[((unsigned)(void*)(addr) >> 3U) % SWAP_LOCK_COUNT]
-
-
-int64_t android_quasiatomic_swap_64(int64_t value, volatile int64_t* addr) {
- int64_t oldValue;
- pthread_mutex_t* lock = SWAP_LOCK(addr);
-
- pthread_mutex_lock(lock);
-
- oldValue = *addr;
- *addr = value;
-
- pthread_mutex_unlock(lock);
- return oldValue;
-}
-
-int android_quasiatomic_cmpxchg_64(int64_t oldvalue, int64_t newvalue,
- volatile int64_t* addr) {
- int result;
- pthread_mutex_t* lock = SWAP_LOCK(addr);
-
- pthread_mutex_lock(lock);
-
- if (*addr == oldvalue) {
- *addr = newvalue;
- result = 0;
- } else {
- result = 1;
- }
- pthread_mutex_unlock(lock);
- return result;
-}
-
-int64_t android_quasiatomic_read_64(volatile int64_t* addr) {
- int64_t result;
- pthread_mutex_t* lock = SWAP_LOCK(addr);
-
- pthread_mutex_lock(lock);
- result = *addr;
- pthread_mutex_unlock(lock);
- return result;
-}
-
-/*****************************************************************************/
-#elif __sh__
-// implementation for SuperH is in atomic-android-sh.c.
-
-#else
-
-#error "Unsupported atomic operations for this platform"
-
-#endif
-
-
-
-#if NEED_QUASIATOMICS
-
-/* Note that a spinlock is *not* a good idea in general
- * since they can introduce subtle issues. For example,
- * a real-time thread trying to acquire a spinlock already
- * acquired by another thread will never yeld, making the
- * CPU loop endlessly!
- *
- * However, this code is only used on the Linux simulator
- * so it's probably ok for us.
- *
- * The alternative is to use a pthread mutex, but
- * these must be initialized before being used, and
- * then you have the problem of lazily initializing
- * a mutex without any other synchronization primitive.
- */
-
-/* global spinlock for all 64-bit quasiatomic operations */
-static int32_t quasiatomic_spinlock = 0;
-
-int android_quasiatomic_cmpxchg_64(int64_t oldvalue, int64_t newvalue,
- volatile int64_t* addr) {
- int result;
-
- while (android_atomic_cmpxchg(0, 1, &quasiatomic_spinlock)) {
-#ifdef HAVE_WIN32_THREADS
- Sleep(0);
-#else
- sched_yield();
-#endif
- }
-
- if (*addr == oldvalue) {
- *addr = newvalue;
- result = 0;
- } else {
- result = 1;
- }
-
- android_atomic_swap(0, &quasiatomic_spinlock);
-
- return result;
-}
-
-int64_t android_quasiatomic_read_64(volatile int64_t* addr) {
- int64_t result;
-
- while (android_atomic_cmpxchg(0, 1, &quasiatomic_spinlock)) {
-#ifdef HAVE_WIN32_THREADS
- Sleep(0);
-#else
- sched_yield();
-#endif
- }
-
- result = *addr;
- android_atomic_swap(0, &quasiatomic_spinlock);
-
- return result;
-}
-
-int64_t android_quasiatomic_swap_64(int64_t value, volatile int64_t* addr) {
- int64_t result;
-
- while (android_atomic_cmpxchg(0, 1, &quasiatomic_spinlock)) {
-#ifdef HAVE_WIN32_THREADS
- Sleep(0);
-#else
- sched_yield();
-#endif
- }
-
- result = *addr;
- *addr = value;
- android_atomic_swap(0, &quasiatomic_spinlock);
-
- return result;
-}
-
-#endif
+#include <cutils/atomic-inline.h>
diff --git a/libcutils/mspace.c b/libcutils/mspace.c
index 63b199d..6d3b35c 100644
--- a/libcutils/mspace.c
+++ b/libcutils/mspace.c
@@ -271,4 +271,16 @@
}
return 0;
}
+
+void *contiguous_mspace_sbrk0(mspace msp) {
+ struct mspace_contig_state *cs;
+ mstate ms;
+ const unsigned int pagesize = PAGESIZE;
+
+ ms = (mstate)msp;
+ cs = (struct mspace_contig_state *)((uintptr_t)ms & ~(pagesize-1));
+ assert(cs->magic == CONTIG_STATE_MAGIC);
+ assert(cs->m == ms);
+ return cs->brk;
+}
#endif
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index ed9d699..f8b7254 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -454,7 +454,7 @@
numVecs = numLines*3; // 3 iovecs per line.
if (numVecs > INLINE_VECS) {
- vec = (struct iovec*)malloc(sizeof(struct iovec)*numLines);
+ vec = (struct iovec*)malloc(sizeof(struct iovec)*numVecs);
if (vec == NULL) {
msg = "LOG: write failed, no memory";
numVecs = 3;
diff --git a/libnetutils/dhcpclient.c b/libnetutils/dhcpclient.c
index b247016..ff00432 100644
--- a/libnetutils/dhcpclient.c
+++ b/libnetutils/dhcpclient.c
@@ -70,7 +70,7 @@
vsnprintf(errmsg, sizeof(errmsg), fmt, ap);
va_end(ap);
- LOGD(errmsg);
+ LOGD("%s", errmsg);
}
const char *dhcp_lasterror()
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
index 29410c8..125c3ce 100644
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -19,6 +19,8 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
@@ -39,15 +41,14 @@
Assembly::Assembly(size_t size)
: mCount(1), mSize(0)
{
- mBase = (uint32_t*)malloc(size);
- if (mBase) {
- mSize = size;
- }
+ mBase = (uint32_t*)mspace_malloc(getMspace(), size);
+ mSize = size;
+ ensureMbaseExecutable();
}
Assembly::~Assembly()
{
- free(mBase);
+ mspace_free(getMspace(), mBase);
}
void Assembly::incStrong(const void*) const
@@ -75,11 +76,32 @@
ssize_t Assembly::resize(size_t newSize)
{
- mBase = (uint32_t*)realloc(mBase, newSize);
+ mBase = (uint32_t*)mspace_realloc(getMspace(), mBase, newSize);
mSize = newSize;
+ ensureMbaseExecutable();
return size();
}
+mspace Assembly::getMspace()
+{
+ static mspace msp = create_contiguous_mspace(2 * 1024, 1024 * 1024, /*locked=*/ false);
+ return msp;
+}
+
+void Assembly::ensureMbaseExecutable()
+{
+ long pagesize = sysconf(_SC_PAGESIZE);
+ long pagemask = ~(pagesize - 1); // assumes pagesize is a power of 2
+
+ uint32_t* pageStart = (uint32_t*) (((uintptr_t) mBase) & pagemask);
+ size_t adjustedLength = (mBase - pageStart) * sizeof(uint32_t) + mSize;
+
+ if (mBase && mprotect(pageStart, adjustedLength, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
+ mspace_free(getMspace(), mBase);
+ mBase = NULL;
+ }
+}
+
// ----------------------------------------------------------------------------
CodeCache::CodeCache(size_t size)
diff --git a/libpixelflinger/codeflinger/CodeCache.h b/libpixelflinger/codeflinger/CodeCache.h
index 8ff1366..aaafd26 100644
--- a/libpixelflinger/codeflinger/CodeCache.h
+++ b/libpixelflinger/codeflinger/CodeCache.h
@@ -22,6 +22,7 @@
#include <stdint.h>
#include <pthread.h>
#include <sys/types.h>
+#include <cutils/mspace.h>
#include "tinyutils/KeyedVector.h"
#include "tinyutils/smartpointer.h"
@@ -67,9 +68,12 @@
typedef void weakref_type;
private:
+ static mspace getMspace();
+ void ensureMbaseExecutable();
+
mutable int32_t mCount;
uint32_t* mBase;
- ssize_t mSize;
+ size_t mSize;
};
// ----------------------------------------------------------------------------
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index 80f678d..640b6df 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -35,7 +35,7 @@
if ((len = read(c->getSocket(), buffer, sizeof(buffer) -1)) < 0) {
SLOGE("read() failed (%s)", strerror(errno));
- return errno;
+ return false;
} else if (!len)
return false;
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index e9ae23a..8e5f154 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -1,5 +1,6 @@
#include <alloca.h>
#include <errno.h>
+#include <sys/socket.h>
#include <sys/types.h>
#include <pthread.h>
#include <string.h>
@@ -9,9 +10,24 @@
#include <sysutils/SocketClient.h>
-SocketClient::SocketClient(int socket) {
- mSocket = socket;
+SocketClient::SocketClient(int socket)
+ : mSocket(socket)
+ , mPid(-1)
+ , mUid(-1)
+ , mGid(-1)
+{
pthread_mutex_init(&mWriteMutex, NULL);
+
+ struct ucred creds;
+ socklen_t szCreds = sizeof(creds);
+ memset(&creds, 0, szCreds);
+
+ int err = getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
+ if (err == 0) {
+ mPid = creds.pid;
+ mUid = creds.uid;
+ mGid = creds.gid;
+ }
}
int SocketClient::sendMsg(int code, const char *msg, bool addErrno) {
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 7af221f..1bc06db 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -198,6 +198,7 @@
pthread_mutex_unlock(&mClientsLock);
}
FD_CLR(fd, &read_fds);
+ pthread_mutex_lock(&mClientsLock);
continue;
}
}
diff --git a/logcat/event.logtags b/logcat/event.logtags
index f146738..0083c57 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -104,7 +104,7 @@
#
20001 dvm_gc_info (custom|2),(custom|2),(custom|2),(custom|2)
20002 dvm_gc_madvise_info (total|1|2),(zygote|1|2)
-20003 dvm_lock_sample (process|3),(main|1|5),(thread|3),(time|1|3),(file|3),(line|1|5),(sample_percent|1|6)
+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)
75001 sqlite_mem_alarm_max (max|1|2)
@@ -160,6 +160,24 @@
60002 view_build_drawing_cache (View created drawing cache|1|5)
60003 view_use_drawing_cache (View drawn using bitmap cache|1|5)
+# graphics timestamp
+60100 sf_app_dequeue_before (buffer|1),(identity|1),(time|2)
+60101 sf_app_dequeue_after (buffer|1),(identity|1),(time|2)
+60102 sf_app_lock_before (buffer|1),(identity|1),(time|2)
+60103 sf_app_lock_after (buffer|1),(identity|1),(time|2)
+60104 sf_app_queue (buffer|1),(identity|1),(time|2)
+60105 sf_repaint (buffer|1),(time|2)
+60106 sf_composition_complete (buffer|1),(time|2)
+60107 sf_unlock_clients (buffer|1),(time|2)
+60108 sf_swapbuffers (buffer|1),(time|2)
+60109 sf_repaint_done (buffer|1),(time|2)
+60110 sf_fb_post_before (buffer|1),(time|2)
+60111 sf_fb_post_after (buffer|1),(time|2)
+60112 sf_fb_dequeue_before (buffer|1),(time|2)
+60113 sf_fb_dequeue_after (buffer|1),(time|2)
+60114 sf_fb_lock_before (buffer|1),(time|2)
+60115 sf_fb_lock_after (buffer|1),(time|2)
+
# 0 for screen off, 1 for screen on, 2 for key-guard done
70000 screen_toggled (screen_state|1|5)
diff --git a/logwrapper/logwrapper.c b/logwrapper/logwrapper.c
index 6466795..bdf53e8 100644
--- a/logwrapper/logwrapper.c
+++ b/logwrapper/logwrapper.c
@@ -27,8 +27,8 @@
#include "cutils/log.h"
void fatal(const char *msg) {
- fprintf(stderr, msg);
- LOG(LOG_ERROR, "logwrapper", msg);
+ fprintf(stderr, "%s", msg);
+ LOG(LOG_ERROR, "logwrapper", "%s", msg);
exit(-1);
}
diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c
index 3642647..a94cb9c 100644
--- a/mkbootimg/mkbootimg.c
+++ b/mkbootimg/mkbootimg.c
@@ -64,6 +64,7 @@
" [ --cmdline <kernel-commandline> ]\n"
" [ --board <boardname> ]\n"
" [ --base <address> ]\n"
+ " [ --pagesize <pagesize> ]\n"
" -o|--output <filename>\n"
);
return 1;
@@ -71,7 +72,7 @@
-static unsigned char padding[2048] = { 0, };
+static unsigned char padding[4096] = { 0, };
int write_padding(int fd, unsigned pagesize, unsigned itemsize)
{
@@ -120,8 +121,6 @@
hdr.second_addr = 0x10F00000;
hdr.tags_addr = 0x10000100;
- hdr.page_size = pagesize;
-
while(argc > 0){
char *arg = argv[0];
char *val = argv[1];
@@ -148,10 +147,18 @@
hdr.tags_addr = base + 0x00000100;
} else if(!strcmp(arg, "--board")) {
board = val;
+ } else if(!strcmp(arg,"--pagesize")) {
+ pagesize = strtoul(val, 0, 10);
+ if ((pagesize != 2048) && (pagesize != 4096)) {
+ fprintf(stderr,"error: unsupported page size %d\n", pagesize);
+ return -1;
+ }
} else {
return usage();
}
}
+ hdr.page_size = pagesize;
+
if(bootimg == 0) {
fprintf(stderr,"error: no output filename specified\n");
diff --git a/patch.txt b/patch.txt
new file mode 100644
index 0000000..258965d
--- /dev/null
+++ b/patch.txt
@@ -0,0 +1,16 @@
+diff --git a/init/util.c b/init/util.c
+index 4d98cc2..0667593 100755
+--- a/init/util.c
++++ b/init/util.c
+@@ -657,8 +657,9 @@ static void get_hardware_name(void)
+ if (x) {
+ x += 2;
+ n = 0;
+- while (*x && !isspace(*x)) {
+- hardware[n++] = tolower(*x);
++ while (*x && *x != '\n') {
++ if (!isspace(*x))
++ hardware[n++] = tolower(*x);
+ x++;
+ if (n == 31) break;
+ }
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 9a56bfd..380bb60 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -37,8 +37,15 @@
$(file) : $(LOCAL_PATH)/init.rc | $(ACP)
$(transform-prebuilt-to-target)
ALL_PREBUILT += $(file)
+$(INSTALLED_RAMDISK_TARGET): $(file)
endif
+file := $(TARGET_ROOT_OUT)/ueventd.rc
+$(file) : $(LOCAL_PATH)/ueventd.rc | $(ACP)
+ $(transform-prebuilt-to-target)
+ALL_PREBUILT += $(file)
+$(INSTALLED_RAMDISK_TARGET): $(file)
+
# Just like /system/etc/init.goldfish.sh, the /init.godlfish.rc is here
# to allow -user builds to properly run the dex pre-optimization pass in
# the emulator.
@@ -46,6 +53,13 @@
$(file) : $(LOCAL_PATH)/etc/init.goldfish.rc | $(ACP)
$(transform-prebuilt-to-target)
ALL_PREBUILT += $(file)
+$(INSTALLED_RAMDISK_TARGET): $(file)
+
+file := $(TARGET_ROOT_OUT)/ueventd.goldfish.rc
+$(file) : $(LOCAL_PATH)/etc/ueventd.goldfish.rc | $(ACP)
+ $(transform-prebuilt-to-target)
+ALL_PREBUILT += $(file)
+$(INSTALLED_RAMDISK_TARGET): $(file)
# create some directories (some are mount points)
DIRS := $(addprefix $(TARGET_ROOT_OUT)/, \
diff --git a/rootdir/etc/ueventd.goldfish.rc b/rootdir/etc/ueventd.goldfish.rc
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/rootdir/etc/ueventd.goldfish.rc
diff --git a/rootdir/init.lowmem.rc b/rootdir/init.lowmem.rc
new file mode 100644
index 0000000..7c08054
--- /dev/null
+++ b/rootdir/init.lowmem.rc
@@ -0,0 +1,19 @@
+# Adjustments to the out-of-memory killer, for devices that are
+# tight on memory. These should not be used if not needed, as they
+# can result in more paging.
+
+on early-boot
+
+ setprop ro.FOREGROUND_APP_MEM 1536
+ setprop ro.VISIBLE_APP_MEM 2048
+ setprop ro.PERCEPTIBLE_APP_MEM 2048
+ setprop ro.HEAVY_WEIGHT_APP_MEM 2048
+ setprop ro.SECONDARY_SERVER_MEM 4096
+ setprop ro.BACKUP_APP_MEM 4096
+ setprop ro.HOME_APP_MEM 4096
+ setprop ro.HIDDEN_APP_MEM 5120
+ setprop ro.EMPTY_APP_MEM 6144
+
+on boot
+
+ write /sys/module/lowmemorykiller/parameters/minfree 1536,2048,3072,4096,5120,6144
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a01fdb5..d1b27d0 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -1,3 +1,5 @@
+on early-init
+ start ueventd
on init
@@ -6,20 +8,25 @@
loglevel 3
# setup the global environment
- export PATH /sbin:/system/sbin:/system/bin:/system/xbin
- export LD_LIBRARY_PATH /system/lib
+ export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
+ export LD_LIBRARY_PATH /vendor/lib:/system/lib
export ANDROID_BOOTLOGO 1
export ANDROID_ROOT /system
export ANDROID_ASSETS /system/app
export ANDROID_DATA /data
export EXTERNAL_STORAGE /mnt/sdcard
export ASEC_MOUNTPOINT /mnt/asec
- export BOOTCLASSPATH /system/framework/core.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar
+ 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
# Backward compatibility
symlink /system/etc /etc
symlink /sys/kernel/debug /d
+# Right now vendor lives on the same filesystem as system,
+# but someday that may change.
+ symlink /system/vendor /vendor
+
# create mountpoints
mkdir /mnt 0775 root system
mkdir /mnt/sdcard 0000 system system
@@ -51,7 +58,9 @@
mkdir /mnt/asec 0700 root system
mount tmpfs tmpfs /mnt/asec mode=0755,gid=1000
- mount rootfs rootfs / ro remount
+ # Filesystem image public mount points.
+ mkdir /mnt/obb 0700 root system
+ mount tmpfs tmpfs /mnt/obb mode=0755,gid=1000
write /proc/sys/kernel/panic_on_oops 1
write /proc/sys/kernel/hung_task_timeout_secs 0
@@ -80,13 +89,19 @@
# 5.0 %
write /dev/cpuctl/bg_non_interactive/cpu.shares 52
+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
# We chown/chmod /data again so because mount is run as root + defaults
- mount yaffs2 mtd@userdata /data nosuid nodev
chown system system /data
chmod 0771 /data
@@ -110,7 +125,6 @@
write /proc/apanic_console 1
# Same reason as /data above
- mount yaffs2 mtd@cache /cache nosuid nodev
chown system cache /cache
chmod 0770 /cache
@@ -180,32 +194,35 @@
# killed by the kernel. These are used in ActivityManagerService.
setprop ro.FOREGROUND_APP_ADJ 0
setprop ro.VISIBLE_APP_ADJ 1
- setprop ro.SECONDARY_SERVER_ADJ 2
- setprop ro.BACKUP_APP_ADJ 2
- setprop ro.HOME_APP_ADJ 4
+ setprop ro.PERCEPTIBLE_APP_ADJ 2
+ setprop ro.HEAVY_WEIGHT_APP_ADJ 3
+ setprop ro.SECONDARY_SERVER_ADJ 4
+ setprop ro.BACKUP_APP_ADJ 5
+ setprop ro.HOME_APP_ADJ 6
setprop ro.HIDDEN_APP_MIN_ADJ 7
- setprop ro.CONTENT_PROVIDER_ADJ 14
setprop ro.EMPTY_APP_ADJ 15
# Define the memory thresholds at which the above process classes will
# be killed. These numbers are in pages (4k).
- setprop ro.FOREGROUND_APP_MEM 1536
- setprop ro.VISIBLE_APP_MEM 2048
- setprop ro.SECONDARY_SERVER_MEM 4096
- setprop ro.BACKUP_APP_MEM 4096
- setprop ro.HOME_APP_MEM 4096
- setprop ro.HIDDEN_APP_MEM 5120
- setprop ro.CONTENT_PROVIDER_MEM 5632
- setprop ro.EMPTY_APP_MEM 6144
+ setprop ro.FOREGROUND_APP_MEM 2048
+ setprop ro.VISIBLE_APP_MEM 3072
+ setprop ro.PERCEPTIBLE_APP_MEM 4096
+ setprop ro.HEAVY_WEIGHT_APP_MEM 4096
+ setprop ro.SECONDARY_SERVER_MEM 6144
+ setprop ro.BACKUP_APP_MEM 6144
+ setprop ro.HOME_APP_MEM 6144
+ setprop ro.HIDDEN_APP_MEM 7168
+ setprop ro.EMPTY_APP_MEM 8192
# Write value must be consistent with the above properties.
-# Note that the driver only supports 6 slots, so we have HOME_APP at the
-# same memory level as services.
- write /sys/module/lowmemorykiller/parameters/adj 0,1,2,7,14,15
+# Note that the driver only supports 6 slots, so we have combined some of
+# the classes into the same memory level; the associated processes of higher
+# classes will still be killed first.
+ write /sys/module/lowmemorykiller/parameters/adj 0,1,2,4,7,15
write /proc/sys/vm/overcommit_memory 1
write /proc/sys/vm/min_free_order_shift 4
- write /sys/module/lowmemorykiller/parameters/minfree 1536,2048,4096,5120,5632,6144
+ write /sys/module/lowmemorykiller/parameters/minfree 2048,3072,4096,6144,7168,8192
# Set init its forked children's oom_adj.
write /proc/1/oom_adj -16
@@ -265,8 +282,17 @@
## Daemon processes to be run by init.
##
+service ueventd /sbin/ueventd
+ critical
+
service console /system/bin/sh
console
+ disabled
+ user shell
+ group log
+
+on property:ro.secure=0
+ start console
# adbd is controlled by the persist.service.adb.enable system property
service adbd /sbin/adbd
@@ -301,13 +327,14 @@
socket rild stream 660 root radio
socket rild-debug stream 660 radio system
user root
- group radio cache inet misc audio
+ group radio cache inet misc audio sdcard_rw
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
+ onrestart restart netd
service drm /system/bin/drmserver
user drm
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
new file mode 100644
index 0000000..616566e
--- /dev/null
+++ b/rootdir/ueventd.rc
@@ -0,0 +1,82 @@
+/dev/null 0666 root root
+/dev/zero 0666 root root
+/dev/full 0666 root root
+/dev/ptmx 0666 root root
+/dev/tty 0666 root root
+/dev/random 0666 root root
+/dev/urandom 0666 root root
+/dev/ashmem 0666 root root
+/dev/binder 0666 root root
+
+# logger should be world writable (for logging) but not readable
+/dev/log/* 0662 root log
+
+# the msm hw3d client device node is world writable/readable.
+/dev/msm_hw3dc 0666 root root
+
+# gpu driver for adreno200 is globally accessible
+/dev/kgsl 0666 root root
+
+# these should not be world writable
+/dev/diag 0660 radio radio
+/dev/diag_arm9 0660 radio radio
+/dev/android_adb 0660 adb adb
+/dev/android_adb_enable 0660 adb adb
+/dev/ttyMSM0 0600 bluetooth bluetooth
+/dev/ttyHS0 0600 bluetooth bluetooth
+/dev/uinput 0660 system bluetooth
+/dev/alarm 0664 system radio
+/dev/tty0 0660 root system
+/dev/graphics/* 0660 root graphics
+/dev/msm_hw3dm 0660 system graphics
+/dev/input/* 0660 root input
+/dev/eac 0660 root audio
+/dev/cam 0660 root camera
+/dev/pmem 0660 system graphics
+/dev/pmem_adsp* 0660 system audio
+/dev/pmem_camera* 0660 system camera
+/dev/oncrpc/* 0660 root system
+/dev/adsp/* 0660 system audio
+/dev/snd/* 0660 system audio
+/dev/mt9t013 0660 system system
+/dev/msm_camera/* 0660 system system
+/dev/akm8976_daemon 0640 compass system
+/dev/akm8976_aot 0640 compass system
+/dev/akm8973_daemon 0640 compass system
+/dev/akm8973_aot 0640 compass system
+/dev/bma150 0640 compass system
+/dev/cm3602 0640 compass system
+/dev/akm8976_pffd 0640 compass system
+/dev/lightsensor 0640 system system
+/dev/msm_pcm_out* 0660 system audio
+/dev/msm_pcm_in* 0660 system audio
+/dev/msm_pcm_ctl* 0660 system audio
+/dev/msm_snd* 0660 system audio
+/dev/msm_mp3* 0660 system audio
+/dev/audience_a1026* 0660 system audio
+/dev/tpa2018d1* 0660 system audio
+/dev/msm_audpre 0660 system audio
+/dev/msm_audio_ctl 0660 system audio
+/dev/htc-acoustic 0660 system audio
+/dev/vdec 0660 system audio
+/dev/q6venc 0660 system audio
+/dev/snd/dsp 0660 system audio
+/dev/snd/dsp1 0660 system audio
+/dev/snd/mixer 0660 system audio
+/dev/smd0 0640 radio radio
+/dev/qemu_trace 0666 system system
+/dev/qmi 0640 radio radio
+/dev/qmi0 0640 radio radio
+/dev/qmi1 0640 radio radio
+/dev/qmi2 0640 radio radio
+/dev/bus/usb/* 0660 root usb
+
+# CDMA radio interface MUX
+/dev/ts0710mux* 0640 radio radio
+/dev/ppp 0660 radio vpn
+/dev/tun 0640 vpn vpn
+
+# sysfs properties
+/sys/devices/virtual/input/input* enable 0660 root input
+/sys/devices/virtual/input/input* poll_delay 0660 root input
+
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
new file mode 100644
index 0000000..c430ac8
--- /dev/null
+++ b/sdcard/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= sdcard.c
+LOCAL_MODULE:= sdcard
+
+LOCAL_SHARED_LIBRARIES := libc
+
+include $(BUILD_EXECUTABLE)
diff --git a/sdcard/fuse.h b/sdcard/fuse.h
new file mode 100644
index 0000000..3138da9
--- /dev/null
+++ b/sdcard/fuse.h
@@ -0,0 +1,578 @@
+/*
+ FUSE: Filesystem in Userspace
+ Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu>
+
+ This program can be distributed under the terms of the GNU GPL.
+ See the file COPYING.
+*/
+
+/*
+ * from the libfuse FAQ (and consistent with the Linux Kernel license):
+ *
+ * Under what conditions may I distribute a filesystem that uses the
+ * raw kernel interface of FUSE?
+ *
+ * There are no restrictions whatsoever for using the raw kernel interface.
+ *
+ */
+
+/*
+ * This file defines the kernel interface of FUSE
+ *
+ * Protocol changelog:
+ *
+ * 7.9:
+ * - new fuse_getattr_in input argument of GETATTR
+ * - add lk_flags in fuse_lk_in
+ * - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in
+ * - add blksize field to fuse_attr
+ * - add file flags field to fuse_read_in and fuse_write_in
+ *
+ * 7.10
+ * - add nonseekable open flag
+ *
+ * 7.11
+ * - add IOCTL message
+ * - add unsolicited notification support
+ * - add POLL message and NOTIFY_POLL notification
+ *
+ * 7.12
+ * - add umask flag to input argument of open, mknod and mkdir
+ * - add notification messages for invalidation of inodes and
+ * directory entries
+ *
+ * 7.13
+ * - make max number of background requests and congestion threshold
+ * tunables
+ */
+
+#ifndef _LINUX_FUSE_H
+#define _LINUX_FUSE_H
+
+#include <linux/types.h>
+
+/*
+ * Version negotiation:
+ *
+ * Both the kernel and userspace send the version they support in the
+ * INIT request and reply respectively.
+ *
+ * If the major versions match then both shall use the smallest
+ * of the two minor versions for communication.
+ *
+ * If the kernel supports a larger major version, then userspace shall
+ * reply with the major version it supports, ignore the rest of the
+ * INIT message and expect a new INIT message from the kernel with a
+ * matching major version.
+ *
+ * If the library supports a larger major version, then it shall fall
+ * back to the major protocol version sent by the kernel for
+ * communication and reply with that major version (and an arbitrary
+ * supported minor version).
+ */
+
+/** Version number of this interface */
+#define FUSE_KERNEL_VERSION 7
+
+/** Minor version number of this interface */
+#define FUSE_KERNEL_MINOR_VERSION 13
+
+/** The node ID of the root inode */
+#define FUSE_ROOT_ID 1
+
+/* Make sure all structures are padded to 64bit boundary, so 32bit
+ userspace works under 64bit kernels */
+
+struct fuse_attr {
+ __u64 ino;
+ __u64 size;
+ __u64 blocks;
+ __u64 atime;
+ __u64 mtime;
+ __u64 ctime;
+ __u32 atimensec;
+ __u32 mtimensec;
+ __u32 ctimensec;
+ __u32 mode;
+ __u32 nlink;
+ __u32 uid;
+ __u32 gid;
+ __u32 rdev;
+ __u32 blksize;
+ __u32 padding;
+};
+
+struct fuse_kstatfs {
+ __u64 blocks;
+ __u64 bfree;
+ __u64 bavail;
+ __u64 files;
+ __u64 ffree;
+ __u32 bsize;
+ __u32 namelen;
+ __u32 frsize;
+ __u32 padding;
+ __u32 spare[6];
+};
+
+struct fuse_file_lock {
+ __u64 start;
+ __u64 end;
+ __u32 type;
+ __u32 pid; /* tgid */
+};
+
+/**
+ * Bitmasks for fuse_setattr_in.valid
+ */
+#define FATTR_MODE (1 << 0)
+#define FATTR_UID (1 << 1)
+#define FATTR_GID (1 << 2)
+#define FATTR_SIZE (1 << 3)
+#define FATTR_ATIME (1 << 4)
+#define FATTR_MTIME (1 << 5)
+#define FATTR_FH (1 << 6)
+#define FATTR_ATIME_NOW (1 << 7)
+#define FATTR_MTIME_NOW (1 << 8)
+#define FATTR_LOCKOWNER (1 << 9)
+
+/**
+ * Flags returned by the OPEN request
+ *
+ * FOPEN_DIRECT_IO: bypass page cache for this open file
+ * FOPEN_KEEP_CACHE: don't invalidate the data cache on open
+ * FOPEN_NONSEEKABLE: the file is not seekable
+ */
+#define FOPEN_DIRECT_IO (1 << 0)
+#define FOPEN_KEEP_CACHE (1 << 1)
+#define FOPEN_NONSEEKABLE (1 << 2)
+
+/**
+ * INIT request/reply flags
+ *
+ * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
+ * FUSE_DONT_MASK: don't apply umask to file mode on create operations
+ */
+#define FUSE_ASYNC_READ (1 << 0)
+#define FUSE_POSIX_LOCKS (1 << 1)
+#define FUSE_FILE_OPS (1 << 2)
+#define FUSE_ATOMIC_O_TRUNC (1 << 3)
+#define FUSE_EXPORT_SUPPORT (1 << 4)
+#define FUSE_BIG_WRITES (1 << 5)
+#define FUSE_DONT_MASK (1 << 6)
+
+/**
+ * CUSE INIT request/reply flags
+ *
+ * CUSE_UNRESTRICTED_IOCTL: use unrestricted ioctl
+ */
+#define CUSE_UNRESTRICTED_IOCTL (1 << 0)
+
+/**
+ * Release flags
+ */
+#define FUSE_RELEASE_FLUSH (1 << 0)
+
+/**
+ * Getattr flags
+ */
+#define FUSE_GETATTR_FH (1 << 0)
+
+/**
+ * Lock flags
+ */
+#define FUSE_LK_FLOCK (1 << 0)
+
+/**
+ * WRITE flags
+ *
+ * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed
+ * FUSE_WRITE_LOCKOWNER: lock_owner field is valid
+ */
+#define FUSE_WRITE_CACHE (1 << 0)
+#define FUSE_WRITE_LOCKOWNER (1 << 1)
+
+/**
+ * Read flags
+ */
+#define FUSE_READ_LOCKOWNER (1 << 1)
+
+/**
+ * Ioctl flags
+ *
+ * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
+ * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
+ * FUSE_IOCTL_RETRY: retry with new iovecs
+ *
+ * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
+ */
+#define FUSE_IOCTL_COMPAT (1 << 0)
+#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
+#define FUSE_IOCTL_RETRY (1 << 2)
+
+#define FUSE_IOCTL_MAX_IOV 256
+
+/**
+ * Poll flags
+ *
+ * FUSE_POLL_SCHEDULE_NOTIFY: request poll notify
+ */
+#define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0)
+
+enum fuse_opcode {
+ FUSE_LOOKUP = 1,
+ FUSE_FORGET = 2, /* no reply */
+ FUSE_GETATTR = 3,
+ FUSE_SETATTR = 4,
+ FUSE_READLINK = 5,
+ FUSE_SYMLINK = 6,
+ FUSE_MKNOD = 8,
+ FUSE_MKDIR = 9,
+ FUSE_UNLINK = 10,
+ FUSE_RMDIR = 11,
+ FUSE_RENAME = 12,
+ FUSE_LINK = 13,
+ FUSE_OPEN = 14,
+ FUSE_READ = 15,
+ FUSE_WRITE = 16,
+ FUSE_STATFS = 17,
+ FUSE_RELEASE = 18,
+ FUSE_FSYNC = 20,
+ FUSE_SETXATTR = 21,
+ FUSE_GETXATTR = 22,
+ FUSE_LISTXATTR = 23,
+ FUSE_REMOVEXATTR = 24,
+ FUSE_FLUSH = 25,
+ FUSE_INIT = 26,
+ FUSE_OPENDIR = 27,
+ FUSE_READDIR = 28,
+ FUSE_RELEASEDIR = 29,
+ FUSE_FSYNCDIR = 30,
+ FUSE_GETLK = 31,
+ FUSE_SETLK = 32,
+ FUSE_SETLKW = 33,
+ FUSE_ACCESS = 34,
+ FUSE_CREATE = 35,
+ FUSE_INTERRUPT = 36,
+ FUSE_BMAP = 37,
+ FUSE_DESTROY = 38,
+ FUSE_IOCTL = 39,
+ FUSE_POLL = 40,
+
+ /* CUSE specific operations */
+ CUSE_INIT = 4096,
+};
+
+enum fuse_notify_code {
+ FUSE_NOTIFY_POLL = 1,
+ FUSE_NOTIFY_INVAL_INODE = 2,
+ FUSE_NOTIFY_INVAL_ENTRY = 3,
+ FUSE_NOTIFY_CODE_MAX,
+};
+
+/* The read buffer is required to be at least 8k, but may be much larger */
+#define FUSE_MIN_READ_BUFFER 8192
+
+#define FUSE_COMPAT_ENTRY_OUT_SIZE 120
+
+struct fuse_entry_out {
+ __u64 nodeid; /* Inode ID */
+ __u64 generation; /* Inode generation: nodeid:gen must
+ be unique for the fs's lifetime */
+ __u64 entry_valid; /* Cache timeout for the name */
+ __u64 attr_valid; /* Cache timeout for the attributes */
+ __u32 entry_valid_nsec;
+ __u32 attr_valid_nsec;
+ struct fuse_attr attr;
+};
+
+struct fuse_forget_in {
+ __u64 nlookup;
+};
+
+struct fuse_getattr_in {
+ __u32 getattr_flags;
+ __u32 dummy;
+ __u64 fh;
+};
+
+#define FUSE_COMPAT_ATTR_OUT_SIZE 96
+
+struct fuse_attr_out {
+ __u64 attr_valid; /* Cache timeout for the attributes */
+ __u32 attr_valid_nsec;
+ __u32 dummy;
+ struct fuse_attr attr;
+};
+
+#define FUSE_COMPAT_MKNOD_IN_SIZE 8
+
+struct fuse_mknod_in {
+ __u32 mode;
+ __u32 rdev;
+ __u32 umask;
+ __u32 padding;
+};
+
+struct fuse_mkdir_in {
+ __u32 mode;
+ __u32 umask;
+};
+
+struct fuse_rename_in {
+ __u64 newdir;
+};
+
+struct fuse_link_in {
+ __u64 oldnodeid;
+};
+
+struct fuse_setattr_in {
+ __u32 valid;
+ __u32 padding;
+ __u64 fh;
+ __u64 size;
+ __u64 lock_owner;
+ __u64 atime;
+ __u64 mtime;
+ __u64 unused2;
+ __u32 atimensec;
+ __u32 mtimensec;
+ __u32 unused3;
+ __u32 mode;
+ __u32 unused4;
+ __u32 uid;
+ __u32 gid;
+ __u32 unused5;
+};
+
+struct fuse_open_in {
+ __u32 flags;
+ __u32 unused;
+};
+
+struct fuse_create_in {
+ __u32 flags;
+ __u32 mode;
+ __u32 umask;
+ __u32 padding;
+};
+
+struct fuse_open_out {
+ __u64 fh;
+ __u32 open_flags;
+ __u32 padding;
+};
+
+struct fuse_release_in {
+ __u64 fh;
+ __u32 flags;
+ __u32 release_flags;
+ __u64 lock_owner;
+};
+
+struct fuse_flush_in {
+ __u64 fh;
+ __u32 unused;
+ __u32 padding;
+ __u64 lock_owner;
+};
+
+struct fuse_read_in {
+ __u64 fh;
+ __u64 offset;
+ __u32 size;
+ __u32 read_flags;
+ __u64 lock_owner;
+ __u32 flags;
+ __u32 padding;
+};
+
+#define FUSE_COMPAT_WRITE_IN_SIZE 24
+
+struct fuse_write_in {
+ __u64 fh;
+ __u64 offset;
+ __u32 size;
+ __u32 write_flags;
+ __u64 lock_owner;
+ __u32 flags;
+ __u32 padding;
+};
+
+struct fuse_write_out {
+ __u32 size;
+ __u32 padding;
+};
+
+#define FUSE_COMPAT_STATFS_SIZE 48
+
+struct fuse_statfs_out {
+ struct fuse_kstatfs st;
+};
+
+struct fuse_fsync_in {
+ __u64 fh;
+ __u32 fsync_flags;
+ __u32 padding;
+};
+
+struct fuse_setxattr_in {
+ __u32 size;
+ __u32 flags;
+};
+
+struct fuse_getxattr_in {
+ __u32 size;
+ __u32 padding;
+};
+
+struct fuse_getxattr_out {
+ __u32 size;
+ __u32 padding;
+};
+
+struct fuse_lk_in {
+ __u64 fh;
+ __u64 owner;
+ struct fuse_file_lock lk;
+ __u32 lk_flags;
+ __u32 padding;
+};
+
+struct fuse_lk_out {
+ struct fuse_file_lock lk;
+};
+
+struct fuse_access_in {
+ __u32 mask;
+ __u32 padding;
+};
+
+struct fuse_init_in {
+ __u32 major;
+ __u32 minor;
+ __u32 max_readahead;
+ __u32 flags;
+};
+
+struct fuse_init_out {
+ __u32 major;
+ __u32 minor;
+ __u32 max_readahead;
+ __u32 flags;
+ __u16 max_background;
+ __u16 congestion_threshold;
+ __u32 max_write;
+};
+
+#define CUSE_INIT_INFO_MAX 4096
+
+struct cuse_init_in {
+ __u32 major;
+ __u32 minor;
+ __u32 unused;
+ __u32 flags;
+};
+
+struct cuse_init_out {
+ __u32 major;
+ __u32 minor;
+ __u32 unused;
+ __u32 flags;
+ __u32 max_read;
+ __u32 max_write;
+ __u32 dev_major; /* chardev major */
+ __u32 dev_minor; /* chardev minor */
+ __u32 spare[10];
+};
+
+struct fuse_interrupt_in {
+ __u64 unique;
+};
+
+struct fuse_bmap_in {
+ __u64 block;
+ __u32 blocksize;
+ __u32 padding;
+};
+
+struct fuse_bmap_out {
+ __u64 block;
+};
+
+struct fuse_ioctl_in {
+ __u64 fh;
+ __u32 flags;
+ __u32 cmd;
+ __u64 arg;
+ __u32 in_size;
+ __u32 out_size;
+};
+
+struct fuse_ioctl_out {
+ __s32 result;
+ __u32 flags;
+ __u32 in_iovs;
+ __u32 out_iovs;
+};
+
+struct fuse_poll_in {
+ __u64 fh;
+ __u64 kh;
+ __u32 flags;
+ __u32 padding;
+};
+
+struct fuse_poll_out {
+ __u32 revents;
+ __u32 padding;
+};
+
+struct fuse_notify_poll_wakeup_out {
+ __u64 kh;
+};
+
+struct fuse_in_header {
+ __u32 len;
+ __u32 opcode;
+ __u64 unique;
+ __u64 nodeid;
+ __u32 uid;
+ __u32 gid;
+ __u32 pid;
+ __u32 padding;
+};
+
+struct fuse_out_header {
+ __u32 len;
+ __s32 error;
+ __u64 unique;
+};
+
+struct fuse_dirent {
+ __u64 ino;
+ __u64 off;
+ __u32 namelen;
+ __u32 type;
+ char name[0];
+};
+
+#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
+#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1))
+#define FUSE_DIRENT_SIZE(d) \
+ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
+
+struct fuse_notify_inval_inode_out {
+ __u64 ino;
+ __s64 off;
+ __s64 len;
+};
+
+struct fuse_notify_inval_entry_out {
+ __u64 parent;
+ __u32 namelen;
+ __u32 padding;
+};
+
+#endif /* _LINUX_FUSE_H */
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
new file mode 100644
index 0000000..82e6354
--- /dev/null
+++ b/sdcard/sdcard.c
@@ -0,0 +1,795 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/uio.h>
+#include <dirent.h>
+
+#include <private/android_filesystem_config.h>
+
+#include "fuse.h"
+
+/* README
+ *
+ * What is this?
+ *
+ * sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
+ * directory permissions (all files are given fixed owner, group, and
+ * permissions at creation, owner, group, and permissions are not
+ * changeable, symlinks and hardlinks are not createable, etc.
+ *
+ * usage: sdcard <path> <uid> <gid>
+ *
+ * It must be run as root, but will change to uid/gid as soon as it
+ * mounts a filesystem on /mnt/sdcard. It will refuse to run if uid or
+ * gid are zero.
+ *
+ *
+ * Things I believe to be true:
+ *
+ * - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
+ * CREAT) must bump that node's refcount
+ * - don't forget that FORGET can forget multiple references (req->nlookup)
+ * - if an op that returns a fuse_entry fails writing the reply to the
+ * kernel, you must rollback the refcount to reflect the reference the
+ * kernel did not actually acquire
+ *
+ *
+ * Bugs:
+ *
+ * - need to move/rename node on RENAME
+ */
+
+#define FUSE_TRACE 0
+
+#if FUSE_TRACE
+#define TRACE(x...) fprintf(stderr,x)
+#else
+#define TRACE(x...) do {} while (0)
+#endif
+
+#define ERROR(x...) fprintf(stderr,x)
+
+#define FUSE_UNKNOWN_INO 0xffffffff
+
+#define MOUNT_POINT "/mnt/sdcard"
+
+struct handle {
+ struct node *node;
+ int fd;
+};
+
+struct dirhandle {
+ struct node *node;
+ DIR *d;
+};
+
+struct node {
+ __u64 nid;
+ __u64 gen;
+
+ struct node *next;
+ struct node *child;
+ struct node *all;
+ struct node *parent;
+
+ __u32 refcount;
+ __u32 namelen;
+
+ char name[1];
+};
+
+struct fuse {
+ __u64 next_generation;
+ __u64 next_node_id;
+
+ int fd;
+
+ struct node *all;
+
+ struct node root;
+ char rootpath[1024];
+};
+
+#define PATH_BUFFER_SIZE 1024
+
+char *node_get_path(struct node *node, char *buf, const char *name)
+{
+ char *out = buf + PATH_BUFFER_SIZE - 1;
+ int len;
+ out[0] = 0;
+
+ if (name) {
+ len = strlen(name);
+ goto start;
+ }
+
+ while (node) {
+ name = node->name;
+ len = node->namelen;
+ node = node->parent;
+ start:
+ if ((len + 1) > (out - buf))
+ return 0;
+ out -= len;
+ memcpy(out, name, len);
+ out --;
+ out[0] = '/';
+ }
+
+ return out;
+}
+
+void attr_from_stat(struct fuse_attr *attr, struct stat *s)
+{
+ attr->ino = s->st_ino;
+ attr->size = s->st_size;
+ attr->blocks = s->st_blocks;
+ attr->atime = s->st_atime;
+ attr->mtime = s->st_mtime;
+ attr->ctime = s->st_ctime;
+ attr->atimensec = s->st_atime_nsec;
+ attr->mtimensec = s->st_mtime_nsec;
+ attr->ctimensec = s->st_ctime_nsec;
+ attr->mode = s->st_mode;
+ attr->nlink = s->st_nlink;
+
+ /* force permissions to something reasonable:
+ * world readable
+ * writable by the sdcard group
+ */
+ if (attr->mode & 0100) {
+ attr->mode = (attr->mode & (~0777)) | 0775;
+ } else {
+ attr->mode = (attr->mode & (~0777)) | 0664;
+ }
+
+ /* all files owned by root.sdcard */
+ attr->uid = 0;
+ attr->gid = AID_SDCARD_RW;
+}
+
+int node_get_attr(struct node *node, struct fuse_attr *attr)
+{
+ int res;
+ struct stat s;
+ char *path, buffer[PATH_BUFFER_SIZE];
+
+ path = node_get_path(node, buffer, 0);
+ res = lstat(path, &s);
+ if (res < 0) {
+ ERROR("lstat('%s') errno %d\n", path, errno);
+ return -1;
+ }
+
+ attr_from_stat(attr, &s);
+ attr->ino = node->nid;
+
+ return 0;
+}
+
+struct node *node_create(struct node *parent, const char *name, __u64 nid, __u64 gen)
+{
+ struct node *node;
+ int namelen = strlen(name);
+
+ node = calloc(1, sizeof(struct node) + namelen);
+ if (node == 0) {
+ return 0;
+ }
+
+ node->nid = nid;
+ node->gen = gen;
+ node->parent = parent;
+ node->next = parent->child;
+ parent->child = node;
+ memcpy(node->name, name, namelen + 1);
+ node->namelen = namelen;
+ parent->refcount++;
+
+ return node;
+}
+
+void fuse_init(struct fuse *fuse, int fd, const char *path)
+{
+ fuse->fd = fd;
+ fuse->next_node_id = 2;
+ fuse->next_generation = 0;
+
+ fuse->all = &fuse->root;
+
+ fuse->root.nid = FUSE_ROOT_ID; /* 1 */
+ fuse->root.next = 0;
+ fuse->root.child = 0;
+ fuse->root.parent = 0;
+
+ fuse->root.all = 0;
+ fuse->root.refcount = 2;
+
+ strcpy(fuse->root.name, path);
+ fuse->root.namelen = strlen(fuse->root.name);
+}
+
+static inline void *id_to_ptr(__u64 nid)
+{
+ return (void *) nid;
+}
+
+static inline __u64 ptr_to_id(void *ptr)
+{
+ return (__u64) ptr;
+}
+
+
+struct node *lookup_by_inode(struct fuse *fuse, __u64 nid)
+{
+ if (nid == FUSE_ROOT_ID) {
+ return &fuse->root;
+ } else {
+ return id_to_ptr(nid);
+ }
+}
+
+struct node *lookup_child_by_name(struct node *node, const char *name)
+{
+ for (node = node->child; node; node = node->next) {
+ if (!strcmp(name, node->name)) {
+ return node;
+ }
+ }
+ return 0;
+}
+
+struct node *lookup_child_by_inode(struct node *node, __u64 nid)
+{
+ for (node = node->child; node; node = node->next) {
+ if (node->nid == nid) {
+ return node;
+ }
+ }
+ return 0;
+}
+
+struct node *node_lookup(struct fuse *fuse, struct node *parent, const char *name,
+ struct fuse_attr *attr)
+{
+ int res;
+ struct stat s;
+ char *path, buffer[PATH_BUFFER_SIZE];
+ struct node *node;
+
+ path = node_get_path(parent, buffer, name);
+ /* XXX error? */
+
+ res = lstat(path, &s);
+ if (res < 0)
+ return 0;
+
+ node = lookup_child_by_name(parent, name);
+ if (!node) {
+ node = node_create(parent, name, fuse->next_node_id++, fuse->next_generation++);
+ if (!node)
+ return 0;
+ node->nid = ptr_to_id(node);
+ node->all = fuse->all;
+ fuse->all = node;
+ }
+
+ attr_from_stat(attr, &s);
+ attr->ino = node->nid;
+
+ return node;
+}
+
+void node_release(struct node *node)
+{
+ TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount);
+ node->refcount--;
+ if (node->refcount == 0) {
+ if (node->parent->child == node) {
+ node->parent->child = node->parent->child->next;
+ } else {
+ struct node *node2;
+
+ node2 = node->parent->child;
+ while (node2->next != node)
+ node2 = node2->next;
+ node2->next = node->next;
+ }
+
+ TRACE("DESTROY %p (%s)\n", node, node->name);
+
+ node_release(node->parent);
+
+ node->parent = 0;
+ node->next = 0;
+
+ /* TODO: remove debugging - poison memory */
+ memset(node, 0xef, sizeof(*node) + strlen(node->name));
+
+ free(node);
+ }
+}
+
+void fuse_status(struct fuse *fuse, __u64 unique, int err)
+{
+ struct fuse_out_header hdr;
+ hdr.len = sizeof(hdr);
+ hdr.error = err;
+ hdr.unique = unique;
+ if (err) {
+// ERROR("*** %d ***\n", err);
+ }
+ write(fuse->fd, &hdr, sizeof(hdr));
+}
+
+void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
+{
+ struct fuse_out_header hdr;
+ struct iovec vec[2];
+ int res;
+
+ hdr.len = len + sizeof(hdr);
+ hdr.error = 0;
+ hdr.unique = unique;
+
+ vec[0].iov_base = &hdr;
+ vec[0].iov_len = sizeof(hdr);
+ vec[1].iov_base = data;
+ vec[1].iov_len = len;
+
+ res = writev(fuse->fd, vec, 2);
+ if (res < 0) {
+ ERROR("*** REPLY FAILED *** %d\n", errno);
+ }
+}
+
+void lookup_entry(struct fuse *fuse, struct node *node,
+ const char *name, __u64 unique)
+{
+ struct fuse_entry_out out;
+
+ memset(&out, 0, sizeof(out));
+
+ node = node_lookup(fuse, node, name, &out.attr);
+ if (!node) {
+ fuse_status(fuse, unique, -ENOENT);
+ return;
+ }
+
+ node->refcount++;
+// fprintf(stderr,"ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount);
+ out.nodeid = node->nid;
+ out.generation = node->gen;
+ out.entry_valid = 10;
+ out.attr_valid = 10;
+
+ fuse_reply(fuse, unique, &out, sizeof(out));
+}
+
+void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *data, unsigned len)
+{
+ struct node *node;
+
+ if ((len < sizeof(*hdr)) || (hdr->len != len)) {
+ ERROR("malformed header\n");
+ return;
+ }
+
+ len -= hdr->len;
+
+ if (hdr->nodeid) {
+ node = lookup_by_inode(fuse, hdr->nodeid);
+ if (!node) {
+ fuse_status(fuse, hdr->unique, -ENOENT);
+ return;
+ }
+ } else {
+ node = 0;
+ }
+
+ switch (hdr->opcode) {
+ case FUSE_LOOKUP: { /* bytez[] -> entry_out */
+ TRACE("LOOKUP %llx %s\n", hdr->nodeid, (char*) data);
+ lookup_entry(fuse, node, (char*) data, hdr->unique);
+ return;
+ }
+ case FUSE_FORGET: {
+ struct fuse_forget_in *req = data;
+ TRACE("FORGET %llx (%s) #%lld\n", hdr->nodeid, node->name, req->nlookup);
+ /* no reply */
+ while (req->nlookup--)
+ node_release(node);
+ return;
+ }
+ case FUSE_GETATTR: { /* getattr_in -> attr_out */
+ struct fuse_getattr_in *req = data;
+ struct fuse_attr_out out;
+
+ TRACE("GETATTR flags=%x fh=%llx\n",req->getattr_flags, req->fh);
+
+ memset(&out, 0, sizeof(out));
+ node_get_attr(node, &out.attr);
+ out.attr_valid = 10;
+
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ return;
+ }
+ case FUSE_SETATTR: { /* setattr_in -> attr_out */
+ struct fuse_setattr_in *req = data;
+ struct fuse_attr_out out;
+ TRACE("SETATTR fh=%llx id=%llx valid=%x\n",
+ req->fh, hdr->nodeid, req->valid);
+
+ /* XXX */
+
+ memset(&out, 0, sizeof(out));
+ node_get_attr(node, &out.attr);
+ out.attr_valid = 10;
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ return;
+ }
+// case FUSE_READLINK:
+// case FUSE_SYMLINK:
+ case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
+ struct fuse_mknod_in *req = data;
+ char *path, buffer[PATH_BUFFER_SIZE];
+ char *name = ((char*) data) + sizeof(*req);
+ int res;
+ TRACE("MKNOD %s @ %llx\n", name, hdr->nodeid);
+ path = node_get_path(node, buffer, name);
+
+ req->mode = (req->mode & (~0777)) | 0664;
+ res = mknod(path, req->mode, req->rdev); /* XXX perm?*/
+ if (res < 0) {
+ fuse_status(fuse, hdr->unique, -errno);
+ } else {
+ lookup_entry(fuse, node, name, hdr->unique);
+ }
+ return;
+ }
+ case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
+ struct fuse_mkdir_in *req = data;
+ struct fuse_entry_out out;
+ char *path, buffer[PATH_BUFFER_SIZE];
+ char *name = ((char*) data) + sizeof(*req);
+ int res;
+ TRACE("MKDIR %s @ %llx 0%o\n", name, hdr->nodeid, req->mode);
+ path = node_get_path(node, buffer, name);
+
+ req->mode = (req->mode & (~0777)) | 0775;
+ res = mkdir(path, req->mode);
+ if (res < 0) {
+ fuse_status(fuse, hdr->unique, -errno);
+ } else {
+ lookup_entry(fuse, node, name, hdr->unique);
+ }
+ return;
+ }
+ case FUSE_UNLINK: { /* bytez[] -> */
+ char *path, buffer[PATH_BUFFER_SIZE];
+ int res;
+ TRACE("UNLINK %s @ %llx\n", (char*) data, hdr->nodeid);
+ path = node_get_path(node, buffer, (char*) data);
+ res = unlink(path);
+ fuse_status(fuse, hdr->unique, res ? -errno : 0);
+ return;
+ }
+ case FUSE_RMDIR: { /* bytez[] -> */
+ char *path, buffer[PATH_BUFFER_SIZE];
+ int res;
+ TRACE("RMDIR %s @ %llx\n", (char*) data, hdr->nodeid);
+ path = node_get_path(node, buffer, (char*) data);
+ res = rmdir(path);
+ fuse_status(fuse, hdr->unique, res ? -errno : 0);
+ return;
+ }
+ case FUSE_RENAME: { /* rename_in, oldname, newname -> */
+ struct fuse_rename_in *req = data;
+ char *oldname = ((char*) data) + sizeof(*req);
+ char *newname = oldname + strlen(oldname) + 1;
+ char *oldpath, oldbuffer[PATH_BUFFER_SIZE];
+ char *newpath, newbuffer[PATH_BUFFER_SIZE];
+ struct node *newnode;
+ int res;
+
+ newnode = lookup_by_inode(fuse, req->newdir);
+ if (!newnode) {
+ fuse_status(fuse, hdr->unique, -ENOENT);
+ return;
+ }
+
+ oldpath = node_get_path(node, oldbuffer, oldname);
+ newpath = node_get_path(newnode, newbuffer, newname);
+
+ res = rename(oldpath, newpath);
+ fuse_status(fuse, hdr->unique, res ? -errno : 0);
+ return;
+ }
+// case FUSE_LINK:
+ case FUSE_OPEN: { /* open_in -> open_out */
+ struct fuse_open_in *req = data;
+ struct fuse_open_out out;
+ char *path, buffer[PATH_BUFFER_SIZE];
+ struct handle *h;
+
+ h = malloc(sizeof(*h));
+ if (!h) {
+ fuse_status(fuse, hdr->unique, -ENOMEM);
+ return;
+ }
+
+ 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);
+ if (h->fd < 0) {
+ ERROR("ERROR\n");
+ fuse_status(fuse, hdr->unique, errno);
+ free(h);
+ return;
+ }
+ out.fh = ptr_to_id(h);
+ out.open_flags = 0;
+ out.padding = 0;
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ return;
+ }
+ case FUSE_READ: { /* read_in -> byte[] */
+ char buffer[128 * 1024];
+ struct fuse_read_in *req = data;
+ struct handle *h = id_to_ptr(req->fh);
+ int res;
+ TRACE("READ %p(%d) %u@%llu\n", h, h->fd, req->size, req->offset);
+ if (req->size > sizeof(buffer)) {
+ fuse_status(fuse, hdr->unique, -EINVAL);
+ return;
+ }
+ res = pread(h->fd, buffer, req->size, req->offset);
+ if (res < 0) {
+ fuse_status(fuse, hdr->unique, errno);
+ return;
+ }
+ fuse_reply(fuse, hdr->unique, buffer, res);
+ return;
+ }
+ case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
+ struct fuse_write_in *req = data;
+ struct fuse_write_out out;
+ struct handle *h = id_to_ptr(req->fh);
+ int res;
+ TRACE("WRITE %p(%d) %u@%llu\n", h, h->fd, req->size, req->offset);
+ res = pwrite(h->fd, ((char*) data) + sizeof(*req), req->size, req->offset);
+ if (res < 0) {
+ fuse_status(fuse, hdr->unique, errno);
+ return;
+ }
+ out.size = res;
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ goto oops;
+ }
+ case FUSE_STATFS: { /* getattr_in -> attr_out */
+ struct statfs stat;
+ struct fuse_statfs_out out;
+ int res;
+
+ TRACE("STATFS\n");
+
+ if (statfs(fuse->root.name, &stat)) {
+ fuse_status(fuse, hdr->unique, -errno);
+ return;
+ }
+
+ memset(&out, 0, sizeof(out));
+ out.st.blocks = stat.f_blocks;
+ out.st.bfree = stat.f_bfree;
+ out.st.bavail = stat.f_bavail;
+ out.st.files = stat.f_files;
+ out.st.ffree = stat.f_ffree;
+ out.st.bsize = stat.f_bsize;
+ out.st.namelen = stat.f_namelen;
+ out.st.frsize = stat.f_frsize;
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ return;
+ }
+ case FUSE_RELEASE: { /* release_in -> */
+ struct fuse_release_in *req = data;
+ struct handle *h = id_to_ptr(req->fh);
+ TRACE("RELEASE %p(%d)\n", h, h->fd);
+ close(h->fd);
+ free(h);
+ fuse_status(fuse, hdr->unique, 0);
+ return;
+ }
+// case FUSE_FSYNC:
+// case FUSE_SETXATTR:
+// case FUSE_GETXATTR:
+// case FUSE_LISTXATTR:
+// case FUSE_REMOVEXATTR:
+ case FUSE_FLUSH:
+ fuse_status(fuse, hdr->unique, 0);
+ return;
+ case FUSE_OPENDIR: { /* open_in -> open_out */
+ struct fuse_open_in *req = data;
+ struct fuse_open_out out;
+ char *path, buffer[PATH_BUFFER_SIZE];
+ struct dirhandle *h;
+
+ h = malloc(sizeof(*h));
+ if (!h) {
+ fuse_status(fuse, hdr->unique, -ENOMEM);
+ return;
+ }
+
+ path = node_get_path(node, buffer, 0);
+ TRACE("OPENDIR %llx '%s'\n", hdr->nodeid, path);
+ h->d = opendir(path);
+ if (h->d == 0) {
+ ERROR("ERROR\n");
+ fuse_status(fuse, hdr->unique, -errno);
+ free(h);
+ return;
+ }
+ out.fh = ptr_to_id(h);
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ return;
+ }
+ case FUSE_READDIR: {
+ struct fuse_read_in *req = data;
+ char buffer[8192];
+ struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
+ struct dirent *de;
+ struct dirhandle *h = id_to_ptr(req->fh);
+ TRACE("READDIR %p\n", h);
+ de = readdir(h->d);
+ if (!de) {
+ fuse_status(fuse, hdr->unique, 0);
+ return;
+ }
+ fde->ino = FUSE_UNKNOWN_INO;
+ fde->off = 0;
+ fde->type = de->d_type;
+ fde->namelen = strlen(de->d_name);
+ memcpy(fde->name, de->d_name, fde->namelen + 1);
+ fuse_reply(fuse, hdr->unique, fde,
+ FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
+ return;
+ }
+ case FUSE_RELEASEDIR: { /* release_in -> */
+ struct fuse_release_in *req = data;
+ struct dirhandle *h = id_to_ptr(req->fh);
+ TRACE("RELEASEDIR %p\n",h);
+ closedir(h->d);
+ free(h);
+ fuse_status(fuse, hdr->unique, 0);
+ return;
+ }
+// case FUSE_FSYNCDIR:
+ case FUSE_INIT: { /* init_in -> init_out */
+ struct fuse_init_in *req = data;
+ struct fuse_init_out out;
+
+ TRACE("INIT ver=%d.%d maxread=%d flags=%x\n",
+ req->major, req->minor, req->max_readahead, req->flags);
+
+ out.major = FUSE_KERNEL_VERSION;
+ out.minor = FUSE_KERNEL_MINOR_VERSION;
+ out.max_readahead = req->max_readahead;
+ out.flags = 0;
+ out.max_background = 32;
+ out.congestion_threshold = 32;
+ out.max_write = 256 * 1024;
+
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ return;
+ }
+ default: {
+ struct fuse_out_header h;
+ ERROR("NOTIMPL op=%d uniq=%llx nid=%llx\n",
+ hdr->opcode, hdr->unique, hdr->nodeid);
+
+ oops:
+ h.len = sizeof(h);
+ h.error = -ENOSYS;
+ h.unique = hdr->unique;
+ write(fuse->fd, &h, sizeof(h));
+ break;
+ }
+ }
+}
+
+void handle_fuse_requests(struct fuse *fuse)
+{
+ unsigned char req[256 * 1024 + 128];
+ int len;
+
+ for (;;) {
+ len = read(fuse->fd, req, 8192);
+ if (len < 0) {
+ if (errno == EINTR)
+ continue;
+ ERROR("handle_fuse_requests: errno=%d\n", errno);
+ return;
+ }
+ handle_fuse_request(fuse, (void*) req, (void*) (req + sizeof(struct fuse_in_header)), len);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ struct fuse fuse;
+ char opts[256];
+ int fd;
+ int res;
+ unsigned uid;
+ unsigned gid;
+ const char *path;
+
+ if (argc != 4) {
+ ERROR("usage: sdcard <path> <uid> <gid>\n");
+ return -1;
+ }
+
+ uid = strtoul(argv[2], 0, 10);
+ gid = strtoul(argv[3], 0, 10);
+ if (!uid || !gid) {
+ ERROR("uid and gid must be nonzero\n");
+ return -1;
+ }
+
+ path = argv[1];
+
+ /* cleanup from previous instance, if necessary */
+ umount2(MOUNT_POINT, 2);
+
+ fd = open("/dev/fuse", O_RDWR);
+ if (fd < 0){
+ ERROR("cannot open fuse device (%d)\n", errno);
+ return -1;
+ }
+
+ sprintf(opts, "fd=%i,rootmode=40000,default_permissions,allow_other,"
+ "user_id=%d,group_id=%d", fd, uid, gid);
+
+ res = mount("/dev/fuse", MOUNT_POINT, "fuse", MS_NOSUID | MS_NODEV, opts);
+ if (res < 0) {
+ ERROR("cannot mount fuse filesystem (%d)\n", errno);
+ return -1;
+ }
+
+ if (setgid(gid) < 0) {
+ ERROR("cannot setgid!\n");
+ return -1;
+ }
+ if (setuid(uid) < 0) {
+ ERROR("cannot setuid!\n");
+ return -1;
+ }
+
+ fuse_init(&fuse, fd, path);
+
+ umask(0);
+ handle_fuse_requests(&fuse);
+
+ return 0;
+}
diff --git a/sh/ThirdPartyProject.prop b/sh/ThirdPartyProject.prop
new file mode 100644
index 0000000..eb9167e
--- /dev/null
+++ b/sh/ThirdPartyProject.prop
@@ -0,0 +1,9 @@
+# Copyright 2010 Google Inc. All Rights Reserved.
+#Fri Jul 16 10:03:08 PDT 2010
+currentVersion=Unknown
+version=1.17
+isNative=true
+name=ash
+keywords=ash
+onDevice=true
+homepage=http\://www.in-ulm.de/~mascheck/various/ash/
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 58937cf..ef3980a 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -53,7 +53,8 @@
uptime \
vmstat \
nandread \
- ionice
+ ionice \
+ lsof
LOCAL_SRC_FILES:= \
toolbox.c \
diff --git a/toolbox/NOTICE b/toolbox/NOTICE
index 12f28b9..895b49a 100644
--- a/toolbox/NOTICE
+++ b/toolbox/NOTICE
@@ -1,5 +1,67 @@
-Copyright (c) 2008, The Android Open Source Project
+Copyright (c) 2010, The Android Open Source Project.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of The Android Open Source Project nor the names
+ of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+
+Copyright (c) 2009, The Android Open Source Project.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of The Android Open Source Project nor the names
+ of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+
+Copyright (c) 2008, The Android Open Source Project.
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/toolbox/df.c b/toolbox/df.c
index 90476bd..63940a1 100644
--- a/toolbox/df.c
+++ b/toolbox/df.c
@@ -6,6 +6,21 @@
static int ok = EXIT_SUCCESS;
+static void printsize(long long n)
+{
+ char unit = 'K';
+ n /= 1024;
+ if (n > 1024) {
+ n /= 1024;
+ unit = 'M';
+ }
+ if (n > 1024) {
+ n /= 1024;
+ unit = 'G';
+ }
+ printf("%4lld%c", n, unit);
+}
+
static void df(char *s, int always) {
struct statfs st;
@@ -14,18 +29,19 @@
ok = EXIT_FAILURE;
} else {
if (st.f_blocks == 0 && !always)
- return;
-
- printf("%s: %lldK total, %lldK used, %lldK available (block size %d)\n",
- s,
- ((long long)st.f_blocks * (long long)st.f_bsize) / 1024,
- ((long long)(st.f_blocks - (long long)st.f_bfree) * st.f_bsize) / 1024,
- ((long long)st.f_bfree * (long long)st.f_bsize) / 1024,
- (int) st.f_bsize);
+ return;
+ printf("%-20s ", s);
+ printsize((long long)st.f_blocks * (long long)st.f_bsize);
+ printf(" ");
+ printsize((long long)(st.f_blocks - (long long)st.f_bfree) * st.f_bsize);
+ printf(" ");
+ printsize((long long)st.f_bfree * (long long)st.f_bsize);
+ printf(" %d\n", (int) st.f_bsize);
}
}
int df_main(int argc, char *argv[]) {
+ printf("Filesystem Size Used Free Blksize\n");
if (argc == 1) {
char s[2000];
FILE *f = fopen("/proc/mounts", "r");
diff --git a/toolbox/ls.c b/toolbox/ls.c
index 6c8de7a..962bf47 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -297,8 +297,8 @@
date, name);
break;
case S_IFREG:
- printf("%s %-8s %-8s %8d %s %s\n",
- mode, user, group, (int) s.st_size, date, name);
+ printf("%s %-8s %-8s %8lld %s %s\n",
+ mode, user, group, s.st_size, date, name);
break;
case S_IFLNK: {
char linkto[256];
diff --git a/toolbox/lsof.c b/toolbox/lsof.c
new file mode 100644
index 0000000..99891db
--- /dev/null
+++ b/toolbox/lsof.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2010, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define BUF_MAX 1024
+#define CMD_DISPLAY_MAX 10
+
+struct pid_info_t {
+ pid_t pid;
+
+ char cmdline[CMD_DISPLAY_MAX];
+
+ char path[PATH_MAX];
+ ssize_t parent_length;
+};
+
+void print_header()
+{
+ printf("%-9s %5s %10s %4s %9s %18s %9s %10s %s\n",
+ "COMMAND",
+ "PID",
+ "USER",
+ "FD",
+ "TYPE",
+ "DEVICE",
+ "SIZE/OFF",
+ "NODE",
+ "NAME");
+}
+
+void print_type(char *type, struct pid_info_t* info)
+{
+ static ssize_t link_dest_size;
+ static char link_dest[PATH_MAX];
+
+ strncat(info->path, type, sizeof(info->path));
+ if ((link_dest_size = readlink(info->path, link_dest, sizeof(link_dest)-1)) < 0) {
+ if (errno == ENOENT)
+ goto out;
+
+ snprintf(link_dest, sizeof(link_dest), "%s (readlink: %s)", info->path, strerror(errno));
+ } else {
+ link_dest[link_dest_size] = '\0';
+ }
+
+ // Things that are just the root filesystem are uninteresting (we already know)
+ if (!strcmp(link_dest, "/"))
+ goto out;
+
+ printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n", info->cmdline, info->pid, "???", type,
+ "???", "???", "???", "???", link_dest);
+
+out:
+ info->path[info->parent_length] = '\0';
+}
+
+// Prints out all file that have been memory mapped
+void print_maps(struct pid_info_t* info)
+{
+ FILE *maps;
+ char buffer[PATH_MAX + 100];
+
+ size_t offset;
+ int major, minor;
+ char device[10];
+ long int inode;
+ char file[PATH_MAX];
+
+ strncat(info->path, "maps", sizeof(info->path));
+
+ maps = fopen(info->path, "r");
+ if (!maps)
+ goto out;
+
+ while (fscanf(maps, "%*x-%*x %*s %zx %5s %ld %s\n", &offset, device, &inode,
+ file) == 4) {
+ // We don't care about non-file maps
+ if (inode == 0 || !strcmp(device, "00:00"))
+ continue;
+
+ printf("%-9s %5d %10s %4s %9s %18s %9zd %10ld %s\n", info->cmdline, info->pid, "???", "mem",
+ "???", device, offset, inode, file);
+ }
+
+ fclose(maps);
+
+out:
+ info->path[info->parent_length] = '\0';
+}
+
+// Prints out all open file descriptors
+void print_fds(struct pid_info_t* info)
+{
+ static char* fd_path = "fd/";
+ strncat(info->path, fd_path, sizeof(info->path));
+
+ int previous_length = info->parent_length;
+ info->parent_length += strlen(fd_path);
+
+ DIR *dir = opendir(info->path);
+ if (dir == NULL) {
+ char msg[BUF_MAX];
+ snprintf(msg, sizeof(msg), "%s (opendir: %s)", info->path, strerror(errno));
+ printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n", info->cmdline, info->pid, "???", "FDS",
+ "", "", "", "", msg);
+ goto out;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(dir))) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+ continue;
+
+ print_type(de->d_name, info);
+ }
+ closedir(dir);
+
+out:
+ info->parent_length = previous_length;
+ info->path[info->parent_length] = '\0';
+}
+
+void lsof_dumpinfo(pid_t pid)
+{
+ int fd;
+ struct pid_info_t info;
+ info.pid = pid;
+
+ snprintf(info.path, sizeof(info.path), "/proc/%d/", pid);
+
+ info.parent_length = strlen(info.path);
+
+ // Read the command line information; each argument is terminated with NULL.
+ strncat(info.path, "cmdline", sizeof(info.path));
+ fd = open(info.path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Couldn't read %s\n", info.path);
+ return;
+ }
+ char cmdline[PATH_MAX];
+ if (read(fd, cmdline, sizeof(cmdline)) < 0) {
+ fprintf(stderr, "Error reading cmdline: %s: %s\n", info.path, strerror(errno));
+ close(fd);
+ return;
+ }
+ close(fd);
+ info.path[info.parent_length] = '\0';
+
+ // We only want the basename of the cmdline
+ strncpy(info.cmdline, basename(cmdline), sizeof(info.cmdline));
+ info.cmdline[sizeof(info.cmdline)-1] = '\0';
+
+ // Read each of these symlinks
+ print_type("cwd", &info);
+ print_type("exe", &info);
+ print_type("root", &info);
+
+ print_fds(&info);
+ print_maps(&info);
+}
+
+int lsof_main(int argc, char *argv[])
+{
+ DIR *dir = opendir("/proc");
+ if (dir == NULL) {
+ fprintf(stderr, "Couldn't open /proc\n");
+ return -1;
+ }
+
+ print_header();
+
+ struct dirent* de;
+ while ((de = readdir(dir))) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+ continue;
+
+ // Only inspect directories that are PID numbers
+ char* endptr;
+ long int pid = strtol(de->d_name, &endptr, 10);
+ if (*endptr != '\0')
+ continue;
+
+ lsof_dumpinfo(pid);
+ }
+ closedir(dir);
+
+ return 0;
+}
diff --git a/toolbox/netstat.c b/toolbox/netstat.c
index 6404309..5768599 100644
--- a/toolbox/netstat.c
+++ b/toolbox/netstat.c
@@ -9,7 +9,7 @@
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
+ * the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google, Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this
@@ -22,23 +22,37 @@
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
typedef union iaddr iaddr;
+typedef union iaddr6 iaddr6;
union iaddr {
unsigned u;
unsigned char b[4];
};
-
+
+union iaddr6 {
+ struct {
+ unsigned a;
+ unsigned b;
+ unsigned c;
+ unsigned d;
+ } u;
+ unsigned char b[16];
+};
+
static const char *state2str(unsigned state)
{
switch(state){
@@ -57,64 +71,84 @@
}
}
-void addr2str(iaddr addr, unsigned port, char *buf)
+/* addr + : + port + \0 */
+#define ADDR_LEN INET6_ADDRSTRLEN + 1 + 5 + 1
+
+static void addr2str(int af, const void *addr, unsigned port, char *buf)
{
- if(port) {
- snprintf(buf, 64, "%d.%d.%d.%d:%d",
- addr.b[0], addr.b[1], addr.b[2], addr.b[3], port);
- } else {
- snprintf(buf, 64, "%d.%d.%d.%d:*",
- addr.b[0], addr.b[1], addr.b[2], addr.b[3]);
+ if (inet_ntop(af, addr, buf, ADDR_LEN) == NULL) {
+ *buf = '\0';
+ return;
}
+ size_t len = strlen(buf);
+ if (port) {
+ snprintf(buf+len, ADDR_LEN-len, ":%d", port);
+ } else {
+ strncat(buf+len, ":*", ADDR_LEN-len-1);
+ }
+}
+
+static void ipv4(const char *filename, const char *label) {
+ FILE *fp = fopen(filename, "r");
+ if (fp == NULL) {
+ return;
+ }
+ char buf[BUFSIZ];
+ fgets(buf, BUFSIZ, fp);
+ while (fgets(buf, BUFSIZ, fp)){
+ char lip[ADDR_LEN];
+ char rip[ADDR_LEN];
+ iaddr laddr, raddr;
+ unsigned lport, rport, state, txq, rxq, num;
+ int n = sscanf(buf, " %d: %x:%x %x:%x %x %x:%x",
+ &num, &laddr.u, &lport, &raddr.u, &rport,
+ &state, &txq, &rxq);
+ if (n == 8) {
+ addr2str(AF_INET, &laddr, lport, lip);
+ addr2str(AF_INET, &raddr, rport, rip);
+
+ printf("%4s %6d %6d %-22s %-22s %s\n",
+ label, txq, rxq, lip, rip,
+ state2str(state));
+ }
+ }
+ fclose(fp);
+}
+
+static void ipv6(const char *filename, const char *label) {
+ FILE *fp = fopen(filename, "r");
+ if (fp == NULL) {
+ return;
+ }
+ char buf[BUFSIZ];
+ fgets(buf, BUFSIZ, fp);
+ while (fgets(buf, BUFSIZ, fp)){
+ char lip[ADDR_LEN];
+ char rip[ADDR_LEN];
+ iaddr6 laddr6, raddr6;
+ unsigned lport, rport, state, txq, rxq, num;
+ int n = sscanf(buf, " %d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %x:%x",
+ &num, &laddr6.u.a, &laddr6.u.b, &laddr6.u.c, &laddr6.u.d, &lport,
+ &raddr6.u.a, &raddr6.u.b, &raddr6.u.c, &raddr6.u.d, &rport,
+ &state, &txq, &rxq);
+ if (n == 14) {
+ addr2str(AF_INET6, &laddr6, lport, lip);
+ addr2str(AF_INET6, &raddr6, rport, rip);
+
+ printf("%4s %6d %6d %-22s %-22s %s\n",
+ label, txq, rxq, lip, rip,
+ state2str(state));
+ }
+ }
+ fclose(fp);
}
int netstat_main(int argc, char *argv[])
{
- char buf[512];
- char lip[64];
- char rip[64];
- iaddr laddr, raddr;
- unsigned lport, rport, state, txq, rxq, num;
- int n;
- FILE *fp;
-
printf("Proto Recv-Q Send-Q Local Address Foreign Address State\n");
-
- fp = fopen("/proc/net/tcp", "r");
- if(fp != 0) {
- fgets(buf, 512, fp);
- while(fgets(buf, 512, fp)){
- n = sscanf(buf, " %d: %x:%x %x:%x %x %x:%x",
- &num, &laddr.u, &lport, &raddr.u, &rport,
- &state, &txq, &rxq);
- if(n == 8) {
- addr2str(laddr, lport, lip);
- addr2str(raddr, rport, rip);
-
- printf("tcp %6d %6d %-22s %-22s %s\n",
- txq, rxq, lip, rip,
- state2str(state));
- }
- }
- fclose(fp);
- }
- fp = fopen("/proc/net/udp", "r");
- if(fp != 0) {
- fgets(buf, 512, fp);
- while(fgets(buf, 512, fp)){
- n = sscanf(buf, " %d: %x:%x %x:%x %x %x:%x",
- &num, &laddr.u, &lport, &raddr.u, &rport,
- &state, &txq, &rxq);
- if(n == 8) {
- addr2str(laddr, lport, lip);
- addr2str(raddr, rport, rip);
-
- printf("udp %6d %6d %-22s %-22s\n",
- txq, rxq, lip, rip);
- }
- }
- fclose(fp);
- }
-
+ ipv4("/proc/net/tcp", "tcp");
+ ipv4("/proc/net/udp", "udp");
+ ipv6("/proc/net/tcp6", "tcp6");
+ ipv6("/proc/net/udp6", "udp6");
return 0;
}
diff --git a/toolbox/uptime.c b/toolbox/uptime.c
index 8b1983d..3d8061c 100644
--- a/toolbox/uptime.c
+++ b/toolbox/uptime.c
@@ -1,17 +1,32 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (c) 2010, The Android Open Source Project
+ * All rights reserved.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
*/
#include <sys/time.h>