toolbox: add setprop, start, and stop

Move these from toybox as they're Android specific and more easily
maintained here.

A few changes during the conversion:
* Report error in setprop if value is not a UTF8 string; this would
  previously fail only after attempting to set the property
* Inform users to check dmesg for further failure messages for all
  three programs
* Only start/stop zygote_secondary if the device is not single arch

Bug: 117321744
Bug: 133901248
Test: setprop works, start and stop work on single and multi-arch.

Change-Id: Id2194cf2b65221bde38aff91f0e86b33edb37f42
This commit is contained in:
Tom Cherry 2019-06-05 10:26:54 -07:00
parent c76078e4b6
commit 65a1ee83a8
5 changed files with 205 additions and 0 deletions

View file

@ -211,3 +211,32 @@ tac tail tar taskset tee time timeout top touch tr traceroute traceroute6
true truncate tty tunctl ulimit umount uname uniq unix2dos unlink
unshare uptime usleep uudecode uuencode uuidgen vconfig vmstat watch
wc which whoami xargs xxd yes zcat
## Android R
BSD: grep fsck\_msdos newfs\_msdos
bzip2: bzcat bzip2 bunzip2
one-true-awk: awk
toolbox: getevent getprop setprop start stop
toybox: acpi base64 basename bc blkid blockdev cal cat chattr chcon chgrp
chmod chown chroot chrt cksum clear cmp comm cp cpio cut date dd df
diff dirname dmesg dos2unix du echo egrep env expand expr fallocate
false fgrep file find flock fmt free freeramdisk fsfreeze getconf
getenforce getfattr grep groups gunzip gzip head help hostname hwclock
i2cdetect i2cdump i2cget i2cset iconv id ifconfig inotifyd insmod
install ionice iorenice iotop kill killall ln load\_policy log logname
losetup ls lsattr lsmod lsof lspci lsusb makedevs md5sum microcom
mkdir mkfifo mknod mkswap mktemp modinfo modprobe more mount mountpoint
mv nbd-client nc netcat netstat nice nl nohup nproc nsenter od partprobe
paste patch pgrep pidof ping ping6 pivot\_root pkill pmap printenv
printf prlimit ps pwd pwdx readlink realpath renice restorecon rev
rfkill rm rmdir rmmod runcon sed sendevent seq setenforce setfattr
setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep sort split
stat strings stty swapoff swapon sync sysctl tac tail tar taskset tee
time timeout top touch tr traceroute traceroute6 true truncate tty tunctl
ulimit umount uname uniq unix2dos unlink unshare uptime usleep uudecode
uuencode uuidgen vconfig vmstat watch wc which whoami xargs xxd yes zcat

View file

@ -28,6 +28,8 @@ cc_defaults {
"toolbox.c",
"getevent.c",
"getprop.cpp",
"setprop.cpp",
"start.cpp",
],
generated_headers: [
"toolbox_input_labels",
@ -40,6 +42,9 @@ cc_defaults {
symlinks: [
"getevent",
"getprop",
"setprop",
"start",
"stop",
],
}

79
toolbox/setprop.cpp Normal file
View file

@ -0,0 +1,79 @@
/*
* Copyright (C) 2019 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 <ctype.h>
#include <stdlib.h>
#include <sys/system_properties.h>
#include <iostream>
#include <android-base/properties.h>
#include <android-base/strings.h>
using android::base::SetProperty;
using android::base::StartsWith;
extern "C" int setprop_main(int argc, char** argv) {
if (argc != 3) {
std::cout << "usage: setprop NAME VALUE\n"
"\n"
"Sets an Android system property."
<< std::endl;
return EXIT_FAILURE;
}
auto name = std::string{argv[1]};
auto value = std::string{argv[2]};
// SetProperty() doesn't tell us why it failed, and actually can't recognize most failures, so
// we duplicate some of init's checks here to help the user.
if (name.front() == '.' || name.back() == '.') {
std::cerr << "Property names must not start or end with a '.'" << std::endl;
return EXIT_FAILURE;
}
if (name.find("..") != std::string::npos) {
std::cerr << "'..' is not allowed in a property name" << std::endl;
return EXIT_FAILURE;
}
for (const auto& c : name) {
if (!isalnum(c) && !strchr(":@_.-", c)) {
std::cerr << "Invalid character '" << c << "' in name '" << name << "'" << std::endl;
return EXIT_FAILURE;
}
}
if (value.size() >= PROP_VALUE_MAX && !StartsWith(value, "ro.")) {
std::cerr << "Value '" << value << "' is too long, " << value.size()
<< " bytes vs a max of " << PROP_VALUE_MAX << std::endl;
return EXIT_FAILURE;
}
if (mbstowcs(nullptr, value.data(), 0) == static_cast<std::size_t>(-1)) {
std::cerr << "Value '" << value << "' is not a UTF8 encoded string" << std::endl;
return EXIT_FAILURE;
}
if (!SetProperty(name, value)) {
std::cerr << "Failed to set property '" << name << "' to '" << value
<< "'.\nSee dmesg for error reason." << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

89
toolbox/start.cpp Normal file
View file

@ -0,0 +1,89 @@
/*
* Copyright (C) 2019 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 <unistd.h>
#include <iostream>
#include <string>
#include <vector>
#include <android-base/properties.h>
using android::base::GetProperty;
using android::base::SetProperty;
using namespace std::literals;
static void ControlService(bool start, const std::string& service) {
if (!android::base::SetProperty(start ? "ctl.start" : "ctl.stop", service)) {
std::cerr << "Unable to " << (start ? "start" : "stop") << " service '" << service
<< "'\nSee dmesg for error reason." << std::endl;
exit(EXIT_FAILURE);
}
}
static void ControlDefaultServices(bool start) {
std::vector<std::string> services = {"netd", "surfaceflinger", "zygote"};
// Only start zygote_secondary if not single arch.
std::string zygote_configuration = GetProperty("ro.zygote", "");
if (zygote_configuration != "zygote32" && zygote_configuration != "zygote64") {
services.emplace_back("zygote_secondary");
}
if (start) {
for (const auto& service : services) {
ControlService(true, service);
}
} else {
for (auto it = services.crbegin(); it != services.crend(); ++it) {
ControlService(false, *it);
}
}
}
static int StartStop(int argc, char** argv, bool start) {
if (getuid()) {
std::cerr << "Must be root" << std::endl;
return EXIT_FAILURE;
}
if (argc == 1) {
ControlDefaultServices(start);
}
if (argc == 2 && argv[1] == "--help"s) {
std::cout << "usage: " << (start ? "start" : "stop")
<< " [SERVICE...]\n"
"\n"
<< (start ? "Starts" : "Stops")
<< " the given system service, or netd/surfaceflinger/zygotes." << std::endl;
return EXIT_SUCCESS;
}
for (int i = 1; i < argc; ++i) {
ControlService(start, argv[i]);
}
return EXIT_SUCCESS;
}
extern "C" int start_main(int argc, char** argv) {
return StartStop(argc, argv, true);
}
extern "C" int stop_main(int argc, char** argv) {
return StartStop(argc, argv, false);
}

View file

@ -1,3 +1,6 @@
TOOL(getevent)
TOOL(getprop)
TOOL(setprop)
TOOL(start)
TOOL(stop)
TOOL(toolbox)