blob: 291486a34b2408815a192022f6a9865f1e8aff2a [file] [edit]
//
// Copyright (C) 2025 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.
//
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/result.h>
#include <android-base/unique_fd.h>
#include <apex_file.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "erofs.h"
#include "ext4.h"
#include "list.h"
using android::apex::ApexFile;
using android::base::ErrnoError;
using android::base::Error;
using android::base::Result;
using android::base::unique_fd;
using namespace std::string_literals;
struct Args {
std::string apex_file;
bool show_security_context;
};
Result<void> PrintList(Args args) {
auto apex_file = OR_RETURN(ApexFile::Open(args.apex_file));
// If the apex is .capex, decompress it first.
TemporaryDir temp_dir;
if (apex_file.IsCompressed()) {
auto original_apex_path = std::string(temp_dir.path) + "/original.apex";
OR_RETURN(apex_file.Decompress(original_apex_path));
apex_file = OR_RETURN(ApexFile::Open(original_apex_path));
}
if (!apex_file.GetFsType().has_value())
return Error() << "Invalid apex: no fs type";
if (!apex_file.GetImageSize().has_value())
return Error() << "Invalid apex: no image size";
if (!apex_file.GetImageOffset().has_value())
return Error() << "Invalid apex: no image offset";
std::map lister = {
std::pair{"ext4"s, &Ext4List},
std::pair{"erofs"s, &ErofsList},
};
auto fs_type = *apex_file.GetFsType();
if (!lister.contains(fs_type)) {
return Error() << "Invalid filesystem type: " << fs_type;
}
// Extract apex_payload.img
TemporaryFile temp_file;
{
unique_fd src(open(apex_file.GetPath().c_str(), O_RDONLY | O_CLOEXEC));
off_t offset = *apex_file.GetImageOffset();
size_t size = *apex_file.GetImageSize();
if (sendfile(temp_file.fd, src, &offset, size) < 0) {
return ErrnoError()
<< "Failed to create a temporary file for apex payload";
}
}
for (const auto& entry : OR_RETURN(lister[fs_type](temp_file.path))) {
std::cout << entry.path;
if (args.show_security_context) {
std::cout << " " << entry.security_context;
}
std::cout << "\n";
}
return {};
}
Result<Args> ParseArgs(std::vector<std::string> args) {
if (args.size() == 2) {
return Args{
.apex_file = args[1],
.show_security_context = false,
};
}
if (args.size() == 3 && args[1] == "-Z") {
return Args{
.apex_file = args[2],
.show_security_context = true,
};
}
return Error() << "Invalid args\n"
<< "usage: " << args[0] << " [-Z] APEX_FILE\n";
}
Result<void> TryMain(std::vector<std::string> args) {
auto parse_args = OR_RETURN(ParseArgs(args));
OR_RETURN(PrintList(parse_args));
return {};
}
int main(int argc, char** argv) {
android::base::SetMinimumLogSeverity(android::base::ERROR);
if (auto st = TryMain(std::vector<std::string>{argv, argv + argc});
!st.ok()) {
std::cerr << st.error() << "\n";
return 1;
}
return 0;
}