Merge "Refactor the code."
diff --git a/adb/Android.mk b/adb/Android.mk
index 8d38077..4f19d47 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -208,10 +208,11 @@
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
-LOCAL_C_INCLUDES += system/extras/ext4_utils system/core/fs_mgr/include
+LOCAL_C_INCLUDES += system/extras/ext4_utils
LOCAL_STATIC_LIBRARIES := \
libadbd \
+ libbase \
libfs_mgr \
liblog \
libcutils \
diff --git a/adb/adb_main.cpp b/adb/adb_main.cpp
index a03fcf1..fb17e89 100644
--- a/adb/adb_main.cpp
+++ b/adb/adb_main.cpp
@@ -110,6 +110,13 @@
#if defined(ALLOW_ADBD_ROOT)
char value[PROPERTY_VALUE_MAX];
+ // The emulator is never secure, so don't drop privileges there.
+ // TODO: this seems like a bug --- shouldn't the emulator behave like a device?
+ property_get("ro.kernel.qemu", value, "");
+ if (strcmp(value, "1") == 0) {
+ return false;
+ }
+
// The properties that affect `adb root` and `adb unroot` are ro.secure and
// ro.debuggable. In this context the names don't make the expected behavior
// particularly obvious.
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 3330baa..f9ca5ed 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -209,7 +209,11 @@
" adb get-devpath - prints: <device-path>\n"
" adb status-window - continuously print device status for a specified device\n"
" adb remount - remounts the /system, /vendor (if present) and /oem (if present) partitions on the device read-write\n"
- " adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
+ " adb reboot [bootloader|recovery]\n"
+ " - reboots the device, optionally into the bootloader or recovery program.\n"
+ " adb reboot sideload - reboots the device into the sideload mode in recovery program (adb root required).\n"
+ " adb reboot sideload-auto-reboot\n"
+ " - reboots into the sideload mode, then reboots automatically after the sideload regardless of the result.\n"
" adb reboot-bootloader - reboots the device into the bootloader\n"
" adb root - restarts the adbd daemon with root permissions\n"
" adb unroot - restarts the adbd daemon without root permissions\n"
@@ -1126,6 +1130,17 @@
}
}
+static int adb_connect_command(const char* command) {
+ int fd = adb_connect(command);
+ if (fd != -1) {
+ read_and_dump(fd);
+ adb_close(fd);
+ return 0;
+ }
+ fprintf(stderr, "Error: %s\n", adb_error());
+ return 1;
+}
+
int adb_commandline(int argc, const char **argv)
{
char buf[4096];
@@ -1475,20 +1490,14 @@
!strcmp(argv[0], "disable-verity") ||
!strcmp(argv[0], "enable-verity")) {
char command[100];
- if (!strcmp(argv[0], "reboot-bootloader"))
+ if (!strcmp(argv[0], "reboot-bootloader")) {
snprintf(command, sizeof(command), "reboot:bootloader");
- else if (argc > 1)
+ } else if (argc > 1) {
snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
- else
+ } else {
snprintf(command, sizeof(command), "%s:", argv[0]);
- int fd = adb_connect(command);
- if (fd >= 0) {
- read_and_dump(fd);
- adb_close(fd);
- return 0;
}
- fprintf(stderr,"error: %s\n", adb_error());
- return 1;
+ return adb_connect_command(command);
}
else if (!strcmp(argv[0], "bugreport")) {
if (argc != 1) return usage();
@@ -1713,15 +1722,7 @@
return adb_auth_keygen(argv[1]);
}
else if (!strcmp(argv[0], "jdwp")) {
- int fd = adb_connect("jdwp");
- if (fd >= 0) {
- read_and_dump(fd);
- adb_close(fd);
- return 0;
- } else {
- fprintf(stderr, "error: %s\n", adb_error());
- return -1;
- }
+ return adb_connect_command("jdwp");
}
/* "adb /?" is a common idiom under Windows */
else if (!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
diff --git a/adb/services.cpp b/adb/services.cpp
index abf8ea5..12eb406 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -32,6 +32,7 @@
#endif
#if !ADB_HOST
+#include "base/file.h"
#include "cutils/android_reboot.h"
#include "cutils/properties.h"
#endif
@@ -132,31 +133,72 @@
adb_close(fd);
}
-void reboot_service(int fd, void *arg)
-{
+static bool reboot_service_impl(int fd, const char* arg) {
+ const char* reboot_arg = arg;
+ bool auto_reboot = false;
+
+ if (strcmp(reboot_arg, "sideload-auto-reboot") == 0) {
+ auto_reboot = true;
+ reboot_arg = "sideload";
+ }
+
char buf[100];
- char property_val[PROPERTY_VALUE_MAX];
- int ret;
+ // It reboots into sideload mode by setting "--sideload" or "--sideload_auto_reboot"
+ // in the command file.
+ if (strcmp(reboot_arg, "sideload") == 0) {
+ if (getuid() != 0) {
+ snprintf(buf, sizeof(buf), "'adb root' is required for 'adb reboot sideload'.\n");
+ WriteStringFully(fd, buf);
+ return false;
+ }
+
+ const char* const recovery_dir = "/cache/recovery";
+ const char* const command_file = "/cache/recovery/command";
+ // Ensure /cache/recovery exists.
+ if (adb_mkdir(recovery_dir, 0770) == -1 && errno != EEXIST) {
+ D("Failed to create directory '%s': %s\n", recovery_dir, strerror(errno));
+ return false;
+ }
+
+ bool write_status = android::base::WriteStringToFile(
+ auto_reboot ? "--sideload_auto_reboot" : "--sideload", command_file);
+ if (!write_status) {
+ return false;
+ }
+
+ reboot_arg = "recovery";
+ }
sync();
- ret = snprintf(property_val, sizeof(property_val), "reboot,%s", (char *) arg);
- if (ret >= (int) sizeof(property_val)) {
+ char property_val[PROPERTY_VALUE_MAX];
+ int ret = snprintf(property_val, sizeof(property_val), "reboot,%s", reboot_arg);
+ if (ret >= static_cast<int>(sizeof(property_val))) {
snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret);
- WriteFdExactly(fd, buf, strlen(buf));
- goto cleanup;
+ WriteStringFully(fd, buf);
+ return false;
}
ret = property_set(ANDROID_RB_PROPERTY, property_val);
if (ret < 0) {
snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret);
- WriteFdExactly(fd, buf, strlen(buf));
- goto cleanup;
+ WriteStringFully(fd, buf);
+ return false;
}
- // Don't return early. Give the reboot command time to take effect
- // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
- while(1) { pause(); }
-cleanup:
+
+ return true;
+}
+
+void reboot_service(int fd, void* arg)
+{
+ if (reboot_service_impl(fd, static_cast<const char*>(arg))) {
+ // Don't return early. Give the reboot command time to take effect
+ // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
+ while (1) {
+ pause();
+ }
+ }
+
free(arg);
adb_close(fd);
}
diff --git a/base/Android.mk b/base/Android.mk
index 7bd317b..ad85c6b 100644
--- a/base/Android.mk
+++ b/base/Android.mk
@@ -18,13 +18,11 @@
libbase_src_files := \
file.cpp \
- logging.cpp \
stringprintf.cpp \
strings.cpp \
libbase_test_src_files := \
file_test.cpp \
- logging_test.cpp \
stringprintf_test.cpp \
strings_test.cpp \
test_main.cpp \
@@ -40,7 +38,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libbase
LOCAL_CLANG := true
-LOCAL_SRC_FILES := $(libbase_src_files)
+LOCAL_SRC_FILES := $(libbase_src_files) logging.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_CPPFLAGS := $(libbase_cppflags)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
@@ -63,6 +61,9 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libbase
LOCAL_SRC_FILES := $(libbase_src_files)
+ifneq ($(HOST_OS),windows)
+ LOCAL_SRC_FILES += logging.cpp
+endif
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_CPPFLAGS := $(libbase_cppflags)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
@@ -84,7 +85,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libbase_test
LOCAL_CLANG := true
-LOCAL_SRC_FILES := $(libbase_test_src_files)
+LOCAL_SRC_FILES := $(libbase_test_src_files) logging_test.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_CPPFLAGS := $(libbase_cppflags)
LOCAL_SHARED_LIBRARIES := libbase
@@ -96,6 +97,9 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libbase_test
LOCAL_SRC_FILES := $(libbase_test_src_files)
+ifneq ($(HOST_OS),windows)
+ LOCAL_SRC_FILES += logging_test.cpp
+endif
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_CPPFLAGS := $(libbase_cppflags)
LOCAL_SHARED_LIBRARIES := libbase
diff --git a/include/cutils/klog.h b/include/cutils/klog.h
index d5ae6d7..295d62b 100644
--- a/include/cutils/klog.h
+++ b/include/cutils/klog.h
@@ -18,6 +18,7 @@
#define _CUTILS_KLOG_H_
#include <sys/cdefs.h>
+#include <sys/uio.h>
#include <stdarg.h>
__BEGIN_DECLS
@@ -26,9 +27,10 @@
int klog_get_level(void);
void klog_set_level(int level);
/* TODO: void klog_close(void); - and make klog_fd users thread safe. */
+
void klog_write(int level, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
-void klog_vwrite(int level, const char *fmt, va_list ap);
+void klog_writev(int level, const struct iovec* iov, int iov_count);
__END_DECLS
diff --git a/init/Android.mk b/init/Android.mk
index 5b8094f..94d3dad 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -18,17 +18,21 @@
-Wno-unused-parameter \
-Werror \
+init_clang := true
+
# --
include $(CLEAR_VARS)
LOCAL_CPPFLAGS := $(init_cflags)
LOCAL_SRC_FILES:= \
init_parser.cpp \
+ log.cpp \
parser.cpp \
util.cpp \
LOCAL_STATIC_LIBRARIES := libbase
LOCAL_MODULE := libinit
+LOCAL_CLANG := $(init_clang)
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -68,6 +72,7 @@
ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd
+LOCAL_CLANG := $(init_clang)
include $(BUILD_EXECUTABLE)
@@ -84,4 +89,5 @@
libbase \
LOCAL_STATIC_LIBRARIES := libinit
+LOCAL_CLANG := $(init_clang)
include $(BUILD_NATIVE_TEST)
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index 03c8b30..95687cb 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -195,13 +195,8 @@
}
// Create kernel process accounting file.
- {
- int fd = open( LOG_ACCT, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC,0644);
- if (fd >= 0) {
- close(fd);
- acct( LOG_ACCT );
- }
- }
+ close(open(LOG_ACCT, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644));
+ acct(LOG_ACCT);
log_header();
return count;
@@ -210,11 +205,12 @@
int do_bootchart_init(int nargs, char** args) {
g_remaining_samples = bootchart_init();
if (g_remaining_samples < 0) {
- ERROR("bootcharting init failure: %s\n", strerror(errno));
+ ERROR("Bootcharting init failure: %s\n", strerror(errno));
} else if (g_remaining_samples > 0) {
- NOTICE("bootcharting started (will run for %d ms)\n", g_remaining_samples*BOOTCHART_POLLING_MS);
+ NOTICE("Bootcharting started (will run for %d s).\n",
+ (g_remaining_samples * BOOTCHART_POLLING_MS) / 1000);
} else {
- NOTICE("bootcharting ignored\n");
+ NOTICE("Not bootcharting.\n");
}
return 0;
}
diff --git a/init/devices.cpp b/init/devices.cpp
index 9bce39a..96b1696 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -364,13 +364,6 @@
return 0;
}
-static inline suseconds_t get_usecs(void)
-{
- struct timeval tv;
- gettimeofday(&tv, 0);
- return tv.tv_sec * (suseconds_t) 1000000 + tv.tv_usec;
-}
-
static void parse_event(const char *msg, struct uevent *uevent)
{
uevent->action = "";
@@ -990,12 +983,7 @@
}
}
-void device_init(void)
-{
- suseconds_t t0, t1;
- struct stat info;
- int fd;
-
+void device_init() {
sehandle = NULL;
if (is_selinux_enabled() > 0) {
sehandle = selinux_android_file_context_handle();
@@ -1004,26 +992,22 @@
/* is 256K enough? udev uses 16MB! */
device_fd = uevent_open_socket(256*1024, true);
- if(device_fd < 0)
+ if (device_fd == -1) {
return;
-
- fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+ }
fcntl(device_fd, F_SETFL, O_NONBLOCK);
- if (stat(COLDBOOT_DONE, &info) < 0) {
- t0 = get_usecs();
- coldboot("/sys/class");
- coldboot("/sys/block");
- coldboot("/sys/devices");
- t1 = get_usecs();
- fd = open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000);
- close(fd);
- if (LOG_UEVENTS) {
- INFO("coldboot %ld uS\n", ((long) (t1 - t0)));
- }
- } else if (LOG_UEVENTS) {
- INFO("skipping coldboot, already done\n");
+ if (access(COLDBOOT_DONE, F_OK) == 0) {
+ NOTICE("Skipping coldboot, already done!\n");
+ return;
}
+
+ Timer t;
+ coldboot("/sys/class");
+ coldboot("/sys/block");
+ coldboot("/sys/devices");
+ close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
+ NOTICE("Coldboot took %.2fs.\n", t.duration());
}
int get_device_fd()
diff --git a/init/init.cpp b/init/init.cpp
index 1449bc6..b1d65db 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -83,7 +83,7 @@
bool waiting_for_exec = false;
void service::NotifyStateChange(const char* new_state) {
- if (!properties_inited()) {
+ if (!properties_initialized()) {
// If properties aren't available yet, we can't set them.
return;
}
@@ -246,7 +246,7 @@
}
}
- NOTICE("starting '%s'\n", svc->name);
+ NOTICE("Starting service '%s'...\n", svc->name);
pid_t pid = fork();
if (pid == 0) {
@@ -256,7 +256,7 @@
int fd, sz;
umask(077);
- if (properties_inited()) {
+ if (properties_initialized()) {
get_property_workspace(&fd, &sz);
snprintf(tmp, sizeof(tmp), "%d,%d", dup(fd), sz);
add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
@@ -397,7 +397,7 @@
}
if (svc->pid) {
- NOTICE("service '%s' is being killed\n", svc->name);
+ NOTICE("Service '%s' is being killed...\n", svc->name);
kill(-svc->pid, SIGKILL);
svc->NotifyStateChange("stopping");
} else {
@@ -559,17 +559,18 @@
}
}
-void execute_one_command(void)
-{
- int ret, i;
+void execute_one_command() {
+ Timer t;
+
char cmd_str[256] = "";
char name_str[256] = "";
if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
cur_action = action_remove_queue_head();
cur_command = NULL;
- if (!cur_action)
+ if (!cur_action) {
return;
+ }
build_triggers_string(name_str, sizeof(name_str), cur_action);
@@ -579,20 +580,26 @@
cur_command = get_next_command(cur_action, cur_command);
}
- if (!cur_command)
+ if (!cur_command) {
return;
+ }
- ret = cur_command->func(cur_command->nargs, cur_command->args);
+ int result = cur_command->func(cur_command->nargs, cur_command->args);
if (klog_get_level() >= KLOG_INFO_LEVEL) {
- for (i = 0; i < cur_command->nargs; i++) {
+ for (int i = 0; i < cur_command->nargs; i++) {
strlcat(cmd_str, cur_command->args[i], sizeof(cmd_str));
if (i < cur_command->nargs - 1) {
strlcat(cmd_str, " ", sizeof(cmd_str));
}
}
- INFO("command '%s' action=%s status=%d (%s:%d)\n",
- cmd_str, cur_action ? name_str : "", ret, cur_command->filename,
- cur_command->line);
+ char source[256];
+ if (cur_command->filename) {
+ snprintf(source, sizeof(source), " (%s:%d)", cur_command->filename, cur_command->line);
+ } else {
+ *source = '\0';
+ }
+ INFO("Command '%s' action=%s%s returned %d took %.2fs\n",
+ cmd_str, cur_action ? name_str : "", source, result, t.duration());
}
}
@@ -928,40 +935,25 @@
return 0;
}
-static int audit_callback(void *data, security_class_t /*cls*/, char *buf, size_t len)
-{
+static int audit_callback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
snprintf(buf, len, "property=%s", !data ? "NULL" : (char *)data);
return 0;
}
-int log_callback(int type, const char *fmt, ...)
-{
- int level;
- va_list ap;
- switch (type) {
- case SELINUX_WARNING:
- level = KLOG_WARNING_LEVEL;
- break;
- case SELINUX_INFO:
- level = KLOG_INFO_LEVEL;
- break;
- default:
- level = KLOG_ERROR_LEVEL;
- break;
- }
- va_start(ap, fmt);
- klog_vwrite(level, fmt, ap);
- va_end(ap);
- return 0;
-}
+static void selinux_initialize() {
+ Timer t;
-static void selinux_initialize(void)
-{
+ selinux_callback cb;
+ cb.func_log = selinux_klog_callback;
+ selinux_set_callback(SELINUX_CB_LOG, cb);
+ cb.func_audit = audit_callback;
+ selinux_set_callback(SELINUX_CB_AUDIT, cb);
+
if (selinux_is_disabled()) {
return;
}
- INFO("loading selinux policy\n");
+ INFO("Loading SELinux policy...\n");
if (selinux_android_load_policy() < 0) {
ERROR("SELinux: Failed to load policy; rebooting into recovery mode\n");
android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
@@ -972,14 +964,18 @@
bool is_enforcing = selinux_is_enforcing();
INFO("SELinux: security_setenforce(%d)\n", is_enforcing);
security_setenforce(is_enforcing);
+
+ NOTICE("(Initializing SELinux took %.2fs.)\n", t.duration());
}
int main(int argc, char** argv) {
- if (!strcmp(basename(argv[0]), "ueventd"))
+ if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
+ }
- if (!strcmp(basename(argv[0]), "watchdogd"))
+ if (!strcmp(basename(argv[0]), "watchdogd")) {
return watchdogd_main(argc, argv);
+ }
// Clear the umask.
umask(0);
@@ -1008,36 +1004,32 @@
// to the outside world.
open_devnull_stdio();
klog_init();
+ klog_set_level(KLOG_NOTICE_LEVEL);
+
+ NOTICE("init started!\n");
+
property_init();
+ // If arguments are passed both on the command line and in DT,
+ // properties set in DT always have priority over the command-line ones.
process_kernel_dt();
- /* in case one is passing arguments both on the command line and in DT
- * Properties set in DT always have priority over the command-line ones
- */
process_kernel_cmdline();
- /* now propogate the kernel variables to internal variables
- * used by init as well as the current required properties
- */
+ // Propogate the kernel variables to internal variables
+ // used by init as well as the current required properties.
export_kernel_boot_props();
- selinux_callback cb;
- cb.func_log = log_callback;
- selinux_set_callback(SELINUX_CB_LOG, cb);
- cb.func_audit = audit_callback;
- selinux_set_callback(SELINUX_CB_AUDIT, cb);
-
selinux_initialize();
// These directories were necessarily created before initial policy load
// and therefore need their security context restored to the proper value.
// This must happen before /dev is populated by ueventd.
+ INFO("Running restorecon...\n");
restorecon("/dev");
restorecon("/dev/socket");
restorecon("/dev/__properties__");
restorecon_recursive("/sys");
- INFO("property init\n");
property_load_boot_defaults();
init_parse_config_file("/init.rc");
@@ -1049,7 +1041,7 @@
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(console_init_action, "console_init");
- // Execute all the boot actions to get us started.
+ // Trigger all the boot actions to get us started.
action_for_each_trigger("init", action_add_queue_tail);
// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 57eb299..294dc19 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -14,15 +14,16 @@
* limitations under the License.
*/
+#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdarg.h>
#include <string.h>
-#include <stddef.h>
-#include <ctype.h>
+#include <unistd.h>
#include "init.h"
#include "parser.h"
@@ -351,7 +352,7 @@
struct import* import = (struct import*) calloc(1, sizeof(struct import));
import->filename = strdup(conf_file);
list_add_tail(import_list, &import->list);
- INFO("found import '%s', adding to import list", import->filename);
+ INFO("Added '%s' to import list\n", import->filename);
}
static void parse_new_section(struct parse_state *state, int kw,
@@ -439,6 +440,7 @@
int init_parse_config_file(const char* path) {
INFO("Parsing %s...\n", path);
+ Timer t;
std::string data;
if (!read_file(path, &data)) {
return -1;
@@ -446,6 +448,8 @@
parse_config(path, data);
dump_parser_state();
+
+ NOTICE("(Parsing %s took %.2fs.)\n", path, t.duration());
return 0;
}
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 2e996ea..27894a2 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -109,7 +109,7 @@
if (!strcmp(adb_enabled, "running")) {
svc = service_find_by_keychord(id);
if (svc) {
- INFO("starting service %s from keychord\n", svc->name);
+ INFO("Starting service %s from keychord\n", svc->name);
service_start(svc, NULL);
} else {
ERROR("service for keychord %d not found\n", id);
diff --git a/init/log.cpp b/init/log.cpp
new file mode 100644
index 0000000..d32f2da
--- /dev/null
+++ b/init/log.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+
+#include <selinux/selinux.h>
+
+#include "log.h"
+
+static void init_klog_vwrite(int level, const char* fmt, va_list ap) {
+ static const char* tag = basename(getprogname());
+
+ char prefix[64];
+ snprintf(prefix, sizeof(prefix), "<%d>%s: ", level, tag);
+
+ char msg[512];
+ vsnprintf(msg, sizeof(msg), fmt, ap);
+
+ iovec iov[2];
+ iov[0].iov_base = prefix;
+ iov[0].iov_len = strlen(prefix);
+ iov[1].iov_base = msg;
+ iov[1].iov_len = strlen(msg);
+
+ klog_writev(level, iov, 2);
+}
+
+void init_klog_write(int level, const char* fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ init_klog_vwrite(level, fmt, ap);
+ va_end(ap);
+}
+
+int selinux_klog_callback(int type, const char *fmt, ...) {
+ int level = KLOG_ERROR_LEVEL;
+ if (type == SELINUX_WARNING) {
+ level = KLOG_WARNING_LEVEL;
+ } else if (type == SELINUX_INFO) {
+ level = KLOG_INFO_LEVEL;
+ }
+ va_list ap;
+ va_start(ap, fmt);
+ init_klog_vwrite(level, fmt, ap);
+ va_end(ap);
+ return 0;
+}
diff --git a/init/log.h b/init/log.h
index e9cb65a..b804d1f 100644
--- a/init/log.h
+++ b/init/log.h
@@ -19,10 +19,11 @@
#include <cutils/klog.h>
-#define ERROR(x...) KLOG_ERROR("init", x)
-#define NOTICE(x...) KLOG_NOTICE("init", x)
-#define INFO(x...) KLOG_INFO("init", x)
+#define ERROR(x...) init_klog_write(KLOG_ERROR_LEVEL, x)
+#define NOTICE(x...) init_klog_write(KLOG_NOTICE_LEVEL, x)
+#define INFO(x...) init_klog_write(KLOG_INFO_LEVEL, x)
-extern int log_callback(int type, const char *fmt, ...);
+void init_klog_write(int level, const char* fmt, ...) __printflike(2, 3);
+int selinux_klog_callback(int level, const char* fmt, ...) __printflike(2, 3);
#endif
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 363b377..2fa81d4 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -54,7 +54,7 @@
#define PERSISTENT_PROPERTY_DIR "/data/property"
static int persistent_properties_loaded = 0;
-static int property_area_inited = 0;
+static bool property_area_initialized = false;
static int property_set_fd = -1;
@@ -63,34 +63,25 @@
int fd;
};
-static int init_workspace(workspace *w, size_t size)
-{
- int fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW);
- if (fd < 0)
- return -1;
-
- w->size = size;
- w->fd = fd;
- return 0;
-}
-
static workspace pa_workspace;
-static int init_property_area(void)
-{
- if (property_area_inited)
- return -1;
+void property_init() {
+ if (property_area_initialized) {
+ return;
+ }
- if(__system_property_area_init())
- return -1;
+ property_area_initialized = true;
- if(init_workspace(&pa_workspace, 0))
- return -1;
+ if (__system_property_area_init()) {
+ return;
+ }
- fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
-
- property_area_inited = 1;
- return 0;
+ pa_workspace.size = 0;
+ pa_workspace.fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
+ if (pa_workspace.fd == -1) {
+ ERROR("Failed to open %s: %s\n", PROP_FILENAME, strerror(errno));
+ return;
+ }
}
static int check_mac_perms(const char *name, char *sctx)
@@ -419,12 +410,13 @@
* Filter is used to decide which properties to load: NULL loads all keys,
* "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
*/
-static void load_properties_from_file(const char *fn, const char *filter)
-{
+static void load_properties_from_file(const char* filename, const char* filter) {
+ Timer t;
std::string data;
- if (read_file(fn, &data)) {
+ if (read_file(filename, &data)) {
load_properties(&data[0], filter);
}
+ NOTICE("(Loading properties from %s took %.2fs.)\n", filename, t.duration());
}
static void load_persistent_properties() {
@@ -485,19 +477,12 @@
}
}
-void property_init(void)
-{
- init_property_area();
-}
-
-void property_load_boot_defaults(void)
-{
+void property_load_boot_defaults() {
load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL);
}
-int properties_inited(void)
-{
- return property_area_inited;
+bool properties_initialized() {
+ return property_area_initialized;
}
static void load_override_properties() {
@@ -510,21 +495,18 @@
}
}
-
/* When booting an encrypted system, /data is not mounted when the
* property service is started, so any properties stored there are
* not loaded. Vold triggers init to load these properties once it
* has mounted /data.
*/
-void load_persist_props(void)
-{
+void load_persist_props(void) {
load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
}
-void load_all_props(void)
-{
+void load_all_props() {
load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL);
load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);
@@ -537,12 +519,10 @@
load_persistent_properties();
}
-void start_property_service(void)
-{
- int fd;
+void start_property_service() {
+ int fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);
+ if (fd == -1) return;
- fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);
- if(fd < 0) return;
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, O_NONBLOCK);
@@ -550,7 +530,6 @@
property_set_fd = fd;
}
-int get_property_set_fd()
-{
+int get_property_set_fd() {
return property_set_fd;
}
diff --git a/init/property_service.h b/init/property_service.h
index 6e7fc00..825a7dd 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -29,7 +29,7 @@
void get_property_workspace(int *fd, int *sz);
extern int __property_get(const char *name, char *value);
extern int property_set(const char *name, const char *value);
-extern int properties_inited();
+extern bool properties_initialized();
int get_property_set_fd(void);
#ifndef __clang__
diff --git a/init/readme.txt b/init/readme.txt
index 4c8d0d3..630dd03 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -323,12 +323,11 @@
Bootcharting
------------
-
This version of init contains code to perform "bootcharting": generating log
files that can be later processed by the tools provided by www.bootchart.org.
-On the emulator, use the new -bootchart <timeout> option to boot with
-bootcharting activated for <timeout> seconds.
+On the emulator, use the -bootchart <timeout> option to boot with bootcharting
+activated for <timeout> seconds.
On a device, create /data/bootchart/start with a command like the following:
@@ -349,9 +348,13 @@
bootchart command-line utility:
sudo apt-get install pybootchartgui
- ANDROID_SERIAL=<device serial number>
+ # grab-bootchart.sh uses $ANDROID_SERIAL.
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
+One thing to watch for is that the bootchart will show init as if it started
+running at 0s. You'll have to look at dmesg to work out when the kernel
+actually started init.
+
Debugging init
--------------
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index c428b96..8be4af5 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -18,18 +18,23 @@
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <sys/wait.h>
-#include <cutils/sockets.h>
+#include <unistd.h>
+
+#include <base/stringprintf.h>
#include <cutils/android_reboot.h>
#include <cutils/list.h>
+#include <cutils/sockets.h>
#include "init.h"
#include "log.h"
#include "util.h"
+#define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */
+#define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery */
+
static int signal_fd = -1;
static int signal_recv_fd = -1;
@@ -37,8 +42,17 @@
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 */
+std::string DescribeStatus(int status) {
+ if (WIFEXITED(status)) {
+ return android::base::StringPrintf("exited with status %d", WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ return android::base::StringPrintf("killed by signal %d", WTERMSIG(status));
+ } else if (WIFSTOPPED(status)) {
+ return android::base::StringPrintf("stopped by signal %d", WSTOPSIG(status));
+ } else {
+ return "state changed";
+ }
+}
static int wait_for_one_process() {
int status;
@@ -46,28 +60,26 @@
if (pid <= 0) {
return -1;
}
- INFO("waitpid returned pid %d, status = %08x\n", pid, status);
service* svc = service_find_by_pid(pid);
+
+ std::string name;
+ if (svc) {
+ name = android::base::StringPrintf("Service '%s' (pid %d)", svc->name, pid);
+ } else {
+ name = android::base::StringPrintf("Untracked pid %d", pid);
+ }
+
+ NOTICE("%s %s\n", name.c_str(), DescribeStatus(status).c_str());
+
if (!svc) {
- if (WIFEXITED(status)) {
- ERROR("untracked pid %d exited with status %d\n", pid, WEXITSTATUS(status));
- } else if (WIFSIGNALED(status)) {
- ERROR("untracked pid %d killed by signal %d\n", pid, WTERMSIG(status));
- } else if (WIFSTOPPED(status)) {
- ERROR("untracked pid %d stopped by signal %d\n", pid, WSTOPSIG(status));
- } else {
- ERROR("untracked pid %d state changed\n", pid);
- }
return 0;
}
// TODO: all the code from here down should be a member function on service.
- NOTICE("process '%s', pid %d exited\n", svc->name, pid);
-
if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {
- NOTICE("process '%s' killing any children in process group\n", svc->name);
+ NOTICE("Service '%s' (pid %d) killing any children in process group\n", svc->name, pid);
kill(-pid, SIGKILL);
}
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 5af6e3d..c63fdaa 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -14,16 +14,17 @@
* limitations under the License.
*/
-#include <poll.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
#include <ctype.h>
+#include <fcntl.h>
+#include <poll.h>
#include <signal.h>
-#include <selinux/selinux.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <base/stringprintf.h>
#include <private/android_filesystem_config.h>
+#include <selinux/selinux.h>
#include "ueventd.h"
#include "log.h"
@@ -34,11 +35,6 @@
int ueventd_main(int argc, char **argv)
{
- struct pollfd ufd;
- int nr;
- char hardware[PROP_VALUE_MAX];
- char tmp[32];
-
/*
* init sets the umask to 077 for forked processes. We need to
* create files with exact permissions, without modification by
@@ -55,38 +51,35 @@
open_devnull_stdio();
klog_init();
- if (LOG_UEVENTS) {
- /* Ensure we're at a logging level that will show the events */
- if (klog_get_level() < KLOG_INFO_LEVEL) {
- klog_set_level(KLOG_INFO_LEVEL);
- }
- }
+ klog_set_level(KLOG_NOTICE_LEVEL);
- union selinux_callback cb;
- cb.func_log = log_callback;
+ NOTICE("ueventd started!\n");
+
+ selinux_callback cb;
+ cb.func_log = selinux_klog_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
- INFO("starting ueventd\n");
-
+ char hardware[PROP_VALUE_MAX];
property_get("ro.hardware", hardware);
ueventd_parse_config_file("/ueventd.rc");
-
- snprintf(tmp, sizeof(tmp), "/ueventd.%s.rc", hardware);
- ueventd_parse_config_file(tmp);
+ ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware).c_str());
device_init();
+ pollfd ufd;
ufd.events = POLLIN;
ufd.fd = get_device_fd();
- while(1) {
+ while (true) {
ufd.revents = 0;
- nr = poll(&ufd, 1, -1);
- if (nr <= 0)
+ int nr = poll(&ufd, 1, -1);
+ if (nr <= 0) {
continue;
- if (ufd.revents & POLLIN)
- handle_device_fd();
+ }
+ if (ufd.revents & POLLIN) {
+ handle_device_fd();
+ }
}
return 0;
diff --git a/init/util.cpp b/init/util.cpp
index 8b238d4..3b49b30 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -258,22 +258,16 @@
return -1;
}
-/*
- * gettime() - returns the time in seconds of the system's monotonic clock or
- * zero on error.
- */
-time_t gettime(void)
-{
- struct timespec ts;
- int ret;
+time_t gettime() {
+ timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ return now.tv_sec;
+}
- ret = clock_gettime(CLOCK_MONOTONIC, &ts);
- if (ret < 0) {
- ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
- return 0;
- }
-
- return ts.tv_sec;
+uint64_t gettime_ns() {
+ timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec;
}
int mkdir_recursive(const char *pathname, mode_t mode)
diff --git a/init/util.h b/init/util.h
index e0b3c69..8fec7a8 100644
--- a/init/util.h
+++ b/init/util.h
@@ -33,7 +33,22 @@
bool read_file(const char* path, std::string* content);
int write_file(const char* path, const char* content);
-time_t gettime(void);
+time_t gettime();
+uint64_t gettime_ns();
+
+class Timer {
+ public:
+ Timer() : t0(gettime_ns()) {
+ }
+
+ double duration() {
+ return static_cast<double>(gettime_ns() - t0) / 1000000000.0;
+ }
+
+ private:
+ uint64_t t0;
+};
+
unsigned int decode_uid(const char *s);
int mkdir_recursive(const char *pathname, mode_t mode);
diff --git a/init/watchdogd.cpp b/init/watchdogd.cpp
index 0790811..881a4df 100644
--- a/init/watchdogd.cpp
+++ b/init/watchdogd.cpp
@@ -27,52 +27,45 @@
#define DEV_NAME "/dev/watchdog"
-int watchdogd_main(int argc, char **argv)
-{
- int fd;
- int ret;
- int interval = 10;
- int margin = 10;
- int timeout;
-
+int watchdogd_main(int argc, char **argv) {
open_devnull_stdio();
klog_init();
+ klog_set_level(KLOG_NOTICE_LEVEL);
- INFO("Starting watchdogd\n");
+ int interval = 10;
+ if (argc >= 2) interval = atoi(argv[1]);
- if (argc >= 2)
- interval = atoi(argv[1]);
+ int margin = 10;
+ if (argc >= 3) margin = atoi(argv[2]);
- if (argc >= 3)
- margin = atoi(argv[2]);
+ NOTICE("watchdogd started (interval %d, margin %d)!\n", interval, margin);
- timeout = interval + margin;
-
- fd = open(DEV_NAME, O_RDWR|O_CLOEXEC);
- if (fd < 0) {
+ int fd = open(DEV_NAME, O_RDWR|O_CLOEXEC);
+ if (fd == -1) {
ERROR("watchdogd: Failed to open %s: %s\n", DEV_NAME, strerror(errno));
return 1;
}
- ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
+ int timeout = interval + margin;
+ int ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
if (ret) {
ERROR("watchdogd: Failed to set timeout to %d: %s\n", timeout, strerror(errno));
ret = ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
if (ret) {
ERROR("watchdogd: Failed to get timeout: %s\n", strerror(errno));
} else {
- if (timeout > margin)
+ if (timeout > margin) {
interval = timeout - margin;
- else
+ } else {
interval = 1;
+ }
ERROR("watchdogd: Adjusted interval to timeout returned by driver: timeout %d, interval %d, margin %d\n",
timeout, interval, margin);
}
}
- while(1) {
+ while (true) {
write(fd, "", 1);
sleep(interval);
}
}
-
diff --git a/libbacktrace/Android.build.mk b/libbacktrace/Android.build.mk
index ded0aac..35fed6d 100644
--- a/libbacktrace/Android.build.mk
+++ b/libbacktrace/Android.build.mk
@@ -35,6 +35,9 @@
$($(module)_cflags) \
$($(module)_cflags_$(build_type)) \
+LOCAL_CLANG_CFLAGS += \
+ $(libbacktrace_common_clang_cflags) \
+
LOCAL_CONLYFLAGS += \
$(libbacktrace_common_conlyflags) \
$($(module)_conlyflags) \
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index 20d7046..b875efd 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -26,6 +26,10 @@
libbacktrace_common_cppflags := \
-std=gnu++11 \
+# The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
+libbacktrace_common_clang_cflags += \
+ -Wno-inline-asm
+
build_host := false
ifeq ($(HOST_OS),linux)
ifeq ($(HOST_ARCH),$(filter $(HOST_ARCH),x86 x86_64))
diff --git a/libcutils/klog.c b/libcutils/klog.c
index fbb7b72..f574f08 100644
--- a/libcutils/klog.c
+++ b/libcutils/klog.c
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-#include <sys/stat.h>
-#include <sys/types.h>
+#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include <cutils/klog.h>
@@ -36,41 +37,36 @@
klog_level = level;
}
-void klog_init(void)
-{
- static const char *name = "/dev/__kmsg__";
-
+void klog_init(void) {
if (klog_fd >= 0) return; /* Already initialized */
+ static const char* name = "/dev/__kmsg__";
if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {
- klog_fd = open(name, O_WRONLY);
- if (klog_fd < 0)
- return;
- fcntl(klog_fd, F_SETFD, FD_CLOEXEC);
+ klog_fd = open(name, O_WRONLY | O_CLOEXEC);
unlink(name);
}
}
#define LOG_BUF_MAX 512
-void klog_vwrite(int level, const char *fmt, va_list ap)
-{
- char buf[LOG_BUF_MAX];
-
+void klog_writev(int level, const struct iovec* iov, int iov_count) {
if (level > klog_level) return;
if (klog_fd < 0) klog_init();
if (klog_fd < 0) return;
-
- vsnprintf(buf, LOG_BUF_MAX, fmt, ap);
- buf[LOG_BUF_MAX - 1] = 0;
-
- write(klog_fd, buf, strlen(buf));
+ TEMP_FAILURE_RETRY(writev(klog_fd, iov, iov_count));
}
-void klog_write(int level, const char *fmt, ...)
-{
+void klog_write(int level, const char* fmt, ...) {
+ char buf[LOG_BUF_MAX];
va_list ap;
va_start(ap, fmt);
- klog_vwrite(level, fmt, ap);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
+
+ buf[LOG_BUF_MAX - 1] = 0;
+
+ struct iovec iov[1];
+ iov[0].iov_base = buf;
+ iov[0].iov_len = strlen(buf);
+ klog_writev(level, iov, 1);
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index bc36c3e..3ae0954 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -32,8 +32,6 @@
on init
sysclktz 0
- loglevel 3
-
# Backward compatibility.
symlink /system/etc /etc
symlink /sys/kernel/debug /d
diff --git a/run-as/run-as.c b/run-as/run-as.c
index cc05e63..368b8f1 100644
--- a/run-as/run-as.c
+++ b/run-as/run-as.c
@@ -15,22 +15,25 @@
** limitations under the License.
*/
-#define PROGNAME "run-as"
-#define LOG_TAG PROGNAME
+#define PROGNAME "run-as"
+#define LOG_TAG PROGNAME
+#include <dirent.h>
+#include <errno.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
+#include <sys/capability.h>
+#include <sys/cdefs.h>
#include <sys/stat.h>
-#include <dirent.h>
-#include <errno.h>
-#include <unistd.h>
+#include <sys/types.h>
#include <time.h>
-#include <stdarg.h>
+#include <unistd.h>
-#include <selinux/android.h>
#include <private/android_filesystem_config.h>
+#include <selinux/android.h>
+
#include "package.h"
/*
@@ -83,37 +86,37 @@
* - Run the 'gdbserver' binary executable to allow native debugging
*/
-static void
-usage(void)
-{
- const char* str = "Usage: " PROGNAME " <package-name> <command> [<args>]\n\n";
- write(1, str, strlen(str));
- exit(1);
-}
-
-
-static void
+__noreturn static void
panic(const char* format, ...)
{
va_list args;
+ int e = errno;
fprintf(stderr, "%s: ", PROGNAME);
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
- exit(1);
+ exit(e ? -e : 1);
}
+static void
+usage(void)
+{
+ panic("Usage:\n " PROGNAME " <package-name> <command> [<args>]\n");
+}
int main(int argc, char **argv)
{
const char* pkgname;
int myuid, uid, gid;
PackageInfo info;
+ struct __user_cap_header_struct capheader;
+ struct __user_cap_data_struct capdata[2];
/* check arguments */
- if (argc < 2)
+ if (argc < 2) {
usage();
+ }
/* check userid of caller - must be 'shell' or 'root' */
myuid = getuid();
@@ -121,29 +124,37 @@
panic("only 'shell' or 'root' users can run this program\n");
}
- /* retrieve package information from system */
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capdata[CAP_TO_INDEX(CAP_SETUID)].effective |= CAP_TO_MASK(CAP_SETUID);
+ capdata[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID);
+ capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
+ capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
+
+ if (capset(&capheader, &capdata[0]) < 0) {
+ panic("Could not set capabilities: %s\n", strerror(errno));
+ }
+
+ /* retrieve package information from system (does setegid) */
pkgname = argv[1];
if (get_package_info(pkgname, &info) < 0) {
panic("Package '%s' is unknown\n", pkgname);
- return 1;
}
/* reject system packages */
if (info.uid < AID_APP) {
panic("Package '%s' is not an application\n", pkgname);
- return 1;
}
/* reject any non-debuggable package */
if (!info.isDebuggable) {
panic("Package '%s' is not debuggable\n", pkgname);
- return 1;
}
/* check that the data directory path is valid */
if (check_data_path(info.dataDir, info.uid) < 0) {
panic("Package '%s' has corrupt installation\n", pkgname);
- return 1;
}
/* Ensure that we change all real/effective/saved IDs at the
@@ -152,38 +163,30 @@
uid = gid = info.uid;
if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) {
panic("Permission denied\n");
- return 1;
+ }
+
+ /* Required if caller has uid and gid all non-zero */
+ memset(&capdata, 0, sizeof(capdata));
+ if (capset(&capheader, &capdata[0]) < 0) {
+ panic("Could not clear all capabilities: %s\n", strerror(errno));
}
if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) {
- panic("Could not set SELinux security context: %s\n", strerror(errno));
- return 1;
+ panic("Could not set SELinux security context: %s\n", strerror(errno));
}
/* cd into the data directory */
- {
- int ret;
- do {
- ret = chdir(info.dataDir);
- } while (ret < 0 && errno == EINTR);
-
- if (ret < 0) {
- panic("Could not cd to package's data directory: %s\n", strerror(errno));
- return 1;
- }
+ if (TEMP_FAILURE_RETRY(chdir(info.dataDir)) < 0) {
+ panic("Could not cd to package's data directory: %s\n", strerror(errno));
}
/* User specified command for exec. */
- if (argc >= 3 ) {
- if (execvp(argv[2], argv+2) < 0) {
- panic("exec failed for %s Error:%s\n", argv[2], strerror(errno));
- return -errno;
- }
+ if ((argc >= 3) && (execvp(argv[2], argv+2) < 0)) {
+ panic("exec failed for %s: %s\n", argv[2], strerror(errno));
}
/* Default exec shell. */
execlp("/system/bin/sh", "sh", NULL);
- panic("exec failed\n");
- return 1;
+ panic("exec failed: %s\n", strerror(errno));
}
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index a0a9909..4e54eb8 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -47,7 +47,6 @@
iftop \
ioctl \
ionice \
- load_policy \
log \
ls \
lsof \
@@ -58,7 +57,6 @@
prlimit \
renice \
restorecon \
- route \
sendevent \
setprop \
start \
diff --git a/toolbox/load_policy.c b/toolbox/load_policy.c
deleted file mode 100644
index 90d48c4..0000000
--- a/toolbox/load_policy.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-
-int load_policy_main(int argc, char **argv)
-{
- int fd, rc;
- struct stat sb;
- void *map;
- const char *path;
-
- if (argc != 2) {
- fprintf(stderr, "usage: %s policy-file\n", argv[0]);
- exit(1);
- }
-
- path = argv[1];
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "Could not open %s: %s\n", path, strerror(errno));
- exit(2);
- }
-
- if (fstat(fd, &sb) < 0) {
- fprintf(stderr, "Could not stat %s: %s\n", path, strerror(errno));
- exit(3);
- }
-
- map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (map == MAP_FAILED) {
- fprintf(stderr, "Could not mmap %s: %s\n", path, strerror(errno));
- exit(4);
- }
-
- rc = security_load_policy(map, sb.st_size);
- if (rc < 0) {
- fprintf(stderr, "Could not load %s: %s\n", path, strerror(errno));
- exit(5);
- }
- munmap(map, sb.st_size);
- close(fd);
- exit(0);
-}
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index 01517fd..5b98a01 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -798,6 +798,7 @@
__unused int oflag,struct bpb *bpb)
{
struct hd_geometry geom;
+ u_long block_size;
if (ioctl(fd, BLKSSZGET, &bpb->bps)) {
fprintf(stderr, "Error getting bytes / sector (%s)\n", strerror(errno));
@@ -806,11 +807,18 @@
ckgeom(fname, bpb->bps, "bytes/sector");
- if (ioctl(fd, BLKGETSIZE, &bpb->bsec)) {
+ if (ioctl(fd, BLKGETSIZE, &block_size)) {
fprintf(stderr, "Error getting blocksize (%s)\n", strerror(errno));
exit(1);
}
+ if (block_size > UINT32_MAX) {
+ fprintf(stderr, "Error blocksize too large: %lu\n", block_size);
+ exit(1);
+ }
+
+ bpb->bsec = (u_int)block_size;
+
if (ioctl(fd, HDIO_GETGEO, &geom)) {
fprintf(stderr, "Error getting gemoetry (%s) - trying sane values\n", strerror(errno));
geom.heads = 64;
diff --git a/toolbox/route.c b/toolbox/route.c
deleted file mode 100644
index 3e10014..0000000
--- a/toolbox/route.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2009, The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <linux/route.h>
-
-static inline int set_address(const char *address, struct sockaddr *sa) {
- return inet_aton(address, &((struct sockaddr_in *)sa)->sin_addr);
-}
-
-/* current support the following routing entries */
-/* route add default dev wlan0 */
-/* route add default gw 192.168.1.1 dev wlan0 */
-/* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */
-
-int route_main(int argc, char *argv[])
-{
- struct rtentry rt = {
- .rt_dst = {.sa_family = AF_INET},
- .rt_genmask = {.sa_family = AF_INET},
- .rt_gateway = {.sa_family = AF_INET},
- };
-
- errno = EINVAL;
- if (argc > 2 && !strcmp(argv[1], "add")) {
- if (!strcmp(argv[2], "default")) {
- /* route add default dev wlan0 */
- if (argc > 4 && !strcmp(argv[3], "dev")) {
- rt.rt_flags = RTF_UP;
- rt.rt_dev = argv[4];
- errno = 0;
- goto apply;
- }
-
- /* route add default gw 192.168.1.1 dev wlan0 */
- if (argc > 6 && !strcmp(argv[3], "gw") && !strcmp(argv[5], "dev")) {
- rt.rt_flags = RTF_UP | RTF_GATEWAY;
- rt.rt_dev = argv[6];
- if (set_address(argv[4], &rt.rt_gateway)) {
- errno = 0;
- }
- goto apply;
- }
- }
-
- /* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */
- if (argc > 7 && !strcmp(argv[2], "-net") &&
- !strcmp(argv[4], "netmask")) {
- if (!strcmp(argv[6], "gw")) {
- rt.rt_flags = RTF_UP | RTF_GATEWAY;
- if (set_address(argv[3], &rt.rt_dst) &&
- set_address(argv[5], &rt.rt_genmask) &&
- set_address(argv[7], &rt.rt_gateway)) {
- errno = 0;
- }
- goto apply;
- } else if (!strcmp(argv[6], "dev")) {
- rt.rt_flags = RTF_UP;
- rt.rt_dev = argv[7];
- if (set_address(argv[3], &rt.rt_dst) &&
- set_address(argv[5], &rt.rt_genmask)) {
- errno = 0;
- }
- goto apply;
- }
- }
- }
-
-apply:
- if (!errno) {
- int s = socket(AF_INET, SOCK_DGRAM, 0);
- if (s != -1 && (ioctl(s, SIOCADDRT, &rt) != -1 || errno == EEXIST)) {
- return 0;
- }
- }
- puts(strerror(errno));
- return errno;
-}