Merge "Make init handle reboots"
diff --git a/adb/adb.c b/adb/adb.c
index 9d2b86e..6580c6e 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -1199,9 +1199,8 @@
 #endif
     int i;
     for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
-        if (i == CAP_SETUID || i == CAP_SETGID || i == CAP_SYS_BOOT) {
+        if (i == CAP_SETUID || i == CAP_SETGID) {
             // CAP_SETUID CAP_SETGID needed by /system/bin/run-as
-            // CAP_SYS_BOOT          needed by /system/bin/reboot
             continue;
         }
         int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
@@ -1302,13 +1301,6 @@
     /* don't listen on a port (default 5037) if running in secure mode */
     /* don't run as root if we are running in secure mode */
     if (should_drop_privileges()) {
-        struct __user_cap_header_struct header;
-        struct __user_cap_data_struct cap[2];
-
-        if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
-            exit(1);
-        }
-
         drop_capabilities_bounding_set_if_needed();
 
         /* add extra groups:
@@ -1338,16 +1330,6 @@
             exit(1);
         }
 
-        memset(&header, 0, sizeof(header));
-        memset(cap, 0, sizeof(cap));
-
-        /* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */
-        header.version = _LINUX_CAPABILITY_VERSION_3;
-        header.pid = 0;
-        cap[CAP_TO_INDEX(CAP_SYS_BOOT)].effective |= CAP_TO_MASK(CAP_SYS_BOOT);
-        cap[CAP_TO_INDEX(CAP_SYS_BOOT)].permitted |= CAP_TO_MASK(CAP_SYS_BOOT);
-        capset(&header, cap);
-
         D("Local port disabled\n");
     } else {
         char local_name[30];
diff --git a/adb/services.c b/adb/services.c
index 54d21a8..e82a0ea 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -165,6 +165,7 @@
 void reboot_service(int fd, void *arg)
 {
     char buf[100];
+    char property_val[PROPERTY_VALUE_MAX];
     int pid, ret;
 
     sync();
@@ -182,11 +183,19 @@
         waitpid(pid, &ret, 0);
     }
 
-    ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
+    ret = snprintf(property_val, sizeof(property_val), "reboot,%s", (char *) arg);
+    if (ret >= (int) sizeof(property_val)) {
+        snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret);
+        writex(fd, buf, strlen(buf));
+        goto cleanup;
+    }
+
+    ret = property_set(ANDROID_RB_PROPERTY, property_val);
     if (ret < 0) {
-        snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
+        snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret);
         writex(fd, buf, strlen(buf));
     }
+cleanup:
     free(arg);
     adb_close(fd);
 }
diff --git a/include/cutils/android_reboot.h b/include/cutils/android_reboot.h
index 0c79be7..8c30e8e 100644
--- a/include/cutils/android_reboot.h
+++ b/include/cutils/android_reboot.h
@@ -24,9 +24,8 @@
 #define ANDROID_RB_POWEROFF 0xDEAD0002
 #define ANDROID_RB_RESTART2 0xDEAD0003
 
