Tianjie Xu | 1536db8 | 2019-05-14 10:54:43 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2019 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 "updater/updater_runtime.h" |
| 18 | |
| 19 | #include <string.h> |
| 20 | #include <sys/mount.h> |
| 21 | #include <sys/stat.h> |
| 22 | #include <sys/wait.h> |
| 23 | #include <unistd.h> |
| 24 | |
| 25 | #include <android-base/file.h> |
| 26 | #include <android-base/logging.h> |
| 27 | #include <android-base/properties.h> |
| 28 | #include <android-base/strings.h> |
| 29 | #include <android-base/unique_fd.h> |
| 30 | #include <ext4_utils/wipe.h> |
| 31 | #include <selinux/label.h> |
| 32 | #include <tune2fs.h> |
| 33 | |
Tao Bao | d628cfc | 2019-10-01 12:08:33 -0700 | [diff] [blame] | 34 | #include "mounts.h" |
Tianjie Xu | 1536db8 | 2019-05-14 10:54:43 -0700 | [diff] [blame] | 35 | #include "otautil/sysutil.h" |
| 36 | |
| 37 | std::string UpdaterRuntime::GetProperty(const std::string_view key, |
| 38 | const std::string_view default_value) const { |
| 39 | return android::base::GetProperty(std::string(key), std::string(default_value)); |
| 40 | } |
| 41 | |
| 42 | std::string UpdaterRuntime::FindBlockDeviceName(const std::string_view name) const { |
| 43 | return std::string(name); |
| 44 | } |
| 45 | |
Hongguang Chen | 586565f | 2020-03-15 21:09:21 -0700 | [diff] [blame] | 46 | static struct { |
| 47 | const char* name; |
| 48 | unsigned flag; |
| 49 | } mount_flags_list[] = { |
| 50 | { "noatime", MS_NOATIME }, |
| 51 | { "noexec", MS_NOEXEC }, |
| 52 | { "nosuid", MS_NOSUID }, |
| 53 | { "nodev", MS_NODEV }, |
| 54 | { "nodiratime", MS_NODIRATIME }, |
| 55 | { "ro", MS_RDONLY }, |
| 56 | { "rw", 0 }, |
| 57 | { "remount", MS_REMOUNT }, |
| 58 | { "bind", MS_BIND }, |
| 59 | { "rec", MS_REC }, |
| 60 | { "unbindable", MS_UNBINDABLE }, |
| 61 | { "private", MS_PRIVATE }, |
| 62 | { "slave", MS_SLAVE }, |
| 63 | { "shared", MS_SHARED }, |
| 64 | { "defaults", 0 }, |
| 65 | { 0, 0 }, |
| 66 | }; |
| 67 | |
| 68 | static bool setMountFlag(const std::string& flag, unsigned* mount_flags) { |
| 69 | for (const auto& [name, value] : mount_flags_list) { |
| 70 | if (flag == name) { |
| 71 | *mount_flags |= value; |
| 72 | return true; |
| 73 | } |
| 74 | } |
| 75 | return false; |
| 76 | } |
| 77 | |
| 78 | static bool parseMountFlags(const std::string& flags, unsigned* mount_flags, |
| 79 | std::string* fs_options) { |
| 80 | bool is_flag_set = false; |
| 81 | std::vector<std::string> flag_list; |
| 82 | for (const auto& flag : android::base::Split(flags, ",")) { |
| 83 | if (!setMountFlag(flag, mount_flags)) { |
| 84 | // Unknown flag, so it must be a filesystem specific option. |
| 85 | flag_list.push_back(flag); |
| 86 | } else { |
| 87 | is_flag_set = true; |
| 88 | } |
| 89 | } |
| 90 | *fs_options = android::base::Join(flag_list, ','); |
| 91 | return is_flag_set; |
| 92 | } |
| 93 | |
Tianjie Xu | 1536db8 | 2019-05-14 10:54:43 -0700 | [diff] [blame] | 94 | int UpdaterRuntime::Mount(const std::string_view location, const std::string_view mount_point, |
| 95 | const std::string_view fs_type, const std::string_view mount_options) { |
| 96 | std::string mount_point_string(mount_point); |
Hongguang Chen | 586565f | 2020-03-15 21:09:21 -0700 | [diff] [blame] | 97 | std::string mount_options_string(mount_options); |
Tianjie Xu | 1536db8 | 2019-05-14 10:54:43 -0700 | [diff] [blame] | 98 | char* secontext = nullptr; |
Hongguang Chen | 586565f | 2020-03-15 21:09:21 -0700 | [diff] [blame] | 99 | unsigned mount_flags = 0; |
| 100 | std::string fs_options; |
| 101 | |
Tianjie Xu | 1536db8 | 2019-05-14 10:54:43 -0700 | [diff] [blame] | 102 | if (sehandle_) { |
| 103 | selabel_lookup(sehandle_, &secontext, mount_point_string.c_str(), 0755); |
| 104 | setfscreatecon(secontext); |
| 105 | } |
| 106 | |
| 107 | mkdir(mount_point_string.c_str(), 0755); |
| 108 | |
| 109 | if (secontext) { |
| 110 | freecon(secontext); |
| 111 | setfscreatecon(nullptr); |
| 112 | } |
| 113 | |
Hongguang Chen | 586565f | 2020-03-15 21:09:21 -0700 | [diff] [blame] | 114 | if (!parseMountFlags(mount_options_string, &mount_flags, &fs_options)) { |
| 115 | // Fall back to default |
| 116 | mount_flags = MS_NOATIME | MS_NODEV | MS_NODIRATIME; |
| 117 | } |
| 118 | |
Tianjie Xu | 1536db8 | 2019-05-14 10:54:43 -0700 | [diff] [blame] | 119 | return mount(std::string(location).c_str(), mount_point_string.c_str(), |
Hongguang Chen | 586565f | 2020-03-15 21:09:21 -0700 | [diff] [blame] | 120 | std::string(fs_type).c_str(), mount_flags, fs_options.c_str()); |
Tianjie Xu | 1536db8 | 2019-05-14 10:54:43 -0700 | [diff] [blame] | 121 | } |
| 122 | |
| 123 | bool UpdaterRuntime::IsMounted(const std::string_view mount_point) const { |
| 124 | scan_mounted_volumes(); |
| 125 | MountedVolume* vol = find_mounted_volume_by_mount_point(std::string(mount_point).c_str()); |
| 126 | return vol != nullptr; |
| 127 | } |
| 128 | |
| 129 | std::pair<bool, int> UpdaterRuntime::Unmount(const std::string_view mount_point) { |
| 130 | scan_mounted_volumes(); |
| 131 | MountedVolume* vol = find_mounted_volume_by_mount_point(std::string(mount_point).c_str()); |
| 132 | if (vol == nullptr) { |
| 133 | return { false, -1 }; |
| 134 | } |
| 135 | |
| 136 | int ret = unmount_mounted_volume(vol); |
| 137 | return { true, ret }; |
| 138 | } |
| 139 | |
| 140 | bool UpdaterRuntime::ReadFileToString(const std::string_view filename, std::string* content) const { |
| 141 | return android::base::ReadFileToString(std::string(filename), content); |
| 142 | } |
| 143 | |
| 144 | bool UpdaterRuntime::WriteStringToFile(const std::string_view content, |
| 145 | const std::string_view filename) const { |
| 146 | return android::base::WriteStringToFile(std::string(content), std::string(filename)); |
| 147 | } |
| 148 | |
| 149 | int UpdaterRuntime::WipeBlockDevice(const std::string_view filename, size_t len) const { |
| 150 | android::base::unique_fd fd(open(std::string(filename).c_str(), O_WRONLY)); |
| 151 | if (fd == -1) { |
| 152 | PLOG(ERROR) << "Failed to open " << filename; |
| 153 | return false; |
| 154 | } |
| 155 | // The wipe_block_device function in ext4_utils returns 0 on success and 1 for failure. |
| 156 | return wipe_block_device(fd, len); |
| 157 | } |
| 158 | |
| 159 | int UpdaterRuntime::RunProgram(const std::vector<std::string>& args, bool is_vfork) const { |
| 160 | CHECK(!args.empty()); |
| 161 | auto argv = StringVectorToNullTerminatedArray(args); |
| 162 | LOG(INFO) << "about to run program [" << args[0] << "] with " << argv.size() << " args"; |
| 163 | |
| 164 | pid_t child = is_vfork ? vfork() : fork(); |
| 165 | if (child == 0) { |
| 166 | execv(argv[0], argv.data()); |
| 167 | PLOG(ERROR) << "run_program: execv failed"; |
| 168 | _exit(EXIT_FAILURE); |
| 169 | } |
| 170 | |
| 171 | int status; |
| 172 | waitpid(child, &status, 0); |
| 173 | if (WIFEXITED(status)) { |
| 174 | if (WEXITSTATUS(status) != 0) { |
| 175 | LOG(ERROR) << "run_program: child exited with status " << WEXITSTATUS(status); |
| 176 | } |
| 177 | } else if (WIFSIGNALED(status)) { |
| 178 | LOG(ERROR) << "run_program: child terminated by signal " << WTERMSIG(status); |
| 179 | } |
| 180 | |
| 181 | return status; |
| 182 | } |
| 183 | |
| 184 | int UpdaterRuntime::Tune2Fs(const std::vector<std::string>& args) const { |
| 185 | auto tune2fs_args = StringVectorToNullTerminatedArray(args); |
| 186 | // tune2fs changes the filesystem parameters on an ext2 filesystem; it returns 0 on success. |
| 187 | return tune2fs_main(tune2fs_args.size() - 1, tune2fs_args.data()); |
| 188 | } |