1 /*
2 * Copyright (C) 2021 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 "cpio.h"
18
19 #include <sys/types.h>
20 #include <sys/wait.h>
21
22 #include <vector>
23
24 #include <android-base/logging.h>
25 #include <android-base/strings.h>
26
27 using android::base::ErrnoError;
28 using android::base::Error;
29 using android::base::Join;
30
31 namespace android {
32
33 namespace {
ToCStringArray(std::vector<std::string> * args)34 std::vector<char*> ToCStringArray(std::vector<std::string>* args) {
35 std::vector<char*> ret;
36 ret.reserve(args->size() + 1);
37 for (auto& arg : *args) {
38 ret.push_back(arg.data());
39 }
40 ret.push_back(nullptr);
41 return ret;
42 }
43
44 // Wrapper of fork() / execvp() / wait() paradigm. Child process chdir() into
45 // the directory before execv()
Exec(std::vector<std::string> * args,std::string_view working_directory)46 android::base::Result<void> Exec(std::vector<std::string>* args,
47 std::string_view working_directory) {
48 pid_t pid = fork();
49 if (pid == -1)
50 return ErrnoError() << "Unable to execute `" << Join(*args, " ")
51 << "`: failed to fork";
52 if (pid == 0) {
53 // child process
54 CHECK(0 == chdir(working_directory.data())) << strerror(errno);
55 // execvp needs char*, so copy the strings to heap.
56 auto c_args = ToCStringArray(args);
57 (void)close(STDIN_FILENO);
58 (void)execvp(c_args[0], c_args.data());
59 // execvp only returns on error.
60 PLOG(FATAL) << "Unable to execute `" << Join(*args, " ")
61 << "`: execvp returns";
62 }
63 // parent process
64 int status;
65 if (pid != waitpid(pid, &status, 0))
66 return ErrnoError() << "Unable to execute `" << Join(*args, " ")
67 << "`; failed to waitpid(" << pid << ")";
68 if (!WIFEXITED(status))
69 return Error() << "Unable to execute `" << Join(*args, " ")
70 << "`: not exited normally";
71 if (0 != WEXITSTATUS(status))
72 return Error() << "Unable to execute `" << Join(*args, " ")
73 << "`: exit status " << WEXITSTATUS(status);
74 return {};
75 }
76
77 } // namespace
78
79 // Extract CPIO archive at |archive_path| to a temporary directory.
CpioExtract(std::string_view archive_path)80 android::base::Result<std::unique_ptr<TemporaryDir>> CpioExtract(
81 std::string_view archive_path) {
82 std::vector<std::string> args{"cpio", "-i", "-F", archive_path.data()};
83
84 auto extracted_ramdisk = std::make_unique<TemporaryDir>();
85 auto res = Exec(&args, extracted_ramdisk->path);
86 if (!res.ok()) return res.error();
87 return extracted_ramdisk;
88 }
89
90 } // namespace android
91