Home | History | Annotate | Download | only in launch
      1 /*
      2  * Copyright (C) 2018 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 "host/commands/launch/boot_image_unpacker.h"
     18 
     19 #include <string.h>
     20 #include <unistd.h>
     21 
     22 #include <sstream>
     23 
     24 #include <glog/logging.h>
     25 
     26 #include "common/libs/utils/subprocess.h"
     27 #include "host/commands/launch/bootimg.h"
     28 
     29 namespace cvd {
     30 
     31 namespace {
     32 
     33 // Extracts size bytes from file, starting at offset bytes from the beginning to
     34 // path.
     35 bool ExtractFile(SharedFD source, off_t offset, size_t size,
     36                  const std::string& path) {
     37   auto dest = SharedFD::Open(path.c_str(), O_CREAT | O_RDWR, 0755);
     38   if (!dest->IsOpen()) {
     39     LOG(ERROR) << "Unable to open " << path;
     40     return false;
     41   }
     42   auto off = source->LSeek(offset, SEEK_SET);
     43   if (off != offset) {
     44     LOG(ERROR) << "Failed to lseek: " << source->StrError();
     45     return false;
     46   }
     47   return dest->CopyFrom(*source, size);
     48 }
     49 }  // namespace
     50 
     51 std::unique_ptr<BootImageUnpacker> BootImageUnpacker::FromImage(
     52     const std::string& path) {
     53   auto boot_img = SharedFD::Open(path.c_str(), O_RDONLY);
     54   if (!boot_img->IsOpen()) {
     55     LOG(ERROR) << "Unable to open boot image (" << path
     56                << "): " << boot_img->StrError();
     57     return nullptr;
     58   }
     59   boot_img_hdr header;
     60   auto bytes_read = boot_img->Read(&header, sizeof(header));
     61   if (bytes_read != sizeof(header)) {
     62     LOG(ERROR) << "Error reading boot image header";
     63     return nullptr;
     64   }
     65 
     66   std::ostringstream cmdline;
     67   cmdline << reinterpret_cast<char*>(&header.cmdline[0]);
     68   if (header.extra_cmdline[0] != '\0') {
     69     cmdline << " ";
     70     cmdline << reinterpret_cast<char*>(&header.extra_cmdline[0]);
     71   }
     72 
     73   uint32_t page_size = header.page_size;
     74   // See system/core/mkbootimg/include/mkbootimg/bootimg.h for the origin of
     75   // these offset calculations
     76   uint32_t kernel_offset = page_size;
     77   uint32_t ramdisk_offset =
     78       kernel_offset +
     79       ((header.kernel_size + page_size - 1) / page_size) * page_size;
     80 
     81   std::unique_ptr<BootImageUnpacker> ret(new BootImageUnpacker(
     82       boot_img, cmdline.str(), header.kernel_size, kernel_offset,
     83       header.ramdisk_size, ramdisk_offset));
     84 
     85   return ret;
     86 }
     87 
     88 std::string BootImageUnpacker::kernel_cmdline() const {
     89   return kernel_cmdline_;
     90 }
     91 
     92 bool BootImageUnpacker::ExtractKernelImage(const std::string& path) const {
     93   if (kernel_image_size_ == 0) return false;
     94   return ExtractFile(boot_image_, kernel_image_offset_, kernel_image_size_,
     95                      path);
     96 }
     97 bool BootImageUnpacker::ExtractRamdiskImage(const std::string& path) const {
     98   if (ramdisk_image_size_ == 0) return false;
     99   return ExtractFile(boot_image_, ramdisk_image_offset_, ramdisk_image_size_,
    100                      path);
    101 }
    102 
    103 bool BootImageUnpacker::Unpack(const std::string& ramdisk_image_path,
    104                                const std::string& kernel_image_path) {
    105   if (HasRamdiskImage()) {
    106     if (!ExtractRamdiskImage(ramdisk_image_path)) {
    107       LOG(ERROR) << "Error extracting ramdisk from boot image";
    108       return false;
    109     }
    110   }
    111   if (!kernel_image_path.empty()) {
    112     if (HasKernelImage()) {
    113       if (!ExtractKernelImage(kernel_image_path)) {
    114         LOG(ERROR) << "Error extracting kernel from boot image";
    115         return false;
    116       }
    117     } else {
    118       LOG(ERROR) << "No kernel found on boot image";
    119       return false;
    120     }
    121   }
    122   return true;
    123 }
    124 
    125 }  // namespace cvd
    126