-/* Flags */
-#define ANDROID_RB_FLAG_NO_SYNC       0x1
-#define ANDROID_RB_FLAG_NO_REMOUNT_RO 0x2
+/* Properties */
+#define ANDROID_RB_PROPERTY "sys.powerctl"
 
 int android_reboot(int cmd, int flags, char *arg);
 
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 850e0bd..d69b332 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -230,7 +230,6 @@
 
     /* the following files have enhanced capabilities and ARE included in user builds. */
     { 00750, AID_ROOT,      AID_SHELL,     (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" },
-    { 00750, AID_ROOT,      AID_SHELL,     1 << CAP_SYS_BOOT, "system/bin/reboot" },
 
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
diff --git a/init/builtins.c b/init/builtins.c
index 0f9f131..9ae9ba3 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -32,6 +32,7 @@
 #include <sys/wait.h>
 #include <linux/loop.h>
 #include <cutils/partition_utils.h>
+#include <cutils/android_reboot.h>
 #include <sys/system_properties.h>
 #include <fs_mgr.h>
 
@@ -599,6 +600,43 @@
     return 0;
 }
 
+int do_powerctl(int nargs, char **args)
+{
+    char command[PROP_VALUE_MAX];
+    int res;
+    int len = 0;
+    int cmd = 0;
+    char *reboot_target;
+
+    res = expand_props(command, args[1], sizeof(command));
+    if (res) {
+        ERROR("powerctl: cannot expand '%s'\n", args[1]);
+        return -EINVAL;
+    }
+
+    if (strncmp(command, "shutdown", 8) == 0) {
+        cmd = ANDROID_RB_POWEROFF;
+        len = 8;
+    } else if (strncmp(command, "reboot", 6) == 0) {
+        cmd = ANDROID_RB_RESTART2;
+        len = 6;
+    } else {
+        ERROR("powerctl: unrecognized command '%s'\n", command);
+        return -EINVAL;
+    }
+
+    if (command[len] == ',') {
+        reboot_target = &command[len + 1];
+    } else if (command[len] == '\0') {
+        reboot_target = "";
+    } else {
+        ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
+        return -EINVAL;
+    }
+
+    return android_reboot(cmd, 0, reboot_target);
+}
+
 int do_trigger(int nargs, char **args)
 {
     action_for_each_trigger(args[1], action_add_queue_tail);
diff --git a/init/init_parser.c b/init/init_parser.c
index 686640e..a1d2423 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -130,6 +130,8 @@
         if (!strcmp(s, "neshot")) return K_oneshot;
         if (!strcmp(s, "nrestart")) return K_onrestart;
         break;
+    case 'p':
+        if (!strcmp(s, "owerctl")) return K_powerctl;
     case 'r':
         if (!strcmp(s, "estart")) return K_restart;
         if (!strcmp(s, "estorecon")) return K_restorecon;
diff --git a/init/keywords.h b/init/keywords.h
index f188db5..f147506 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -14,6 +14,7 @@
 int do_mkdir(int nargs, char **args);
 int do_mount_all(int nargs, char **args);
 int do_mount(int nargs, char **args);
+int do_powerctl(int nargs, char **args);
 int do_restart(int nargs, char **args);
 int do_restorecon(int nargs, char **args);
 int do_rm(int nargs, char **args);
@@ -66,6 +67,7 @@
     KEYWORD(on,          SECTION, 0, 0)
     KEYWORD(oneshot,     OPTION,  0, 0)
     KEYWORD(onrestart,   OPTION,  0, 0)
+    KEYWORD(powerctl,    COMMAND, 1, do_powerctl)
     KEYWORD(restart,     COMMAND, 1, do_restart)
     KEYWORD(restorecon,  COMMAND, 1, do_restorecon)
     KEYWORD(rm,          COMMAND, 1, do_rm)
diff --git a/init/property_service.c b/init/property_service.c
old mode 100755
new mode 100644
index 5780001..6bf06b4
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -77,6 +77,7 @@
     { "runtime.",         AID_SYSTEM,   0 },
     { "hw.",              AID_SYSTEM,   0 },
     { "sys.",             AID_SYSTEM,   0 },
+    { "sys.powerctl",     AID_SHELL,    0 },
     { "service.",         AID_SYSTEM,   0 },
     { "wlan.",            AID_SYSTEM,   0 },
     { "bluetooth.",       AID_BLUETOOTH,   0 },
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index 33a7358..16f82bb 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -105,11 +105,8 @@
 {
     int ret;
 
-    if (!(flags & ANDROID_RB_FLAG_NO_SYNC))
-        sync();
-
-    if (!(flags & ANDROID_RB_FLAG_NO_REMOUNT_RO))
-        remount_ro();
+    sync();
+    remount_ro();
 
     switch (cmd) {
         case ANDROID_RB_RESTART:
diff --git a/reboot/reboot.c b/reboot/reboot.c
index 45d8a8e..0e5170d 100644
--- a/reboot/reboot.c
+++ b/reboot/reboot.c
@@ -17,35 +17,34 @@
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <cutils/properties.h>
 #include <cutils/android_reboot.h>
 #include <unistd.h>
 
 int main(int argc, char *argv[])
 {
     int ret;
-    int nosync = 0;
-    int poweroff = 0;
-    int flags = 0;
+    size_t prop_len;
+    char property_val[PROPERTY_VALUE_MAX];
+    const char *cmd = "reboot";
+    char *optarg = "";
 
     opterr = 0;
     do {
         int c;
 
-        c = getopt(argc, argv, "np");
+        c = getopt(argc, argv, "p");
 
         if (c == EOF) {
             break;
         }
 
         switch (c) {
-        case 'n':
-            nosync = 1;
-            break;
         case 'p':
-            poweroff = 1;
+            cmd = "shutdown";
             break;
         case '?':
-            fprintf(stderr, "usage: %s [-n] [-p] [rebootcommand]\n", argv[0]);
+            fprintf(stderr, "usage: %s [-p] [rebootcommand]\n", argv[0]);
             exit(EXIT_FAILURE);
         }
     } while (1);
@@ -55,20 +54,20 @@
         exit(EXIT_FAILURE);
     }
 
-    if(nosync)
-        /* also set NO_REMOUNT_RO as remount ro includes an implicit sync */
-        flags = ANDROID_RB_FLAG_NO_SYNC | ANDROID_RB_FLAG_NO_REMOUNT_RO;
+    if (argc > optind)
+        optarg = argv[optind];
 
-    if(poweroff)
-        ret = android_reboot(ANDROID_RB_POWEROFF, flags, 0);
-    else if(argc > optind)
-        ret = android_reboot(ANDROID_RB_RESTART2, flags, argv[optind]);
-    else
-        ret = android_reboot(ANDROID_RB_RESTART, flags, 0);
+    prop_len = snprintf(property_val, sizeof(property_val), "%s,%s", cmd, optarg);
+    if (prop_len >= sizeof(property_val)) {
+        fprintf(stderr, "reboot command too long: %s\n", optarg);
+        exit(EXIT_FAILURE);
+    }
+
+    ret = property_set(ANDROID_RB_PROPERTY, property_val);
     if(ret < 0) {
         perror("reboot");
         exit(EXIT_FAILURE);
     }
-    fprintf(stderr, "reboot returned\n");
+    fprintf(stderr, "Done\n");
     return 0;
 }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index c3ef503..f783768 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -398,6 +398,9 @@
     class_reset late_start
     class_reset main
 
+on property:sys.powerctl=*
+    powerctl ${sys.powerctl}
+
 ## Daemon processes to be run by init.
 ##
 service ueventd /sbin/ueventd