diff --git a/adb/adb.c b/adb/adb.c index 956df544e..e8d2c8fa8 100644 --- a/adb/adb.c +++ b/adb/adb.c @@ -30,6 +30,8 @@ #if !ADB_HOST #include +#include +#include #else #include "usb_vendors.h" #endif @@ -879,6 +881,11 @@ int adb_main(int is_daemon) /* don't listen on port 5037 if we are running in secure mode */ /* don't run as root if we are running in secure mode */ if (secure) { + struct __user_cap_header_struct header; + struct __user_cap_data_struct cap; + + prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); + /* add extra groups: ** AID_ADB to access the USB driver ** AID_LOG to read system logs (adb logcat) @@ -896,6 +903,13 @@ int adb_main(int is_daemon) setgid(AID_SHELL); setuid(AID_SHELL); + /* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */ + header.version = _LINUX_CAPABILITY_VERSION; + header.pid = 0; + cap.effective = cap.permitted = (1 << CAP_SYS_BOOT); + cap.inheritable = 0; + capset(&header, &cap); + D("Local port 5037 disabled\n"); } else { if(install_listener("tcp:5037", "*smartsocket*", NULL)) { diff --git a/adb/adb.h b/adb/adb.h index 95610a738..8d57bf26c 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -33,7 +33,7 @@ #define ADB_VERSION_MAJOR 1 // Used for help/version information #define ADB_VERSION_MINOR 0 // Used for help/version information -#define ADB_SERVER_VERSION 21 // Increment this when we want to force users to start a new adb server +#define ADB_SERVER_VERSION 22 // Increment this when we want to force users to start a new adb server typedef struct amessage amessage; typedef struct apacket apacket; diff --git a/adb/commandline.c b/adb/commandline.c index ad1021ca3..4ec5c8b7e 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -148,6 +148,7 @@ void help() " adb get-serialno - prints: \n" " adb status-window - continuously print device status for a specified device\n" " adb remount - remounts the /system partition on the device read-write\n" + " adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n" " adb root - restarts adb with root permissions\n" "\n" "networking:\n" @@ -918,6 +919,22 @@ top: return 1; } + if(!strcmp(argv[0], "reboot")) { + int fd; + if (argc > 1) + snprintf(buf, sizeof(buf), "reboot:%s", argv[1]); + else + snprintf(buf, sizeof(buf), "reboot:"); + fd = adb_connect(buf); + if(fd >= 0) { + read_and_dump(fd); + adb_close(fd); + return 0; + } + fprintf(stderr,"error: %s\n", adb_error()); + return 1; + } + if(!strcmp(argv[0], "root")) { int fd = adb_connect("root:"); if(fd >= 0) { diff --git a/adb/services.c b/adb/services.c index 78d092b83..517da55f5 100644 --- a/adb/services.c +++ b/adb/services.c @@ -33,6 +33,7 @@ # endif #else #include +#include #endif typedef struct stinfo stinfo; @@ -133,6 +134,20 @@ void restart_root_service(int fd, void *cookie) } } +void reboot_service(int fd, char *arg) +{ + char buf[100]; + int ret; + + sync(); + ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, arg); + if (ret < 0) { + snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno)); + writex(fd, buf, strlen(buf)); + } + adb_close(fd); +} + #endif #if 0 @@ -399,6 +414,11 @@ int service_to_fd(const char *name) ret = create_service_thread(file_sync_service, NULL); } else if(!strncmp(name, "remount:", 8)) { ret = create_service_thread(remount_service, NULL); + } else if(!strncmp(name, "reboot:", 7)) { + char* arg = name + 7; + if (*name == 0) + arg = NULL; + ret = create_service_thread(reboot_service, arg); } else if(!strncmp(name, "root:", 5)) { ret = create_service_thread(restart_root_service, NULL); #endif