Merge changes I316c13e3,I4d99744d,Id9614b72,I7c98a0b7
am: a78b5b300b
Change-Id: I0e4221611fb34489b2ecdd713933a2e4ba4e5055
This commit is contained in:
commit
e0db940e52
11 changed files with 237 additions and 145 deletions
|
@ -91,14 +91,25 @@ void Action::ExecuteCommand(const Command& command) const {
|
|||
auto result = command.InvokeFunc();
|
||||
auto duration = t.duration();
|
||||
|
||||
// There are many legacy paths in rootdir/init.rc that will virtually never exist on a new
|
||||
// device, such as '/sys/class/leds/jogball-backlight/brightness'. As of this writing, there
|
||||
// are 198 such failures on bullhead. Instead of spamming the log reporting them, we do not
|
||||
// report such failures unless we're running at the DEBUG log level.
|
||||
bool report_failure = !result.has_value();
|
||||
if (report_failure && android::base::GetMinimumLogSeverity() > android::base::DEBUG &&
|
||||
result.error_errno() == ENOENT) {
|
||||
report_failure = false;
|
||||
}
|
||||
|
||||
// Any action longer than 50ms will be warned to user as slow operation
|
||||
if (duration > 50ms || android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
|
||||
if (report_failure || duration > 50ms ||
|
||||
android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
|
||||
std::string trigger_name = BuildTriggersString();
|
||||
std::string cmd_str = command.BuildCommandString();
|
||||
|
||||
LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << " (" << filename_
|
||||
<< ":" << command.line() << ") took " << duration.count() << "ms and "
|
||||
<< (result ? "succeeded" : "failed: " + result.error());
|
||||
<< (result ? "succeeded" : "failed: " + result.error_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -127,7 +127,9 @@ static Result<Success> do_enable(const std::vector<std::string>& args) {
|
|||
Service* svc = ServiceList::GetInstance().FindService(args[1]);
|
||||
if (!svc) return Error() << "Could not find service";
|
||||
|
||||
if (!svc->Enable()) return Error() << "Could not enable service";
|
||||
if (auto result = svc->Enable(); !result) {
|
||||
return Error() << "Could not enable service: " << result.error();
|
||||
}
|
||||
|
||||
return Success();
|
||||
}
|
||||
|
@ -137,8 +139,8 @@ static Result<Success> do_exec(const std::vector<std::string>& args) {
|
|||
if (!service) {
|
||||
return Error() << "Could not create exec service";
|
||||
}
|
||||
if (!service->ExecStart()) {
|
||||
return Error() << "Could not start exec service";
|
||||
if (auto result = service->ExecStart(); !result) {
|
||||
return Error() << "Could not start exec service: " << result.error();
|
||||
}
|
||||
|
||||
ServiceList::GetInstance().AddService(std::move(service));
|
||||
|
@ -151,16 +153,16 @@ static Result<Success> do_exec_start(const std::vector<std::string>& args) {
|
|||
return Error() << "Service not found";
|
||||
}
|
||||
|
||||
if (!service->ExecStart()) {
|
||||
return Error() << "Could not start Service";
|
||||
if (auto result = service->ExecStart(); !result) {
|
||||
return Error() << "Could not start exec service: " << result.error();
|
||||
}
|
||||
|
||||
return Success();
|
||||
}
|
||||
|
||||
static Result<Success> do_export(const std::vector<std::string>& args) {
|
||||
if (!add_environment(args[1].c_str(), args[2].c_str())) {
|
||||
return Error();
|
||||
if (setenv(args[1].c_str(), args[2].c_str(), 1) == -1) {
|
||||
return ErrnoError() << "setenv() failed";
|
||||
}
|
||||
return Success();
|
||||
}
|
||||
|
@ -602,7 +604,9 @@ static Result<Success> do_setrlimit(const std::vector<std::string>& args) {
|
|||
static Result<Success> do_start(const std::vector<std::string>& args) {
|
||||
Service* svc = ServiceList::GetInstance().FindService(args[1]);
|
||||
if (!svc) return Error() << "service " << args[1] << " not found";
|
||||
if (!svc->Start()) return Error() << "failed to start service";
|
||||
if (auto result = svc->Start(); !result) {
|
||||
return Error() << "Could not start service: " << result.error();
|
||||
}
|
||||
return Success();
|
||||
}
|
||||
|
||||
|
@ -627,6 +631,11 @@ static Result<Success> do_trigger(const std::vector<std::string>& args) {
|
|||
|
||||
static Result<Success> do_symlink(const std::vector<std::string>& args) {
|
||||
if (symlink(args[1].c_str(), args[2].c_str()) < 0) {
|
||||
// The symlink builtin is often used to create symlinks for older devices to be backwards
|
||||
// compatible with new paths, therefore we skip reporting this error.
|
||||
if (errno == EEXIST && android::base::GetMinimumLogSeverity() > android::base::DEBUG) {
|
||||
return Success();
|
||||
}
|
||||
return ErrnoError() << "symlink() failed";
|
||||
}
|
||||
return Success();
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include <cutils/android_get_control_file.h>
|
||||
#include <cutils/sockets.h>
|
||||
|
||||
#include "init.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace android {
|
||||
|
@ -62,7 +61,7 @@ void DescriptorInfo::CreateAndPublish(const std::string& globalContext) const {
|
|||
[] (char& c) { c = isalnum(c) ? c : '_'; });
|
||||
|
||||
std::string val = std::to_string(fd);
|
||||
add_environment(publishedName.c_str(), val.c_str());
|
||||
setenv(publishedName.c_str(), val.c_str(), 1);
|
||||
|
||||
// make sure we don't close on exec
|
||||
fcntl(fd, F_SETFD, 0);
|
||||
|
|
|
@ -71,8 +71,6 @@ static char qemu[32];
|
|||
|
||||
std::string default_console = "/dev/console";
|
||||
|
||||
const char *ENV[32];
|
||||
|
||||
static int epoll_fd = -1;
|
||||
|
||||
static std::unique_ptr<Timer> waiting_for_prop(nullptr);
|
||||
|
@ -126,38 +124,6 @@ void register_epoll_handler(int fd, void (*fn)()) {
|
|||
}
|
||||
}
|
||||
|
||||
/* add_environment - add "key=value" to the current environment */
|
||||
int add_environment(const char *key, const char *val)
|
||||
{
|
||||
size_t n;
|
||||
size_t key_len = strlen(key);
|
||||
|
||||
/* The last environment entry is reserved to terminate the list */
|
||||
for (n = 0; n < (arraysize(ENV) - 1); n++) {
|
||||
|
||||
/* Delete any existing entry for this key */
|
||||
if (ENV[n] != NULL) {
|
||||
size_t entry_key_len = strcspn(ENV[n], "=");
|
||||
if ((entry_key_len == key_len) && (strncmp(ENV[n], key, entry_key_len) == 0)) {
|
||||
free((char*)ENV[n]);
|
||||
ENV[n] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add entry if a free slot is available */
|
||||
if (ENV[n] == NULL) {
|
||||
char* entry;
|
||||
asprintf(&entry, "%s=%s", key, val);
|
||||
ENV[n] = entry;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
LOG(ERROR) << "No env. room to store: '" << key << "':'" << val << "'";
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool start_waiting_for_property(const char *name, const char *value)
|
||||
{
|
||||
if (waiting_for_prop) {
|
||||
|
@ -429,8 +395,6 @@ int main(int argc, char** argv) {
|
|||
install_reboot_signal_handlers();
|
||||
}
|
||||
|
||||
add_environment("PATH", _PATH_DEFPATH);
|
||||
|
||||
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
|
||||
|
||||
if (is_first_stage) {
|
||||
|
@ -439,6 +403,8 @@ int main(int argc, char** argv) {
|
|||
// Clear the umask.
|
||||
umask(0);
|
||||
|
||||
clearenv();
|
||||
setenv("PATH", _PATH_DEFPATH, 1);
|
||||
// Get the basic filesystem setup we need put together in the initramdisk
|
||||
// on / and then we'll let the rc file figure out the rest.
|
||||
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
|
||||
|
|
|
@ -30,9 +30,7 @@ namespace init {
|
|||
// Note: These globals are *only* valid in init, so they should not be used in ueventd,
|
||||
// watchdogd, or any files that may be included in those, such as devices.cpp and util.cpp.
|
||||
// TODO: Have an Init class and remove all globals.
|
||||
extern const char *ENV[32];
|
||||
extern std::string default_console;
|
||||
|
||||
extern std::vector<std::string> late_import_paths;
|
||||
|
||||
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
|
||||
|
@ -43,8 +41,6 @@ void property_changed(const std::string& name, const std::string& value);
|
|||
|
||||
void register_epoll_handler(int fd, void (*fn)());
|
||||
|
||||
int add_environment(const char* key, const char* val);
|
||||
|
||||
bool start_waiting_for_property(const char *name, const char *value);
|
||||
|
||||
void DumpState();
|
||||
|
|
111
init/result.h
111
init/result.h
|
@ -21,9 +21,13 @@
|
|||
// There are 3 classes that implement this functionality and one additional helper type.
|
||||
//
|
||||
// Result<T> either contains a member of type T that can be accessed using similar semantics as
|
||||
// std::optional<T> or it contains a std::string describing an error, which can be accessed via
|
||||
// std::optional<T> or it contains a ResultError describing an error, which can be accessed via
|
||||
// Result<T>::error().
|
||||
//
|
||||
// ResultError is a type that contains both a std::string describing the error and a copy of errno
|
||||
// from when the error occurred. ResultError can be used in an ostream directly to print its
|
||||
// string value.
|
||||
//
|
||||
// Success is a typedef that aids in creating Result<T> that do not contain a return value.
|
||||
// Result<Success> is the correct return type for a function that either returns successfully or
|
||||
// returns an error value. Returning Success() from a function that returns Result<Success> is the
|
||||
|
@ -33,10 +37,20 @@
|
|||
// to T or from the constructor arguments for T. This allows you to return a type T directly from
|
||||
// a function that returns Result<T>.
|
||||
//
|
||||
// Error and ErrnoError are used to construct a Result<T> that has failed. Each of these classes
|
||||
// take an ostream as an input and are implicitly cast to a Result<T> containing that failure.
|
||||
// ErrnoError() additionally appends ": " + strerror(errno) to the end of the failure string to aid
|
||||
// in interacting with C APIs.
|
||||
// Error and ErrnoError are used to construct a Result<T> that has failed. The Error class takes
|
||||
// an ostream as an input and are implicitly cast to a Result<T> containing that failure.
|
||||
// ErrnoError() is a helper function to create an Error class that appends ": " + strerror(errno)
|
||||
// to the end of the failure string to aid in interacting with C APIs. Alternatively, an errno
|
||||
// value can be directly specified via the Error() constructor.
|
||||
//
|
||||
// ResultError can be used in the ostream when using Error to construct a Result<T>. In this case,
|
||||
// the string that the ResultError takes is passed through the stream normally, but the errno is
|
||||
// passed to the Result<T>. This can be used to pass errno from a failing C function up multiple
|
||||
// callers.
|
||||
//
|
||||
// ResultError can also directly construct a Result<T>. This is particularly useful if you have a
|
||||
// function that return Result<T> but you have a Result<U> and want to return its error. In this
|
||||
// case, you can return the .error() from the Result<U> to construct the Result<T>.
|
||||
|
||||
// An example of how to use these is below:
|
||||
// Result<U> CalculateResult(const T& input) {
|
||||
|
@ -66,9 +80,29 @@
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
struct ResultError {
|
||||
template <typename T>
|
||||
ResultError(T&& error_string, int error_errno)
|
||||
: error_string(std::forward<T>(error_string)), error_errno(error_errno) {}
|
||||
|
||||
std::string error_string;
|
||||
int error_errno;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const ResultError& t) {
|
||||
os << t.error_string;
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, ResultError&& t) {
|
||||
os << std::move(t.error_string);
|
||||
return os;
|
||||
}
|
||||
|
||||
class Error {
|
||||
public:
|
||||
Error() : append_errno_(0) {}
|
||||
Error() : errno_(0), append_errno_(false) {}
|
||||
Error(int errno_to_append) : errno_(errno_to_append), append_errno_(true) {}
|
||||
|
||||
template <typename T>
|
||||
Error&& operator<<(T&& t) {
|
||||
|
@ -76,30 +110,45 @@ class Error {
|
|||
return std::move(*this);
|
||||
}
|
||||
|
||||
const std::string str() const {
|
||||
if (append_errno_) {
|
||||
return ss_.str() + ": " + strerror(append_errno_);
|
||||
}
|
||||
return ss_.str();
|
||||
Error&& operator<<(const ResultError& result_error) {
|
||||
ss_ << result_error.error_string;
|
||||
errno_ = result_error.error_errno;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
Error&& operator<<(ResultError&& result_error) {
|
||||
ss_ << std::move(result_error.error_string);
|
||||
errno_ = result_error.error_errno;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
const std::string str() const {
|
||||
std::string str = ss_.str();
|
||||
if (append_errno_) {
|
||||
if (str.empty()) {
|
||||
return strerror(errno_);
|
||||
}
|
||||
return str + ": " + strerror(errno_);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
int get_errno() const { return errno_; }
|
||||
|
||||
Error(const Error&) = delete;
|
||||
Error(Error&&) = delete;
|
||||
Error& operator=(const Error&) = delete;
|
||||
Error& operator=(Error&&) = delete;
|
||||
|
||||
protected:
|
||||
Error(int append_errno) : append_errno_(append_errno) {}
|
||||
|
||||
private:
|
||||
std::stringstream ss_;
|
||||
int append_errno_;
|
||||
int errno_;
|
||||
bool append_errno_;
|
||||
};
|
||||
|
||||
class ErrnoError : public Error {
|
||||
public:
|
||||
ErrnoError() : Error(errno) {}
|
||||
};
|
||||
inline Error ErrnoError() {
|
||||
return Error(errno);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class Result {
|
||||
|
@ -107,7 +156,13 @@ class Result {
|
|||
template <typename... U>
|
||||
Result(U&&... result) : contents_(std::in_place_index_t<0>(), std::forward<U>(result)...) {}
|
||||
|
||||
Result(Error&& fb) : contents_(std::in_place_index_t<1>(), fb.str()) {}
|
||||
Result(Error&& error) : contents_(std::in_place_index_t<1>(), error.str(), error.get_errno()) {}
|
||||
Result(const ResultError& result_error)
|
||||
: contents_(std::in_place_index_t<1>(), result_error.error_string,
|
||||
result_error.error_errno) {}
|
||||
Result(ResultError&& result_error)
|
||||
: contents_(std::in_place_index_t<1>(), std::move(result_error.error_string),
|
||||
result_error.error_errno) {}
|
||||
|
||||
bool has_value() const { return contents_.index() == 0; }
|
||||
|
||||
|
@ -116,9 +171,17 @@ class Result {
|
|||
T&& value() && { return std::get<0>(std::move(contents_)); }
|
||||
const T&& value() const && { return std::get<0>(std::move(contents_)); }
|
||||
|
||||
const std::string& error() const & { return std::get<1>(contents_); }
|
||||
std::string&& error() && { return std::get<1>(std::move(contents_)); }
|
||||
const std::string&& error() const && { return std::get<1>(std::move(contents_)); }
|
||||
const ResultError& error() const & { return std::get<1>(contents_); }
|
||||
ResultError&& error() && { return std::get<1>(std::move(contents_)); }
|
||||
const ResultError&& error() const && { return std::get<1>(std::move(contents_)); }
|
||||
|
||||
const std::string& error_string() const & { return std::get<1>(contents_).error_string; }
|
||||
std::string&& error_string() && { return std::get<1>(std::move(contents_)).error_string; }
|
||||
const std::string&& error_string() const && {
|
||||
return std::get<1>(std::move(contents_)).error_string;
|
||||
}
|
||||
|
||||
int error_errno() const { return std::get<1>(contents_).error_errno; }
|
||||
|
||||
explicit operator bool() const { return has_value(); }
|
||||
|
||||
|
@ -131,7 +194,7 @@ class Result {
|
|||
const T* operator->() const { return &value(); }
|
||||
|
||||
private:
|
||||
std::variant<T, std::string> contents_;
|
||||
std::variant<T, ResultError> contents_;
|
||||
};
|
||||
|
||||
using Success = std::monostate;
|
||||
|
|
|
@ -74,7 +74,8 @@ TEST(result, result_error) {
|
|||
ASSERT_FALSE(result);
|
||||
ASSERT_FALSE(result.has_value());
|
||||
|
||||
EXPECT_EQ("failure1", result.error());
|
||||
EXPECT_EQ(0, result.error_errno());
|
||||
EXPECT_EQ("failure1", result.error_string());
|
||||
}
|
||||
|
||||
TEST(result, result_error_empty) {
|
||||
|
@ -82,7 +83,8 @@ TEST(result, result_error_empty) {
|
|||
ASSERT_FALSE(result);
|
||||
ASSERT_FALSE(result.has_value());
|
||||
|
||||
EXPECT_EQ("", result.error());
|
||||
EXPECT_EQ(0, result.error_errno());
|
||||
EXPECT_EQ("", result.error_string());
|
||||
}
|
||||
|
||||
TEST(result, result_error_rvalue) {
|
||||
|
@ -96,7 +98,8 @@ TEST(result, result_error_rvalue) {
|
|||
ASSERT_FALSE(MakeRvalueErrorResult());
|
||||
ASSERT_FALSE(MakeRvalueErrorResult().has_value());
|
||||
|
||||
EXPECT_EQ("failure1", MakeRvalueErrorResult().error());
|
||||
EXPECT_EQ(0, MakeRvalueErrorResult().error_errno());
|
||||
EXPECT_EQ("failure1", MakeRvalueErrorResult().error_string());
|
||||
}
|
||||
|
||||
TEST(result, result_errno_error) {
|
||||
|
@ -107,7 +110,72 @@ TEST(result, result_errno_error) {
|
|||
ASSERT_FALSE(result);
|
||||
ASSERT_FALSE(result.has_value());
|
||||
|
||||
EXPECT_EQ("failure1: "s + strerror(test_errno), result.error());
|
||||
EXPECT_EQ(test_errno, result.error_errno());
|
||||
EXPECT_EQ("failure1: "s + strerror(test_errno), result.error_string());
|
||||
}
|
||||
|
||||
TEST(result, result_errno_error_no_text) {
|
||||
constexpr int test_errno = 6;
|
||||
errno = test_errno;
|
||||
Result<Success> result = ErrnoError();
|
||||
|
||||
ASSERT_FALSE(result);
|
||||
ASSERT_FALSE(result.has_value());
|
||||
|
||||
EXPECT_EQ(test_errno, result.error_errno());
|
||||
EXPECT_EQ(strerror(test_errno), result.error_string());
|
||||
}
|
||||
|
||||
TEST(result, result_error_from_other_result) {
|
||||
auto error_text = "test error"s;
|
||||
Result<Success> result = Error() << error_text;
|
||||
|
||||
ASSERT_FALSE(result);
|
||||
ASSERT_FALSE(result.has_value());
|
||||
|
||||
Result<std::string> result2 = result.error();
|
||||
|
||||
ASSERT_FALSE(result2);
|
||||
ASSERT_FALSE(result2.has_value());
|
||||
|
||||
EXPECT_EQ(0, result.error_errno());
|
||||
EXPECT_EQ(error_text, result.error_string());
|
||||
}
|
||||
|
||||
TEST(result, result_error_through_ostream) {
|
||||
auto error_text = "test error"s;
|
||||
Result<Success> result = Error() << error_text;
|
||||
|
||||
ASSERT_FALSE(result);
|
||||
ASSERT_FALSE(result.has_value());
|
||||
|
||||
Result<std::string> result2 = Error() << result.error();
|
||||
|
||||
ASSERT_FALSE(result2);
|
||||
ASSERT_FALSE(result2.has_value());
|
||||
|
||||
EXPECT_EQ(0, result.error_errno());
|
||||
EXPECT_EQ(error_text, result.error_string());
|
||||
}
|
||||
|
||||
TEST(result, result_errno_error_through_ostream) {
|
||||
auto error_text = "test error"s;
|
||||
constexpr int test_errno = 6;
|
||||
errno = 6;
|
||||
Result<Success> result = ErrnoError() << error_text;
|
||||
|
||||
errno = 0;
|
||||
|
||||
ASSERT_FALSE(result);
|
||||
ASSERT_FALSE(result.has_value());
|
||||
|
||||
Result<std::string> result2 = Error() << result.error();
|
||||
|
||||
ASSERT_FALSE(result2);
|
||||
ASSERT_FALSE(result2.has_value());
|
||||
|
||||
EXPECT_EQ(test_errno, result.error_errno());
|
||||
EXPECT_EQ(error_text + ": " + strerror(test_errno), result.error_string());
|
||||
}
|
||||
|
||||
TEST(result, constructor_forwarding) {
|
||||
|
@ -215,7 +283,7 @@ TEST(result, die_on_access_failed_result) {
|
|||
|
||||
TEST(result, die_on_get_error_succesful_result) {
|
||||
Result<std::string> result = "success";
|
||||
ASSERT_DEATH(result.error(), "");
|
||||
ASSERT_DEATH(result.error_string(), "");
|
||||
}
|
||||
|
||||
} // namespace init
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
#include "selinux.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
@ -126,8 +125,7 @@ bool ForkExecveAndWaitForCompletion(const char* filename, char* const argv[]) {
|
|||
}
|
||||
TEMP_FAILURE_RETRY(close(pipe_fds[1]));
|
||||
|
||||
const char* envp[] = {_PATH_DEFPATH, nullptr};
|
||||
if (execve(filename, argv, (char**)envp) == -1) {
|
||||
if (execv(filename, argv) == -1) {
|
||||
PLOG(ERROR) << "Failed to execve " << filename;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -57,22 +57,20 @@ using android::base::WriteStringToFile;
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
static std::string ComputeContextFromExecutable(std::string& service_name,
|
||||
const std::string& service_path) {
|
||||
static Result<std::string> ComputeContextFromExecutable(std::string& service_name,
|
||||
const std::string& service_path) {
|
||||
std::string computed_context;
|
||||
|
||||
char* raw_con = nullptr;
|
||||
char* raw_filecon = nullptr;
|
||||
|
||||
if (getcon(&raw_con) == -1) {
|
||||
LOG(ERROR) << "could not get context while starting '" << service_name << "'";
|
||||
return "";
|
||||
return Error() << "Could not get security context";
|
||||
}
|
||||
std::unique_ptr<char> mycon(raw_con);
|
||||
|
||||
if (getfilecon(service_path.c_str(), &raw_filecon) == -1) {
|
||||
LOG(ERROR) << "could not get file context while starting '" << service_name << "'";
|
||||
return "";
|
||||
return Error() << "Could not get file context";
|
||||
}
|
||||
std::unique_ptr<char> filecon(raw_filecon);
|
||||
|
||||
|
@ -84,12 +82,10 @@ static std::string ComputeContextFromExecutable(std::string& service_name,
|
|||
free(new_con);
|
||||
}
|
||||
if (rc == 0 && computed_context == mycon.get()) {
|
||||
LOG(ERROR) << "service " << service_name << " does not have a SELinux domain defined";
|
||||
return "";
|
||||
return Error() << "Service does not have an SELinux domain defined";
|
||||
}
|
||||
if (rc < 0) {
|
||||
LOG(ERROR) << "could not get context while starting '" << service_name << "'";
|
||||
return "";
|
||||
return Error() << "Could not get process context";
|
||||
}
|
||||
return computed_context;
|
||||
}
|
||||
|
@ -147,14 +143,6 @@ static void ExpandArgs(const std::vector<std::string>& args, std::vector<char*>*
|
|||
strs->push_back(nullptr);
|
||||
}
|
||||
|
||||
ServiceEnvironmentInfo::ServiceEnvironmentInfo() {
|
||||
}
|
||||
|
||||
ServiceEnvironmentInfo::ServiceEnvironmentInfo(const std::string& name,
|
||||
const std::string& value)
|
||||
: name(name), value(value) {
|
||||
}
|
||||
|
||||
unsigned long Service::next_start_order_ = 1;
|
||||
bool Service::is_exec_service_running_ = false;
|
||||
|
||||
|
@ -507,7 +495,7 @@ Result<Success> Service::ParseSeclabel(const std::vector<std::string>& args) {
|
|||
}
|
||||
|
||||
Result<Success> Service::ParseSetenv(const std::vector<std::string>& args) {
|
||||
envvars_.emplace_back(args[1], args[2]);
|
||||
environment_vars_.emplace_back(args[1], args[2]);
|
||||
return Success();
|
||||
}
|
||||
|
||||
|
@ -637,16 +625,16 @@ Result<Success> Service::ParseLine(const std::vector<std::string>& args) {
|
|||
static const OptionParserMap parser_map;
|
||||
auto parser = parser_map.FindFunction(args);
|
||||
|
||||
if (!parser) return Error() << parser.error();
|
||||
if (!parser) return parser.error();
|
||||
|
||||
return std::invoke(*parser, this, args);
|
||||
}
|
||||
|
||||
bool Service::ExecStart() {
|
||||
Result<Success> Service::ExecStart() {
|
||||
flags_ |= SVC_ONESHOT;
|
||||
|
||||
if (!Start()) {
|
||||
return false;
|
||||
if (auto result = Start(); !result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
flags_ |= SVC_EXEC;
|
||||
|
@ -656,10 +644,10 @@ bool Service::ExecStart() {
|
|||
<< supp_gids_.size() << " context " << (!seclabel_.empty() ? seclabel_ : "default")
|
||||
<< ") started; waiting...";
|
||||
|
||||
return true;
|
||||
return Success();
|
||||
}
|
||||
|
||||
bool Service::Start() {
|
||||
Result<Success> Service::Start() {
|
||||
// Starting a service removes it from the disabled or reset state and
|
||||
// immediately takes it out of the restarting state if it was in there.
|
||||
flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
|
||||
|
@ -668,7 +656,8 @@ bool Service::Start() {
|
|||
// process of exiting, we've ensured that they will immediately restart
|
||||
// on exit, unless they are ONESHOT.
|
||||
if (flags_ & SVC_RUNNING) {
|
||||
return false;
|
||||
// It is not an error to try to start a service that is already running.
|
||||
return Success();
|
||||
}
|
||||
|
||||
bool needs_console = (flags_ & SVC_CONSOLE);
|
||||
|
@ -681,28 +670,27 @@ bool Service::Start() {
|
|||
// properly registered for the device node
|
||||
int console_fd = open(console_.c_str(), O_RDWR | O_CLOEXEC);
|
||||
if (console_fd < 0) {
|
||||
PLOG(ERROR) << "service '" << name_ << "' couldn't open console '" << console_ << "'";
|
||||
flags_ |= SVC_DISABLED;
|
||||
return false;
|
||||
return ErrnoError() << "Couldn't open console '" << console_ << "'";
|
||||
}
|
||||
close(console_fd);
|
||||
}
|
||||
|
||||
struct stat sb;
|
||||
if (stat(args_[0].c_str(), &sb) == -1) {
|
||||
PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
|
||||
flags_ |= SVC_DISABLED;
|
||||
return false;
|
||||
return ErrnoError() << "Cannot find '" << args_[0] << "'";
|
||||
}
|
||||
|
||||
std::string scon;
|
||||
if (!seclabel_.empty()) {
|
||||
scon = seclabel_;
|
||||
} else {
|
||||
scon = ComputeContextFromExecutable(name_, args_[0]);
|
||||
if (scon == "") {
|
||||
return false;
|
||||
auto result = ComputeContextFromExecutable(name_, args_[0]);
|
||||
if (!result) {
|
||||
return result.error();
|
||||
}
|
||||
scon = *result;
|
||||
}
|
||||
|
||||
LOG(INFO) << "starting service '" << name_ << "'...";
|
||||
|
@ -723,8 +711,8 @@ bool Service::Start() {
|
|||
SetUpPidNamespace(name_);
|
||||
}
|
||||
|
||||
for (const auto& ei : envvars_) {
|
||||
add_environment(ei.name.c_str(), ei.value.c_str());
|
||||
for (const auto& [key, value] : environment_vars_) {
|
||||
setenv(key.c_str(), value.c_str(), 1);
|
||||
}
|
||||
|
||||
std::for_each(descriptors_.begin(), descriptors_.end(),
|
||||
|
@ -779,7 +767,7 @@ bool Service::Start() {
|
|||
|
||||
std::vector<char*> strs;
|
||||
ExpandArgs(args_, &strs);
|
||||
if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
|
||||
if (execv(strs[0], (char**)&strs[0]) < 0) {
|
||||
PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
|
||||
}
|
||||
|
||||
|
@ -787,9 +775,8 @@ bool Service::Start() {
|
|||
}
|
||||
|
||||
if (pid < 0) {
|
||||
PLOG(ERROR) << "failed to fork for '" << name_ << "'";
|
||||
pid_ = 0;
|
||||
return false;
|
||||
return ErrnoError() << "Failed to fork";
|
||||
}
|
||||
|
||||
if (oom_score_adjust_ != -1000) {
|
||||
|
@ -831,24 +818,24 @@ bool Service::Start() {
|
|||
}
|
||||
|
||||
NotifyStateChange("running");
|
||||
return true;
|
||||
return Success();
|
||||
}
|
||||
|
||||
bool Service::StartIfNotDisabled() {
|
||||
Result<Success> Service::StartIfNotDisabled() {
|
||||
if (!(flags_ & SVC_DISABLED)) {
|
||||
return Start();
|
||||
} else {
|
||||
flags_ |= SVC_DISABLED_START;
|
||||
}
|
||||
return true;
|
||||
return Success();
|
||||
}
|
||||
|
||||
bool Service::Enable() {
|
||||
Result<Success> Service::Enable() {
|
||||
flags_ &= ~(SVC_DISABLED | SVC_RC_DISABLED);
|
||||
if (flags_ & SVC_DISABLED_START) {
|
||||
return Start();
|
||||
}
|
||||
return true;
|
||||
return Success();
|
||||
}
|
||||
|
||||
void Service::Reset() {
|
||||
|
@ -874,7 +861,9 @@ void Service::Restart() {
|
|||
StopOrReset(SVC_RESTART);
|
||||
} else if (!(flags_ & SVC_RESTARTING)) {
|
||||
/* Just start the service since it's not running. */
|
||||
Start();
|
||||
if (auto result = Start(); !result) {
|
||||
LOG(ERROR) << "Could not restart '" << name_ << "': " << result.error();
|
||||
}
|
||||
} /* else: Service is restarting anyways. */
|
||||
}
|
||||
|
||||
|
|
|
@ -57,13 +57,6 @@
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
struct ServiceEnvironmentInfo {
|
||||
ServiceEnvironmentInfo();
|
||||
ServiceEnvironmentInfo(const std::string& name, const std::string& value);
|
||||
std::string name;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
class Service {
|
||||
public:
|
||||
Service(const std::string& name, const std::vector<std::string>& args);
|
||||
|
@ -77,10 +70,10 @@ class Service {
|
|||
|
||||
bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
|
||||
Result<Success> ParseLine(const std::vector<std::string>& args);
|
||||
bool ExecStart();
|
||||
bool Start();
|
||||
bool StartIfNotDisabled();
|
||||
bool Enable();
|
||||
Result<Success> ExecStart();
|
||||
Result<Success> Start();
|
||||
Result<Success> StartIfNotDisabled();
|
||||
Result<Success> Enable();
|
||||
void Reset();
|
||||
void Stop();
|
||||
void Terminate();
|
||||
|
@ -178,7 +171,7 @@ class Service {
|
|||
std::string seclabel_;
|
||||
|
||||
std::vector<std::unique_ptr<DescriptorInfo>> descriptors_;
|
||||
std::vector<ServiceEnvironmentInfo> envvars_;
|
||||
std::vector<std::pair<std::string, std::string>> environment_vars_;
|
||||
|
||||
Action onrestart_; // Commands to execute on restart.
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ TEST(util, ReadFile_ENOENT) {
|
|||
auto file_contents = ReadFile("/proc/does-not-exist");
|
||||
EXPECT_EQ(ENOENT, errno);
|
||||
ASSERT_FALSE(file_contents);
|
||||
EXPECT_EQ("open() failed: No such file or directory", file_contents.error());
|
||||
EXPECT_EQ("open() failed: No such file or directory", file_contents.error_string());
|
||||
}
|
||||
|
||||
TEST(util, ReadFileGroupWriteable) {
|
||||
|
@ -45,7 +45,7 @@ TEST(util, ReadFileGroupWriteable) {
|
|||
EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0620, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
|
||||
auto file_contents = ReadFile(tf.path);
|
||||
ASSERT_FALSE(file_contents) << strerror(errno);
|
||||
EXPECT_EQ("Skipping insecure file", file_contents.error());
|
||||
EXPECT_EQ("Skipping insecure file", file_contents.error_string());
|
||||
}
|
||||
|
||||
TEST(util, ReadFileWorldWiteable) {
|
||||
|
@ -56,7 +56,7 @@ TEST(util, ReadFileWorldWiteable) {
|
|||
EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0602, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
|
||||
auto file_contents = ReadFile(tf.path);
|
||||
ASSERT_FALSE(file_contents) << strerror(errno);
|
||||
EXPECT_EQ("Skipping insecure file", file_contents.error());
|
||||
EXPECT_EQ("Skipping insecure file", file_contents.error_string());
|
||||
}
|
||||
|
||||
TEST(util, ReadFileSymbolicLink) {
|
||||
|
@ -65,7 +65,7 @@ TEST(util, ReadFileSymbolicLink) {
|
|||
auto file_contents = ReadFile("/charger");
|
||||
EXPECT_EQ(ELOOP, errno);
|
||||
ASSERT_FALSE(file_contents);
|
||||
EXPECT_EQ("open() failed: Too many symbolic links encountered", file_contents.error());
|
||||
EXPECT_EQ("open() failed: Too many symbolic links encountered", file_contents.error_string());
|
||||
}
|
||||
|
||||
TEST(util, ReadFileSuccess) {
|
||||
|
@ -130,7 +130,7 @@ TEST(util, DecodeUid) {
|
|||
|
||||
decoded_uid = DecodeUid("toot");
|
||||
EXPECT_FALSE(decoded_uid);
|
||||
EXPECT_EQ("getpwnam failed: No such file or directory", decoded_uid.error());
|
||||
EXPECT_EQ("getpwnam failed: No such file or directory", decoded_uid.error_string());
|
||||
|
||||
decoded_uid = DecodeUid("123");
|
||||
EXPECT_TRUE(decoded_uid);
|
||||
|
|
Loading…
Reference in a new issue