2008-10-21 16:00:00 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2008 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.
|
|
|
|
*/
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
#include "builtins.h"
|
|
|
|
|
2016-04-05 22:43:40 +02:00
|
|
|
#include <dirent.h>
|
2015-03-20 17:45:18 +01:00
|
|
|
#include <errno.h>
|
2008-10-21 16:00:00 +02:00
|
|
|
#include <fcntl.h>
|
2017-08-04 22:22:36 +02:00
|
|
|
#include <fts.h>
|
2017-04-07 01:30:22 +02:00
|
|
|
#include <linux/loop.h>
|
|
|
|
#include <linux/module.h>
|
2015-07-08 23:57:07 +02:00
|
|
|
#include <mntent.h>
|
2015-03-20 17:45:18 +01:00
|
|
|
#include <net/if.h>
|
2016-04-05 17:10:25 +02:00
|
|
|
#include <sched.h>
|
2017-04-07 01:30:22 +02:00
|
|
|
#include <signal.h>
|
2008-10-21 16:00:00 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2015-03-20 17:45:18 +01:00
|
|
|
#include <string.h>
|
2008-10-21 16:00:00 +02:00
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <sys/resource.h>
|
2017-04-07 01:30:22 +02:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/stat.h>
|
2016-03-28 01:55:59 +02:00
|
|
|
#include <sys/syscall.h>
|
2017-04-07 22:46:21 +02:00
|
|
|
#include <sys/system_properties.h>
|
2015-01-30 06:31:23 +01:00
|
|
|
#include <sys/time.h>
|
2015-03-20 17:45:18 +01:00
|
|
|
#include <sys/types.h>
|
2012-04-18 02:20:16 +02:00
|
|
|
#include <sys/wait.h>
|
2015-03-20 17:45:18 +01:00
|
|
|
#include <unistd.h>
|
2012-01-13 14:48:47 +01:00
|
|
|
|
2017-07-06 23:20:11 +02:00
|
|
|
#include <android-base/chrono_utils.h>
|
2016-04-05 22:43:40 +02:00
|
|
|
#include <android-base/file.h>
|
2017-04-07 01:30:22 +02:00
|
|
|
#include <android-base/logging.h>
|
2015-12-18 20:39:59 +01:00
|
|
|
#include <android-base/parseint.h>
|
2017-03-29 01:40:41 +02:00
|
|
|
#include <android-base/properties.h>
|
2017-08-01 23:10:11 +02:00
|
|
|
#include <android-base/stringprintf.h>
|
2017-03-29 01:40:41 +02:00
|
|
|
#include <android-base/strings.h>
|
2017-08-01 23:10:11 +02:00
|
|
|
#include <android-base/unique_fd.h>
|
2016-06-25 03:28:03 +02:00
|
|
|
#include <bootloader_message/bootloader_message.h>
|
2015-03-20 17:45:18 +01:00
|
|
|
#include <cutils/android_reboot.h>
|
2016-10-06 02:53:30 +02:00
|
|
|
#include <ext4_utils/ext4_crypt.h>
|
|
|
|
#include <ext4_utils/ext4_crypt_init_extensions.h>
|
2017-03-29 01:40:41 +02:00
|
|
|
#include <fs_mgr.h>
|
2017-04-07 01:30:22 +02:00
|
|
|
#include <selinux/android.h>
|
|
|
|
#include <selinux/label.h>
|
|
|
|
#include <selinux/selinux.h>
|
2017-08-16 20:34:50 +02:00
|
|
|
#include <system/thread_defs.h>
|
2015-03-20 17:45:18 +01:00
|
|
|
|
2015-07-24 02:53:11 +02:00
|
|
|
#include "action.h"
|
2015-08-26 20:43:36 +02:00
|
|
|
#include "bootchart.h"
|
2008-10-21 16:00:00 +02:00
|
|
|
#include "init.h"
|
2017-07-27 21:54:48 +02:00
|
|
|
#include "parser.h"
|
2008-10-21 16:00:00 +02:00
|
|
|
#include "property_service.h"
|
2017-03-13 19:54:47 +01:00
|
|
|
#include "reboot.h"
|
2017-08-25 19:39:25 +02:00
|
|
|
#include "rlimit_parser.h"
|
2015-07-31 21:45:25 +02:00
|
|
|
#include "service.h"
|
2010-04-14 05:35:46 +02:00
|
|
|
#include "util.h"
|
2008-10-21 16:00:00 +02:00
|
|
|
|
2016-12-19 22:03:47 +01:00
|
|
|
using namespace std::literals::string_literals;
|
|
|
|
|
2017-08-01 23:10:11 +02:00
|
|
|
using android::base::unique_fd;
|
|
|
|
|
builtins.c: Don't require file open() for chmod/chown
42a9349dc4e98019d27d7f8d19bc6c431695d7e1 modified init's
builtin chmod, chown, and mkdir calls to avoid following
symlinks. This addressed a number of attacks we were seeing
at the time where poorly written init scripts were following
attacker supplied symlinks resulting in rooting vulnerabilities.
To avoid race conditions, the previous implementation only ran
fchown / fchmod on file descriptors opened with open(O_NOFOLLOW).
Unfortunately, unlike the normal "chown" or "chmod" calls, this
requires read or write access to the underlying file. This
isn't ideal, as opening some files may have side effects, or
init may not have permission to open certain files (such as when
SELinux is enabled).
Instead of using open(O_NOFOLLOW) + fchown(), use lchown() instead.
As before, the target of the symlink won't be modified by chown.
This also supports setting the ownership of symlinks.
Instead of using open(O_NOFOLLOW) + fchmod(), use
fchmodat(AT_SYMLINK_NOFOLLOW) instead. As before, the target of the
symlink won't be modified by chmod.
This change will continue to ensure that chown/chmod/mkdir doesn't
follow symlinks, without requiring init to open every file in
read-only or read-write mode.
This change depends on bionic commit I1eba0cdb2c509d9193ceecf28f13118188a3cfa7
Addresses the following mako/occam SELinux denial:
audit(1422770408.951:6): avc: denied { write } for pid=1 comm="init" name="smd7" dev="tmpfs" ino=7207 scontext=u:r:init:s0 tcontext=u:object_r:radio_device:s0 tclass=chr_file
Change-Id: I14fde956784d65c44e7aa91dd7eea9a004df3081
2015-02-01 06:39:46 +01:00
|
|
|
#define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
|
|
|
|
|
2017-06-22 21:53:17 +02:00
|
|
|
namespace android {
|
|
|
|
namespace init {
|
|
|
|
|
2016-11-11 02:43:47 +01:00
|
|
|
static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s;
|
2015-12-18 20:39:59 +01:00
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> reboot_into_recovery(const std::vector<std::string>& options) {
|
2016-05-10 17:52:06 +02:00
|
|
|
std::string err;
|
|
|
|
if (!write_bootloader_message(options, &err)) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "Failed to set bootloader message: " << err;
|
2016-05-10 17:52:06 +02:00
|
|
|
}
|
2017-06-28 07:08:45 +02:00
|
|
|
property_set("sys.powerctl", "reboot,recovery");
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2015-07-08 23:57:07 +02:00
|
|
|
}
|
|
|
|
|
2017-07-28 01:20:58 +02:00
|
|
|
template <typename F>
|
|
|
|
static void ForEachServiceInClass(const std::string& classname, F function) {
|
|
|
|
for (const auto& service : ServiceList::GetInstance()) {
|
|
|
|
if (service->classnames().count(classname)) std::invoke(function, service);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_class_start(const std::vector<std::string>& args) {
|
2017-07-28 01:20:58 +02:00
|
|
|
// Starting a class does not start services which are explicitly disabled.
|
|
|
|
// They must be started individually.
|
|
|
|
ForEachServiceInClass(args[1], &Service::StartIfNotDisabled);
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_class_stop(const std::vector<std::string>& args) {
|
2017-07-28 01:20:58 +02:00
|
|
|
ForEachServiceInClass(args[1], &Service::Stop);
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_class_reset(const std::vector<std::string>& args) {
|
2017-07-28 01:20:58 +02:00
|
|
|
ForEachServiceInClass(args[1], &Service::Reset);
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2010-12-04 01:33:31 +01:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_class_restart(const std::vector<std::string>& args) {
|
2017-07-28 01:20:58 +02:00
|
|
|
ForEachServiceInClass(args[1], &Service::Restart);
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2017-03-10 23:04:37 +01:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_domainname(const std::vector<std::string>& args) {
|
2017-08-03 21:54:07 +02:00
|
|
|
if (auto result = WriteFile("/proc/sys/kernel/domainname", args[1]); !result) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "Unable to write to /proc/sys/kernel/domainname: " << result.error();
|
2017-05-05 03:17:33 +02:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_enable(const std::vector<std::string>& args) {
|
2017-07-28 01:20:58 +02:00
|
|
|
Service* svc = ServiceList::GetInstance().FindService(args[1]);
|
2017-08-01 22:50:23 +02:00
|
|
|
if (!svc) return Error() << "Could not find service";
|
|
|
|
|
2017-08-23 01:13:59 +02:00
|
|
|
if (auto result = svc->Enable(); !result) {
|
|
|
|
return Error() << "Could not enable service: " << result.error();
|
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
|
|
|
|
return Success();
|
2014-05-03 06:14:29 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_exec(const std::vector<std::string>& args) {
|
2017-07-28 23:48:41 +02:00
|
|
|
auto service = Service::MakeTemporaryOneshotService(args);
|
|
|
|
if (!service) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "Could not create exec service";
|
2017-07-28 23:48:41 +02:00
|
|
|
}
|
2017-08-23 01:13:59 +02:00
|
|
|
if (auto result = service->ExecStart(); !result) {
|
|
|
|
return Error() << "Could not start exec service: " << result.error();
|
2017-07-28 23:48:41 +02:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
|
2017-07-28 01:20:58 +02:00
|
|
|
ServiceList::GetInstance().AddService(std::move(service));
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2017-03-28 01:27:30 +02:00
|
|
|
}
|
|
|
|
|
2017-09-18 21:16:27 +02:00
|
|
|
static Result<Success> do_exec_background(const std::vector<std::string>& args) {
|
|
|
|
auto service = Service::MakeTemporaryOneshotService(args);
|
|
|
|
if (!service) {
|
|
|
|
return Error() << "Could not create exec background service";
|
|
|
|
}
|
|
|
|
if (auto result = service->Start(); !result) {
|
|
|
|
return Error() << "Could not start exec background service: " << result.error();
|
|
|
|
}
|
|
|
|
|
|
|
|
ServiceList::GetInstance().AddService(std::move(service));
|
|
|
|
return Success();
|
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_exec_start(const std::vector<std::string>& args) {
|
2017-07-28 01:20:58 +02:00
|
|
|
Service* service = ServiceList::GetInstance().FindService(args[1]);
|
2017-07-28 23:48:41 +02:00
|
|
|
if (!service) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "Service not found";
|
2017-07-28 23:48:41 +02:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
|
2017-08-23 01:13:59 +02:00
|
|
|
if (auto result = service->ExecStart(); !result) {
|
|
|
|
return Error() << "Could not start exec service: " << result.error();
|
2017-07-28 23:48:41 +02:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
|
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_export(const std::vector<std::string>& args) {
|
2017-08-23 00:41:03 +02:00
|
|
|
if (setenv(args[1].c_str(), args[2].c_str(), 1) == -1) {
|
|
|
|
return ErrnoError() << "setenv() failed";
|
2017-08-01 22:50:23 +02:00
|
|
|
}
|
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_hostname(const std::vector<std::string>& args) {
|
2017-08-03 21:54:07 +02:00
|
|
|
if (auto result = WriteFile("/proc/sys/kernel/hostname", args[1]); !result) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "Unable to write to /proc/sys/kernel/hostname: " << result.error();
|
2017-05-05 03:17:33 +02:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_ifup(const std::vector<std::string>& args) {
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
strlcpy(ifr.ifr_name, args[1].c_str(), IFNAMSIZ);
|
|
|
|
|
|
|
|
unique_fd s(TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_DGRAM, 0)));
|
|
|
|
if (s < 0) return ErrnoError() << "opening socket failed";
|
|
|
|
|
|
|
|
if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
|
|
|
|
return ErrnoError() << "ioctl(..., SIOCGIFFLAGS, ...) failed";
|
|
|
|
}
|
|
|
|
|
|
|
|
ifr.ifr_flags |= IFF_UP;
|
|
|
|
|
|
|
|
if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
|
|
|
|
return ErrnoError() << "ioctl(..., SIOCSIFFLAGS, ...) failed";
|
|
|
|
}
|
|
|
|
|
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_insmod(const std::vector<std::string>& args) {
|
2016-05-17 12:49:10 +02:00
|
|
|
int flags = 0;
|
|
|
|
auto it = args.begin() + 1;
|
2008-12-18 03:08:08 +01:00
|
|
|
|
2016-05-17 12:49:10 +02:00
|
|
|
if (!(*it).compare("-f")) {
|
|
|
|
flags = MODULE_INIT_IGNORE_VERMAGIC | MODULE_INIT_IGNORE_MODVERSIONS;
|
|
|
|
it++;
|
2008-12-18 03:08:08 +01:00
|
|
|
}
|
|
|
|
|
2016-05-17 12:49:10 +02:00
|
|
|
std::string filename = *it++;
|
|
|
|
std::string options = android::base::Join(std::vector<std::string>(it, args.end()), ' ');
|
2017-08-01 22:50:23 +02:00
|
|
|
|
|
|
|
unique_fd fd(TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
|
|
|
|
if (fd == -1) return ErrnoError() << "open(\"" << filename << "\") failed";
|
|
|
|
|
|
|
|
int rc = syscall(__NR_finit_module, fd.get(), options.c_str(), flags);
|
|
|
|
if (rc == -1) return ErrnoError() << "finit_module for \"" << filename << "\" failed";
|
|
|
|
|
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-10 21:22:44 +02:00
|
|
|
// mkdir <path> [mode] [owner] [group]
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_mkdir(const std::vector<std::string>& args) {
|
2008-10-21 16:00:00 +02:00
|
|
|
mode_t mode = 0755;
|
2015-07-30 22:52:55 +02:00
|
|
|
if (args.size() >= 3) {
|
2016-10-12 02:09:00 +02:00
|
|
|
mode = std::strtoul(args[2].c_str(), 0, 8);
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-10 21:22:44 +02:00
|
|
|
if (!make_dir(args[1], mode)) {
|
|
|
|
/* chmod in case the directory already exists */
|
|
|
|
if (errno == EEXIST) {
|
|
|
|
if (fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return ErrnoError() << "fchmodat() failed";
|
2017-08-10 21:22:44 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-08-01 22:50:23 +02:00
|
|
|
return ErrnoError() << "mkdir() failed";
|
2017-08-10 21:22:44 +02:00
|
|
|
}
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2015-07-30 22:52:55 +02:00
|
|
|
if (args.size() >= 4) {
|
2017-08-03 21:54:07 +02:00
|
|
|
auto uid = DecodeUid(args[3]);
|
|
|
|
if (!uid) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "Unable to decode UID for '" << args[3] << "': " << uid.error();
|
2017-05-05 02:40:33 +02:00
|
|
|
}
|
2017-08-03 21:54:07 +02:00
|
|
|
Result<gid_t> gid = -1;
|
2008-10-21 16:00:00 +02:00
|
|
|
|
2015-07-30 22:52:55 +02:00
|
|
|
if (args.size() == 5) {
|
2017-08-03 21:54:07 +02:00
|
|
|
gid = DecodeUid(args[4]);
|
|
|
|
if (!gid) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "Unable to decode GID for '" << args[3] << "': " << gid.error();
|
2017-05-05 02:40:33 +02:00
|
|
|
}
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-03 21:54:07 +02:00
|
|
|
if (lchown(args[1].c_str(), *uid, *gid) == -1) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return ErrnoError() << "lchown failed";
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
2012-08-15 00:43:46 +02:00
|
|
|
|
|
|
|
/* chown may have cleared S_ISUID and S_ISGID, chmod again */
|
|
|
|
if (mode & (S_ISUID | S_ISGID)) {
|
2017-08-10 21:22:44 +02:00
|
|
|
if (fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return ErrnoError() << "fchmodat failed";
|
2012-08-15 00:43:46 +02:00
|
|
|
}
|
|
|
|
}
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2016-05-10 17:52:06 +02:00
|
|
|
if (e4crypt_is_native()) {
|
|
|
|
if (e4crypt_set_directory_policy(args[1].c_str())) {
|
2016-12-19 22:03:47 +01:00
|
|
|
const std::vector<std::string> options = {
|
|
|
|
"--prompt_and_wipe_data",
|
|
|
|
"--reason=set_policy_failed:"s + args[1]};
|
|
|
|
reboot_into_recovery(options);
|
init: fix crash when reboot is triggered by a builtin
Builtin commands may set the sys.powerctl property, which causes
reboot to be immediately processed. Unfortunately, part of the reboot
processing involves clearing the action queue, so when this scenario
happens, ActionManager::ExecuteOneCommand() can abort due to its state
being unexpectedly changed.
Longer term, the real fix here is to split init and property service.
In this case, the property sets will be sent to property service and
the reboot will only be processed once property service responds back
to init that the property has been set. Since that will not happen
within the action queue, there will be no risk of failure.
Short term, this change sets a flag in init to shutdown the device
before the next action is run, which defers the shutdown enough to fix
the crash, but continues to prevent any further commands from running.
Bug: 65374456
Test: force bullhead into the repro case and observe that it no longer
repros
Change-Id: I89c73dad8d7912a845d694b095cab061b8dcc05e
2017-09-13 23:39:45 +02:00
|
|
|
return Success();
|
2016-05-10 17:52:06 +02:00
|
|
|
}
|
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2016-06-23 20:11:39 +02:00
|
|
|
/* umount <path> */
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_umount(const std::vector<std::string>& args) {
|
|
|
|
if (umount(args[1].c_str()) < 0) {
|
|
|
|
return ErrnoError() << "umount() failed";
|
|
|
|
}
|
|
|
|
return Success();
|
2016-06-23 20:11:39 +02:00
|
|
|
}
|
|
|
|
|
2008-10-21 16:00:00 +02:00
|
|
|
static struct {
|
|
|
|
const char *name;
|
|
|
|
unsigned flag;
|
|
|
|
} mount_flags[] = {
|
|
|
|
{ "noatime", MS_NOATIME },
|
2011-07-14 13:39:09 +02:00
|
|
|
{ "noexec", MS_NOEXEC },
|
2008-10-21 16:00:00 +02:00
|
|
|
{ "nosuid", MS_NOSUID },
|
|
|
|
{ "nodev", MS_NODEV },
|
|
|
|
{ "nodiratime", MS_NODIRATIME },
|
|
|
|
{ "ro", MS_RDONLY },
|
|
|
|
{ "rw", 0 },
|
|
|
|
{ "remount", MS_REMOUNT },
|
2012-08-14 20:34:34 +02:00
|
|
|
{ "bind", MS_BIND },
|
|
|
|
{ "rec", MS_REC },
|
|
|
|
{ "unbindable", MS_UNBINDABLE },
|
|
|
|
{ "private", MS_PRIVATE },
|
|
|
|
{ "slave", MS_SLAVE },
|
|
|
|
{ "shared", MS_SHARED },
|
2008-10-21 16:00:00 +02:00
|
|
|
{ "defaults", 0 },
|
|
|
|
{ 0, 0 },
|
|
|
|
};
|
|
|
|
|
2010-12-04 01:33:31 +01:00
|
|
|
#define DATA_MNT_POINT "/data"
|
|
|
|
|
2008-10-21 16:00:00 +02:00
|
|
|
/* mount <type> <device> <path> <flags ...> <options> */
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_mount(const std::vector<std::string>& args) {
|
2017-08-01 23:10:11 +02:00
|
|
|
const char* options = nullptr;
|
2008-10-21 16:00:00 +02:00
|
|
|
unsigned flags = 0;
|
2017-08-01 23:10:11 +02:00
|
|
|
bool wait = false;
|
2008-10-21 16:00:00 +02:00
|
|
|
|
2017-08-01 23:10:11 +02:00
|
|
|
for (size_t na = 4; na < args.size(); na++) {
|
|
|
|
size_t i;
|
2008-10-21 16:00:00 +02:00
|
|
|
for (i = 0; mount_flags[i].name; i++) {
|
2015-07-30 22:52:55 +02:00
|
|
|
if (!args[na].compare(mount_flags[i].name)) {
|
2008-10-21 16:00:00 +02:00
|
|
|
flags |= mount_flags[i].flag;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-20 02:10:24 +02:00
|
|
|
if (!mount_flags[i].name) {
|
2017-08-01 23:10:11 +02:00
|
|
|
if (!args[na].compare("wait")) {
|
|
|
|
wait = true;
|
|
|
|
// If our last argument isn't a flag, wolf it up as an option string.
|
|
|
|
} else if (na + 1 == args.size()) {
|
2015-07-30 22:52:55 +02:00
|
|
|
options = args[na].c_str();
|
2017-08-01 23:10:11 +02:00
|
|
|
}
|
2010-04-20 02:10:24 +02:00
|
|
|
}
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 23:10:11 +02:00
|
|
|
const char* system = args[1].c_str();
|
|
|
|
const char* source = args[2].c_str();
|
|
|
|
const char* target = args[3].c_str();
|
2008-11-20 04:37:30 +01:00
|
|
|
|
2017-08-01 23:10:11 +02:00
|
|
|
if (android::base::StartsWith(source, "loop@")) {
|
|
|
|
int mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
|
|
|
|
unique_fd fd(TEMP_FAILURE_RETRY(open(source + 5, mode | O_CLOEXEC)));
|
2017-08-01 22:50:23 +02:00
|
|
|
if (fd < 0) return ErrnoError() << "open(" << source + 5 << ", " << mode << ") failed";
|
2008-11-20 04:37:30 +01:00
|
|
|
|
2017-08-01 23:10:11 +02:00
|
|
|
for (size_t n = 0;; n++) {
|
|
|
|
std::string tmp = android::base::StringPrintf("/dev/block/loop%zu", n);
|
|
|
|
unique_fd loop(TEMP_FAILURE_RETRY(open(tmp.c_str(), mode | O_CLOEXEC)));
|
2017-08-01 22:50:23 +02:00
|
|
|
if (loop < 0) return ErrnoError() << "open(" << tmp << ", " << mode << ") failed";
|
2008-11-20 04:37:30 +01:00
|
|
|
|
2017-08-01 23:10:11 +02:00
|
|
|
loop_info info;
|
2008-11-20 04:37:30 +01:00
|
|
|
/* if it is a blank loop device */
|
|
|
|
if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
|
|
|
|
/* if it becomes our loop device */
|
2017-08-01 23:10:11 +02:00
|
|
|
if (ioctl(loop, LOOP_SET_FD, fd.get()) >= 0) {
|
|
|
|
if (mount(tmp.c_str(), target, system, flags, options) < 0) {
|
2008-11-20 04:37:30 +01:00
|
|
|
ioctl(loop, LOOP_CLR_FD, 0);
|
2017-08-01 22:50:23 +02:00
|
|
|
return ErrnoError() << "mount() failed";
|
2008-11-20 04:37:30 +01:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2008-11-20 04:37:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "out of loopback devices";
|
2008-11-20 04:37:30 +01:00
|
|
|
} else {
|
2010-04-20 02:10:24 +02:00
|
|
|
if (wait)
|
2016-11-11 02:43:47 +01:00
|
|
|
wait_for_file(source, kCommandRetryTimeout);
|
2008-11-20 04:37:30 +01:00
|
|
|
if (mount(source, target, system, flags, options) < 0) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return ErrnoError() << "mount() failed";
|
2008-11-20 04:37:30 +01:00
|
|
|
}
|
|
|
|
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
2011-02-18 03:09:47 +01:00
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2012-04-18 02:20:16 +02:00
|
|
|
}
|
2011-03-09 02:01:29 +01:00
|
|
|
|
2016-01-14 04:18:21 +01:00
|
|
|
/* Imports .rc files from the specified paths. Default ones are applied if none is given.
|
|
|
|
*
|
|
|
|
* start_index: index of the first path in the args list
|
|
|
|
*/
|
2016-08-23 20:58:09 +02:00
|
|
|
static void import_late(const std::vector<std::string>& args, size_t start_index, size_t end_index) {
|
2017-07-27 21:54:48 +02:00
|
|
|
auto& action_manager = ActionManager::GetInstance();
|
2017-07-28 01:20:58 +02:00
|
|
|
auto& service_list = ServiceList::GetInstance();
|
|
|
|
Parser parser = CreateParser(action_manager, service_list);
|
2016-08-23 20:58:09 +02:00
|
|
|
if (end_index <= start_index) {
|
2017-02-22 12:37:57 +01:00
|
|
|
// Fallbacks for partitions on which early mount isn't enabled.
|
2017-07-27 21:54:48 +02:00
|
|
|
for (const auto& path : late_import_paths) {
|
|
|
|
parser.ParseConfig(path);
|
2016-01-14 04:18:21 +01:00
|
|
|
}
|
2017-07-27 21:54:48 +02:00
|
|
|
late_import_paths.clear();
|
2016-01-14 04:18:21 +01:00
|
|
|
} else {
|
2016-08-23 20:58:09 +02:00
|
|
|
for (size_t i = start_index; i < end_index; ++i) {
|
2016-01-14 04:18:21 +01:00
|
|
|
parser.ParseConfig(args[i]);
|
|
|
|
}
|
2015-07-22 23:23:33 +02:00
|
|
|
}
|
2017-03-13 20:24:49 +01:00
|
|
|
|
|
|
|
// Turning this on and letting the INFO logging be discarded adds 0.2s to
|
|
|
|
// Nexus 9 boot time, so it's disabled by default.
|
2017-04-20 00:31:58 +02:00
|
|
|
if (false) DumpState();
|
2015-07-22 23:23:33 +02:00
|
|
|
}
|
|
|
|
|
2016-08-23 20:58:09 +02:00
|
|
|
/* mount_fstab
|
2016-01-14 04:18:21 +01:00
|
|
|
*
|
2016-08-23 20:58:09 +02:00
|
|
|
* Call fs_mgr_mount_all() to mount the given fstab
|
2014-07-02 23:26:54 +02:00
|
|
|
*/
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<int> mount_fstab(const char* fstabfile, int mount_mode) {
|
2012-04-18 02:20:16 +02:00
|
|
|
/*
|
|
|
|
* Call fs_mgr_mount_all() to mount all filesystems. We fork(2) and
|
|
|
|
* do the call in the child to provide protection to the main init
|
|
|
|
* process if anything goes wrong (crash or memory leak), and wait for
|
|
|
|
* the child to finish in the parent.
|
|
|
|
*/
|
2016-08-05 01:09:39 +02:00
|
|
|
pid_t pid = fork();
|
2012-04-18 02:20:16 +02:00
|
|
|
if (pid > 0) {
|
|
|
|
/* Parent. Wait for the child to return */
|
2016-08-05 01:09:39 +02:00
|
|
|
int status;
|
2014-09-16 23:31:23 +02:00
|
|
|
int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
|
2016-06-25 00:12:21 +02:00
|
|
|
if (wp_ret == -1) {
|
|
|
|
// Unexpected error code. We will continue anyway.
|
|
|
|
PLOG(WARNING) << "waitpid failed";
|
2014-09-16 23:31:23 +02:00
|
|
|
}
|
|
|
|
|
2012-04-18 02:20:16 +02:00
|
|
|
if (WIFEXITED(status)) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return WEXITSTATUS(status);
|
2012-04-18 02:20:16 +02:00
|
|
|
} else {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "child aborted";
|
2011-02-18 03:09:47 +01:00
|
|
|
}
|
2012-04-18 02:20:16 +02:00
|
|
|
} else if (pid == 0) {
|
|
|
|
/* child, call fs_mgr_mount_all() */
|
2016-08-05 01:09:39 +02:00
|
|
|
|
|
|
|
// So we can always see what fs_mgr_mount_all() does.
|
|
|
|
// Only needed if someone explicitly changes the default log level in their init.rc.
|
|
|
|
android::base::ScopedLogSeverity info(android::base::INFO);
|
|
|
|
|
|
|
|
struct fstab* fstab = fs_mgr_read_fstab(fstabfile);
|
2016-08-23 20:58:09 +02:00
|
|
|
int child_ret = fs_mgr_mount_all(fstab, mount_mode);
|
2013-02-13 21:58:40 +01:00
|
|
|
fs_mgr_free_fstab(fstab);
|
2012-04-18 02:20:16 +02:00
|
|
|
if (child_ret == -1) {
|
2016-06-25 00:12:21 +02:00
|
|
|
PLOG(ERROR) << "fs_mgr_mount_all returned an error";
|
2011-02-18 03:09:47 +01:00
|
|
|
}
|
2014-07-02 22:16:04 +02:00
|
|
|
_exit(child_ret);
|
2012-04-18 02:20:16 +02:00
|
|
|
} else {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "fork() failed";
|
2011-02-18 03:09:47 +01:00
|
|
|
}
|
2016-08-23 20:58:09 +02:00
|
|
|
}
|
2011-02-18 03:09:47 +01:00
|
|
|
|
2016-08-23 20:58:09 +02:00
|
|
|
/* Queue event based on fs_mgr return code.
|
|
|
|
*
|
|
|
|
* code: return code of fs_mgr_mount_all
|
|
|
|
*
|
|
|
|
* This function might request a reboot, in which case it will
|
|
|
|
* not return.
|
|
|
|
*
|
|
|
|
* return code is processed based on input code
|
|
|
|
*/
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> queue_fs_event(int code) {
|
2016-08-23 20:58:09 +02:00
|
|
|
if (code == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
|
2016-04-19 00:37:31 +02:00
|
|
|
ActionManager::GetInstance().QueueEventTrigger("encrypt");
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2016-08-23 20:58:09 +02:00
|
|
|
} else if (code == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
|
2012-04-18 02:20:16 +02:00
|
|
|
property_set("ro.crypto.state", "encrypted");
|
2015-04-29 00:07:10 +02:00
|
|
|
property_set("ro.crypto.type", "block");
|
2016-04-19 00:37:31 +02:00
|
|
|
ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2016-08-23 20:58:09 +02:00
|
|
|
} else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
|
2012-04-18 02:20:16 +02:00
|
|
|
property_set("ro.crypto.state", "unencrypted");
|
2016-03-05 00:52:33 +01:00
|
|
|
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2016-08-23 20:58:09 +02:00
|
|
|
} else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
|
2016-03-05 00:52:33 +01:00
|
|
|
property_set("ro.crypto.state", "unsupported");
|
2015-07-24 02:53:11 +02:00
|
|
|
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2016-08-23 20:58:09 +02:00
|
|
|
} else if (code == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
|
2014-07-02 23:26:54 +02:00
|
|
|
/* Setup a wipe via recovery, and reboot into recovery */
|
2016-06-25 00:12:21 +02:00
|
|
|
PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery.";
|
2016-12-19 22:03:47 +01:00
|
|
|
const std::vector<std::string> options = {"--wipe_data", "--reason=fs_mgr_mount_all" };
|
2017-08-01 22:50:23 +02:00
|
|
|
reboot_into_recovery(options);
|
init: fix crash when reboot is triggered by a builtin
Builtin commands may set the sys.powerctl property, which causes
reboot to be immediately processed. Unfortunately, part of the reboot
processing involves clearing the action queue, so when this scenario
happens, ActionManager::ExecuteOneCommand() can abort due to its state
being unexpectedly changed.
Longer term, the real fix here is to split init and property service.
In this case, the property sets will be sent to property service and
the reboot will only be processed once property service responds back
to init that the property has been set. Since that will not happen
within the action queue, there will be no risk of failure.
Short term, this change sets a flag in init to shutdown the device
before the next action is run, which defers the shutdown enough to fix
the crash, but continues to prevent any further commands from running.
Bug: 65374456
Test: force bullhead into the repro case and observe that it no longer
repros
Change-Id: I89c73dad8d7912a845d694b095cab061b8dcc05e
2017-09-13 23:39:45 +02:00
|
|
|
return Success();
|
2014-07-02 23:26:54 +02:00
|
|
|
/* If reboot worked, there is no return. */
|
2016-08-23 20:58:09 +02:00
|
|
|
} else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
|
2015-03-26 16:49:42 +01:00
|
|
|
if (e4crypt_install_keyring()) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "e4crypt_install_keyring() failed";
|
2015-03-26 16:49:42 +01:00
|
|
|
}
|
|
|
|
property_set("ro.crypto.state", "encrypted");
|
2015-04-29 00:07:10 +02:00
|
|
|
property_set("ro.crypto.type", "file");
|
2015-03-26 16:49:42 +01:00
|
|
|
|
|
|
|
// Although encrypted, we have device key, so we do not need to
|
|
|
|
// do anything different from the nonencrypted case.
|
2015-07-24 02:53:11 +02:00
|
|
|
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2016-08-23 20:58:09 +02:00
|
|
|
} else if (code > 0) {
|
2017-08-01 22:50:23 +02:00
|
|
|
Error() << "fs_mgr_mount_all() returned unexpected error " << code;
|
2012-04-18 02:20:16 +02:00
|
|
|
}
|
2014-07-02 22:16:04 +02:00
|
|
|
/* else ... < 0: error */
|
2011-02-18 03:09:47 +01:00
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "Invalid code: " << code;
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2016-08-23 20:58:09 +02:00
|
|
|
/* mount_all <fstab> [ <path> ]* [--<options>]*
|
|
|
|
*
|
|
|
|
* This function might request a reboot, in which case it will
|
|
|
|
* not return.
|
|
|
|
*/
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_mount_all(const std::vector<std::string>& args) {
|
2016-08-23 20:58:09 +02:00
|
|
|
std::size_t na = 0;
|
|
|
|
bool import_rc = true;
|
|
|
|
bool queue_event = true;
|
|
|
|
int mount_mode = MOUNT_MODE_DEFAULT;
|
|
|
|
const char* fstabfile = args[1].c_str();
|
|
|
|
std::size_t path_arg_end = args.size();
|
2017-03-04 03:57:09 +01:00
|
|
|
const char* prop_post_fix = "default";
|
2016-08-23 20:58:09 +02:00
|
|
|
|
|
|
|
for (na = args.size() - 1; na > 1; --na) {
|
|
|
|
if (args[na] == "--early") {
|
2016-11-16 21:08:30 +01:00
|
|
|
path_arg_end = na;
|
|
|
|
queue_event = false;
|
|
|
|
mount_mode = MOUNT_MODE_EARLY;
|
2017-03-04 03:57:09 +01:00
|
|
|
prop_post_fix = "early";
|
2016-08-23 20:58:09 +02:00
|
|
|
} else if (args[na] == "--late") {
|
|
|
|
path_arg_end = na;
|
|
|
|
import_rc = false;
|
|
|
|
mount_mode = MOUNT_MODE_LATE;
|
2017-03-04 03:57:09 +01:00
|
|
|
prop_post_fix = "late";
|
2016-08-23 20:58:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-23 01:50:31 +02:00
|
|
|
std::string prop_name = "ro.boottime.init.mount_all."s + prop_post_fix;
|
2017-07-06 23:20:11 +02:00
|
|
|
android::base::Timer t;
|
2017-08-01 22:50:23 +02:00
|
|
|
auto mount_fstab_return_code = mount_fstab(fstabfile, mount_mode);
|
|
|
|
if (!mount_fstab_return_code) {
|
|
|
|
return Error() << "mount_fstab() failed " << mount_fstab_return_code.error();
|
|
|
|
}
|
2017-07-06 23:20:11 +02:00
|
|
|
property_set(prop_name, std::to_string(t.duration().count()));
|
2016-08-23 20:58:09 +02:00
|
|
|
|
|
|
|
if (import_rc) {
|
|
|
|
/* Paths of .rc files are specified at the 2nd argument and beyond */
|
|
|
|
import_late(args, 2, path_arg_end);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (queue_event) {
|
|
|
|
/* queue_fs_event will queue event based on mount_fstab return code
|
|
|
|
* and return processed return code*/
|
2017-08-01 22:50:23 +02:00
|
|
|
auto queue_fs_result = queue_fs_event(*mount_fstab_return_code);
|
|
|
|
if (!queue_fs_result) {
|
|
|
|
return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
|
|
|
|
}
|
2016-08-23 20:58:09 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2016-08-23 20:58:09 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_swapon_all(const std::vector<std::string>& args) {
|
2013-07-10 03:42:09 +02:00
|
|
|
struct fstab *fstab;
|
|
|
|
int ret;
|
|
|
|
|
2015-07-30 22:52:55 +02:00
|
|
|
fstab = fs_mgr_read_fstab(args[1].c_str());
|
2013-07-10 03:42:09 +02:00
|
|
|
ret = fs_mgr_swapon_all(fstab);
|
|
|
|
fs_mgr_free_fstab(fstab);
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
if (ret != 0) return Error() << "fs_mgr_swapon_all() failed";
|
|
|
|
return Success();
|
2013-07-10 03:42:09 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_setprop(const std::vector<std::string>& args) {
|
2017-06-23 01:50:31 +02:00
|
|
|
property_set(args[1], args[2]);
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_setrlimit(const std::vector<std::string>& args) {
|
2017-08-25 19:39:25 +02:00
|
|
|
auto rlimit = ParseRlimit(args);
|
|
|
|
if (!rlimit) return rlimit.error();
|
2017-08-01 22:50:23 +02:00
|
|
|
|
2017-08-25 19:39:25 +02:00
|
|
|
if (setrlimit(rlimit->first, &rlimit->second) == -1) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return ErrnoError() << "setrlimit failed";
|
|
|
|
}
|
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_start(const std::vector<std::string>& args) {
|
2017-07-28 01:20:58 +02:00
|
|
|
Service* svc = ServiceList::GetInstance().FindService(args[1]);
|
2017-08-01 22:50:23 +02:00
|
|
|
if (!svc) return Error() << "service " << args[1] << " not found";
|
2017-08-23 01:13:59 +02:00
|
|
|
if (auto result = svc->Start(); !result) {
|
|
|
|
return Error() << "Could not start service: " << result.error();
|
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_stop(const std::vector<std::string>& args) {
|
2017-07-28 01:20:58 +02:00
|
|
|
Service* svc = ServiceList::GetInstance().FindService(args[1]);
|
2017-08-01 22:50:23 +02:00
|
|
|
if (!svc) return Error() << "service " << args[1] << " not found";
|
2015-07-31 21:45:25 +02:00
|
|
|
svc->Stop();
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_restart(const std::vector<std::string>& args) {
|
2017-07-28 01:20:58 +02:00
|
|
|
Service* svc = ServiceList::GetInstance().FindService(args[1]);
|
2017-08-01 22:50:23 +02:00
|
|
|
if (!svc) return Error() << "service " << args[1] << " not found";
|
2015-07-31 21:45:25 +02:00
|
|
|
svc->Restart();
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_trigger(const std::vector<std::string>& args) {
|
2015-07-24 02:53:11 +02:00
|
|
|
ActionManager::GetInstance().QueueEventTrigger(args[1]);
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_symlink(const std::vector<std::string>& args) {
|
|
|
|
if (symlink(args[1].c_str(), args[2].c_str()) < 0) {
|
2017-08-23 01:15:26 +02:00
|
|
|
// 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();
|
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
return ErrnoError() << "symlink() failed";
|
|
|
|
}
|
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_rm(const std::vector<std::string>& args) {
|
|
|
|
if (unlink(args[1].c_str()) < 0) {
|
|
|
|
return ErrnoError() << "unlink() failed";
|
|
|
|
}
|
|
|
|
return Success();
|
2011-01-19 02:37:41 +01:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_rmdir(const std::vector<std::string>& args) {
|
|
|
|
if (rmdir(args[1].c_str()) < 0) {
|
|
|
|
return ErrnoError() << "rmdir() failed";
|
|
|
|
}
|
|
|
|
return Success();
|
2011-01-19 02:37:41 +01:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_sysclktz(const std::vector<std::string>& args) {
|
2016-10-12 02:09:00 +02:00
|
|
|
struct timezone tz = {};
|
2017-08-01 22:50:23 +02:00
|
|
|
if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) {
|
|
|
|
return Error() << "Unable to parse mins_west_of_gmt";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (settimeofday(nullptr, &tz) == -1) {
|
|
|
|
return ErrnoError() << "settimeofday() failed";
|
2016-10-12 02:09:00 +02:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2008-12-18 03:08:08 +01:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_verity_load_state(const std::vector<std::string>& args) {
|
2015-03-20 17:45:18 +01:00
|
|
|
int mode = -1;
|
2017-03-01 17:03:56 +01:00
|
|
|
bool loaded = fs_mgr_load_verity_state(&mode);
|
|
|
|
if (loaded && mode != VERITY_MODE_DEFAULT) {
|
2015-07-24 02:53:11 +02:00
|
|
|
ActionManager::GetInstance().QueueEventTrigger("verity-logging");
|
2015-02-16 12:03:34 +01:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
if (!loaded) return Error() << "Could not load verity state";
|
|
|
|
|
|
|
|
return Success();
|
2015-02-16 12:03:34 +01:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static void verity_update_property(fstab_rec *fstab, const char *mount_point,
|
|
|
|
int mode, int status) {
|
2017-06-23 01:50:31 +02:00
|
|
|
property_set("partition."s + mount_point + ".verified", std::to_string(mode));
|
2015-03-19 11:00:34 +01:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_verity_update_state(const std::vector<std::string>& args) {
|
|
|
|
if (!fs_mgr_update_verity_state(verity_update_property)) {
|
|
|
|
return Error() << "fs_mgr_update_verity_state() failed";
|
|
|
|
}
|
|
|
|
return Success();
|
2015-03-19 11:00:34 +01:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_write(const std::vector<std::string>& args) {
|
2017-08-03 21:54:07 +02:00
|
|
|
if (auto result = WriteFile(args[1], args[2]); !result) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "Unable to write to file '" << args[1] << "': " << result.error();
|
2017-05-05 03:17:33 +02:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
|
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-16 20:34:50 +02:00
|
|
|
static Result<Success> readahead_file(const std::string& filename, bool fully) {
|
|
|
|
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY)));
|
|
|
|
if (fd == -1) {
|
|
|
|
return ErrnoError() << "Error opening file";
|
|
|
|
}
|
|
|
|
if (posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED)) {
|
|
|
|
return ErrnoError() << "Error posix_fadvise file";
|
|
|
|
}
|
|
|
|
if (readahead(fd, 0, std::numeric_limits<size_t>::max())) {
|
|
|
|
return ErrnoError() << "Error readahead file";
|
|
|
|
}
|
|
|
|
if (fully) {
|
|
|
|
char buf[BUFSIZ];
|
|
|
|
ssize_t n;
|
|
|
|
while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
|
|
|
|
}
|
|
|
|
if (n != 0) {
|
|
|
|
return ErrnoError() << "Error reading file";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Success();
|
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_readahead(const std::vector<std::string>& args) {
|
2017-08-04 22:22:36 +02:00
|
|
|
struct stat sb;
|
|
|
|
|
|
|
|
if (stat(args[1].c_str(), &sb)) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return ErrnoError() << "Error opening " << args[1];
|
2017-08-04 22:22:36 +02:00
|
|
|
}
|
|
|
|
|
2017-08-16 20:34:50 +02:00
|
|
|
bool readfully = false;
|
|
|
|
if (args.size() == 3 && args[2] == "--fully") {
|
|
|
|
readfully = true;
|
|
|
|
}
|
2017-08-04 22:22:36 +02:00
|
|
|
// We will do readahead in a forked process in order not to block init
|
|
|
|
// since it may block while it reads the
|
|
|
|
// filesystem metadata needed to locate the requested blocks. This
|
|
|
|
// occurs frequently with ext[234] on large files using indirect blocks
|
|
|
|
// instead of extents, giving the appearance that the call blocks until
|
|
|
|
// the requested data has been read.
|
|
|
|
pid_t pid = fork();
|
|
|
|
if (pid == 0) {
|
2017-08-16 20:34:50 +02:00
|
|
|
if (setpriority(PRIO_PROCESS, 0, static_cast<int>(ANDROID_PRIORITY_LOWEST)) != 0) {
|
|
|
|
PLOG(WARNING) << "setpriority failed";
|
|
|
|
}
|
|
|
|
if (android_set_ioprio(0, IoSchedClass_IDLE, 7)) {
|
|
|
|
PLOG(WARNING) << "ioprio_get failed";
|
|
|
|
}
|
2017-08-04 22:22:36 +02:00
|
|
|
android::base::Timer t;
|
|
|
|
if (S_ISREG(sb.st_mode)) {
|
2017-08-16 20:34:50 +02:00
|
|
|
if (auto result = readahead_file(args[1], readfully); !result) {
|
|
|
|
LOG(WARNING) << "Unable to readahead '" << args[1] << "': " << result.error();
|
2017-08-04 22:22:36 +02:00
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
} else if (S_ISDIR(sb.st_mode)) {
|
|
|
|
char* paths[] = {const_cast<char*>(args[1].data()), nullptr};
|
|
|
|
std::unique_ptr<FTS, decltype(&fts_close)> fts(
|
|
|
|
fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr), fts_close);
|
|
|
|
if (!fts) {
|
|
|
|
PLOG(ERROR) << "Error opening directory: " << args[1];
|
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
// Traverse the entire hierarchy and do readahead
|
|
|
|
for (FTSENT* ftsent = fts_read(fts.get()); ftsent != nullptr;
|
|
|
|
ftsent = fts_read(fts.get())) {
|
|
|
|
if (ftsent->fts_info & FTS_F) {
|
2017-08-16 20:34:50 +02:00
|
|
|
const std::string filename = ftsent->fts_accpath;
|
|
|
|
if (auto result = readahead_file(filename, readfully); !result) {
|
|
|
|
LOG(WARNING)
|
|
|
|
<< "Unable to readahead '" << filename << "': " << result.error();
|
2017-08-04 22:22:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-08-16 20:34:50 +02:00
|
|
|
LOG(INFO) << "Readahead " << args[1] << " took " << t << " asynchronously";
|
2017-08-04 22:22:36 +02:00
|
|
|
_exit(0);
|
|
|
|
} else if (pid < 0) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return ErrnoError() << "Fork failed";
|
2017-08-04 22:22:36 +02:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2017-08-04 22:22:36 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_copy(const std::vector<std::string>& args) {
|
2017-08-03 21:54:07 +02:00
|
|
|
auto file_contents = ReadFile(args[1]);
|
|
|
|
if (!file_contents) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "Could not read input file '" << args[1] << "': " << file_contents.error();
|
2017-05-05 03:17:33 +02:00
|
|
|
}
|
2017-08-03 21:54:07 +02:00
|
|
|
if (auto result = WriteFile(args[2], *file_contents); !result) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "Could not write to output file '" << args[2] << "': " << result.error();
|
2009-08-27 01:39:25 +02:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
|
|
|
|
return Success();
|
2009-08-27 01:39:25 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_chown(const std::vector<std::string>& args) {
|
2017-08-03 21:54:07 +02:00
|
|
|
auto uid = DecodeUid(args[1]);
|
|
|
|
if (!uid) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
2017-05-05 02:40:33 +02:00
|
|
|
|
|
|
|
// GID is optional and pushes the index of path out by one if specified.
|
|
|
|
const std::string& path = (args.size() == 4) ? args[3] : args[2];
|
2017-08-03 21:54:07 +02:00
|
|
|
Result<gid_t> gid = -1;
|
2017-05-05 02:40:33 +02:00
|
|
|
|
|
|
|
if (args.size() == 4) {
|
2017-08-03 21:54:07 +02:00
|
|
|
gid = DecodeUid(args[2]);
|
|
|
|
if (!gid) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "Unable to decode GID for '" << args[2] << "': " << gid.error();
|
2017-05-05 02:40:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
if (lchown(path.c_str(), *uid, *gid) == -1) {
|
|
|
|
return ErrnoError() << "lchown() failed";
|
|
|
|
}
|
2017-05-05 02:40:33 +02:00
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static mode_t get_mode(const char *s) {
|
|
|
|
mode_t mode = 0;
|
|
|
|
while (*s) {
|
|
|
|
if (*s >= '0' && *s <= '7') {
|
|
|
|
mode = (mode<<3) | (*s-'0');
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
return mode;
|
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_chmod(const std::vector<std::string>& args) {
|
2015-07-30 22:52:55 +02:00
|
|
|
mode_t mode = get_mode(args[1].c_str());
|
|
|
|
if (fchmodat(AT_FDCWD, args[2].c_str(), mode, AT_SYMLINK_NOFOLLOW) < 0) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return ErrnoError() << "fchmodat() failed";
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_restorecon(const std::vector<std::string>& args) {
|
2013-10-09 22:02:09 +02:00
|
|
|
int ret = 0;
|
2012-01-13 14:48:47 +01:00
|
|
|
|
2016-11-15 00:40:18 +01:00
|
|
|
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) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "flags must precede paths";
|
2016-11-15 00:40:18 +01:00
|
|
|
}
|
|
|
|
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) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "bad flag " << args[i];
|
2016-11-15 00:40:18 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
in_flags = false;
|
2017-05-08 22:38:15 +02:00
|
|
|
if (selinux_android_restorecon(args[i].c_str(), flag) < 0) {
|
2017-08-01 22:50:23 +02:00
|
|
|
ret = errno;
|
2016-11-15 00:40:18 +01:00
|
|
|
}
|
|
|
|
}
|
2012-01-13 14:48:47 +01:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
|
|
|
|
if (ret) return ErrnoError() << "selinux_android_restorecon() failed";
|
|
|
|
return Success();
|
2013-10-09 22:02:09 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_restorecon_recursive(const std::vector<std::string>& args) {
|
2016-11-15 00:40:18 +01:00
|
|
|
std::vector<std::string> non_const_args(args);
|
|
|
|
non_const_args.insert(std::next(non_const_args.begin()), "--recursive");
|
|
|
|
return do_restorecon(non_const_args);
|
2012-01-13 14:48:47 +01:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_loglevel(const std::vector<std::string>& args) {
|
2016-08-05 01:09:39 +02:00
|
|
|
// TODO: support names instead/as well?
|
2016-10-12 02:09:00 +02:00
|
|
|
int log_level = -1;
|
|
|
|
android::base::ParseInt(args[1], &log_level);
|
2016-08-05 01:09:39 +02:00
|
|
|
android::base::LogSeverity severity;
|
|
|
|
switch (log_level) {
|
|
|
|
case 7: severity = android::base::DEBUG; break;
|
|
|
|
case 6: severity = android::base::INFO; break;
|
|
|
|
case 5:
|
|
|
|
case 4: severity = android::base::WARNING; break;
|
|
|
|
case 3: severity = android::base::ERROR; break;
|
|
|
|
case 2:
|
|
|
|
case 1:
|
|
|
|
case 0: severity = android::base::FATAL; break;
|
|
|
|
default:
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "invalid log level " << log_level;
|
2016-08-05 01:09:39 +02:00
|
|
|
}
|
|
|
|
android::base::SetMinimumLogSeverity(severity);
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_load_persist_props(const std::vector<std::string>& args) {
|
2015-08-26 20:43:36 +02:00
|
|
|
load_persist_props();
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2011-03-09 02:01:29 +01:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_load_system_props(const std::vector<std::string>& args) {
|
2015-09-02 00:05:34 +02:00
|
|
|
load_system_props();
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2014-06-17 00:06:21 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_wait(const std::vector<std::string>& args) {
|
|
|
|
auto timeout = kCommandRetryTimeout;
|
|
|
|
if (args.size() == 3) {
|
|
|
|
int timeout_int;
|
|
|
|
if (!android::base::ParseInt(args[2], &timeout_int)) {
|
|
|
|
return Error() << "failed to parse timeout";
|
2016-10-12 02:09:00 +02:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
timeout = std::chrono::seconds(timeout_int);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wait_for_file(args[1].c_str(), timeout) != 0) {
|
|
|
|
return Error() << "wait_for_file() failed";
|
2016-10-12 02:09:00 +02:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
|
|
|
|
return Success();
|
2010-04-20 02:10:24 +02:00
|
|
|
}
|
2015-03-26 16:49:42 +01:00
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_wait_for_prop(const std::vector<std::string>& args) {
|
2017-01-26 01:27:03 +01:00
|
|
|
const char* name = args[1].c_str();
|
|
|
|
const char* value = args[2].c_str();
|
|
|
|
size_t value_len = strlen(value);
|
|
|
|
|
|
|
|
if (!is_legal_property_name(name)) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "is_legal_property_name(" << name << ") failed";
|
2017-01-26 01:27:03 +01:00
|
|
|
}
|
|
|
|
if (value_len >= PROP_VALUE_MAX) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "value too long";
|
2017-01-26 01:27:03 +01:00
|
|
|
}
|
2017-02-02 19:52:39 +01:00
|
|
|
if (!start_waiting_for_property(name, value)) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return Error() << "already waiting for a property";
|
2017-01-26 01:27:03 +01:00
|
|
|
}
|
2017-08-01 22:50:23 +02:00
|
|
|
return Success();
|
2017-01-26 01:27:03 +01:00
|
|
|
}
|
|
|
|
|
2015-05-28 18:35:06 +02:00
|
|
|
static bool is_file_crypto() {
|
2017-03-29 01:40:41 +02:00
|
|
|
return android::base::GetProperty("ro.crypto.type", "") == "file";
|
2015-05-28 18:35:06 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_installkey(const std::vector<std::string>& args) {
|
|
|
|
if (!is_file_crypto()) return Success();
|
|
|
|
|
2017-03-29 23:50:01 +02:00
|
|
|
auto unencrypted_dir = args[1] + e4crypt_unencrypted_folder;
|
2017-08-10 21:22:44 +02:00
|
|
|
if (!make_dir(unencrypted_dir, 0700) && errno != EEXIST) {
|
2017-08-01 22:50:23 +02:00
|
|
|
return ErrnoError() << "Failed to create " << unencrypted_dir;
|
2017-03-29 23:50:01 +02:00
|
|
|
}
|
|
|
|
std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
|
|
|
|
"enablefilecrypto"};
|
|
|
|
return do_exec(exec_args);
|
2015-03-26 16:49:42 +01:00
|
|
|
}
|
2015-05-28 18:35:06 +02:00
|
|
|
|
2017-08-01 22:50:23 +02:00
|
|
|
static Result<Success> do_init_user0(const std::vector<std::string>& args) {
|
2017-05-03 22:19:03 +02:00
|
|
|
std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
|
|
|
|
"init_user0"};
|
|
|
|
return do_exec(exec_args);
|
2016-02-01 17:37:13 +01:00
|
|
|
}
|
|
|
|
|
2017-04-20 01:18:50 +02:00
|
|
|
const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
|
2015-08-26 20:43:36 +02:00
|
|
|
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
|
2017-03-28 01:27:30 +02:00
|
|
|
// clang-format off
|
2015-08-26 20:43:36 +02:00
|
|
|
static const Map builtin_functions = {
|
2016-11-11 02:43:47 +01:00
|
|
|
{"bootchart", {1, 1, do_bootchart}},
|
2015-08-26 20:43:36 +02:00
|
|
|
{"chmod", {2, 2, do_chmod}},
|
|
|
|
{"chown", {2, 3, do_chown}},
|
|
|
|
{"class_reset", {1, 1, do_class_reset}},
|
2017-03-10 23:04:37 +01:00
|
|
|
{"class_restart", {1, 1, do_class_restart}},
|
2015-08-26 20:43:36 +02:00
|
|
|
{"class_start", {1, 1, do_class_start}},
|
|
|
|
{"class_stop", {1, 1, do_class_stop}},
|
|
|
|
{"copy", {2, 2, do_copy}},
|
|
|
|
{"domainname", {1, 1, do_domainname}},
|
|
|
|
{"enable", {1, 1, do_enable}},
|
|
|
|
{"exec", {1, kMax, do_exec}},
|
2017-09-18 21:16:27 +02:00
|
|
|
{"exec_background", {1, kMax, do_exec_background}},
|
2017-03-28 01:27:30 +02:00
|
|
|
{"exec_start", {1, 1, do_exec_start}},
|
2015-08-26 20:43:36 +02:00
|
|
|
{"export", {2, 2, do_export}},
|
|
|
|
{"hostname", {1, 1, do_hostname}},
|
|
|
|
{"ifup", {1, 1, do_ifup}},
|
2016-02-01 17:37:13 +01:00
|
|
|
{"init_user0", {0, 0, do_init_user0}},
|
2015-08-26 20:43:36 +02:00
|
|
|
{"insmod", {1, kMax, do_insmod}},
|
|
|
|
{"installkey", {1, 1, do_installkey}},
|
|
|
|
{"load_persist_props", {0, 0, do_load_persist_props}},
|
2015-09-02 00:05:34 +02:00
|
|
|
{"load_system_props", {0, 0, do_load_system_props}},
|
2015-08-26 20:43:36 +02:00
|
|
|
{"loglevel", {1, 1, do_loglevel}},
|
|
|
|
{"mkdir", {1, 4, do_mkdir}},
|
2016-01-14 04:18:21 +01:00
|
|
|
{"mount_all", {1, kMax, do_mount_all}},
|
2015-08-26 20:43:36 +02:00
|
|
|
{"mount", {3, kMax, do_mount}},
|
2016-06-23 20:11:39 +02:00
|
|
|
{"umount", {1, 1, do_umount}},
|
2017-08-16 20:34:50 +02:00
|
|
|
{"readahead", {1, 2, do_readahead}},
|
2015-08-26 20:43:36 +02:00
|
|
|
{"restart", {1, 1, do_restart}},
|
|
|
|
{"restorecon", {1, kMax, do_restorecon}},
|
|
|
|
{"restorecon_recursive", {1, kMax, do_restorecon_recursive}},
|
|
|
|
{"rm", {1, 1, do_rm}},
|
|
|
|
{"rmdir", {1, 1, do_rmdir}},
|
|
|
|
{"setprop", {2, 2, do_setprop}},
|
|
|
|
{"setrlimit", {3, 3, do_setrlimit}},
|
|
|
|
{"start", {1, 1, do_start}},
|
|
|
|
{"stop", {1, 1, do_stop}},
|
|
|
|
{"swapon_all", {1, 1, do_swapon_all}},
|
|
|
|
{"symlink", {2, 2, do_symlink}},
|
|
|
|
{"sysclktz", {1, 1, do_sysclktz}},
|
|
|
|
{"trigger", {1, 1, do_trigger}},
|
|
|
|
{"verity_load_state", {0, 0, do_verity_load_state}},
|
|
|
|
{"verity_update_state", {0, 0, do_verity_update_state}},
|
|
|
|
{"wait", {1, 2, do_wait}},
|
2017-01-26 01:27:03 +01:00
|
|
|
{"wait_for_prop", {2, 2, do_wait_for_prop}},
|
2015-08-26 20:43:36 +02:00
|
|
|
{"write", {2, 2, do_write}},
|
|
|
|
};
|
2017-03-28 01:27:30 +02:00
|
|
|
// clang-format on
|
2015-08-26 20:43:36 +02:00
|
|
|
return builtin_functions;
|
|
|
|
}
|
2017-06-22 21:53:17 +02:00
|
|
|
|
|
|
|
} // namespace init
|
|
|
|
} // namespace android
|