1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "builtins.h"
18
19#include <dirent.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <fts.h>
23#include <linux/loop.h>
24#include <linux/module.h>
25#include <mntent.h>
26#include <net/if.h>
27#include <sched.h>
28#include <signal.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <sys/mount.h>
33#include <sys/resource.h>
34#include <sys/socket.h>
35#include <sys/stat.h>
36#include <sys/syscall.h>
37#include <sys/system_properties.h>
38#include <sys/time.h>
39#include <sys/types.h>
40#include <sys/wait.h>
41#include <unistd.h>
42
43#include <android-base/chrono_utils.h>
44#include <android-base/file.h>
45#include <android-base/logging.h>
46#include <android-base/parseint.h>
47#include <android-base/properties.h>
48#include <android-base/stringprintf.h>
49#include <android-base/strings.h>
50#include <android-base/unique_fd.h>
51#include <bootloader_message/bootloader_message.h>
52#include <cutils/android_reboot.h>
53#include <ext4_utils/ext4_crypt.h>
54#include <ext4_utils/ext4_crypt_init_extensions.h>
55#include <fs_mgr.h>
56#include <selinux/android.h>
57#include <selinux/label.h>
58#include <selinux/selinux.h>
59#include <system/thread_defs.h>
60
61#include "action_manager.h"
62#include "bootchart.h"
63#include "init.h"
64#include "parser.h"
65#include "property_service.h"
66#include "reboot.h"
67#include "rlimit_parser.h"
68#include "selinux.h"
69#include "service.h"
70#include "subcontext.h"
71#include "util.h"
72
73using namespace std::literals::string_literals;
74
75using android::base::unique_fd;
76
77#define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
78
79namespace android {
80namespace init {
81
82static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s;
83
84static Result<Success> reboot_into_recovery(const std::vector<std::string>& options) {
85    LOG(ERROR) << "Rebooting into recovery";
86    std::string err;
87    if (!write_bootloader_message(options, &err)) {
88        return Error() << "Failed to set bootloader message: " << err;
89    }
90    property_set("sys.powerctl", "reboot,recovery");
91    return Success();
92}
93
94template <typename F>
95static void ForEachServiceInClass(const std::string& classname, F function) {
96    for (const auto& service : ServiceList::GetInstance()) {
97        if (service->classnames().count(classname)) std::invoke(function, service);
98    }
99}
100
101static Result<Success> do_class_start(const BuiltinArguments& args) {
102    // Starting a class does not start services which are explicitly disabled.
103    // They must  be started individually.
104    for (const auto& service : ServiceList::GetInstance()) {
105        if (service->classnames().count(args[1])) {
106            if (auto result = service->StartIfNotDisabled(); !result) {
107                LOG(ERROR) << "Could not start service '" << service->name()
108                           << "' as part of class '" << args[1] << "': " << result.error();
109            }
110        }
111    }
112    return Success();
113}
114
115static Result<Success> do_class_stop(const BuiltinArguments& args) {
116    ForEachServiceInClass(args[1], &Service::Stop);
117    return Success();
118}
119
120static Result<Success> do_class_reset(const BuiltinArguments& args) {
121    ForEachServiceInClass(args[1], &Service::Reset);
122    return Success();
123}
124
125static Result<Success> do_class_restart(const BuiltinArguments& args) {
126    ForEachServiceInClass(args[1], &Service::Restart);
127    return Success();
128}
129
130static Result<Success> do_domainname(const BuiltinArguments& args) {
131    if (auto result = WriteFile("/proc/sys/kernel/domainname", args[1]); !result) {
132        return Error() << "Unable to write to /proc/sys/kernel/domainname: " << result.error();
133    }
134    return Success();
135}
136
137static Result<Success> do_enable(const BuiltinArguments& args) {
138    Service* svc = ServiceList::GetInstance().FindService(args[1]);
139    if (!svc) return Error() << "Could not find service";
140
141    if (auto result = svc->Enable(); !result) {
142        return Error() << "Could not enable service: " << result.error();
143    }
144
145    return Success();
146}
147
148static Result<Success> do_exec(const BuiltinArguments& args) {
149    auto service = Service::MakeTemporaryOneshotService(args.args);
150    if (!service) {
151        return Error() << "Could not create exec service";
152    }
153    if (auto result = service->ExecStart(); !result) {
154        return Error() << "Could not start exec service: " << result.error();
155    }
156
157    ServiceList::GetInstance().AddService(std::move(service));
158    return Success();
159}
160
161static Result<Success> do_exec_background(const BuiltinArguments& args) {
162    auto service = Service::MakeTemporaryOneshotService(args.args);
163    if (!service) {
164        return Error() << "Could not create exec background service";
165    }
166    if (auto result = service->Start(); !result) {
167        return Error() << "Could not start exec background service: " << result.error();
168    }
169
170    ServiceList::GetInstance().AddService(std::move(service));
171    return Success();
172}
173
174static Result<Success> do_exec_start(const BuiltinArguments& args) {
175    Service* service = ServiceList::GetInstance().FindService(args[1]);
176    if (!service) {
177        return Error() << "Service not found";
178    }
179
180    if (auto result = service->ExecStart(); !result) {
181        return Error() << "Could not start exec service: " << result.error();
182    }
183
184    return Success();
185}
186
187static Result<Success> do_export(const BuiltinArguments& args) {
188    if (setenv(args[1].c_str(), args[2].c_str(), 1) == -1) {
189        return ErrnoError() << "setenv() failed";
190    }
191    return Success();
192}
193
194static Result<Success> do_hostname(const BuiltinArguments& args) {
195    if (auto result = WriteFile("/proc/sys/kernel/hostname", args[1]); !result) {
196        return Error() << "Unable to write to /proc/sys/kernel/hostname: " << result.error();
197    }
198    return Success();
199}
200
201static Result<Success> do_ifup(const BuiltinArguments& args) {
202    struct ifreq ifr;
203
204    strlcpy(ifr.ifr_name, args[1].c_str(), IFNAMSIZ);
205
206    unique_fd s(TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_DGRAM, 0)));
207    if (s < 0) return ErrnoError() << "opening socket failed";
208
209    if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
210        return ErrnoError() << "ioctl(..., SIOCGIFFLAGS, ...) failed";
211    }
212
213    ifr.ifr_flags |= IFF_UP;
214
215    if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
216        return ErrnoError() << "ioctl(..., SIOCSIFFLAGS, ...) failed";
217    }
218
219    return Success();
220}
221
222static Result<Success> do_insmod(const BuiltinArguments& args) {
223    int flags = 0;
224    auto it = args.begin() + 1;
225
226    if (!(*it).compare("-f")) {
227        flags = MODULE_INIT_IGNORE_VERMAGIC | MODULE_INIT_IGNORE_MODVERSIONS;
228        it++;
229    }
230
231    std::string filename = *it++;
232    std::string options = android::base::Join(std::vector<std::string>(it, args.end()), ' ');
233
234    unique_fd fd(TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
235    if (fd == -1) return ErrnoError() << "open(\"" << filename << "\") failed";
236
237    int rc = syscall(__NR_finit_module, fd.get(), options.c_str(), flags);
238    if (rc == -1) return ErrnoError() << "finit_module for \"" << filename << "\" failed";
239
240    return Success();
241}
242
243// mkdir <path> [mode] [owner] [group]
244static Result<Success> do_mkdir(const BuiltinArguments& args) {
245    mode_t mode = 0755;
246    if (args.size() >= 3) {
247        mode = std::strtoul(args[2].c_str(), 0, 8);
248    }
249
250    if (!make_dir(args[1], mode)) {
251        /* chmod in case the directory already exists */
252        if (errno == EEXIST) {
253            if (fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) {
254                return ErrnoError() << "fchmodat() failed";
255            }
256        } else {
257            return ErrnoError() << "mkdir() failed";
258        }
259    }
260
261    if (args.size() >= 4) {
262        auto uid = DecodeUid(args[3]);
263        if (!uid) {
264            return Error() << "Unable to decode UID for '" << args[3] << "': " << uid.error();
265        }
266        Result<gid_t> gid = -1;
267
268        if (args.size() == 5) {
269            gid = DecodeUid(args[4]);
270            if (!gid) {
271                return Error() << "Unable to decode GID for '" << args[3] << "': " << gid.error();
272            }
273        }
274
275        if (lchown(args[1].c_str(), *uid, *gid) == -1) {
276            return ErrnoError() << "lchown failed";
277        }
278
279        /* chown may have cleared S_ISUID and S_ISGID, chmod again */
280        if (mode & (S_ISUID | S_ISGID)) {
281            if (fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) {
282                return ErrnoError() << "fchmodat failed";
283            }
284        }
285    }
286
287    if (e4crypt_is_native()) {
288        if (e4crypt_set_directory_policy(args[1].c_str())) {
289            return reboot_into_recovery(
290                {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + args[1]});
291        }
292    }
293    return Success();
294}
295
296/* umount <path> */
297static Result<Success> do_umount(const BuiltinArguments& args) {
298    if (umount(args[1].c_str()) < 0) {
299        return ErrnoError() << "umount() failed";
300    }
301    return Success();
302}
303
304static struct {
305    const char *name;
306    unsigned flag;
307} mount_flags[] = {
308    { "noatime",    MS_NOATIME },
309    { "noexec",     MS_NOEXEC },
310    { "nosuid",     MS_NOSUID },
311    { "nodev",      MS_NODEV },
312    { "nodiratime", MS_NODIRATIME },
313    { "ro",         MS_RDONLY },
314    { "rw",         0 },
315    { "remount",    MS_REMOUNT },
316    { "bind",       MS_BIND },
317    { "rec",        MS_REC },
318    { "unbindable", MS_UNBINDABLE },
319    { "private",    MS_PRIVATE },
320    { "slave",      MS_SLAVE },
321    { "shared",     MS_SHARED },
322    { "defaults",   0 },
323    { 0,            0 },
324};
325
326#define DATA_MNT_POINT "/data"
327
328/* mount <type> <device> <path> <flags ...> <options> */
329static Result<Success> do_mount(const BuiltinArguments& args) {
330    const char* options = nullptr;
331    unsigned flags = 0;
332    bool wait = false;
333
334    for (size_t na = 4; na < args.size(); na++) {
335        size_t i;
336        for (i = 0; mount_flags[i].name; i++) {
337            if (!args[na].compare(mount_flags[i].name)) {
338                flags |= mount_flags[i].flag;
339                break;
340            }
341        }
342
343        if (!mount_flags[i].name) {
344            if (!args[na].compare("wait")) {
345                wait = true;
346                // If our last argument isn't a flag, wolf it up as an option string.
347            } else if (na + 1 == args.size()) {
348                options = args[na].c_str();
349            }
350        }
351    }
352
353    const char* system = args[1].c_str();
354    const char* source = args[2].c_str();
355    const char* target = args[3].c_str();
356
357    if (android::base::StartsWith(source, "loop@")) {
358        int mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
359        unique_fd fd(TEMP_FAILURE_RETRY(open(source + 5, mode | O_CLOEXEC)));
360        if (fd < 0) return ErrnoError() << "open(" << source + 5 << ", " << mode << ") failed";
361
362        for (size_t n = 0;; n++) {
363            std::string tmp = android::base::StringPrintf("/dev/block/loop%zu", n);
364            unique_fd loop(TEMP_FAILURE_RETRY(open(tmp.c_str(), mode | O_CLOEXEC)));
365            if (loop < 0) return ErrnoError() << "open(" << tmp << ", " << mode << ") failed";
366
367            loop_info info;
368            /* if it is a blank loop device */
369            if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
370                /* if it becomes our loop device */
371                if (ioctl(loop, LOOP_SET_FD, fd.get()) >= 0) {
372                    if (mount(tmp.c_str(), target, system, flags, options) < 0) {
373                        ioctl(loop, LOOP_CLR_FD, 0);
374                        return ErrnoError() << "mount() failed";
375                    }
376                    return Success();
377                }
378            }
379        }
380
381        return Error() << "out of loopback devices";
382    } else {
383        if (wait)
384            wait_for_file(source, kCommandRetryTimeout);
385        if (mount(source, target, system, flags, options) < 0) {
386            return ErrnoError() << "mount() failed";
387        }
388
389    }
390
391    return Success();
392}
393
394/* Imports .rc files from the specified paths. Default ones are applied if none is given.
395 *
396 * start_index: index of the first path in the args list
397 */
398static void import_late(const std::vector<std::string>& args, size_t start_index, size_t end_index) {
399    auto& action_manager = ActionManager::GetInstance();
400    auto& service_list = ServiceList::GetInstance();
401    Parser parser = CreateParser(action_manager, service_list);
402    if (end_index <= start_index) {
403        // Fallbacks for partitions on which early mount isn't enabled.
404        for (const auto& path : late_import_paths) {
405            parser.ParseConfig(path);
406        }
407        late_import_paths.clear();
408    } else {
409        for (size_t i = start_index; i < end_index; ++i) {
410            parser.ParseConfig(args[i]);
411        }
412    }
413
414    // Turning this on and letting the INFO logging be discarded adds 0.2s to
415    // Nexus 9 boot time, so it's disabled by default.
416    if (false) DumpState();
417}
418
419/* mount_fstab
420 *
421 *  Call fs_mgr_mount_all() to mount the given fstab
422 */
423static Result<int> mount_fstab(const char* fstabfile, int mount_mode) {
424    /*
425     * Call fs_mgr_mount_all() to mount all filesystems.  We fork(2) and
426     * do the call in the child to provide protection to the main init
427     * process if anything goes wrong (crash or memory leak), and wait for
428     * the child to finish in the parent.
429     */
430    pid_t pid = fork();
431    if (pid > 0) {
432        /* Parent.  Wait for the child to return */
433        int status;
434        int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
435        if (wp_ret == -1) {
436            // Unexpected error code. We will continue anyway.
437            PLOG(WARNING) << "waitpid failed";
438        }
439
440        if (WIFEXITED(status)) {
441            return WEXITSTATUS(status);
442        } else {
443            return Error() << "child aborted";
444        }
445    } else if (pid == 0) {
446        /* child, call fs_mgr_mount_all() */
447
448        // So we can always see what fs_mgr_mount_all() does.
449        // Only needed if someone explicitly changes the default log level in their init.rc.
450        android::base::ScopedLogSeverity info(android::base::INFO);
451
452        struct fstab* fstab = fs_mgr_read_fstab(fstabfile);
453        int child_ret = fs_mgr_mount_all(fstab, mount_mode);
454        fs_mgr_free_fstab(fstab);
455        if (child_ret == -1) {
456            PLOG(ERROR) << "fs_mgr_mount_all returned an error";
457        }
458        _exit(child_ret);
459    } else {
460        return Error() << "fork() failed";
461    }
462}
463
464/* Queue event based on fs_mgr return code.
465 *
466 * code: return code of fs_mgr_mount_all
467 *
468 * This function might request a reboot, in which case it will
469 * not return.
470 *
471 * return code is processed based on input code
472 */
473static Result<Success> queue_fs_event(int code) {
474    if (code == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
475        ActionManager::GetInstance().QueueEventTrigger("encrypt");
476        return Success();
477    } else if (code == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
478        property_set("ro.crypto.state", "encrypted");
479        property_set("ro.crypto.type", "block");
480        ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
481        return Success();
482    } else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
483        property_set("ro.crypto.state", "unencrypted");
484        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
485        return Success();
486    } else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
487        property_set("ro.crypto.state", "unsupported");
488        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
489        return Success();
490    } else if (code == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
491        /* Setup a wipe via recovery, and reboot into recovery */
492        PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery.";
493        const std::vector<std::string> options = {"--wipe_data", "--reason=fs_mgr_mount_all" };
494        return reboot_into_recovery(options);
495        /* If reboot worked, there is no return. */
496    } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
497        if (e4crypt_install_keyring()) {
498            return Error() << "e4crypt_install_keyring() failed";
499        }
500        property_set("ro.crypto.state", "encrypted");
501        property_set("ro.crypto.type", "file");
502
503        // Although encrypted, we have device key, so we do not need to
504        // do anything different from the nonencrypted case.
505        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
506        return Success();
507    } else if (code == FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED) {
508        if (e4crypt_install_keyring()) {
509            return Error() << "e4crypt_install_keyring() failed";
510        }
511        property_set("ro.crypto.state", "encrypted");
512        property_set("ro.crypto.type", "file");
513
514        // Although encrypted, vold has already set the device up, so we do not need to
515        // do anything different from the nonencrypted case.
516        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
517        return Success();
518    } else if (code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
519        if (e4crypt_install_keyring()) {
520            return Error() << "e4crypt_install_keyring() failed";
521        }
522        property_set("ro.crypto.state", "encrypted");
523        property_set("ro.crypto.type", "file");
524
525        // Although encrypted, vold has already set the device up, so we do not need to
526        // do anything different from the nonencrypted case.
527        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
528        return Success();
529    } else if (code > 0) {
530        Error() << "fs_mgr_mount_all() returned unexpected error " << code;
531    }
532    /* else ... < 0: error */
533
534    return Error() << "Invalid code: " << code;
535}
536
537/* mount_all <fstab> [ <path> ]* [--<options>]*
538 *
539 * This function might request a reboot, in which case it will
540 * not return.
541 */
542static Result<Success> do_mount_all(const BuiltinArguments& args) {
543    std::size_t na = 0;
544    bool import_rc = true;
545    bool queue_event = true;
546    int mount_mode = MOUNT_MODE_DEFAULT;
547    const char* fstabfile = args[1].c_str();
548    std::size_t path_arg_end = args.size();
549    const char* prop_post_fix = "default";
550
551    for (na = args.size() - 1; na > 1; --na) {
552        if (args[na] == "--early") {
553            path_arg_end = na;
554            queue_event = false;
555            mount_mode = MOUNT_MODE_EARLY;
556            prop_post_fix = "early";
557        } else if (args[na] == "--late") {
558            path_arg_end = na;
559            import_rc = false;
560            mount_mode = MOUNT_MODE_LATE;
561            prop_post_fix = "late";
562        }
563    }
564
565    std::string prop_name = "ro.boottime.init.mount_all."s + prop_post_fix;
566    android::base::Timer t;
567    auto mount_fstab_return_code = mount_fstab(fstabfile, mount_mode);
568    if (!mount_fstab_return_code) {
569        return Error() << "mount_fstab() failed " << mount_fstab_return_code.error();
570    }
571    property_set(prop_name, std::to_string(t.duration().count()));
572
573    if (import_rc) {
574        /* Paths of .rc files are specified at the 2nd argument and beyond */
575        import_late(args.args, 2, path_arg_end);
576    }
577
578    if (queue_event) {
579        /* queue_fs_event will queue event based on mount_fstab return code
580         * and return processed return code*/
581        auto queue_fs_result = queue_fs_event(*mount_fstab_return_code);
582        if (!queue_fs_result) {
583            return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
584        }
585    }
586
587    return Success();
588}
589
590static Result<Success> do_swapon_all(const BuiltinArguments& args) {
591    struct fstab *fstab;
592    int ret;
593
594    fstab = fs_mgr_read_fstab(args[1].c_str());
595    ret = fs_mgr_swapon_all(fstab);
596    fs_mgr_free_fstab(fstab);
597
598    if (ret != 0) return Error() << "fs_mgr_swapon_all() failed";
599    return Success();
600}
601
602static Result<Success> do_setprop(const BuiltinArguments& args) {
603    property_set(args[1], args[2]);
604    return Success();
605}
606
607static Result<Success> do_setrlimit(const BuiltinArguments& args) {
608    auto rlimit = ParseRlimit(args.args);
609    if (!rlimit) return rlimit.error();
610
611    if (setrlimit(rlimit->first, &rlimit->second) == -1) {
612        return ErrnoError() << "setrlimit failed";
613    }
614    return Success();
615}
616
617static Result<Success> do_start(const BuiltinArguments& args) {
618    Service* svc = ServiceList::GetInstance().FindService(args[1]);
619    if (!svc) return Error() << "service " << args[1] << " not found";
620    if (auto result = svc->Start(); !result) {
621        return Error() << "Could not start service: " << result.error();
622    }
623    return Success();
624}
625
626static Result<Success> do_stop(const BuiltinArguments& args) {
627    Service* svc = ServiceList::GetInstance().FindService(args[1]);
628    if (!svc) return Error() << "service " << args[1] << " not found";
629    svc->Stop();
630    return Success();
631}
632
633static Result<Success> do_restart(const BuiltinArguments& args) {
634    Service* svc = ServiceList::GetInstance().FindService(args[1]);
635    if (!svc) return Error() << "service " << args[1] << " not found";
636    svc->Restart();
637    return Success();
638}
639
640static Result<Success> do_trigger(const BuiltinArguments& args) {
641    ActionManager::GetInstance().QueueEventTrigger(args[1]);
642    return Success();
643}
644
645static int MakeSymlink(const std::string& target, const std::string& linkpath) {
646    std::string secontext;
647    // Passing 0 for mode should work.
648    if (SelabelLookupFileContext(linkpath, 0, &secontext) && !secontext.empty()) {
649        setfscreatecon(secontext.c_str());
650    }
651
652    int rc = symlink(target.c_str(), linkpath.c_str());
653
654    if (!secontext.empty()) {
655        int save_errno = errno;
656        setfscreatecon(nullptr);
657        errno = save_errno;
658    }
659
660    return rc;
661}
662
663static Result<Success> do_symlink(const BuiltinArguments& args) {
664    if (MakeSymlink(args[1], args[2]) < 0) {
665        // The symlink builtin is often used to create symlinks for older devices to be backwards
666        // compatible with new paths, therefore we skip reporting this error.
667        if (errno == EEXIST && android::base::GetMinimumLogSeverity() > android::base::DEBUG) {
668            return Success();
669        }
670        return ErrnoError() << "symlink() failed";
671    }
672    return Success();
673}
674
675static Result<Success> do_rm(const BuiltinArguments& args) {
676    if (unlink(args[1].c_str()) < 0) {
677        return ErrnoError() << "unlink() failed";
678    }
679    return Success();
680}
681
682static Result<Success> do_rmdir(const BuiltinArguments& args) {
683    if (rmdir(args[1].c_str()) < 0) {
684        return ErrnoError() << "rmdir() failed";
685    }
686    return Success();
687}
688
689static Result<Success> do_sysclktz(const BuiltinArguments& args) {
690    struct timezone tz = {};
691    if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) {
692        return Error() << "Unable to parse mins_west_of_gmt";
693    }
694
695    if (settimeofday(nullptr, &tz) == -1) {
696        return ErrnoError() << "settimeofday() failed";
697    }
698    return Success();
699}
700
701static Result<Success> do_verity_load_state(const BuiltinArguments& args) {
702    int mode = -1;
703    bool loaded = fs_mgr_load_verity_state(&mode);
704    if (loaded && mode != VERITY_MODE_DEFAULT) {
705        ActionManager::GetInstance().QueueEventTrigger("verity-logging");
706    }
707    if (!loaded) return Error() << "Could not load verity state";
708
709    return Success();
710}
711
712static void verity_update_property(fstab_rec *fstab, const char *mount_point,
713                                   int mode, int status) {
714    property_set("partition."s + mount_point + ".verified", std::to_string(mode));
715}
716
717static Result<Success> do_verity_update_state(const BuiltinArguments& args) {
718    if (!fs_mgr_update_verity_state(verity_update_property)) {
719        return Error() << "fs_mgr_update_verity_state() failed";
720    }
721    return Success();
722}
723
724static Result<Success> do_write(const BuiltinArguments& args) {
725    if (auto result = WriteFile(args[1], args[2]); !result) {
726        return Error() << "Unable to write to file '" << args[1] << "': " << result.error();
727    }
728
729    return Success();
730}
731
732static Result<Success> readahead_file(const std::string& filename, bool fully) {
733    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY)));
734    if (fd == -1) {
735        return ErrnoError() << "Error opening file";
736    }
737    if (posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED)) {
738        return ErrnoError() << "Error posix_fadvise file";
739    }
740    if (readahead(fd, 0, std::numeric_limits<size_t>::max())) {
741        return ErrnoError() << "Error readahead file";
742    }
743    if (fully) {
744        char buf[BUFSIZ];
745        ssize_t n;
746        while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
747        }
748        if (n != 0) {
749            return ErrnoError() << "Error reading file";
750        }
751    }
752    return Success();
753}
754
755static Result<Success> do_readahead(const BuiltinArguments& args) {
756    struct stat sb;
757
758    if (stat(args[1].c_str(), &sb)) {
759        return ErrnoError() << "Error opening " << args[1];
760    }
761
762    bool readfully = false;
763    if (args.size() == 3 && args[2] == "--fully") {
764        readfully = true;
765    }
766    // We will do readahead in a forked process in order not to block init
767    // since it may block while it reads the
768    // filesystem metadata needed to locate the requested blocks.  This
769    // occurs frequently with ext[234] on large files using indirect blocks
770    // instead of extents, giving the appearance that the call blocks until
771    // the requested data has been read.
772    pid_t pid = fork();
773    if (pid == 0) {
774        if (setpriority(PRIO_PROCESS, 0, static_cast<int>(ANDROID_PRIORITY_LOWEST)) != 0) {
775            PLOG(WARNING) << "setpriority failed";
776        }
777        if (android_set_ioprio(0, IoSchedClass_IDLE, 7)) {
778            PLOG(WARNING) << "ioprio_get failed";
779        }
780        android::base::Timer t;
781        if (S_ISREG(sb.st_mode)) {
782            if (auto result = readahead_file(args[1], readfully); !result) {
783                LOG(WARNING) << "Unable to readahead '" << args[1] << "': " << result.error();
784                _exit(EXIT_FAILURE);
785            }
786        } else if (S_ISDIR(sb.st_mode)) {
787            char* paths[] = {const_cast<char*>(args[1].data()), nullptr};
788            std::unique_ptr<FTS, decltype(&fts_close)> fts(
789                fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr), fts_close);
790            if (!fts) {
791                PLOG(ERROR) << "Error opening directory: " << args[1];
792                _exit(EXIT_FAILURE);
793            }
794            // Traverse the entire hierarchy and do readahead
795            for (FTSENT* ftsent = fts_read(fts.get()); ftsent != nullptr;
796                 ftsent = fts_read(fts.get())) {
797                if (ftsent->fts_info & FTS_F) {
798                    const std::string filename = ftsent->fts_accpath;
799                    if (auto result = readahead_file(filename, readfully); !result) {
800                        LOG(WARNING)
801                            << "Unable to readahead '" << filename << "': " << result.error();
802                    }
803                }
804            }
805        }
806        LOG(INFO) << "Readahead " << args[1] << " took " << t << " asynchronously";
807        _exit(0);
808    } else if (pid < 0) {
809        return ErrnoError() << "Fork failed";
810    }
811    return Success();
812}
813
814static Result<Success> do_copy(const BuiltinArguments& args) {
815    auto file_contents = ReadFile(args[1]);
816    if (!file_contents) {
817        return Error() << "Could not read input file '" << args[1] << "': " << file_contents.error();
818    }
819    if (auto result = WriteFile(args[2], *file_contents); !result) {
820        return Error() << "Could not write to output file '" << args[2] << "': " << result.error();
821    }
822
823    return Success();
824}
825
826static Result<Success> do_chown(const BuiltinArguments& args) {
827    auto uid = DecodeUid(args[1]);
828    if (!uid) {
829        return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error();
830    }
831
832    // GID is optional and pushes the index of path out by one if specified.
833    const std::string& path = (args.size() == 4) ? args[3] : args[2];
834    Result<gid_t> gid = -1;
835
836    if (args.size() == 4) {
837        gid = DecodeUid(args[2]);
838        if (!gid) {
839            return Error() << "Unable to decode GID for '" << args[2] << "': " << gid.error();
840        }
841    }
842
843    if (lchown(path.c_str(), *uid, *gid) == -1) {
844        return ErrnoError() << "lchown() failed";
845    }
846
847    return Success();
848}
849
850static mode_t get_mode(const char *s) {
851    mode_t mode = 0;
852    while (*s) {
853        if (*s >= '0' && *s <= '7') {
854            mode = (mode<<3) | (*s-'0');
855        } else {
856            return -1;
857        }
858        s++;
859    }
860    return mode;
861}
862
863static Result<Success> do_chmod(const BuiltinArguments& args) {
864    mode_t mode = get_mode(args[1].c_str());
865    if (fchmodat(AT_FDCWD, args[2].c_str(), mode, AT_SYMLINK_NOFOLLOW) < 0) {
866        return ErrnoError() << "fchmodat() failed";
867    }
868    return Success();
869}
870
871static Result<Success> do_restorecon(const BuiltinArguments& args) {
872    int ret = 0;
873
874    struct flag_type {const char* name; int value;};
875    static const flag_type flags[] = {
876        {"--recursive", SELINUX_ANDROID_RESTORECON_RECURSE},
877        {"--skip-ce", SELINUX_ANDROID_RESTORECON_SKIPCE},
878        {"--cross-filesystems", SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS},
879        {0, 0}
880    };
881
882    int flag = 0;
883
884    bool in_flags = true;
885    for (size_t i = 1; i < args.size(); ++i) {
886        if (android::base::StartsWith(args[i], "--")) {
887            if (!in_flags) {
888                return Error() << "flags must precede paths";
889            }
890            bool found = false;
891            for (size_t j = 0; flags[j].name; ++j) {
892                if (args[i] == flags[j].name) {
893                    flag |= flags[j].value;
894                    found = true;
895                    break;
896                }
897            }
898            if (!found) {
899                return Error() << "bad flag " << args[i];
900            }
901        } else {
902            in_flags = false;
903            if (selinux_android_restorecon(args[i].c_str(), flag) < 0) {
904                ret = errno;
905            }
906        }
907    }
908
909    if (ret) return ErrnoError() << "selinux_android_restorecon() failed";
910    return Success();
911}
912
913static Result<Success> do_restorecon_recursive(const BuiltinArguments& args) {
914    std::vector<std::string> non_const_args(args.args);
915    non_const_args.insert(std::next(non_const_args.begin()), "--recursive");
916    return do_restorecon({std::move(non_const_args), args.context});
917}
918
919static Result<Success> do_loglevel(const BuiltinArguments& args) {
920    // TODO: support names instead/as well?
921    int log_level = -1;
922    android::base::ParseInt(args[1], &log_level);
923    android::base::LogSeverity severity;
924    switch (log_level) {
925        case 7: severity = android::base::DEBUG; break;
926        case 6: severity = android::base::INFO; break;
927        case 5:
928        case 4: severity = android::base::WARNING; break;
929        case 3: severity = android::base::ERROR; break;
930        case 2:
931        case 1:
932        case 0: severity = android::base::FATAL; break;
933        default:
934            return Error() << "invalid log level " << log_level;
935    }
936    android::base::SetMinimumLogSeverity(severity);
937    return Success();
938}
939
940static Result<Success> do_load_persist_props(const BuiltinArguments& args) {
941    load_persist_props();
942    return Success();
943}
944
945static Result<Success> do_load_system_props(const BuiltinArguments& args) {
946    load_system_props();
947    return Success();
948}
949
950static Result<Success> do_wait(const BuiltinArguments& args) {
951    auto timeout = kCommandRetryTimeout;
952    if (args.size() == 3) {
953        int timeout_int;
954        if (!android::base::ParseInt(args[2], &timeout_int)) {
955            return Error() << "failed to parse timeout";
956        }
957        timeout = std::chrono::seconds(timeout_int);
958    }
959
960    if (wait_for_file(args[1].c_str(), timeout) != 0) {
961        return Error() << "wait_for_file() failed";
962    }
963
964    return Success();
965}
966
967static Result<Success> do_wait_for_prop(const BuiltinArguments& args) {
968    const char* name = args[1].c_str();
969    const char* value = args[2].c_str();
970    size_t value_len = strlen(value);
971
972    if (!IsLegalPropertyName(name)) {
973        return Error() << "IsLegalPropertyName(" << name << ") failed";
974    }
975    if (value_len >= PROP_VALUE_MAX) {
976        return Error() << "value too long";
977    }
978    if (!start_waiting_for_property(name, value)) {
979        return Error() << "already waiting for a property";
980    }
981    return Success();
982}
983
984static bool is_file_crypto() {
985    return android::base::GetProperty("ro.crypto.type", "") == "file";
986}
987
988static Result<Success> ExecWithRebootOnFailure(const std::string& reboot_reason,
989                                               const BuiltinArguments& args) {
990    auto service = Service::MakeTemporaryOneshotService(args.args);
991    if (!service) {
992        return Error() << "Could not create exec service";
993    }
994    service->AddReapCallback([reboot_reason](const siginfo_t& siginfo) {
995        if (siginfo.si_code != CLD_EXITED || siginfo.si_status != 0) {
996            if (e4crypt_is_native()) {
997                LOG(ERROR) << "Rebooting into recovery, reason: " << reboot_reason;
998                reboot_into_recovery({"--prompt_and_wipe_data", "--reason="s + reboot_reason});
999            } else {
1000                LOG(ERROR) << "Failure (reboot suppressed): " << reboot_reason;
1001            }
1002        }
1003    });
1004    if (auto result = service->ExecStart(); !result) {
1005        return Error() << "Could not start exec service: " << result.error();
1006    }
1007    ServiceList::GetInstance().AddService(std::move(service));
1008    return Success();
1009}
1010
1011static Result<Success> do_installkey(const BuiltinArguments& args) {
1012    if (!is_file_crypto()) return Success();
1013
1014    auto unencrypted_dir = args[1] + e4crypt_unencrypted_folder;
1015    if (!make_dir(unencrypted_dir, 0700) && errno != EEXIST) {
1016        return ErrnoError() << "Failed to create " << unencrypted_dir;
1017    }
1018    return ExecWithRebootOnFailure(
1019        "enablefilecrypto_failed",
1020        {{"exec", "/system/bin/vdc", "--wait", "cryptfs", "enablefilecrypto"}, args.context});
1021}
1022
1023static Result<Success> do_init_user0(const BuiltinArguments& args) {
1024    return ExecWithRebootOnFailure(
1025        "init_user0_failed",
1026        {{"exec", "/system/bin/vdc", "--wait", "cryptfs", "init_user0"}, args.context});
1027}
1028
1029// Builtin-function-map start
1030const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
1031    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
1032    // clang-format off
1033    static const Map builtin_functions = {
1034        {"bootchart",               {1,     1,    {false,  do_bootchart}}},
1035        {"chmod",                   {2,     2,    {true,   do_chmod}}},
1036        {"chown",                   {2,     3,    {true,   do_chown}}},
1037        {"class_reset",             {1,     1,    {false,  do_class_reset}}},
1038        {"class_restart",           {1,     1,    {false,  do_class_restart}}},
1039        {"class_start",             {1,     1,    {false,  do_class_start}}},
1040        {"class_stop",              {1,     1,    {false,  do_class_stop}}},
1041        {"copy",                    {2,     2,    {true,   do_copy}}},
1042        {"domainname",              {1,     1,    {true,   do_domainname}}},
1043        {"enable",                  {1,     1,    {false,  do_enable}}},
1044        {"exec",                    {1,     kMax, {false,  do_exec}}},
1045        {"exec_background",         {1,     kMax, {false,  do_exec_background}}},
1046        {"exec_start",              {1,     1,    {false,  do_exec_start}}},
1047        {"export",                  {2,     2,    {false,  do_export}}},
1048        {"hostname",                {1,     1,    {true,   do_hostname}}},
1049        {"ifup",                    {1,     1,    {true,   do_ifup}}},
1050        {"init_user0",              {0,     0,    {false,  do_init_user0}}},
1051        {"insmod",                  {1,     kMax, {true,   do_insmod}}},
1052        {"installkey",              {1,     1,    {false,  do_installkey}}},
1053        {"load_persist_props",      {0,     0,    {false,  do_load_persist_props}}},
1054        {"load_system_props",       {0,     0,    {false,  do_load_system_props}}},
1055        {"loglevel",                {1,     1,    {false,  do_loglevel}}},
1056        {"mkdir",                   {1,     4,    {true,   do_mkdir}}},
1057        // TODO: Do mount operations in vendor_init.
1058        // mount_all is currently too complex to run in vendor_init as it queues action triggers,
1059        // imports rc scripts, etc.  It should be simplified and run in vendor_init context.
1060        // mount and umount are run in the same context as mount_all for symmetry.
1061        {"mount_all",               {1,     kMax, {false,  do_mount_all}}},
1062        {"mount",                   {3,     kMax, {false,  do_mount}}},
1063        {"umount",                  {1,     1,    {false,  do_umount}}},
1064        {"readahead",               {1,     2,    {true,   do_readahead}}},
1065        {"restart",                 {1,     1,    {false,  do_restart}}},
1066        {"restorecon",              {1,     kMax, {true,   do_restorecon}}},
1067        {"restorecon_recursive",    {1,     kMax, {true,   do_restorecon_recursive}}},
1068        {"rm",                      {1,     1,    {true,   do_rm}}},
1069        {"rmdir",                   {1,     1,    {true,   do_rmdir}}},
1070        {"setprop",                 {2,     2,    {true,   do_setprop}}},
1071        {"setrlimit",               {3,     3,    {false,  do_setrlimit}}},
1072        {"start",                   {1,     1,    {false,  do_start}}},
1073        {"stop",                    {1,     1,    {false,  do_stop}}},
1074        {"swapon_all",              {1,     1,    {false,  do_swapon_all}}},
1075        {"symlink",                 {2,     2,    {true,   do_symlink}}},
1076        {"sysclktz",                {1,     1,    {false,  do_sysclktz}}},
1077        {"trigger",                 {1,     1,    {false,  do_trigger}}},
1078        {"verity_load_state",       {0,     0,    {false,  do_verity_load_state}}},
1079        {"verity_update_state",     {0,     0,    {false,  do_verity_update_state}}},
1080        {"wait",                    {1,     2,    {true,   do_wait}}},
1081        {"wait_for_prop",           {2,     2,    {false,  do_wait_for_prop}}},
1082        {"write",                   {2,     2,    {true,   do_write}}},
1083    };
1084    // clang-format on
1085    return builtin_functions;
1086}
1087// Builtin-function-map end
1088
1089}  // namespace init
1090}  // namespace android
1091