Merge changes Ied888249,Id8857c45
* changes: init: check the arguments of builtins during the build init: don't log in expand_props directly
This commit is contained in:
commit
549ea4801b
22 changed files with 518 additions and 151 deletions
|
|
@ -227,9 +227,10 @@ cc_benchmark {
|
|||
|
||||
genrule {
|
||||
name: "generated_stub_builtin_function_map",
|
||||
tool_files: ["host_builtin_map.py"],
|
||||
out: ["generated_stub_builtin_function_map.h"],
|
||||
srcs: ["builtins.cpp"],
|
||||
cmd: "sed -n '/Builtin-function-map start/{:a;n;/Builtin-function-map end/q;p;ba}' $(in) | sed -e 's/do_[^}]*/do_stub/g' > $(out)",
|
||||
srcs: ["builtins.cpp", "check_builtins.cpp"],
|
||||
cmd: "$(location host_builtin_map.py) --builtins $(location builtins.cpp) --check_builtins $(location check_builtins.cpp) > $(out)",
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
|
|
@ -260,6 +261,7 @@ cc_binary {
|
|||
"action_manager.cpp",
|
||||
"action_parser.cpp",
|
||||
"capabilities.cpp",
|
||||
"check_builtins.cpp",
|
||||
"epoll.cpp",
|
||||
"keychords.cpp",
|
||||
"import_parser.cpp",
|
||||
|
|
|
|||
|
|
@ -35,9 +35,11 @@ Result<void> RunBuiltinFunction(const BuiltinFunction& function,
|
|||
builtin_arguments.args.resize(args.size());
|
||||
builtin_arguments.args[0] = args[0];
|
||||
for (std::size_t i = 1; i < args.size(); ++i) {
|
||||
if (!expand_props(args[i], &builtin_arguments.args[i])) {
|
||||
return Error() << "cannot expand '" << args[i] << "'";
|
||||
auto expanded_arg = ExpandProps(args[i]);
|
||||
if (!expanded_arg) {
|
||||
return expanded_arg.error();
|
||||
}
|
||||
builtin_arguments.args[i] = std::move(*expanded_arg);
|
||||
}
|
||||
|
||||
return function(builtin_arguments);
|
||||
|
|
@ -66,6 +68,30 @@ Result<void> Command::InvokeFunc(Subcontext* subcontext) const {
|
|||
return RunBuiltinFunction(func_, args_, kInitContext);
|
||||
}
|
||||
|
||||
Result<void> Command::CheckCommand() const {
|
||||
auto builtin_arguments = BuiltinArguments("host_init_verifier");
|
||||
|
||||
builtin_arguments.args.resize(args_.size());
|
||||
builtin_arguments.args[0] = args_[0];
|
||||
for (size_t i = 1; i < args_.size(); ++i) {
|
||||
auto expanded_arg = ExpandProps(args_[i]);
|
||||
if (!expanded_arg) {
|
||||
if (expanded_arg.error().message().find("doesn't exist while expanding") !=
|
||||
std::string::npos) {
|
||||
// If we failed because we won't have a property, use an empty string, which is
|
||||
// never returned from the parser, to indicate that this field cannot be checked.
|
||||
builtin_arguments.args[i] = "";
|
||||
} else {
|
||||
return expanded_arg.error();
|
||||
}
|
||||
} else {
|
||||
builtin_arguments.args[i] = std::move(*expanded_arg);
|
||||
}
|
||||
}
|
||||
|
||||
return func_(builtin_arguments);
|
||||
}
|
||||
|
||||
std::string Command::BuildCommandString() const {
|
||||
return Join(args_, ' ');
|
||||
}
|
||||
|
|
@ -105,6 +131,18 @@ std::size_t Action::NumCommands() const {
|
|||
return commands_.size();
|
||||
}
|
||||
|
||||
size_t Action::CheckAllCommands() const {
|
||||
size_t failures = 0;
|
||||
for (const auto& command : commands_) {
|
||||
if (auto result = command.CheckCommand(); !result) {
|
||||
LOG(ERROR) << "Command '" << command.BuildCommandString() << "' (" << filename_ << ":"
|
||||
<< command.line() << ") failed: " << result.error();
|
||||
++failures;
|
||||
}
|
||||
}
|
||||
return failures;
|
||||
}
|
||||
|
||||
void Action::ExecuteOneCommand(std::size_t command) const {
|
||||
// We need a copy here since some Command execution may result in
|
||||
// changing commands_ vector by importing .rc files through parser
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _INIT_ACTION_H
|
||||
#define _INIT_ACTION_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
|
@ -41,6 +40,7 @@ class Command {
|
|||
|
||||
Result<void> InvokeFunc(Subcontext* subcontext) const;
|
||||
std::string BuildCommandString() const;
|
||||
Result<void> CheckCommand() const;
|
||||
|
||||
int line() const { return line_; }
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ class Action {
|
|||
|
||||
Result<void> AddCommand(std::vector<std::string>&& args, int line);
|
||||
void AddCommand(BuiltinFunction f, std::vector<std::string>&& args, int line);
|
||||
std::size_t NumCommands() const;
|
||||
size_t NumCommands() const;
|
||||
void ExecuteOneCommand(std::size_t command) const;
|
||||
void ExecuteAllCommands() const;
|
||||
bool CheckEvent(const EventTrigger& event_trigger) const;
|
||||
|
|
@ -71,6 +71,7 @@ class Action {
|
|||
bool CheckEvent(const BuiltinAction& builtin_action) const;
|
||||
std::string BuildTriggersString() const;
|
||||
void DumpState() const;
|
||||
size_t CheckAllCommands() const;
|
||||
|
||||
bool oneshot() const { return oneshot_; }
|
||||
const std::string& filename() const { return filename_; }
|
||||
|
|
@ -96,5 +97,3 @@ class Action {
|
|||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -23,6 +23,14 @@ namespace init {
|
|||
|
||||
ActionManager::ActionManager() : current_command_(0) {}
|
||||
|
||||
size_t ActionManager::CheckAllCommands() {
|
||||
size_t failures = 0;
|
||||
for (const auto& action : actions_) {
|
||||
failures += action->CheckAllCommands();
|
||||
}
|
||||
return failures;
|
||||
}
|
||||
|
||||
ActionManager& ActionManager::GetInstance() {
|
||||
static ActionManager instance;
|
||||
return instance;
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _INIT_ACTION_MANAGER_H
|
||||
#define _INIT_ACTION_MANAGER_H
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -32,6 +31,7 @@ class ActionManager {
|
|||
|
||||
// Exposed for testing
|
||||
ActionManager();
|
||||
size_t CheckAllCommands();
|
||||
|
||||
void AddAction(std::unique_ptr<Action> action);
|
||||
void QueueEventTrigger(const std::string& trigger);
|
||||
|
|
@ -55,5 +55,3 @@ class ActionManager {
|
|||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -201,26 +201,26 @@ static Result<void> do_enable(const BuiltinArguments& args) {
|
|||
static Result<void> do_exec(const BuiltinArguments& args) {
|
||||
auto service = Service::MakeTemporaryOneshotService(args.args);
|
||||
if (!service) {
|
||||
return Error() << "Could not create exec service";
|
||||
return Error() << "Could not create exec service: " << service.error();
|
||||
}
|
||||
if (auto result = service->ExecStart(); !result) {
|
||||
if (auto result = (*service)->ExecStart(); !result) {
|
||||
return Error() << "Could not start exec service: " << result.error();
|
||||
}
|
||||
|
||||
ServiceList::GetInstance().AddService(std::move(service));
|
||||
ServiceList::GetInstance().AddService(std::move(*service));
|
||||
return {};
|
||||
}
|
||||
|
||||
static Result<void> do_exec_background(const BuiltinArguments& args) {
|
||||
auto service = Service::MakeTemporaryOneshotService(args.args);
|
||||
if (!service) {
|
||||
return Error() << "Could not create exec background service";
|
||||
return Error() << "Could not create exec background service: " << service.error();
|
||||
}
|
||||
if (auto result = service->Start(); !result) {
|
||||
if (auto result = (*service)->Start(); !result) {
|
||||
return Error() << "Could not start exec background service: " << result.error();
|
||||
}
|
||||
|
||||
ServiceList::GetInstance().AddService(std::move(service));
|
||||
ServiceList::GetInstance().AddService(std::move(*service));
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
@ -344,7 +344,7 @@ static Result<void> do_mkdir(const BuiltinArguments& args) {
|
|||
if (args.size() == 5) {
|
||||
gid = DecodeUid(args[4]);
|
||||
if (!gid) {
|
||||
return Error() << "Unable to decode GID for '" << args[3] << "': " << gid.error();
|
||||
return Error() << "Unable to decode GID for '" << args[4] << "': " << gid.error();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -936,40 +936,17 @@ static Result<void> do_chmod(const BuiltinArguments& args) {
|
|||
}
|
||||
|
||||
static Result<void> do_restorecon(const BuiltinArguments& args) {
|
||||
auto restorecon_info = ParseRestorecon(args.args);
|
||||
if (!restorecon_info) {
|
||||
return restorecon_info.error();
|
||||
}
|
||||
|
||||
const auto& [flag, paths] = *restorecon_info;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
struct flag_type {const char* name; int value;};
|
||||
static const flag_type flags[] = {
|
||||
{"--recursive", SELINUX_ANDROID_RESTORECON_RECURSE},
|
||||
{"--skip-ce", SELINUX_ANDROID_RESTORECON_SKIPCE},
|
||||
{"--cross-filesystems", SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
int flag = 0;
|
||||
|
||||
bool in_flags = true;
|
||||
for (size_t i = 1; i < args.size(); ++i) {
|
||||
if (android::base::StartsWith(args[i], "--")) {
|
||||
if (!in_flags) {
|
||||
return Error() << "flags must precede paths";
|
||||
}
|
||||
bool found = false;
|
||||
for (size_t j = 0; flags[j].name; ++j) {
|
||||
if (args[i] == flags[j].name) {
|
||||
flag |= flags[j].value;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return Error() << "bad flag " << args[i];
|
||||
}
|
||||
} else {
|
||||
in_flags = false;
|
||||
if (selinux_android_restorecon(args[i].c_str(), flag) < 0) {
|
||||
ret = errno;
|
||||
}
|
||||
for (const auto& path : paths) {
|
||||
if (selinux_android_restorecon(path.c_str(), flag) < 0) {
|
||||
ret = errno;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1056,9 +1033,9 @@ static Result<void> ExecWithRebootOnFailure(const std::string& reboot_reason,
|
|||
const BuiltinArguments& args) {
|
||||
auto service = Service::MakeTemporaryOneshotService(args.args);
|
||||
if (!service) {
|
||||
return Error() << "Could not create exec service";
|
||||
return Error() << "Could not create exec service: " << service.error();
|
||||
}
|
||||
service->AddReapCallback([reboot_reason](const siginfo_t& siginfo) {
|
||||
(*service)->AddReapCallback([reboot_reason](const siginfo_t& siginfo) {
|
||||
if (siginfo.si_code != CLD_EXITED || siginfo.si_status != 0) {
|
||||
// TODO (b/122850122): support this in gsi
|
||||
if (fscrypt_is_native() && !android::gsi::IsGsiRunning()) {
|
||||
|
|
@ -1073,10 +1050,10 @@ static Result<void> ExecWithRebootOnFailure(const std::string& reboot_reason,
|
|||
}
|
||||
}
|
||||
});
|
||||
if (auto result = service->ExecStart(); !result) {
|
||||
if (auto result = (*service)->ExecStart(); !result) {
|
||||
return Error() << "Could not start exec service: " << result.error();
|
||||
}
|
||||
ServiceList::GetInstance().AddService(std::move(service));
|
||||
ServiceList::GetInstance().AddService(std::move(*service));
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
|||
197
init/check_builtins.cpp
Normal file
197
init/check_builtins.cpp
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Note that these check functions cannot check expanded arguments from properties, since they will
|
||||
// not know what those properties would be at runtime. They will be passed an empty string in the
|
||||
// situation that the input line had a property expansion without a default value, since an empty
|
||||
// string is otherwise an impossible value. They should therefore disregard checking empty
|
||||
// arguments.
|
||||
|
||||
#include "check_builtins.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/parseint.h>
|
||||
#include <android-base/strings.h>
|
||||
|
||||
#include "builtin_arguments.h"
|
||||
#include "rlimit_parser.h"
|
||||
#include "service.h"
|
||||
#include "util.h"
|
||||
|
||||
using android::base::ParseInt;
|
||||
using android::base::StartsWith;
|
||||
|
||||
#define ReturnIfAnyArgsEmpty() \
|
||||
for (const auto& arg : args) { \
|
||||
if (arg.empty()) { \
|
||||
return {}; \
|
||||
} \
|
||||
}
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
||||
Result<void> check_chown(const BuiltinArguments& args) {
|
||||
if (!args[1].empty()) {
|
||||
auto uid = DecodeUid(args[1]);
|
||||
if (!uid) {
|
||||
return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error();
|
||||
}
|
||||
}
|
||||
|
||||
// GID is optional and pushes the index of path out by one if specified.
|
||||
if (args.size() == 4 && !args[2].empty()) {
|
||||
auto gid = DecodeUid(args[2]);
|
||||
if (!gid) {
|
||||
return Error() << "Unable to decode GID for '" << args[2] << "': " << gid.error();
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> check_exec(const BuiltinArguments& args) {
|
||||
ReturnIfAnyArgsEmpty();
|
||||
|
||||
auto result = Service::MakeTemporaryOneshotService(args.args);
|
||||
if (!result) {
|
||||
return result.error();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> check_exec_background(const BuiltinArguments& args) {
|
||||
return check_exec(std::move(args));
|
||||
}
|
||||
|
||||
Result<void> check_load_system_props(const BuiltinArguments& args) {
|
||||
return Error() << "'load_system_props' is deprecated";
|
||||
}
|
||||
|
||||
Result<void> check_loglevel(const BuiltinArguments& args) {
|
||||
ReturnIfAnyArgsEmpty();
|
||||
|
||||
int log_level = -1;
|
||||
ParseInt(args[1], &log_level);
|
||||
if (log_level < 0 || log_level > 7) {
|
||||
return Error() << "loglevel must be in the range of 0-7";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> check_mkdir(const BuiltinArguments& args) {
|
||||
if (args.size() >= 4) {
|
||||
if (!args[3].empty()) {
|
||||
auto uid = DecodeUid(args[3]);
|
||||
if (!uid) {
|
||||
return Error() << "Unable to decode UID for '" << args[3] << "': " << uid.error();
|
||||
}
|
||||
}
|
||||
|
||||
if (args.size() == 5 && !args[4].empty()) {
|
||||
auto gid = DecodeUid(args[4]);
|
||||
if (!gid) {
|
||||
return Error() << "Unable to decode GID for '" << args[4] << "': " << gid.error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> check_restorecon(const BuiltinArguments& args) {
|
||||
ReturnIfAnyArgsEmpty();
|
||||
|
||||
auto restorecon_info = ParseRestorecon(args.args);
|
||||
if (!restorecon_info) {
|
||||
return restorecon_info.error();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> check_restorecon_recursive(const BuiltinArguments& args) {
|
||||
return check_restorecon(std::move(args));
|
||||
}
|
||||
|
||||
Result<void> check_setprop(const BuiltinArguments& args) {
|
||||
const std::string& name = args[1];
|
||||
if (name.empty()) {
|
||||
return {};
|
||||
}
|
||||
const std::string& value = args[2];
|
||||
|
||||
if (!IsLegalPropertyName(name)) {
|
||||
return Error() << "'" << name << "' is not a legal property name";
|
||||
}
|
||||
|
||||
if (!value.empty()) {
|
||||
if (auto result = IsLegalPropertyValue(name, value); !result) {
|
||||
return result.error();
|
||||
}
|
||||
}
|
||||
|
||||
if (StartsWith(name, "ctl.")) {
|
||||
return Error()
|
||||
<< "Do not set ctl. properties from init; call the Service functions directly";
|
||||
}
|
||||
|
||||
static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";
|
||||
if (name == kRestoreconProperty) {
|
||||
return Error() << "Do not set '" << kRestoreconProperty
|
||||
<< "' from init; use the restorecon builtin directly";
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> check_setrlimit(const BuiltinArguments& args) {
|
||||
ReturnIfAnyArgsEmpty();
|
||||
|
||||
auto rlimit = ParseRlimit(args.args);
|
||||
if (!rlimit) return rlimit.error();
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> check_sysclktz(const BuiltinArguments& args) {
|
||||
ReturnIfAnyArgsEmpty();
|
||||
|
||||
struct timezone tz = {};
|
||||
if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) {
|
||||
return Error() << "Unable to parse mins_west_of_gmt";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> check_wait(const BuiltinArguments& args) {
|
||||
if (args.size() == 3 && !args[2].empty()) {
|
||||
int timeout_int;
|
||||
if (!android::base::ParseInt(args[2], &timeout_int)) {
|
||||
return Error() << "failed to parse timeout";
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> check_wait_for_prop(const BuiltinArguments& args) {
|
||||
return check_setprop(std::move(args));
|
||||
}
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
40
init/check_builtins.h
Normal file
40
init/check_builtins.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "builtin_arguments.h"
|
||||
#include "result.h"
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
||||
Result<void> check_chown(const BuiltinArguments& args);
|
||||
Result<void> check_exec(const BuiltinArguments& args);
|
||||
Result<void> check_exec_background(const BuiltinArguments& args);
|
||||
Result<void> check_load_system_props(const BuiltinArguments& args);
|
||||
Result<void> check_loglevel(const BuiltinArguments& args);
|
||||
Result<void> check_mkdir(const BuiltinArguments& args);
|
||||
Result<void> check_restorecon(const BuiltinArguments& args);
|
||||
Result<void> check_restorecon_recursive(const BuiltinArguments& args);
|
||||
Result<void> check_setprop(const BuiltinArguments& args);
|
||||
Result<void> check_setrlimit(const BuiltinArguments& args);
|
||||
Result<void> check_sysclktz(const BuiltinArguments& args);
|
||||
Result<void> check_wait(const BuiltinArguments& args);
|
||||
Result<void> check_wait_for_prop(const BuiltinArguments& args);
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
46
init/host_builtin_map.py
Executable file
46
init/host_builtin_map.py
Executable file
|
|
@ -0,0 +1,46 @@
|
|||
#!/usr/bin/env python
|
||||
"""Generates the builtins map to be used by host_init_verifier.
|
||||
|
||||
It copies the builtin function map from builtins.cpp, then replaces do_xxx() functions with the
|
||||
equivalent check_xxx() if found in check_builtins.cpp.
|
||||
|
||||
"""
|
||||
|
||||
import re
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser('host_builtin_map.py')
|
||||
parser.add_argument('--builtins', required=True, help='Path to builtins.cpp')
|
||||
parser.add_argument('--check_builtins', required=True, help='Path to check_builtins.cpp')
|
||||
args = parser.parse_args()
|
||||
|
||||
CHECK_REGEX = re.compile(r'.+check_(\S+)\(.+')
|
||||
check_functions = []
|
||||
with open(args.check_builtins) as check_file:
|
||||
for line in check_file:
|
||||
match = CHECK_REGEX.match(line)
|
||||
if match:
|
||||
check_functions.append(match.group(1))
|
||||
|
||||
function_map = []
|
||||
with open(args.builtins) as builtins_file:
|
||||
in_function_map = False
|
||||
for line in builtins_file:
|
||||
if '// Builtin-function-map start' in line:
|
||||
in_function_map = True
|
||||
elif '// Builtin-function-map end' in line:
|
||||
in_function_map = False
|
||||
elif in_function_map:
|
||||
function_map.append(line)
|
||||
|
||||
DO_REGEX = re.compile(r'.+do_([^\}]+).+')
|
||||
FUNCTION_REGEX = re.compile(r'(do_[^\}]+)')
|
||||
for line in function_map:
|
||||
match = DO_REGEX.match(line)
|
||||
if match:
|
||||
if match.group(1) in check_functions:
|
||||
print line.replace('do_', 'check_'),
|
||||
else:
|
||||
print FUNCTION_REGEX.sub('check_stub', line),
|
||||
else:
|
||||
print line,
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
// android/api-level.h
|
||||
#define __ANDROID_API_P__ 28
|
||||
#define __ANDROID_API_R__ 30
|
||||
|
||||
// sys/system_properties.h
|
||||
#define PROP_VALUE_MAX 92
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "action.h"
|
||||
#include "action_manager.h"
|
||||
#include "action_parser.h"
|
||||
#include "check_builtins.h"
|
||||
#include "host_import_parser.h"
|
||||
#include "host_init_stubs.h"
|
||||
#include "parser.h"
|
||||
|
|
@ -163,7 +164,7 @@ ReadInterfaceInheritanceHierarchy(const std::string& interface_inheritance_hiera
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
static Result<void> do_stub(const BuiltinArguments& args) {
|
||||
static Result<void> check_stub(const BuiltinArguments& args) {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
@ -238,9 +239,10 @@ int main(int argc, char** argv) {
|
|||
LOG(ERROR) << "Failed to open init rc script '" << *argv << "'";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (parser.parse_error_count() > 0) {
|
||||
LOG(ERROR) << "Failed to parse init script '" << *argv << "' with "
|
||||
<< parser.parse_error_count() << " errors";
|
||||
size_t failures = parser.parse_error_count() + am.CheckAllCommands();
|
||||
if (failures > 0) {
|
||||
LOG(ERROR) << "Failed to parse init script '" << *argv << "' with " << failures
|
||||
<< " errors";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -29,15 +29,14 @@ Result<void> ImportParser::ParseSection(std::vector<std::string>&& args,
|
|||
return Error() << "single argument needed for import\n";
|
||||
}
|
||||
|
||||
std::string conf_file;
|
||||
bool ret = expand_props(args[1], &conf_file);
|
||||
if (!ret) {
|
||||
return Error() << "error while expanding import";
|
||||
auto conf_file = ExpandProps(args[1]);
|
||||
if (!conf_file) {
|
||||
return Error() << "Could not expand import: " << conf_file.error();
|
||||
}
|
||||
|
||||
LOG(INFO) << "Added '" << conf_file << "' to import list";
|
||||
LOG(INFO) << "Added '" << *conf_file << "' to import list";
|
||||
if (filename_.empty()) filename_ = filename;
|
||||
imports_.emplace_back(std::move(conf_file), line);
|
||||
imports_.emplace_back(std::move(*conf_file), line);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -174,13 +174,8 @@ static uint32_t PropertySet(const std::string& name, const std::string& value, s
|
|||
return PROP_ERROR_INVALID_NAME;
|
||||
}
|
||||
|
||||
if (valuelen >= PROP_VALUE_MAX && !StartsWith(name, "ro.")) {
|
||||
*error = "Property value too long";
|
||||
return PROP_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if (mbstowcs(nullptr, value.data(), 0) == static_cast<std::size_t>(-1)) {
|
||||
*error = "Value is not a UTF8 encoded string";
|
||||
if (auto result = IsLegalPropertyValue(name, value); !result) {
|
||||
*error = result.error().message();
|
||||
return PROP_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
|
|
@ -648,13 +643,14 @@ static void LoadProperties(char* data, const char* filter, const char* filename,
|
|||
}
|
||||
|
||||
std::string raw_filename(fn);
|
||||
std::string expanded_filename;
|
||||
if (!expand_props(raw_filename, &expanded_filename)) {
|
||||
LOG(ERROR) << "Could not expand filename '" << raw_filename << "'";
|
||||
auto expanded_filename = ExpandProps(raw_filename);
|
||||
|
||||
if (!expanded_filename) {
|
||||
LOG(ERROR) << "Could not expand filename ': " << expanded_filename.error();
|
||||
continue;
|
||||
}
|
||||
|
||||
load_properties_from_file(expanded_filename.c_str(), key, properties);
|
||||
load_properties_from_file(expanded_filename->c_str(), key, properties);
|
||||
} else {
|
||||
value = strchr(key, '=');
|
||||
if (!value) continue;
|
||||
|
|
|
|||
|
|
@ -497,24 +497,28 @@ void SelinuxSetupKernelLogging() {
|
|||
// This function returns the Android version with which the vendor SEPolicy was compiled.
|
||||
// It is used for version checks such as whether or not vendor_init should be used
|
||||
int SelinuxGetVendorAndroidVersion() {
|
||||
if (!IsSplitPolicyDevice()) {
|
||||
// If this device does not split sepolicy files, it's not a Treble device and therefore,
|
||||
// we assume it's always on the latest platform.
|
||||
return __ANDROID_API_FUTURE__;
|
||||
}
|
||||
static int vendor_android_version = [] {
|
||||
if (!IsSplitPolicyDevice()) {
|
||||
// If this device does not split sepolicy files, it's not a Treble device and therefore,
|
||||
// we assume it's always on the latest platform.
|
||||
return __ANDROID_API_FUTURE__;
|
||||
}
|
||||
|
||||
std::string version;
|
||||
if (!GetVendorMappingVersion(&version)) {
|
||||
LOG(FATAL) << "Could not read vendor SELinux version";
|
||||
}
|
||||
std::string version;
|
||||
if (!GetVendorMappingVersion(&version)) {
|
||||
LOG(FATAL) << "Could not read vendor SELinux version";
|
||||
}
|
||||
|
||||
int major_version;
|
||||
std::string major_version_str(version, 0, version.find('.'));
|
||||
if (!ParseInt(major_version_str, &major_version)) {
|
||||
PLOG(FATAL) << "Failed to parse the vendor sepolicy major version " << major_version_str;
|
||||
}
|
||||
int major_version;
|
||||
std::string major_version_str(version, 0, version.find('.'));
|
||||
if (!ParseInt(major_version_str, &major_version)) {
|
||||
PLOG(FATAL) << "Failed to parse the vendor sepolicy major version "
|
||||
<< major_version_str;
|
||||
}
|
||||
|
||||
return major_version;
|
||||
return major_version;
|
||||
}();
|
||||
return vendor_android_version;
|
||||
}
|
||||
|
||||
// This function initializes SELinux then execs init to run in the init SELinux context.
|
||||
|
|
|
|||
|
|
@ -100,9 +100,11 @@ static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigsto
|
|||
expanded_args.resize(args.size());
|
||||
c_strings.push_back(const_cast<char*>(args[0].data()));
|
||||
for (std::size_t i = 1; i < args.size(); ++i) {
|
||||
if (!expand_props(args[i], &expanded_args[i])) {
|
||||
LOG(FATAL) << args[0] << ": cannot expand '" << args[i] << "'";
|
||||
auto expanded_arg = ExpandProps(args[i]);
|
||||
if (!expanded_arg) {
|
||||
LOG(FATAL) << args[0] << ": cannot expand arguments': " << expanded_arg.error();
|
||||
}
|
||||
expanded_args[i] = *expanded_arg;
|
||||
c_strings.push_back(expanded_args[i].data());
|
||||
}
|
||||
c_strings.push_back(nullptr);
|
||||
|
|
@ -633,7 +635,8 @@ void Service::StopOrReset(int how) {
|
|||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Service> Service::MakeTemporaryOneshotService(const std::vector<std::string>& args) {
|
||||
Result<std::unique_ptr<Service>> Service::MakeTemporaryOneshotService(
|
||||
const std::vector<std::string>& args) {
|
||||
// Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
|
||||
// SECLABEL can be a - to denote default
|
||||
std::size_t command_arg = 1;
|
||||
|
|
@ -644,13 +647,11 @@ std::unique_ptr<Service> Service::MakeTemporaryOneshotService(const std::vector<
|
|||
}
|
||||
}
|
||||
if (command_arg > 4 + NR_SVC_SUPP_GIDS) {
|
||||
LOG(ERROR) << "exec called with too many supplementary group ids";
|
||||
return nullptr;
|
||||
return Error() << "exec called with too many supplementary group ids";
|
||||
}
|
||||
|
||||
if (command_arg >= args.size()) {
|
||||
LOG(ERROR) << "exec called without command";
|
||||
return nullptr;
|
||||
return Error() << "exec called without command";
|
||||
}
|
||||
std::vector<std::string> str_args(args.begin() + command_arg, args.end());
|
||||
|
||||
|
|
@ -669,8 +670,7 @@ std::unique_ptr<Service> Service::MakeTemporaryOneshotService(const std::vector<
|
|||
if (command_arg > 3) {
|
||||
uid = DecodeUid(args[2]);
|
||||
if (!uid) {
|
||||
LOG(ERROR) << "Unable to decode UID for '" << args[2] << "': " << uid.error();
|
||||
return nullptr;
|
||||
return Error() << "Unable to decode UID for '" << args[2] << "': " << uid.error();
|
||||
}
|
||||
}
|
||||
Result<gid_t> gid = 0;
|
||||
|
|
@ -678,16 +678,14 @@ std::unique_ptr<Service> Service::MakeTemporaryOneshotService(const std::vector<
|
|||
if (command_arg > 4) {
|
||||
gid = DecodeUid(args[3]);
|
||||
if (!gid) {
|
||||
LOG(ERROR) << "Unable to decode GID for '" << args[3] << "': " << gid.error();
|
||||
return nullptr;
|
||||
return Error() << "Unable to decode GID for '" << args[3] << "': " << gid.error();
|
||||
}
|
||||
std::size_t nr_supp_gids = command_arg - 1 /* -- */ - 4 /* exec SECLABEL UID GID */;
|
||||
for (size_t i = 0; i < nr_supp_gids; ++i) {
|
||||
auto supp_gid = DecodeUid(args[4 + i]);
|
||||
if (!supp_gid) {
|
||||
LOG(ERROR) << "Unable to decode GID for '" << args[4 + i]
|
||||
<< "': " << supp_gid.error();
|
||||
return nullptr;
|
||||
return Error() << "Unable to decode GID for '" << args[4 + i]
|
||||
<< "': " << supp_gid.error();
|
||||
}
|
||||
supp_gids.push_back(*supp_gid);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,8 @@ class Service {
|
|||
const std::vector<gid_t>& supp_gids, int namespace_flags, const std::string& seclabel,
|
||||
Subcontext* subcontext_for_restart_commands, const std::vector<std::string>& args);
|
||||
|
||||
static std::unique_ptr<Service> MakeTemporaryOneshotService(const std::vector<std::string>& args);
|
||||
static Result<std::unique_ptr<Service>> MakeTemporaryOneshotService(
|
||||
const std::vector<std::string>& args);
|
||||
|
||||
bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
|
||||
Result<void> ExecStart();
|
||||
|
|
|
|||
|
|
@ -193,9 +193,9 @@ Result<void> ServiceParser::ParseIoprio(std::vector<std::string>&& args) {
|
|||
Result<void> ServiceParser::ParseKeycodes(std::vector<std::string>&& args) {
|
||||
auto it = args.begin() + 1;
|
||||
if (args.size() == 2 && StartsWith(args[1], "$")) {
|
||||
std::string expanded;
|
||||
if (!expand_props(args[1], &expanded)) {
|
||||
return Error() << "Could not expand property '" << args[1] << "'";
|
||||
auto expanded = ExpandProps(args[1]);
|
||||
if (!expanded) {
|
||||
return expanded.error();
|
||||
}
|
||||
|
||||
// If the property is not set, it defaults to none, in which case there are no keycodes
|
||||
|
|
@ -204,7 +204,7 @@ Result<void> ServiceParser::ParseKeycodes(std::vector<std::string>&& args) {
|
|||
return {};
|
||||
}
|
||||
|
||||
args = Split(expanded, ",");
|
||||
args = Split(*expanded, ",");
|
||||
it = args.begin();
|
||||
}
|
||||
|
||||
|
|
@ -422,9 +422,11 @@ Result<void> ServiceParser::ParseFile(std::vector<std::string>&& args) {
|
|||
FileDescriptor file;
|
||||
file.type = args[2];
|
||||
|
||||
if (!expand_props(args[1], &file.name)) {
|
||||
return Error() << "Could not expand property in file path '" << args[1] << "'";
|
||||
auto file_name = ExpandProps(args[1]);
|
||||
if (!file_name) {
|
||||
return Error() << "Could not expand file path ': " << file_name.error();
|
||||
}
|
||||
file.name = *file_name;
|
||||
if (file.name[0] != '/' || file.name.find("../") != std::string::npos) {
|
||||
return Error() << "file name must not be relative";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,15 +75,15 @@ TEST(service, pod_initialized) {
|
|||
TEST(service, make_temporary_oneshot_service_invalid_syntax) {
|
||||
std::vector<std::string> args;
|
||||
// Nothing.
|
||||
ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
|
||||
ASSERT_FALSE(Service::MakeTemporaryOneshotService(args));
|
||||
|
||||
// No arguments to 'exec'.
|
||||
args.push_back("exec");
|
||||
ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
|
||||
ASSERT_FALSE(Service::MakeTemporaryOneshotService(args));
|
||||
|
||||
// No command in "exec --".
|
||||
args.push_back("--");
|
||||
ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
|
||||
ASSERT_FALSE(Service::MakeTemporaryOneshotService(args));
|
||||
}
|
||||
|
||||
TEST(service, make_temporary_oneshot_service_too_many_supplementary_gids) {
|
||||
|
|
@ -97,7 +97,7 @@ TEST(service, make_temporary_oneshot_service_too_many_supplementary_gids) {
|
|||
}
|
||||
args.push_back("--");
|
||||
args.push_back("/system/bin/id");
|
||||
ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
|
||||
ASSERT_FALSE(Service::MakeTemporaryOneshotService(args));
|
||||
}
|
||||
|
||||
static void Test_make_temporary_oneshot_service(bool dash_dash, bool seclabel, bool uid, bool gid,
|
||||
|
|
@ -122,8 +122,9 @@ static void Test_make_temporary_oneshot_service(bool dash_dash, bool seclabel, b
|
|||
}
|
||||
args.push_back("/system/bin/toybox");
|
||||
args.push_back("id");
|
||||
auto svc = Service::MakeTemporaryOneshotService(args);
|
||||
ASSERT_NE(nullptr, svc);
|
||||
auto service_ret = Service::MakeTemporaryOneshotService(args);
|
||||
ASSERT_TRUE(service_ret);
|
||||
auto svc = std::move(*service_ret);
|
||||
|
||||
if (seclabel) {
|
||||
ASSERT_EQ("u:r:su:s0", svc->seclabel());
|
||||
|
|
|
|||
|
|
@ -151,15 +151,15 @@ void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& exec
|
|||
void SubcontextProcess::ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
|
||||
SubcontextReply* reply) const {
|
||||
for (const auto& arg : expand_args_command.args()) {
|
||||
auto expanded_prop = std::string{};
|
||||
if (!expand_props(arg, &expanded_prop)) {
|
||||
auto expanded_arg = ExpandProps(arg);
|
||||
if (!expanded_arg) {
|
||||
auto* failure = reply->mutable_failure();
|
||||
failure->set_error_string("Failed to expand '" + arg + "'");
|
||||
failure->set_error_string(expanded_arg.error().message());
|
||||
failure->set_error_errno(0);
|
||||
return;
|
||||
} else {
|
||||
auto* expand_args_reply = reply->mutable_expand_args_reply();
|
||||
expand_args_reply->add_expanded_args(expanded_prop);
|
||||
expand_args_reply->add_expanded_args(*expanded_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,7 +166,8 @@ TEST(subcontext, ExpandArgsFailure) {
|
|||
};
|
||||
auto result = subcontext.ExpandArgs(args);
|
||||
ASSERT_FALSE(result);
|
||||
EXPECT_EQ("Failed to expand '" + args[1] + "'", result.error().message());
|
||||
EXPECT_EQ("unexpected end of string in '" + args[1] + "', looking for }",
|
||||
result.error().message());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,13 +41,18 @@
|
|||
#include <selinux/android.h>
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include <android/api-level.h>
|
||||
#include <sys/system_properties.h>
|
||||
|
||||
#include "reboot_utils.h"
|
||||
#include "selabel.h"
|
||||
#include "selinux.h"
|
||||
#else
|
||||
#include "host_init_stubs.h"
|
||||
#endif
|
||||
|
||||
using android::base::boot_clock;
|
||||
using android::base::StartsWith;
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
namespace android {
|
||||
|
|
@ -267,12 +272,10 @@ bool is_dir(const char* pathname) {
|
|||
return S_ISDIR(info.st_mode);
|
||||
}
|
||||
|
||||
bool expand_props(const std::string& src, std::string* dst) {
|
||||
Result<std::string> ExpandProps(const std::string& src) {
|
||||
const char* src_ptr = src.c_str();
|
||||
|
||||
if (!dst) {
|
||||
return false;
|
||||
}
|
||||
std::string dst;
|
||||
|
||||
/* - variables can either be $x.y or ${x.y}, in case they are only part
|
||||
* of the string.
|
||||
|
|
@ -286,19 +289,19 @@ bool expand_props(const std::string& src, std::string* dst) {
|
|||
|
||||
c = strchr(src_ptr, '$');
|
||||
if (!c) {
|
||||
dst->append(src_ptr);
|
||||
return true;
|
||||
dst.append(src_ptr);
|
||||
return dst;
|
||||
}
|
||||
|
||||
dst->append(src_ptr, c);
|
||||
dst.append(src_ptr, c);
|
||||
c++;
|
||||
|
||||
if (*c == '$') {
|
||||
dst->push_back(*(c++));
|
||||
dst.push_back(*(c++));
|
||||
src_ptr = c;
|
||||
continue;
|
||||
} else if (*c == '\0') {
|
||||
return true;
|
||||
return dst;
|
||||
}
|
||||
|
||||
std::string prop_name;
|
||||
|
|
@ -308,8 +311,7 @@ bool expand_props(const std::string& src, std::string* dst) {
|
|||
const char* end = strchr(c, '}');
|
||||
if (!end) {
|
||||
// failed to find closing brace, abort.
|
||||
LOG(ERROR) << "unexpected end of string in '" << src << "', looking for }";
|
||||
return false;
|
||||
return Error() << "unexpected end of string in '" << src << "', looking for }";
|
||||
}
|
||||
prop_name = std::string(c, end);
|
||||
c = end + 1;
|
||||
|
|
@ -320,29 +322,34 @@ bool expand_props(const std::string& src, std::string* dst) {
|
|||
}
|
||||
} else {
|
||||
prop_name = c;
|
||||
LOG(ERROR) << "using deprecated syntax for specifying property '" << c << "', use ${name} instead";
|
||||
if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__) {
|
||||
return Error() << "using deprecated syntax for specifying property '" << c
|
||||
<< "', use ${name} instead";
|
||||
} else {
|
||||
LOG(ERROR) << "using deprecated syntax for specifying property '" << c
|
||||
<< "', use ${name} instead";
|
||||
}
|
||||
c += prop_name.size();
|
||||
}
|
||||
|
||||
if (prop_name.empty()) {
|
||||
LOG(ERROR) << "invalid zero-length property name in '" << src << "'";
|
||||
return false;
|
||||
return Error() << "invalid zero-length property name in '" << src << "'";
|
||||
}
|
||||
|
||||
std::string prop_val = android::base::GetProperty(prop_name, "");
|
||||
if (prop_val.empty()) {
|
||||
if (def_val.empty()) {
|
||||
LOG(ERROR) << "property '" << prop_name << "' doesn't exist while expanding '" << src << "'";
|
||||
return false;
|
||||
return Error() << "property '" << prop_name << "' doesn't exist while expanding '"
|
||||
<< src << "'";
|
||||
}
|
||||
prop_val = def_val;
|
||||
}
|
||||
|
||||
dst->append(prop_val);
|
||||
dst.append(prop_val);
|
||||
src_ptr = c;
|
||||
}
|
||||
|
||||
return true;
|
||||
return dst;
|
||||
}
|
||||
|
||||
static std::string init_android_dt_dir() {
|
||||
|
|
@ -414,6 +421,58 @@ bool IsLegalPropertyName(const std::string& name) {
|
|||
return true;
|
||||
}
|
||||
|
||||
Result<void> IsLegalPropertyValue(const std::string& name, const std::string& value) {
|
||||
if (value.size() >= PROP_VALUE_MAX && !StartsWith(name, "ro.")) {
|
||||
return Error() << "Property value too long";
|
||||
}
|
||||
|
||||
if (mbstowcs(nullptr, value.data(), 0) == static_cast<std::size_t>(-1)) {
|
||||
return Error() << "Value is not a UTF8 encoded string";
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<std::pair<int, std::vector<std::string>>> ParseRestorecon(
|
||||
const std::vector<std::string>& args) {
|
||||
struct flag_type {
|
||||
const char* name;
|
||||
int value;
|
||||
};
|
||||
static const flag_type flags[] = {
|
||||
{"--recursive", SELINUX_ANDROID_RESTORECON_RECURSE},
|
||||
{"--skip-ce", SELINUX_ANDROID_RESTORECON_SKIPCE},
|
||||
{"--cross-filesystems", SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS},
|
||||
{0, 0}};
|
||||
|
||||
int flag = 0;
|
||||
std::vector<std::string> paths;
|
||||
|
||||
bool in_flags = true;
|
||||
for (size_t i = 1; i < args.size(); ++i) {
|
||||
if (android::base::StartsWith(args[i], "--")) {
|
||||
if (!in_flags) {
|
||||
return Error() << "flags must precede paths";
|
||||
}
|
||||
bool found = false;
|
||||
for (size_t j = 0; flags[j].name; ++j) {
|
||||
if (args[i] == flags[j].name) {
|
||||
flag |= flags[j].value;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return Error() << "bad flag " << args[i];
|
||||
}
|
||||
} else {
|
||||
in_flags = false;
|
||||
paths.emplace_back(args[i]);
|
||||
}
|
||||
}
|
||||
return std::pair(flag, paths);
|
||||
}
|
||||
|
||||
static void InitAborter(const char* abort_message) {
|
||||
// When init forks, it continues to use this aborter for LOG(FATAL), but we want children to
|
||||
// simply abort instead of trying to reboot the system.
|
||||
|
|
|
|||
14
init/util.h
14
init/util.h
|
|
@ -14,24 +14,20 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _INIT_UTIL_H_
|
||||
#define _INIT_UTIL_H_
|
||||
#pragma once
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#include <android-base/chrono_utils.h>
|
||||
#include <selinux/label.h>
|
||||
|
||||
#include "result.h"
|
||||
|
||||
using android::base::boot_clock;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
|
@ -52,7 +48,7 @@ void import_kernel_cmdline(bool in_qemu,
|
|||
const std::function<void(const std::string&, const std::string&, bool)>&);
|
||||
bool make_dir(const std::string& path, mode_t mode);
|
||||
bool is_dir(const char* pathname);
|
||||
bool expand_props(const std::string& src, std::string* dst);
|
||||
Result<std::string> ExpandProps(const std::string& src);
|
||||
|
||||
// Returns the platform's Android DT directory as specified in the kernel cmdline.
|
||||
// If the platform does not configure a custom DT path, returns the standard one (based in procfs).
|
||||
|
|
@ -62,11 +58,13 @@ bool read_android_dt_file(const std::string& sub_path, std::string* dt_content);
|
|||
bool is_android_dt_value_expected(const std::string& sub_path, const std::string& expected_content);
|
||||
|
||||
bool IsLegalPropertyName(const std::string& name);
|
||||
Result<void> IsLegalPropertyValue(const std::string& name, const std::string& value);
|
||||
|
||||
Result<std::pair<int, std::vector<std::string>>> ParseRestorecon(
|
||||
const std::vector<std::string>& args);
|
||||
|
||||
void SetStdioToDevNull(char** argv);
|
||||
void InitKernelLogging(char** argv);
|
||||
bool IsRecoveryMode();
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue