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-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
|
|
|
|
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>
|
2015-12-05 07:00:26 +01:00
|
|
|
#include <android-base/stringprintf.h>
|
2017-03-29 01:40:41 +02:00
|
|
|
#include <android-base/strings.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>
|
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"
|
2015-07-31 21:45:25 +02:00
|
|
|
#include "init_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"
|
2015-07-31 21:45:25 +02:00
|
|
|
#include "service.h"
|
2015-12-18 20:39:59 +01:00
|
|
|
#include "signal_handler.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;
|
|
|
|
|
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
|
|
|
|
|
2016-11-11 02:43:47 +01:00
|
|
|
static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s;
|
2015-12-18 20:39:59 +01:00
|
|
|
|
2016-05-17 12:49:10 +02:00
|
|
|
static int insmod(const char *filename, const char *options, int flags) {
|
2016-03-28 01:55:59 +02:00
|
|
|
int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
|
|
|
|
if (fd == -1) {
|
2016-06-25 00:12:21 +02:00
|
|
|
PLOG(ERROR) << "insmod: open(\"" << filename << "\") failed";
|
2008-10-21 16:00:00 +02:00
|
|
|
return -1;
|
2015-02-06 21:19:48 +01:00
|
|
|
}
|
2016-05-17 12:49:10 +02:00
|
|
|
int rc = syscall(__NR_finit_module, fd, options, flags);
|
2016-03-28 01:55:59 +02:00
|
|
|
if (rc == -1) {
|
2016-06-25 00:12:21 +02:00
|
|
|
PLOG(ERROR) << "finit_module for \"" << filename << "\" failed";
|
2016-03-28 01:55:59 +02:00
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
return rc;
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int __ifupdown(const char *interface, int up) {
|
2008-10-21 16:00:00 +02:00
|
|
|
struct ifreq ifr;
|
|
|
|
int s, ret;
|
|
|
|
|
|
|
|
strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
|
|
|
|
|
|
|
|
s = socket(AF_INET, SOCK_DGRAM, 0);
|
|
|
|
if (s < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ret = ioctl(s, SIOCGIFFLAGS, &ifr);
|
|
|
|
if (ret < 0) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (up)
|
|
|
|
ifr.ifr_flags |= IFF_UP;
|
|
|
|
else
|
|
|
|
ifr.ifr_flags &= ~IFF_UP;
|
|
|
|
|
|
|
|
ret = ioctl(s, SIOCSIFFLAGS, &ifr);
|
2015-02-04 19:25:09 +01:00
|
|
|
|
2008-10-21 16:00:00 +02:00
|
|
|
done:
|
|
|
|
close(s);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-12-19 22:03:47 +01:00
|
|
|
static int 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)) {
|
2016-06-27 18:54:25 +02:00
|
|
|
LOG(ERROR) << "failed to set bootloader message: " << err;
|
2016-05-10 17:52:06 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-03-13 19:54:47 +01:00
|
|
|
DoReboot(ANDROID_RB_RESTART2, "reboot", "recovery", false);
|
|
|
|
return 0;
|
2015-07-08 23:57:07 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_class_start(const std::vector<std::string>& args) {
|
2008-10-21 16:00:00 +02:00
|
|
|
/* Starting a class does not start services
|
|
|
|
* which are explicitly disabled. They must
|
|
|
|
* be started individually.
|
|
|
|
*/
|
2015-07-31 21:45:25 +02:00
|
|
|
ServiceManager::GetInstance().
|
|
|
|
ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
|
2008-10-21 16:00:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_class_stop(const std::vector<std::string>& args) {
|
2015-07-31 21:45:25 +02:00
|
|
|
ServiceManager::GetInstance().
|
|
|
|
ForEachServiceInClass(args[1], [] (Service* s) { s->Stop(); });
|
2008-10-21 16:00:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_class_reset(const std::vector<std::string>& args) {
|
2015-07-31 21:45:25 +02:00
|
|
|
ServiceManager::GetInstance().
|
|
|
|
ForEachServiceInClass(args[1], [] (Service* s) { s->Reset(); });
|
2010-12-04 01:33:31 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-10 23:04:37 +01:00
|
|
|
static int do_class_restart(const std::vector<std::string>& args) {
|
|
|
|
ServiceManager::GetInstance().
|
|
|
|
ForEachServiceInClass(args[1], [] (Service* s) { s->Restart(); });
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_domainname(const std::vector<std::string>& args) {
|
2017-05-05 03:17:33 +02:00
|
|
|
std::string err;
|
|
|
|
if (!WriteFile("/proc/sys/kernel/domainname", args[1], &err)) {
|
|
|
|
LOG(ERROR) << err;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_enable(const std::vector<std::string>& args) {
|
2015-07-31 21:45:25 +02:00
|
|
|
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
|
|
|
|
if (!svc) {
|
2014-05-03 06:14:29 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2015-07-31 21:45:25 +02:00
|
|
|
return svc->Enable();
|
2014-05-03 06:14:29 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_exec(const std::vector<std::string>& args) {
|
2017-03-28 01:27:30 +02:00
|
|
|
return ServiceManager::GetInstance().Exec(args) ? 0 : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int do_exec_start(const std::vector<std::string>& args) {
|
|
|
|
return ServiceManager::GetInstance().ExecStart(args[1]) ? 0 : -1;
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_export(const std::vector<std::string>& args) {
|
2015-07-30 22:52:55 +02:00
|
|
|
return add_environment(args[1].c_str(), args[2].c_str());
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_hostname(const std::vector<std::string>& args) {
|
2017-05-05 03:17:33 +02:00
|
|
|
std::string err;
|
|
|
|
if (!WriteFile("/proc/sys/kernel/hostname", args[1], &err)) {
|
|
|
|
LOG(ERROR) << err;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_ifup(const std::vector<std::string>& args) {
|
2015-07-30 22:52:55 +02:00
|
|
|
return __ifupdown(args[1].c_str(), 1);
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int 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()), ' ');
|
|
|
|
return insmod(filename.c_str(), options.c_str(), flags);
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_mkdir(const std::vector<std::string>& args) {
|
2008-10-21 16:00:00 +02:00
|
|
|
mode_t mode = 0755;
|
2011-07-08 21:57:36 +02:00
|
|
|
int ret;
|
2008-10-21 16:00:00 +02:00
|
|
|
|
|
|
|
/* mkdir <path> [mode] [owner] [group] */
|
|
|
|
|
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-05-02 02:10:09 +02:00
|
|
|
ret = make_dir(args[1].c_str(), mode, sehandle);
|
2011-07-08 21:57:36 +02:00
|
|
|
/* chmod in case the directory already exists */
|
|
|
|
if (ret == -1 && errno == EEXIST) {
|
2015-07-30 22:52:55 +02:00
|
|
|
ret = fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW);
|
2011-07-08 21:57:36 +02:00
|
|
|
}
|
|
|
|
if (ret == -1) {
|
2008-10-21 16:00:00 +02:00
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
2015-07-30 22:52:55 +02:00
|
|
|
if (args.size() >= 4) {
|
2017-05-05 02:40:33 +02:00
|
|
|
uid_t uid;
|
|
|
|
std::string decode_uid_err;
|
|
|
|
if (!DecodeUid(args[3], &uid, &decode_uid_err)) {
|
|
|
|
LOG(ERROR) << "Unable to find UID for '" << args[3] << "': " << decode_uid_err;
|
|
|
|
return -1;
|
|
|
|
}
|
2008-10-21 16:00:00 +02:00
|
|
|
gid_t gid = -1;
|
|
|
|
|
2015-07-30 22:52:55 +02:00
|
|
|
if (args.size() == 5) {
|
2017-05-05 02:40:33 +02:00
|
|
|
if (!DecodeUid(args[4], &gid, &decode_uid_err)) {
|
|
|
|
LOG(ERROR) << "Unable to find GID for '" << args[3] << "': " << decode_uid_err;
|
|
|
|
return -1;
|
|
|
|
}
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2015-07-30 22:52:55 +02:00
|
|
|
if (lchown(args[1].c_str(), uid, gid) == -1) {
|
2008-10-21 16:00:00 +02:00
|
|
|
return -errno;
|
|
|
|
}
|
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)) {
|
2015-07-30 22:52:55 +02:00
|
|
|
ret = fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW);
|
2012-08-15 00:43:46 +02:00
|
|
|
if (ret == -1) {
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
}
|
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);
|
2016-05-10 17:52:06 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2016-06-23 20:11:39 +02:00
|
|
|
/* umount <path> */
|
|
|
|
static int do_umount(const std::vector<std::string>& args) {
|
|
|
|
return umount(args[1].c_str());
|
|
|
|
}
|
|
|
|
|
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> */
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_mount(const std::vector<std::string>& args) {
|
2008-10-21 16:00:00 +02:00
|
|
|
char tmp[64];
|
2015-07-30 22:52:55 +02:00
|
|
|
const char *source, *target, *system;
|
|
|
|
const char *options = NULL;
|
2008-10-21 16:00:00 +02:00
|
|
|
unsigned flags = 0;
|
2015-07-30 22:52:55 +02:00
|
|
|
std::size_t na = 0;
|
2008-10-21 16:00:00 +02:00
|
|
|
int n, i;
|
2010-04-20 02:10:24 +02:00
|
|
|
int wait = 0;
|
2008-10-21 16:00:00 +02:00
|
|
|
|
2015-07-30 22:52:55 +02:00
|
|
|
for (na = 4; na < args.size(); na++) {
|
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) {
|
2015-07-30 22:52:55 +02:00
|
|
|
if (!args[na].compare("wait"))
|
2010-04-20 02:10:24 +02:00
|
|
|
wait = 1;
|
|
|
|
/* if our last argument isn't a flag, wolf it up as an option string */
|
2015-07-30 22:52:55 +02:00
|
|
|
else if (na + 1 == args.size())
|
|
|
|
options = args[na].c_str();
|
2010-04-20 02:10:24 +02:00
|
|
|
}
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2015-07-30 22:52:55 +02:00
|
|
|
system = args[1].c_str();
|
|
|
|
source = args[2].c_str();
|
|
|
|
target = args[3].c_str();
|
2008-11-20 04:37:30 +01:00
|
|
|
|
2016-06-25 00:15:03 +02:00
|
|
|
if (!strncmp(source, "loop@", 5)) {
|
2008-11-20 04:37:30 +01:00
|
|
|
int mode, loop, fd;
|
|
|
|
struct loop_info info;
|
|
|
|
|
|
|
|
mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
|
2015-02-02 23:37:22 +01:00
|
|
|
fd = open(source + 5, mode | O_CLOEXEC);
|
2008-11-20 04:37:30 +01:00
|
|
|
if (fd < 0) {
|
|
|
|
return -1;
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
2008-11-20 04:37:30 +01:00
|
|
|
|
|
|
|
for (n = 0; ; n++) {
|
2015-02-18 04:27:51 +01:00
|
|
|
snprintf(tmp, sizeof(tmp), "/dev/block/loop%d", n);
|
2015-02-02 23:37:22 +01:00
|
|
|
loop = open(tmp, mode | O_CLOEXEC);
|
2008-11-20 04:37:30 +01:00
|
|
|
if (loop < 0) {
|
2014-02-06 08:57:27 +01:00
|
|
|
close(fd);
|
2008-11-20 04:37:30 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if it is a blank loop device */
|
|
|
|
if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
|
|
|
|
/* if it becomes our loop device */
|
|
|
|
if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (mount(tmp, target, system, flags, options) < 0) {
|
|
|
|
ioctl(loop, LOOP_CLR_FD, 0);
|
|
|
|
close(loop);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
close(loop);
|
2011-02-18 03:09:47 +01:00
|
|
|
goto exit_success;
|
2008-11-20 04:37:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
close(loop);
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
2016-06-25 00:12:21 +02:00
|
|
|
LOG(ERROR) << "out of loopback devices";
|
2008-11-20 04:37:30 +01:00
|
|
|
return -1;
|
|
|
|
} 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) {
|
2012-04-18 02:20:16 +02:00
|
|
|
return -1;
|
2008-11-20 04:37:30 +01:00
|
|
|
}
|
|
|
|
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
2011-02-18 03:09:47 +01:00
|
|
|
|
|
|
|
exit_success:
|
2012-04-18 02:20:16 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
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) {
|
2015-08-26 20:43:36 +02:00
|
|
|
Parser& parser = Parser::GetInstance();
|
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.
|
|
|
|
if (!parser.is_system_etc_init_loaded()) {
|
|
|
|
parser.ParseConfig("/system/etc/init");
|
|
|
|
parser.set_is_system_etc_init_loaded(true);
|
|
|
|
}
|
|
|
|
if (!parser.is_vendor_etc_init_loaded()) {
|
|
|
|
parser.ParseConfig("/vendor/etc/init");
|
|
|
|
parser.set_is_vendor_etc_init_loaded(true);
|
|
|
|
}
|
|
|
|
if (!parser.is_odm_etc_init_loaded()) {
|
|
|
|
parser.ParseConfig("/odm/etc/init");
|
|
|
|
parser.set_is_odm_etc_init_loaded(true);
|
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
|
|
|
*/
|
2016-08-23 20:58:09 +02:00
|
|
|
static int mount_fstab(const char* fstabfile, int mount_mode) {
|
2012-04-18 02:20:16 +02:00
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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)) {
|
|
|
|
ret = WEXITSTATUS(status);
|
|
|
|
} else {
|
|
|
|
ret = -1;
|
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 {
|
|
|
|
/* fork failed, return an error */
|
|
|
|
return -1;
|
2011-02-18 03:09:47 +01:00
|
|
|
}
|
2016-08-23 20:58:09 +02:00
|
|
|
return ret;
|
|
|
|
}
|
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
|
|
|
|
*/
|
|
|
|
static int queue_fs_event(int code) {
|
|
|
|
int ret = code;
|
|
|
|
if (code == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
|
2016-04-19 00:37:31 +02:00
|
|
|
ActionManager::GetInstance().QueueEventTrigger("encrypt");
|
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");
|
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");
|
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");
|
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" };
|
|
|
|
ret = reboot_into_recovery(options);
|
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()) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
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");
|
2016-08-23 20:58:09 +02:00
|
|
|
} else if (code > 0) {
|
|
|
|
PLOG(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
|
|
|
|
2012-04-18 02:20:16 +02:00
|
|
|
return ret;
|
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.
|
|
|
|
*/
|
|
|
|
static int do_mount_all(const std::vector<std::string>& args) {
|
|
|
|
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-03-04 03:57:09 +01:00
|
|
|
std::string prop_name = android::base::StringPrintf("ro.boottime.init.mount_all.%s",
|
|
|
|
prop_post_fix);
|
|
|
|
Timer t;
|
2016-08-23 20:58:09 +02:00
|
|
|
int ret = mount_fstab(fstabfile, mount_mode);
|
2017-03-04 03:57:09 +01:00
|
|
|
property_set(prop_name.c_str(), std::to_string(t.duration_ms()).c_str());
|
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*/
|
|
|
|
ret = queue_fs_event(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int 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);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_setprop(const std::vector<std::string>& args) {
|
2015-07-30 22:52:55 +02:00
|
|
|
const char* name = args[1].c_str();
|
|
|
|
const char* value = args[2].c_str();
|
2015-07-24 22:26:04 +02:00
|
|
|
property_set(name, value);
|
2008-10-21 16:00:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_setrlimit(const std::vector<std::string>& args) {
|
2008-10-21 16:00:00 +02:00
|
|
|
struct rlimit limit;
|
|
|
|
int resource;
|
2016-10-12 02:09:00 +02:00
|
|
|
if (android::base::ParseInt(args[1], &resource) &&
|
|
|
|
android::base::ParseUint(args[2], &limit.rlim_cur) &&
|
|
|
|
android::base::ParseUint(args[3], &limit.rlim_max)) {
|
|
|
|
return setrlimit(resource, &limit);
|
|
|
|
}
|
|
|
|
LOG(WARNING) << "ignoring setrlimit " << args[1] << " " << args[2] << " " << args[3];
|
|
|
|
return -1;
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_start(const std::vector<std::string>& args) {
|
2015-07-31 21:45:25 +02:00
|
|
|
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
|
|
|
|
if (!svc) {
|
2016-06-25 00:12:21 +02:00
|
|
|
LOG(ERROR) << "do_start: Service " << args[1] << " not found";
|
2015-07-31 21:45:25 +02:00
|
|
|
return -1;
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
2015-07-31 21:45:25 +02:00
|
|
|
if (!svc->Start())
|
|
|
|
return -1;
|
2008-10-21 16:00:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_stop(const std::vector<std::string>& args) {
|
2015-07-31 21:45:25 +02:00
|
|
|
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
|
|
|
|
if (!svc) {
|
2016-06-25 00:12:21 +02:00
|
|
|
LOG(ERROR) << "do_stop: Service " << args[1] << " not found";
|
2015-07-31 21:45:25 +02:00
|
|
|
return -1;
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
2015-07-31 21:45:25 +02:00
|
|
|
svc->Stop();
|
2008-10-21 16:00:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_restart(const std::vector<std::string>& args) {
|
2015-07-31 21:45:25 +02:00
|
|
|
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
|
|
|
|
if (!svc) {
|
2016-06-25 00:12:21 +02:00
|
|
|
LOG(ERROR) << "do_restart: Service " << args[1] << " not found";
|
2015-07-31 21:45:25 +02:00
|
|
|
return -1;
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
2015-07-31 21:45:25 +02:00
|
|
|
svc->Restart();
|
2008-10-21 16:00:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_trigger(const std::vector<std::string>& args) {
|
2015-07-24 02:53:11 +02:00
|
|
|
ActionManager::GetInstance().QueueEventTrigger(args[1]);
|
2008-10-21 16:00:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_symlink(const std::vector<std::string>& args) {
|
2015-07-30 22:52:55 +02:00
|
|
|
return symlink(args[1].c_str(), args[2].c_str());
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_rm(const std::vector<std::string>& args) {
|
2015-07-30 22:52:55 +02:00
|
|
|
return unlink(args[1].c_str());
|
2011-01-19 02:37:41 +01:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_rmdir(const std::vector<std::string>& args) {
|
2015-07-30 22:52:55 +02:00
|
|
|
return rmdir(args[1].c_str());
|
2011-01-19 02:37:41 +01:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_sysclktz(const std::vector<std::string>& args) {
|
2016-10-12 02:09:00 +02:00
|
|
|
struct timezone tz = {};
|
|
|
|
if (android::base::ParseInt(args[1], &tz.tz_minuteswest) && settimeofday(NULL, &tz) != -1) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
2008-12-18 03:08:08 +01:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int 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-03-01 17:03:56 +01:00
|
|
|
return loaded ? 0 : 1;
|
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) {
|
2015-03-30 12:38:38 +02:00
|
|
|
property_set(android::base::StringPrintf("partition.%s.verified", mount_point).c_str(),
|
|
|
|
android::base::StringPrintf("%d", mode).c_str());
|
2015-03-19 11:00:34 +01:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_verity_update_state(const std::vector<std::string>& args) {
|
2017-03-01 17:03:56 +01:00
|
|
|
return fs_mgr_update_verity_state(verity_update_property) ? 0 : 1;
|
2015-03-19 11:00:34 +01:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_write(const std::vector<std::string>& args) {
|
2017-05-05 03:17:33 +02:00
|
|
|
std::string err;
|
|
|
|
if (!WriteFile(args[1], args[2], &err)) {
|
|
|
|
LOG(ERROR) << err;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_copy(const std::vector<std::string>& args) {
|
2016-12-28 09:06:19 +01:00
|
|
|
std::string data;
|
2017-05-05 03:17:33 +02:00
|
|
|
std::string err;
|
|
|
|
if (!ReadFile(args[1], &data, &err)) {
|
|
|
|
LOG(ERROR) << err;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!WriteFile(args[2], data, &err)) {
|
|
|
|
LOG(ERROR) << err;
|
|
|
|
return -1;
|
2009-08-27 01:39:25 +02:00
|
|
|
}
|
2017-05-05 03:17:33 +02:00
|
|
|
return 0;
|
2009-08-27 01:39:25 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_chown(const std::vector<std::string>& args) {
|
2017-05-05 02:40:33 +02:00
|
|
|
uid_t uid;
|
|
|
|
std::string decode_uid_err;
|
|
|
|
if (!DecodeUid(args[1], &uid, &decode_uid_err)) {
|
|
|
|
LOG(ERROR) << "Unable to find UID for '" << args[1] << "': " << decode_uid_err;
|
2008-10-21 16:00:00 +02:00
|
|
|
return -1;
|
|
|
|
}
|
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];
|
|
|
|
gid_t gid = -1;
|
|
|
|
|
|
|
|
if (args.size() == 4) {
|
|
|
|
if (!DecodeUid(args[2], &gid, &decode_uid_err)) {
|
|
|
|
LOG(ERROR) << "Unable to find GID for '" << args[2] << "': " << decode_uid_err;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lchown(path.c_str(), uid, gid) == -1) return -errno;
|
|
|
|
|
2008-10-21 16:00:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int 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) {
|
2008-10-21 16:00:00 +02:00
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int 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) {
|
|
|
|
LOG(ERROR) << "restorecon - flags must precede paths";
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
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) {
|
|
|
|
LOG(ERROR) << "restorecon - bad flag " << args[i];
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
in_flags = false;
|
2017-05-08 22:38:15 +02:00
|
|
|
if (selinux_android_restorecon(args[i].c_str(), flag) < 0) {
|
2016-11-15 00:40:18 +01:00
|
|
|
ret = -errno;
|
|
|
|
}
|
|
|
|
}
|
2012-01-13 14:48:47 +01:00
|
|
|
}
|
2013-10-09 22:02:09 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int 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
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int 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:
|
|
|
|
LOG(ERROR) << "loglevel: invalid log level " << log_level;
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
android::base::SetMinimumLogSeverity(severity);
|
2014-06-26 22:55:03 +02:00
|
|
|
return 0;
|
2008-10-21 16:00:00 +02:00
|
|
|
}
|
|
|
|
|
2015-09-02 00:05:34 +02:00
|
|
|
static int do_load_persist_props(const std::vector<std::string>& args) {
|
2015-08-26 20:43:36 +02:00
|
|
|
load_persist_props();
|
|
|
|
return 0;
|
2011-03-09 02:01:29 +01:00
|
|
|
}
|
|
|
|
|
2015-09-02 00:05:34 +02:00
|
|
|
static int do_load_system_props(const std::vector<std::string>& args) {
|
|
|
|
load_system_props();
|
2015-08-26 20:43:36 +02:00
|
|
|
return 0;
|
2014-06-17 00:06:21 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_wait(const std::vector<std::string>& args) {
|
2015-07-30 22:52:55 +02:00
|
|
|
if (args.size() == 2) {
|
2016-11-11 02:43:47 +01:00
|
|
|
return wait_for_file(args[1].c_str(), kCommandRetryTimeout);
|
2015-07-30 22:52:55 +02:00
|
|
|
} else if (args.size() == 3) {
|
2016-10-12 02:09:00 +02:00
|
|
|
int timeout;
|
|
|
|
if (android::base::ParseInt(args[2], &timeout)) {
|
2016-11-11 02:43:47 +01:00
|
|
|
return wait_for_file(args[1].c_str(), std::chrono::seconds(timeout));
|
2016-10-12 02:09:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
2010-04-20 02:10:24 +02:00
|
|
|
}
|
2015-03-26 16:49:42 +01:00
|
|
|
|
2017-01-26 01:27:03 +01:00
|
|
|
static int do_wait_for_prop(const std::vector<std::string>& args) {
|
|
|
|
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)) {
|
|
|
|
LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
|
|
|
|
<< "\") failed: bad name";
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (value_len >= PROP_VALUE_MAX) {
|
|
|
|
LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
|
|
|
|
<< "\") failed: value too long";
|
|
|
|
return -1;
|
|
|
|
}
|
2017-02-02 19:52:39 +01:00
|
|
|
if (!start_waiting_for_property(name, value)) {
|
2017-01-26 01:27:03 +01:00
|
|
|
LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
|
|
|
|
<< "\") failed: init already in waiting";
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-29 00:07:10 +02:00
|
|
|
/*
|
|
|
|
* Callback to make a directory from the ext4 code
|
|
|
|
*/
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_installkeys_ensure_dir_exists(const char* dir) {
|
2017-05-02 02:10:09 +02:00
|
|
|
if (make_dir(dir, 0700, sehandle) && errno != EEXIST) {
|
2015-04-29 00:07:10 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2015-08-26 20:43:36 +02:00
|
|
|
static int do_installkey(const std::vector<std::string>& args) {
|
2015-05-28 18:35:06 +02:00
|
|
|
if (!is_file_crypto()) {
|
2015-04-29 00:07:10 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2017-03-29 23:50:01 +02:00
|
|
|
auto unencrypted_dir = args[1] + e4crypt_unencrypted_folder;
|
|
|
|
if (do_installkeys_ensure_dir_exists(unencrypted_dir.c_str())) {
|
|
|
|
PLOG(ERROR) << "Failed to create " << unencrypted_dir;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
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
|
|
|
|
2016-02-01 17:37:13 +01:00
|
|
|
static int 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-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}},
|
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;
|
|
|
|
}
|