diff --git a/adb/adb.c b/adb/adb.c index 9d2b86ef9..6580c6e95 100644 --- a/adb/adb.c +++ b/adb/adb.c @@ -1199,9 +1199,8 @@ static void drop_capabilities_bounding_set_if_needed() { #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 @@ int adb_main(int is_daemon, int server_port) /* 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 @@ int adb_main(int is_daemon, int server_port) 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 54d21a8b7..e82a0ea5a 100644 --- a/adb/services.c +++ b/adb/services.c @@ -165,6 +165,7 @@ void restart_usb_service(int fd, void *cookie) void reboot_service(int fd, void *arg) { char buf[100]; + char property_val[PROPERTY_VALUE_MAX]; int pid, ret; sync(); @@ -182,11 +183,19 @@ void reboot_service(int fd, void *arg) 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 0c79be7e3..8c30e8e3f 100644 --- a/include/cutils/android_reboot.h +++ b/include/cutils/android_reboot.h @@ -24,9 +24,8 @@ __BEGIN_DECLS #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 850e0bd75..d69b33225 100644 --- a/include/private/android_filesystem_config.h +++ b/include/private/android_filesystem_config.h @@ -230,7 +230,6 @@ static const struct fs_path_config android_files[] = { /* 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 0f9f13136..9ae9ba3f7 100644 --- a/init/builtins.c +++ b/init/builtins.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -599,6 +600,43 @@ int do_restart(int nargs, char **args) 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 686640ed4..a1d242355 100644 --- a/init/init_parser.c +++ b/init/init_parser.c @@ -130,6 +130,8 @@ int lookup_keyword(const char *s) 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 f188db5d7..f14750647 100644 --- a/init/keywords.h +++ b/init/keywords.h @@ -14,6 +14,7 @@ int do_insmod(int nargs, char **args); 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 @@ enum { 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 578000154..6bf06b4f7 --- a/init/property_service.c +++ b/init/property_service.c @@ -77,6 +77,7 @@ struct { { "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 33a7358ec..16f82bbd5 100644 --- a/libcutils/android_reboot.c +++ b/libcutils/android_reboot.c @@ -105,11 +105,8 @@ int android_reboot(int cmd, int flags, char *arg) { 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 45d8a8ef5..0e5170d42 100644 --- a/reboot/reboot.c +++ b/reboot/reboot.c @@ -17,35 +17,34 @@ #include #include #include +#include #include #include 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 @@ int main(int argc, char *argv[]) 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 c3ef50329..f7837687d 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -398,6 +398,9 @@ on property:vold.decrypt=trigger_shutdown_framework 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