Merge "Recognize IPv6 addresses for "adb connect"."
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 4251f88..1727225 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -175,7 +175,7 @@
for (const auto& elem : elements) {
const auto& flag = trace_flags.find(elem);
if (flag == trace_flags.end()) {
- D("Unknown trace flag: %s", flag->first.c_str());
+ D("Unknown trace flag: %s\n", flag->first.c_str());
continue;
}
diff --git a/adb/adb.h b/adb/adb.h
index 1be83d7..31fe3a5 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -365,7 +365,9 @@
extern const char *adb_device_banner;
extern int HOST;
+#if !ADB_HOST
extern int SHELL_EXIT_NOTIFY_FD;
+#endif // !ADB_HOST
#define CHUNK_SIZE (64*1024)
diff --git a/adb/adb_auth_client.cpp b/adb/adb_auth_client.cpp
index 8e7d38b..884d5be 100644
--- a/adb/adb_auth_client.cpp
+++ b/adb/adb_auth_client.cpp
@@ -212,7 +212,7 @@
ret = snprintf(msg, sizeof(msg), "PK%s", key);
if (ret >= (signed)sizeof(msg)) {
- D("Key too long. ret=%d", ret);
+ D("Key too long. ret=%d\n", ret);
return;
}
D("Sending '%s'\n", msg);
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index e878f8b..8085c1a 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -183,7 +183,7 @@
#if defined(OPENSSL_IS_BORINGSSL)
if (!EVP_EncodedLength(&encoded_length, sizeof(pkey))) {
- D("Public key too large to base64 encode");
+ D("Public key too large to base64 encode\n");
goto out;
}
#else
@@ -194,7 +194,7 @@
encoded = new uint8_t[encoded_length];
if (encoded == nullptr) {
- D("Allocation failure");
+ D("Allocation failure\n");
goto out;
}
@@ -203,7 +203,7 @@
if (fwrite(encoded, encoded_length, 1, outfile) != 1 ||
fwrite(info, strlen(info), 1, outfile) != 1) {
- D("Write error while writing public key");
+ D("Write error while writing public key\n");
goto out;
}
@@ -323,7 +323,7 @@
if (stat(android_dir, &buf)) {
if (adb_mkdir(android_dir, 0750) < 0) {
- D("Cannot mkdir '%s'", android_dir);
+ D("Cannot mkdir '%s'\n", android_dir);
return -1;
}
}
@@ -339,7 +339,7 @@
ret = get_user_keyfilepath(path, sizeof(path));
if (ret < 0 || ret >= (signed)sizeof(path)) {
- D("Error getting user key filename");
+ D("Error getting user key filename\n");
return 0;
}
@@ -414,7 +414,7 @@
char path[PATH_MAX];
int ret = get_user_keyfilepath(path, sizeof(path) - 4);
if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) {
- D("Error getting user key filename");
+ D("Error getting user key filename\n");
return 0;
}
strcat(path, ".pub");
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 9a1b761..75e888d 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -243,7 +243,7 @@
fd = _adb_connect(service, error);
if (fd == -1) {
- D("_adb_connect error: %s", error->c_str());
+ D("_adb_connect error: %s\n", error->c_str());
} else if(fd == -2) {
fprintf(stderr,"** daemon still not running\n");
}
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 0c43c5e..5cd4988 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -42,7 +42,9 @@
// This socket is used when a subproc shell service exists.
// It wakes up the fdevent_loop() and cause the correct handling
// of the shell's pseudo-tty master. I.e. force close it.
+#if !ADB_HOST
int SHELL_EXIT_NOTIFY_FD = -1;
+#endif // !ADB_HOST
static void fatal(const char *fn, const char *fmt, ...)
{
@@ -81,7 +83,6 @@
static void fdevent_plist_enqueue(fdevent *node);
static void fdevent_plist_remove(fdevent *node);
static fdevent *fdevent_plist_dequeue(void);
-static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata);
static fdevent list_pending = {
.next = &list_pending,
@@ -510,6 +511,7 @@
fde->func(fde->fd, events, fde->arg);
}
+#if !ADB_HOST
static void fdevent_subproc_event_func(int fd, unsigned ev,
void* /* userdata */)
{
@@ -569,6 +571,24 @@
}
}
+void fdevent_subproc_setup()
+{
+ int s[2];
+
+ if(adb_socketpair(s)) {
+ FATAL("cannot create shell-exit socket-pair\n");
+ }
+ D("socketpair: (%d,%d)\n", s[0], s[1]);
+
+ SHELL_EXIT_NOTIFY_FD = s[0];
+ fdevent *fde;
+ fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
+ if(!fde)
+ FATAL("cannot create fdevent for shell-exit handler\n");
+ fdevent_add(fde, FDE_READ);
+}
+#endif // !ADB_HOST
+
fdevent *fdevent_create(int fd, fd_func func, void *arg)
{
fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
@@ -661,27 +681,12 @@
fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
}
-void fdevent_subproc_setup()
-{
- int s[2];
-
- if(adb_socketpair(s)) {
- FATAL("cannot create shell-exit socket-pair\n");
- }
- D("socketpair: (%d,%d)", s[0], s[1]);
-
- SHELL_EXIT_NOTIFY_FD = s[0];
- fdevent *fde;
- fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
- if(!fde)
- FATAL("cannot create fdevent for shell-exit handler\n");
- fdevent_add(fde, FDE_READ);
-}
-
void fdevent_loop()
{
fdevent *fde;
+#if !ADB_HOST
fdevent_subproc_setup();
+#endif // !ADB_HOST
for(;;) {
D("--- ---- waiting for events\n");
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index c0f7ec2..23af6c9 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/jdwp_service.cpp
@@ -435,7 +435,7 @@
__FUNCTION__, strerror(errno));
return -1;
}
- D("socketpair: (%d,%d)", fds[0], fds[1]);
+ D("socketpair: (%d,%d)\n", fds[0], fds[1]);
proc->out_fds[ proc->out_count ] = fds[1];
if (++proc->out_count == 1)
diff --git a/adb/services.cpp b/adb/services.cpp
index 678d57b..b9c532a 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -206,7 +206,7 @@
printf("cannot create service socket pair\n");
return -1;
}
- D("socketpair: (%d,%d)", s[0], s[1]);
+ D("socketpair: (%d,%d)\n", s[0], s[1]);
stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
if (sti == nullptr) {
@@ -318,7 +318,7 @@
printf("[ cannot create socket pair - %s ]\n", strerror(errno));
return -1;
}
- D("socketpair: (%d,%d)", sv[0], sv[1]);
+ D("socketpair: (%d,%d)\n", sv[0], sv[1]);
*pid = fork();
if (*pid < 0) {
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index b7c16d9..5efdab5 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -276,6 +276,7 @@
#include "fdevent.h"
#include <cutils/sockets.h>
#include <cutils/misc.h>
+#include <cutils/threads.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/stat.h>
@@ -544,7 +545,7 @@
static __inline__ unsigned long adb_thread_id()
{
- return (unsigned long)pthread_self();
+ return (unsigned long)gettid();
}
#endif /* !_WIN32 */
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 50c99f1..bdc6027 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -361,9 +361,10 @@
0, NULL );
if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
+ const DWORD err = GetLastError();
_fh_close(f);
- D( "adb_open: could not open '%s':", path );
- switch (GetLastError()) {
+ D( "adb_open: could not open '%s': ", path );
+ switch (err) {
case ERROR_FILE_NOT_FOUND:
D( "file not found\n" );
errno = ENOENT;
@@ -375,7 +376,7 @@
return -1;
default:
- D( "unknown error\n" );
+ D( "unknown error: %ld\n", err );
errno = ENOENT;
return -1;
}
@@ -402,9 +403,10 @@
NULL );
if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
+ const DWORD err = GetLastError();
_fh_close(f);
- D( "adb_creat: could not open '%s':", path );
- switch (GetLastError()) {
+ D( "adb_creat: could not open '%s': ", path );
+ switch (err) {
case ERROR_FILE_NOT_FOUND:
D( "file not found\n" );
errno = ENOENT;
@@ -416,7 +418,7 @@
return -1;
default:
- D( "unknown error\n" );
+ D( "unknown error: %ld\n", err );
errno = ENOENT;
return -1;
}
@@ -781,8 +783,9 @@
fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen );
if (fh->fh_socket == INVALID_SOCKET) {
+ const DWORD err = WSAGetLastError();
_fh_close( fh );
- D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError() );
+ D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, err );
return -1;
}
@@ -1546,7 +1549,7 @@
threads = (WaitForAllParam*)malloc((chunks + (remains ? 1 : 0)) *
sizeof(WaitForAllParam));
if (threads == NULL) {
- D("Unable to allocate thread array for %d handles.", handles_count);
+ D("Unable to allocate thread array for %d handles.\n", handles_count);
return (int)WAIT_FAILED;
}
@@ -1554,7 +1557,7 @@
* reset" event that will remain set once it was set. */
main_event = CreateEvent(NULL, TRUE, FALSE, NULL);
if (main_event == NULL) {
- D("Unable to create main event. Error: %d", (int)GetLastError());
+ D("Unable to create main event. Error: %ld\n", GetLastError());
free(threads);
return (int)WAIT_FAILED;
}
@@ -1587,7 +1590,7 @@
&threads[chunk], 0, NULL);
if (threads[chunk].thread == NULL) {
/* Unable to create a waiter thread. Collapse. */
- D("Unable to create a waiting thread %d of %d. errno=%d",
+ D("Unable to create a waiting thread %d of %d. errno=%d\n",
chunk, chunks, errno);
chunks = chunk;
SetEvent(main_event);
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 274449b..87ca5ac 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -283,7 +283,7 @@
p->msg.magic = A_SYNC ^ 0xffffffff;
if(write_packet(t->fd, t->serial, &p)) {
put_apacket(p);
- D("%s: failed to write SYNC apacket to transport", t->serial);
+ D("%s: failed to write SYNC apacket to transport\n", t->serial);
}
oops:
@@ -579,7 +579,7 @@
fatal_errno("cannot open transport socketpair");
}
- D("transport: %s socketpair: (%d,%d) starting", t->serial, s[0], s[1]);
+ D("transport: %s socketpair: (%d,%d) starting\n", t->serial, s[0], s[1]);
t->transport_socket = s[0];
t->fd = s[1];
@@ -617,7 +617,7 @@
if(adb_socketpair(s)){
fatal_errno("cannot open transport registration socketpair");
}
- D("socketpair: (%d,%d)", s[0], s[1]);
+ D("socketpair: (%d,%d)\n", s[0], s[1]);
transport_registration_send = s[0];
transport_registration_recv = s[1];
@@ -789,9 +789,10 @@
if (result->connection_state == kCsUnauthorized) {
*error_out = "device unauthorized.\n";
char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
- *error_out += "This adbd's $ADB_VENDOR_KEYS is ";
+ *error_out += "This adb server's $ADB_VENDOR_KEYS is ";
*error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
- *error_out += "; try 'adb kill-server' if that seems wrong.\n";
+ *error_out += "\n";
+ *error_out += "Try 'adb kill-server' if that seems wrong.\n";
*error_out += "Otherwise check for a confirmation dialog on your device.";
result = NULL;
}
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index d34c454..cfd95dd 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -444,11 +444,11 @@
err = ioctl(h->bulk_in, FUNCTIONFS_CLEAR_HALT);
if (err < 0)
- D("[ kick: source (fd=%d) clear halt failed (%d) ]", h->bulk_in, errno);
+ D("[ kick: source (fd=%d) clear halt failed (%d) ]\n", h->bulk_in, errno);
err = ioctl(h->bulk_out, FUNCTIONFS_CLEAR_HALT);
if (err < 0)
- D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out, errno);
+ D("[ kick: sink (fd=%d) clear halt failed (%d) ]\n", h->bulk_out, errno);
adb_mutex_lock(&h->lock);
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 42f25c7..f467f81 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -162,10 +162,10 @@
} else if (!strcmp(fs_type, "f2fs")) {
char *f2fs_fsck_argv[] = {
F2FS_FSCK_BIN,
- "-f",
+ "-a",
blk_device
};
- INFO("Running %s -f %s\n", F2FS_FSCK_BIN, blk_device);
+ INFO("Running %s -a %s\n", F2FS_FSCK_BIN, blk_device);
ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv,
&status, true, LOG_KLOG | LOG_FILE,
diff --git a/include/cutils/android_reboot.h b/include/cutils/android_reboot.h
index 85e1b7e..a3861a0 100644
--- a/include/cutils/android_reboot.h
+++ b/include/cutils/android_reboot.h
@@ -17,6 +17,8 @@
#ifndef __CUTILS_ANDROID_REBOOT_H__
#define __CUTILS_ANDROID_REBOOT_H__
+#include <mntent.h>
+
__BEGIN_DECLS
/* Commands */
@@ -28,6 +30,9 @@
#define ANDROID_RB_PROPERTY "sys.powerctl"
int android_reboot(int cmd, int flags, const char *arg);
+int android_reboot_with_callback(
+ int cmd, int flags, const char *arg,
+ void (*cb_on_remount)(const struct mntent*));
__END_DECLS
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 02fe2b5..0c071ca 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -77,6 +77,7 @@
#define AID_SDCARD_ALL 1035 /* access all users external storage */
#define AID_LOGD 1036 /* log daemon */
#define AID_SHARED_RELRO 1037 /* creator of shared GNU RELRO files */
+#define AID_DBUS 1038 /* dbus-daemon IPC broker process */
#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
@@ -168,6 +169,7 @@
{ "sdcard_all", AID_SDCARD_ALL, },
{ "logd", AID_LOGD, },
{ "shared_relro", AID_SHARED_RELRO, },
+ { "dbus", AID_DBUS, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
diff --git a/init/builtins.cpp b/init/builtins.cpp
index ca31c50..d5d3faf 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -16,7 +16,9 @@
#include <errno.h>
#include <fcntl.h>
+#include <mntent.h>
#include <net/if.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -38,6 +40,7 @@
#include <base/stringprintf.h>
#include <cutils/partition_utils.h>
#include <cutils/android_reboot.h>
+#include <logwrap/logwrap.h>
#include <private/android_filesystem_config.h>
#include "init.h"
@@ -49,6 +52,8 @@
#include "log.h"
#define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
+#define UNMOUNT_CHECK_MS 5000
+#define UNMOUNT_CHECK_TIMES 10
int add_environment(const char *name, const char *value);
@@ -109,6 +114,67 @@
}
}
+static void unmount_and_fsck(const struct mntent *entry)
+{
+ if (strcmp(entry->mnt_type, "f2fs") && strcmp(entry->mnt_type, "ext4"))
+ return;
+
+ /* First, lazily unmount the directory. This unmount request finishes when
+ * all processes that open a file or directory in |entry->mnt_dir| exit.
+ */
+ TEMP_FAILURE_RETRY(umount2(entry->mnt_dir, MNT_DETACH));
+
+ /* Next, kill all processes except init, kthreadd, and kthreadd's
+ * children to finish the lazy unmount. Killing all processes here is okay
+ * because this callback function is only called right before reboot().
+ * It might be cleaner to selectively kill processes that actually use
+ * |entry->mnt_dir| rather than killing all, probably by reusing a function
+ * like killProcessesWithOpenFiles() in vold/, but the selinux policy does
+ * not allow init to scan /proc/<pid> files which the utility function
+ * heavily relies on. The policy does not allow the process to execute
+ * killall/pkill binaries either. Note that some processes might
+ * automatically restart after kill(), but that is not really a problem
+ * because |entry->mnt_dir| is no longer visible to such new processes.
+ */
+ service_for_each(service_stop);
+ TEMP_FAILURE_RETRY(kill(-1, SIGKILL));
+
+ int count = 0;
+ while (count++ < UNMOUNT_CHECK_TIMES) {
+ int fd = TEMP_FAILURE_RETRY(open(entry->mnt_fsname, O_RDONLY | O_EXCL));
+ if (fd >= 0) {
+ /* |entry->mnt_dir| has sucessfully been unmounted. */
+ close(fd);
+ break;
+ } else if (errno == EBUSY) {
+ /* Some processes using |entry->mnt_dir| are still alive. Wait for a
+ * while then retry.
+ */
+ TEMP_FAILURE_RETRY(
+ usleep(UNMOUNT_CHECK_MS * 1000 / UNMOUNT_CHECK_TIMES));
+ continue;
+ } else {
+ /* Cannot open the device. Give up. */
+ return;
+ }
+ }
+
+ int st;
+ if (!strcmp(entry->mnt_type, "f2fs")) {
+ const char *f2fs_argv[] = {
+ "/system/bin/fsck.f2fs", "-f", entry->mnt_fsname,
+ };
+ android_fork_execvp_ext(ARRAY_SIZE(f2fs_argv), (char **)f2fs_argv,
+ &st, true, LOG_KLOG, true, NULL);
+ } else if (!strcmp(entry->mnt_type, "ext4")) {
+ const char *ext4_argv[] = {
+ "/system/bin/e2fsck", "-f", "-y", entry->mnt_fsname,
+ };
+ android_fork_execvp_ext(ARRAY_SIZE(ext4_argv), (char **)ext4_argv,
+ &st, true, LOG_KLOG, true, NULL);
+ }
+}
+
int do_class_start(int nargs, char **args)
{
/* Starting a class does not start services
@@ -559,6 +625,7 @@
int len = 0;
int cmd = 0;
const char *reboot_target;
+ void (*callback_on_ro_remount)(const struct mntent*) = NULL;
res = expand_props(command, args[1], sizeof(command));
if (res) {
@@ -569,6 +636,7 @@
if (strncmp(command, "shutdown", 8) == 0) {
cmd = ANDROID_RB_POWEROFF;
len = 8;
+ callback_on_ro_remount = unmount_and_fsck;
} else if (strncmp(command, "reboot", 6) == 0) {
cmd = ANDROID_RB_RESTART2;
len = 6;
@@ -586,7 +654,8 @@
return -EINVAL;
}
- return android_reboot(cmd, 0, reboot_target);
+ return android_reboot_with_callback(cmd, 0, reboot_target,
+ callback_on_ro_remount);
}
int do_trigger(int nargs, char **args)
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index 6ae23c1..af7e189 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -14,43 +14,108 @@
* limitations under the License.
*/
-#include <unistd.h>
-#include <sys/reboot.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <errno.h>
#include <fcntl.h>
#include <mntent.h>
+#include <stdbool.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <sys/cdefs.h>
+#include <sys/mount.h>
+#include <sys/reboot.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <cutils/android_reboot.h>
+#include <cutils/klog.h>
+#include <cutils/list.h>
-#define UNUSED __attribute__((unused))
+#define TAG "android_reboot"
+#define READONLY_CHECK_MS 5000
+#define READONLY_CHECK_TIMES 50
-/* Check to see if /proc/mounts contains any writeable filesystems
- * backed by a block device.
- * Return true if none found, else return false.
+typedef struct {
+ struct listnode list;
+ struct mntent entry;
+} mntent_list;
+
+static bool has_mount_option(const char* opts, const char* opt_to_find)
+{
+ bool ret = false;
+ char* copy = NULL;
+ char* opt;
+ char* rem;
+
+ while ((opt = strtok_r(copy ? NULL : (copy = strdup(opts)), ",", &rem))) {
+ if (!strcmp(opt, opt_to_find)) {
+ ret = true;
+ break;
+ }
+ }
+
+ free(copy);
+ return ret;
+}
+
+static bool is_block_device(const char* fsname)
+{
+ return !strncmp(fsname, "/dev/block", 10);
+}
+
+/* Find all read+write block devices in /proc/mounts and add them to
+ * |rw_entries|.
*/
-static int remount_ro_done(void)
+static void find_rw(struct listnode* rw_entries)
{
FILE* fp;
struct mntent* mentry;
- int found_rw_fs = 0;
if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
- /* If we can't read /proc/mounts, just give up. */
- return 1;
+ KLOG_WARNING(TAG, "Failed to open /proc/mounts.\n");
+ return;
}
while ((mentry = getmntent(fp)) != NULL) {
- if (!strncmp(mentry->mnt_fsname, "/dev/block", 10) && strstr(mentry->mnt_opts, "rw,")) {
- found_rw_fs = 1;
- break;
+ if (is_block_device(mentry->mnt_fsname) &&
+ has_mount_option(mentry->mnt_opts, "rw")) {
+ mntent_list* item = (mntent_list*)calloc(1, sizeof(mntent_list));
+ item->entry = *mentry;
+ item->entry.mnt_fsname = strdup(mentry->mnt_fsname);
+ item->entry.mnt_dir = strdup(mentry->mnt_dir);
+ item->entry.mnt_type = strdup(mentry->mnt_type);
+ item->entry.mnt_opts = strdup(mentry->mnt_opts);
+ list_add_tail(rw_entries, &item->list);
}
}
endmntent(fp);
+}
- return !found_rw_fs;
+static void free_entries(struct listnode* entries)
+{
+ struct listnode* node;
+ struct listnode* n;
+ list_for_each_safe(node, n, entries) {
+ mntent_list* item = node_to_item(node, mntent_list, list);
+ free(item->entry.mnt_fsname);
+ free(item->entry.mnt_dir);
+ free(item->entry.mnt_type);
+ free(item->entry.mnt_opts);
+ free(item);
+ }
+}
+
+static mntent_list* find_item(struct listnode* rw_entries, const char* fsname_to_find)
+{
+ struct listnode* node;
+ list_for_each(node, rw_entries) {
+ mntent_list* item = node_to_item(node, mntent_list, list);
+ if (!strcmp(item->entry.mnt_fsname, fsname_to_find)) {
+ return item;
+ }
+ }
+ return NULL;
}
/* Remounting filesystems read-only is difficult when there are files
@@ -64,38 +129,92 @@
* repeatedly until there are no more writable filesystems mounted on
* block devices.
*/
-static void remount_ro(void)
+static void remount_ro(void (*cb_on_remount)(const struct mntent*))
{
- int fd, cnt = 0;
+ int fd, cnt;
+ FILE* fp;
+ struct mntent* mentry;
+ struct listnode* node;
+
+ list_declare(rw_entries);
+ list_declare(ro_entries);
+
+ sync();
+ find_rw(&rw_entries);
/* Trigger the remount of the filesystems as read-only,
* which also marks them clean.
*/
- fd = open("/proc/sysrq-trigger", O_WRONLY);
+ fd = TEMP_FAILURE_RETRY(open("/proc/sysrq-trigger", O_WRONLY));
if (fd < 0) {
- return;
+ KLOG_WARNING(TAG, "Failed to open sysrq-trigger.\n");
+ /* TODO: Try to remount each rw parition manually in readonly mode.
+ * This may succeed if no process is using the partition.
+ */
+ goto out;
}
- write(fd, "u", 1);
+ if (TEMP_FAILURE_RETRY(write(fd, "u", 1)) != 1) {
+ close(fd);
+ KLOG_WARNING(TAG, "Failed to write to sysrq-trigger.\n");
+ /* TODO: The same. Manually remount the paritions. */
+ goto out;
+ }
close(fd);
-
/* Now poll /proc/mounts till it's done */
- while (!remount_ro_done() && (cnt < 50)) {
- usleep(100000);
+ cnt = 0;
+ while (cnt < READONLY_CHECK_TIMES) {
+ if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
+ /* If we can't read /proc/mounts, just give up. */
+ KLOG_WARNING(TAG, "Failed to open /proc/mounts.\n");
+ goto out;
+ }
+ while ((mentry = getmntent(fp)) != NULL) {
+ if (!is_block_device(mentry->mnt_fsname) ||
+ !has_mount_option(mentry->mnt_opts, "ro")) {
+ continue;
+ }
+ mntent_list* item = find_item(&rw_entries, mentry->mnt_fsname);
+ if (item) {
+ /* |item| has now been ro remounted. */
+ list_remove(&item->list);
+ list_add_tail(&ro_entries, &item->list);
+ }
+ }
+ endmntent(fp);
+ if (list_empty(&rw_entries)) {
+ /* All rw block devices are now readonly. */
+ break;
+ }
+ TEMP_FAILURE_RETRY(
+ usleep(READONLY_CHECK_MS * 1000 / READONLY_CHECK_TIMES));
cnt++;
}
- return;
+ list_for_each(node, &rw_entries) {
+ mntent_list* item = node_to_item(node, mntent_list, list);
+ KLOG_WARNING(TAG, "Failed to remount %s in readonly mode.\n",
+ item->entry.mnt_fsname);
+ }
+
+ if (cb_on_remount) {
+ list_for_each(node, &ro_entries) {
+ mntent_list* item = node_to_item(node, mntent_list, list);
+ cb_on_remount(&item->entry);
+ }
+ }
+
+out:
+ free_entries(&rw_entries);
+ free_entries(&ro_entries);
}
-
-int android_reboot(int cmd, int flags UNUSED, const char *arg)
+int android_reboot_with_callback(
+ int cmd, int flags __unused, const char *arg,
+ void (*cb_on_remount)(const struct mntent*))
{
int ret;
-
- sync();
- remount_ro();
-
+ remount_ro(cb_on_remount);
switch (cmd) {
case ANDROID_RB_RESTART:
ret = reboot(RB_AUTOBOOT);
@@ -117,3 +236,7 @@
return ret;
}
+int android_reboot(int cmd, int flags, const char *arg)
+{
+ return android_reboot_with_callback(cmd, flags, arg, NULL);
+}
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 3a6276e..777dafe 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -355,7 +355,8 @@
}
if (poll_fds[0].revents & POLLIN) {
- sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b);
+ sz = TEMP_FAILURE_RETRY(
+ read(parent_read, &buffer[b], sizeof(buffer) - 1 - b));
sz += b;
// Log one line at a time
@@ -490,7 +491,7 @@
}
/* Use ptty instead of socketpair so that STDOUT is not buffered */
- parent_ptty = open("/dev/ptmx", O_RDWR);
+ parent_ptty = TEMP_FAILURE_RETRY(open("/dev/ptmx", O_RDWR));
if (parent_ptty < 0) {
ERROR("Cannot create parent ptty\n");
rc = -1;
@@ -505,7 +506,7 @@
goto err_ptty;
}
- child_ptty = open(child_devname, O_RDWR);
+ child_ptty = TEMP_FAILURE_RETRY(open(child_devname, O_RDWR));
if (child_ptty < 0) {
ERROR("Cannot open child_ptty\n");
rc = -1;
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index de10535..d6dad2d 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -26,7 +26,7 @@
#
# create some directories (some are mount points)
LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
- sbin dev proc sys system data oem acct config storage mnt root)
+ sbin dev proc sys system data oem acct cache config storage mnt root)
include $(BUILD_SYSTEM)/base_rules.mk