1 /* 2 * Copyright (C) 2016 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 #define LOG_TAG "dumpstate" 18 19 #include "DumpstateUtil.h" 20 21 #include <dirent.h> 22 #include <fcntl.h> 23 #include <sys/prctl.h> 24 #include <sys/wait.h> 25 #include <unistd.h> 26 27 #include <vector> 28 29 #include <android-base/file.h> 30 #include <android-base/properties.h> 31 #include <android-base/stringprintf.h> 32 #include <android-base/strings.h> 33 #include <android-base/unique_fd.h> 34 #include <log/log.h> 35 36 #include "DumpstateInternal.h" 37 38 namespace android { 39 namespace os { 40 namespace dumpstate { 41 42 namespace { 43 44 static constexpr const char* kSuPath = "/system/xbin/su"; 45 46 static bool waitpid_with_timeout(pid_t pid, int timeout_ms, int* status) { 47 sigset_t child_mask, old_mask; 48 sigemptyset(&child_mask); 49 sigaddset(&child_mask, SIGCHLD); 50 51 if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) { 52 printf("*** sigprocmask failed: %s\n", strerror(errno)); 53 return false; 54 } 55 56 timespec ts; 57 ts.tv_sec = MSEC_TO_SEC(timeout_ms); 58 ts.tv_nsec = (timeout_ms % 1000) * 1000000; 59 int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, NULL, &ts)); 60 int saved_errno = errno; 61 62 // Set the signals back the way they were. 63 if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) { 64 printf("*** sigprocmask failed: %s\n", strerror(errno)); 65 if (ret == 0) { 66 return false; 67 } 68 } 69 if (ret == -1) { 70 errno = saved_errno; 71 if (errno == EAGAIN) { 72 errno = ETIMEDOUT; 73 } else { 74 printf("*** sigtimedwait failed: %s\n", strerror(errno)); 75 } 76 return false; 77 } 78 79 pid_t child_pid = waitpid(pid, status, WNOHANG); 80 if (child_pid != pid) { 81 if (child_pid != -1) { 82 printf("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid); 83 } else { 84 printf("*** waitpid failed: %s\n", strerror(errno)); 85 } 86 return false; 87 } 88 return true; 89 } 90 } // unnamed namespace 91 92 CommandOptions CommandOptions::DEFAULT = CommandOptions::WithTimeout(10).Build(); 93 CommandOptions CommandOptions::AS_ROOT = CommandOptions::WithTimeout(10).AsRoot().Build(); 94 95 CommandOptions::CommandOptionsBuilder::CommandOptionsBuilder(int64_t timeout_ms) : values(timeout_ms) { 96 } 97 98 CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::Always() { 99 values.always_ = true; 100 return *this; 101 } 102 103 CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRoot() { 104 values.account_mode_ = SU_ROOT; 105 return *this; 106 } 107 108 CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRootIfAvailable() { 109 if (!PropertiesHelper::IsUserBuild()) 110 values.account_mode_ = SU_ROOT; 111 return *this; 112 } 113 114 CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::DropRoot() { 115 values.account_mode_ = DROP_ROOT; 116 return *this; 117 } 118 119 CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::RedirectStderr() { 120 values.output_mode_ = REDIRECT_TO_STDERR; 121 return *this; 122 } 123 124 CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::Log( 125 const std::string& message) { 126 values.logging_message_ = message; 127 return *this; 128 } 129 130 CommandOptions CommandOptions::CommandOptionsBuilder::Build() { 131 return CommandOptions(values); 132 } 133 134 CommandOptions::CommandOptionsValues::CommandOptionsValues(int64_t timeout_ms) 135 : timeout_ms_(timeout_ms), 136 always_(false), 137 account_mode_(DONT_DROP_ROOT), 138 output_mode_(NORMAL_OUTPUT), 139 logging_message_("") { 140 } 141 142 CommandOptions::CommandOptions(const CommandOptionsValues& values) : values(values) { 143 } 144 145 int64_t CommandOptions::Timeout() const { 146 return MSEC_TO_SEC(values.timeout_ms_); 147 } 148 149 int64_t CommandOptions::TimeoutInMs() const { 150 return values.timeout_ms_; 151 } 152 153 bool CommandOptions::Always() const { 154 return values.always_; 155 } 156 157 PrivilegeMode CommandOptions::PrivilegeMode() const { 158 return values.account_mode_; 159 } 160 161 OutputMode CommandOptions::OutputMode() const { 162 return values.output_mode_; 163 } 164 165 std::string CommandOptions::LoggingMessage() const { 166 return values.logging_message_; 167 } 168 169 CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeout(int64_t timeout_sec) { 170 return CommandOptions::CommandOptionsBuilder(SEC_TO_MSEC(timeout_sec)); 171 } 172 173 CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeoutInMs(int64_t timeout_ms) { 174 return CommandOptions::CommandOptionsBuilder(timeout_ms); 175 } 176 177 std::string PropertiesHelper::build_type_ = ""; 178 int PropertiesHelper::dry_run_ = -1; 179 180 bool PropertiesHelper::IsUserBuild() { 181 if (build_type_.empty()) { 182 build_type_ = android::base::GetProperty("ro.build.type", "user"); 183 } 184 return "user" == build_type_; 185 } 186 187 bool PropertiesHelper::IsDryRun() { 188 if (dry_run_ == -1) { 189 dry_run_ = android::base::GetBoolProperty("dumpstate.dry_run", false) ? 1 : 0; 190 } 191 return dry_run_ == 1; 192 } 193 194 int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) { 195 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC))); 196 if (fd.get() < 0) { 197 int err = errno; 198 if (title.empty()) { 199 dprintf(out_fd, "*** Error dumping %s: %s\n", path.c_str(), strerror(err)); 200 } else { 201 dprintf(out_fd, "*** Error dumping %s (%s): %s\n", path.c_str(), title.c_str(), 202 strerror(err)); 203 } 204 fsync(out_fd); 205 return -1; 206 } 207 return DumpFileFromFdToFd(title, path, fd.get(), out_fd, PropertiesHelper::IsDryRun()); 208 } 209 210 int RunCommandToFd(int fd, const std::string& title, const std::vector<std::string>& full_command, 211 const CommandOptions& options) { 212 if (full_command.empty()) { 213 MYLOGE("No arguments on RunCommandToFd(%s)\n", title.c_str()); 214 return -1; 215 } 216 217 int size = full_command.size() + 1; // null terminated 218 int starting_index = 0; 219 if (options.PrivilegeMode() == SU_ROOT) { 220 starting_index = 2; // "su" "root" 221 size += starting_index; 222 } 223 224 std::vector<const char*> args; 225 args.resize(size); 226 227 std::string command_string; 228 if (options.PrivilegeMode() == SU_ROOT) { 229 args[0] = kSuPath; 230 command_string += kSuPath; 231 args[1] = "root"; 232 command_string += " root "; 233 } 234 for (size_t i = 0; i < full_command.size(); i++) { 235 args[i + starting_index] = full_command[i].data(); 236 command_string += args[i + starting_index]; 237 if (i != full_command.size() - 1) { 238 command_string += " "; 239 } 240 } 241 args[size - 1] = nullptr; 242 243 const char* command = command_string.c_str(); 244 245 if (options.PrivilegeMode() == SU_ROOT && PropertiesHelper::IsUserBuild()) { 246 dprintf(fd, "Skipping '%s' on user build.\n", command); 247 return 0; 248 } 249 250 if (!title.empty()) { 251 dprintf(fd, "------ %s (%s) ------\n", title.c_str(), command); 252 fsync(fd); 253 } 254 255 const std::string& logging_message = options.LoggingMessage(); 256 if (!logging_message.empty()) { 257 MYLOGI(logging_message.c_str(), command_string.c_str()); 258 } 259 260 bool silent = (options.OutputMode() == REDIRECT_TO_STDERR); 261 bool redirecting_to_fd = STDOUT_FILENO != fd; 262 263 if (PropertiesHelper::IsDryRun() && !options.Always()) { 264 if (!title.empty()) { 265 dprintf(fd, "\t(skipped on dry run)\n"); 266 } else if (redirecting_to_fd) { 267 // There is no title, but we should still print a dry-run message 268 dprintf(fd, "%s: skipped on dry run\n", command_string.c_str()); 269 } 270 fsync(fd); 271 return 0; 272 } 273 274 const char* path = args[0]; 275 276 uint64_t start = Nanotime(); 277 pid_t pid = fork(); 278 279 /* handle error case */ 280 if (pid < 0) { 281 if (!silent) dprintf(fd, "*** fork: %s\n", strerror(errno)); 282 MYLOGE("*** fork: %s\n", strerror(errno)); 283 return pid; 284 } 285 286 /* handle child case */ 287 if (pid == 0) { 288 if (options.PrivilegeMode() == DROP_ROOT && !DropRootUser()) { 289 if (!silent) { 290 dprintf(fd, "*** failed to drop root before running %s: %s\n", command, 291 strerror(errno)); 292 } 293 MYLOGE("*** could not drop root before running %s: %s\n", command, strerror(errno)); 294 return -1; 295 } 296 297 if (silent) { 298 // Redirects stdout to stderr 299 TEMP_FAILURE_RETRY(dup2(STDERR_FILENO, STDOUT_FILENO)); 300 } else if (redirecting_to_fd) { 301 // Redirect stdout to fd 302 TEMP_FAILURE_RETRY(dup2(fd, STDOUT_FILENO)); 303 close(fd); 304 } 305 306 /* make sure the child dies when dumpstate dies */ 307 prctl(PR_SET_PDEATHSIG, SIGKILL); 308 309 /* just ignore SIGPIPE, will go down with parent's */ 310 struct sigaction sigact; 311 memset(&sigact, 0, sizeof(sigact)); 312 sigact.sa_handler = SIG_IGN; 313 sigaction(SIGPIPE, &sigact, NULL); 314 315 execvp(path, (char**)args.data()); 316 // execvp's result will be handled after waitpid_with_timeout() below, but 317 // if it failed, it's safer to exit dumpstate. 318 MYLOGD("execvp on command '%s' failed (error: %s)\n", command, strerror(errno)); 319 // Must call _exit (instead of exit), otherwise it will corrupt the zip 320 // file. 321 _exit(EXIT_FAILURE); 322 } 323 324 /* handle parent case */ 325 int status; 326 bool ret = waitpid_with_timeout(pid, options.TimeoutInMs(), &status); 327 fsync(fd); 328 329 uint64_t elapsed = Nanotime() - start; 330 if (!ret) { 331 if (errno == ETIMEDOUT) { 332 if (!silent) 333 dprintf(fd, "*** command '%s' timed out after %.3fs (killing pid %d)\n", command, 334 static_cast<float>(elapsed) / NANOS_PER_SEC, pid); 335 MYLOGE("*** command '%s' timed out after %.3fs (killing pid %d)\n", command, 336 static_cast<float>(elapsed) / NANOS_PER_SEC, pid); 337 } else { 338 if (!silent) 339 dprintf(fd, "*** command '%s': Error after %.4fs (killing pid %d)\n", command, 340 static_cast<float>(elapsed) / NANOS_PER_SEC, pid); 341 MYLOGE("command '%s': Error after %.4fs (killing pid %d)\n", command, 342 static_cast<float>(elapsed) / NANOS_PER_SEC, pid); 343 } 344 kill(pid, SIGTERM); 345 if (!waitpid_with_timeout(pid, 5000, nullptr)) { 346 kill(pid, SIGKILL); 347 if (!waitpid_with_timeout(pid, 5000, nullptr)) { 348 if (!silent) 349 dprintf(fd, "could not kill command '%s' (pid %d) even with SIGKILL.\n", 350 command, pid); 351 MYLOGE("could not kill command '%s' (pid %d) even with SIGKILL.\n", command, pid); 352 } 353 } 354 return -1; 355 } 356 357 if (WIFSIGNALED(status)) { 358 if (!silent) 359 dprintf(fd, "*** command '%s' failed: killed by signal %d\n", command, WTERMSIG(status)); 360 MYLOGE("*** command '%s' failed: killed by signal %d\n", command, WTERMSIG(status)); 361 } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) { 362 status = WEXITSTATUS(status); 363 if (!silent) dprintf(fd, "*** command '%s' failed: exit code %d\n", command, status); 364 MYLOGE("*** command '%s' failed: exit code %d\n", command, status); 365 } 366 367 return status; 368 } 369 370 int GetPidByName(const std::string& ps_name) { 371 DIR* proc_dir; 372 struct dirent* ps; 373 unsigned int pid; 374 std::string cmdline; 375 376 if (!(proc_dir = opendir("/proc"))) { 377 MYLOGE("Can't open /proc\n"); 378 return -1; 379 } 380 381 while ((ps = readdir(proc_dir))) { 382 if (!(pid = atoi(ps->d_name))) { 383 continue; 384 } 385 android::base::ReadFileToString("/proc/" + std::string(ps->d_name) + "/cmdline", &cmdline); 386 if (cmdline.find(ps_name) == std::string::npos) { 387 continue; 388 } else { 389 closedir(proc_dir); 390 return pid; 391 } 392 } 393 MYLOGE("can't find the pid\n"); 394 closedir(proc_dir); 395 return -1; 396 } 397 398 } // namespace dumpstate 399 } // namespace os 400 } // namespace android 401