Home | History | Annotate | Download | only in common
      1 //
      2 // Copyright (C) 2012 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 "update_engine/common/utils.h"
     18 
     19 #include <stdint.h>
     20 
     21 #include <dirent.h>
     22 #include <elf.h>
     23 #include <endian.h>
     24 #include <errno.h>
     25 #include <ext2fs/ext2fs.h>
     26 #include <fcntl.h>
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 #include <string.h>
     30 #include <sys/mount.h>
     31 #include <sys/resource.h>
     32 #include <sys/stat.h>
     33 #include <sys/types.h>
     34 #include <sys/wait.h>
     35 #include <unistd.h>
     36 
     37 #include <algorithm>
     38 #include <utility>
     39 #include <vector>
     40 
     41 #include <base/callback.h>
     42 #include <base/files/file_path.h>
     43 #include <base/files/file_util.h>
     44 #include <base/files/scoped_file.h>
     45 #include <base/format_macros.h>
     46 #include <base/location.h>
     47 #include <base/logging.h>
     48 #include <base/posix/eintr_wrapper.h>
     49 #include <base/rand_util.h>
     50 #include <base/strings/string_number_conversions.h>
     51 #include <base/strings/string_split.h>
     52 #include <base/strings/string_util.h>
     53 #include <base/strings/stringprintf.h>
     54 #include <brillo/data_encoding.h>
     55 #include <brillo/message_loops/message_loop.h>
     56 
     57 #include "update_engine/common/clock_interface.h"
     58 #include "update_engine/common/constants.h"
     59 #include "update_engine/common/platform_constants.h"
     60 #include "update_engine/common/prefs_interface.h"
     61 #include "update_engine/common/subprocess.h"
     62 #include "update_engine/payload_consumer/file_descriptor.h"
     63 #include "update_engine/payload_consumer/file_writer.h"
     64 #include "update_engine/payload_consumer/payload_constants.h"
     65 
     66 using base::Time;
     67 using base::TimeDelta;
     68 using std::min;
     69 using std::pair;
     70 using std::string;
     71 using std::vector;
     72 
     73 namespace chromeos_update_engine {
     74 
     75 namespace {
     76 
     77 // The following constants control how UnmountFilesystem should retry if
     78 // umount() fails with an errno EBUSY, i.e. retry 5 times over the course of
     79 // one second.
     80 const int kUnmountMaxNumOfRetries = 5;
     81 const int kUnmountRetryIntervalInMicroseconds = 200 * 1000;  // 200 ms
     82 
     83 // Number of bytes to read from a file to attempt to detect its contents. Used
     84 // in GetFileFormat.
     85 const int kGetFileFormatMaxHeaderSize = 32;
     86 
     87 // The path to the kernel's boot_id.
     88 const char kBootIdPath[] = "/proc/sys/kernel/random/boot_id";
     89 
     90 // Return true if |disk_name| is an MTD or a UBI device. Note that this test is
     91 // simply based on the name of the device.
     92 bool IsMtdDeviceName(const string& disk_name) {
     93   return base::StartsWith(disk_name, "/dev/ubi",
     94                           base::CompareCase::SENSITIVE) ||
     95          base::StartsWith(disk_name, "/dev/mtd", base::CompareCase::SENSITIVE);
     96 }
     97 
     98 // Return the device name for the corresponding partition on a NAND device.
     99 // WARNING: This function returns device names that are not mountable.
    100 string MakeNandPartitionName(int partition_num) {
    101   switch (partition_num) {
    102     case 2:
    103     case 4:
    104     case 6: {
    105       return base::StringPrintf("/dev/mtd%d", partition_num);
    106     }
    107     default: {
    108       return base::StringPrintf("/dev/ubi%d_0", partition_num);
    109     }
    110   }
    111 }
    112 
    113 // Return the device name for the corresponding partition on a NAND device that
    114 // may be mountable (but may not be writable).
    115 string MakeNandPartitionNameForMount(int partition_num) {
    116   switch (partition_num) {
    117     case 2:
    118     case 4:
    119     case 6: {
    120       return base::StringPrintf("/dev/mtd%d", partition_num);
    121     }
    122     case 3:
    123     case 5:
    124     case 7: {
    125       return base::StringPrintf("/dev/ubiblock%d_0", partition_num);
    126     }
    127     default: {
    128       return base::StringPrintf("/dev/ubi%d_0", partition_num);
    129     }
    130   }
    131 }
    132 
    133 // If |path| is absolute, or explicit relative to the current working directory,
    134 // leaves it as is. Otherwise, uses the system's temp directory, as defined by
    135 // base::GetTempDir() and prepends it to |path|. On success stores the full
    136 // temporary path in |template_path| and returns true.
    137 bool GetTempName(const string& path, base::FilePath* template_path) {
    138   if (path[0] == '/' ||
    139       base::StartsWith(path, "./", base::CompareCase::SENSITIVE) ||
    140       base::StartsWith(path, "../", base::CompareCase::SENSITIVE)) {
    141     *template_path = base::FilePath(path);
    142     return true;
    143   }
    144 
    145   base::FilePath temp_dir;
    146 #ifdef __ANDROID__
    147   temp_dir = base::FilePath(constants::kNonVolatileDirectory).Append("tmp");
    148   if (!base::PathExists(temp_dir))
    149     TEST_AND_RETURN_FALSE(base::CreateDirectory(temp_dir));
    150 #else
    151   TEST_AND_RETURN_FALSE(base::GetTempDir(&temp_dir));
    152 #endif  // __ANDROID__
    153   *template_path = temp_dir.Append(path);
    154   return true;
    155 }
    156 
    157 }  // namespace
    158 
    159 namespace utils {
    160 
    161 string ParseECVersion(string input_line) {
    162   base::TrimWhitespaceASCII(input_line, base::TRIM_ALL, &input_line);
    163 
    164   // At this point we want to convert the format key=value pair from mosys to
    165   // a vector of key value pairs.
    166   vector<pair<string, string>> kv_pairs;
    167   if (base::SplitStringIntoKeyValuePairs(input_line, '=', ' ', &kv_pairs)) {
    168     for (const pair<string, string>& kv_pair : kv_pairs) {
    169       // Finally match against the fw_verion which may have quotes.
    170       if (kv_pair.first == "fw_version") {
    171         string output;
    172         // Trim any quotes.
    173         base::TrimString(kv_pair.second, "\"", &output);
    174         return output;
    175       }
    176     }
    177   }
    178   LOG(ERROR) << "Unable to parse fwid from ec info.";
    179   return "";
    180 }
    181 
    182 bool WriteFile(const char* path, const void* data, int data_len) {
    183   DirectFileWriter writer;
    184   TEST_AND_RETURN_FALSE_ERRNO(0 == writer.Open(path,
    185                                                O_WRONLY | O_CREAT | O_TRUNC,
    186                                                0600));
    187   ScopedFileWriterCloser closer(&writer);
    188   TEST_AND_RETURN_FALSE_ERRNO(writer.Write(data, data_len));
    189   return true;
    190 }
    191 
    192 bool ReadAll(
    193     int fd, void* buf, size_t count, size_t* out_bytes_read, bool* eof) {
    194   char* c_buf = static_cast<char*>(buf);
    195   size_t bytes_read = 0;
    196   *eof = false;
    197   while (bytes_read < count) {
    198     ssize_t rc = HANDLE_EINTR(read(fd, c_buf + bytes_read, count - bytes_read));
    199     if (rc < 0) {
    200       // EAGAIN and EWOULDBLOCK are normal return values when there's no more
    201       // input and we are in non-blocking mode.
    202       if (errno != EWOULDBLOCK && errno != EAGAIN) {
    203         PLOG(ERROR) << "Error reading fd " << fd;
    204         *out_bytes_read = bytes_read;
    205         return false;
    206       }
    207       break;
    208     } else if (rc == 0) {
    209       // A value of 0 means that we reached EOF and there is nothing else to
    210       // read from this fd.
    211       *eof = true;
    212       break;
    213     } else {
    214       bytes_read += rc;
    215     }
    216   }
    217   *out_bytes_read = bytes_read;
    218   return true;
    219 }
    220 
    221 bool WriteAll(int fd, const void* buf, size_t count) {
    222   const char* c_buf = static_cast<const char*>(buf);
    223   ssize_t bytes_written = 0;
    224   while (bytes_written < static_cast<ssize_t>(count)) {
    225     ssize_t rc = write(fd, c_buf + bytes_written, count - bytes_written);
    226     TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
    227     bytes_written += rc;
    228   }
    229   return true;
    230 }
    231 
    232 bool PWriteAll(int fd, const void* buf, size_t count, off_t offset) {
    233   const char* c_buf = static_cast<const char*>(buf);
    234   size_t bytes_written = 0;
    235   int num_attempts = 0;
    236   while (bytes_written < count) {
    237     num_attempts++;
    238     ssize_t rc = pwrite(fd, c_buf + bytes_written, count - bytes_written,
    239                         offset + bytes_written);
    240     // TODO(garnold) for debugging failure in chromium-os:31077; to be removed.
    241     if (rc < 0) {
    242       PLOG(ERROR) << "pwrite error; num_attempts=" << num_attempts
    243                   << " bytes_written=" << bytes_written
    244                   << " count=" << count << " offset=" << offset;
    245     }
    246     TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
    247     bytes_written += rc;
    248   }
    249   return true;
    250 }
    251 
    252 bool WriteAll(FileDescriptorPtr fd, const void* buf, size_t count) {
    253   const char* c_buf = static_cast<const char*>(buf);
    254   ssize_t bytes_written = 0;
    255   while (bytes_written < static_cast<ssize_t>(count)) {
    256     ssize_t rc = fd->Write(c_buf + bytes_written, count - bytes_written);
    257     TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
    258     bytes_written += rc;
    259   }
    260   return true;
    261 }
    262 
    263 bool PWriteAll(FileDescriptorPtr fd,
    264                const void* buf,
    265                size_t count,
    266                off_t offset) {
    267   TEST_AND_RETURN_FALSE_ERRNO(fd->Seek(offset, SEEK_SET) !=
    268                               static_cast<off_t>(-1));
    269   return WriteAll(fd, buf, count);
    270 }
    271 
    272 bool PReadAll(int fd, void* buf, size_t count, off_t offset,
    273               ssize_t* out_bytes_read) {
    274   char* c_buf = static_cast<char*>(buf);
    275   ssize_t bytes_read = 0;
    276   while (bytes_read < static_cast<ssize_t>(count)) {
    277     ssize_t rc = pread(fd, c_buf + bytes_read, count - bytes_read,
    278                        offset + bytes_read);
    279     TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
    280     if (rc == 0) {
    281       break;
    282     }
    283     bytes_read += rc;
    284   }
    285   *out_bytes_read = bytes_read;
    286   return true;
    287 }
    288 
    289 bool PReadAll(FileDescriptorPtr fd, void* buf, size_t count, off_t offset,
    290               ssize_t* out_bytes_read) {
    291   TEST_AND_RETURN_FALSE_ERRNO(fd->Seek(offset, SEEK_SET) !=
    292                               static_cast<off_t>(-1));
    293   char* c_buf = static_cast<char*>(buf);
    294   ssize_t bytes_read = 0;
    295   while (bytes_read < static_cast<ssize_t>(count)) {
    296     ssize_t rc = fd->Read(c_buf + bytes_read, count - bytes_read);
    297     TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
    298     if (rc == 0) {
    299       break;
    300     }
    301     bytes_read += rc;
    302   }
    303   *out_bytes_read = bytes_read;
    304   return true;
    305 }
    306 
    307 // Append |nbytes| of content from |buf| to the vector pointed to by either
    308 // |vec_p| or |str_p|.
    309 static void AppendBytes(const uint8_t* buf, size_t nbytes,
    310                         brillo::Blob* vec_p) {
    311   CHECK(buf);
    312   CHECK(vec_p);
    313   vec_p->insert(vec_p->end(), buf, buf + nbytes);
    314 }
    315 static void AppendBytes(const uint8_t* buf, size_t nbytes,
    316                         string* str_p) {
    317   CHECK(buf);
    318   CHECK(str_p);
    319   str_p->append(buf, buf + nbytes);
    320 }
    321 
    322 // Reads from an open file |fp|, appending the read content to the container
    323 // pointer to by |out_p|.  Returns true upon successful reading all of the
    324 // file's content, false otherwise. If |size| is not -1, reads up to |size|
    325 // bytes.
    326 template <class T>
    327 static bool Read(FILE* fp, off_t size, T* out_p) {
    328   CHECK(fp);
    329   CHECK(size == -1 || size >= 0);
    330   uint8_t buf[1024];
    331   while (size == -1 || size > 0) {
    332     off_t bytes_to_read = sizeof(buf);
    333     if (size > 0 && bytes_to_read > size) {
    334       bytes_to_read = size;
    335     }
    336     size_t nbytes = fread(buf, 1, bytes_to_read, fp);
    337     if (!nbytes) {
    338       break;
    339     }
    340     AppendBytes(buf, nbytes, out_p);
    341     if (size != -1) {
    342       CHECK(size >= static_cast<off_t>(nbytes));
    343       size -= nbytes;
    344     }
    345   }
    346   if (ferror(fp)) {
    347     return false;
    348   }
    349   return size == 0 || feof(fp);
    350 }
    351 
    352 // Opens a file |path| for reading and appends its the contents to a container
    353 // |out_p|. Starts reading the file from |offset|. If |offset| is beyond the end
    354 // of the file, returns success. If |size| is not -1, reads up to |size| bytes.
    355 template <class T>
    356 static bool ReadFileChunkAndAppend(const string& path,
    357                                    off_t offset,
    358                                    off_t size,
    359                                    T* out_p) {
    360   CHECK_GE(offset, 0);
    361   CHECK(size == -1 || size >= 0);
    362   base::ScopedFILE fp(fopen(path.c_str(), "r"));
    363   if (!fp.get())
    364     return false;
    365   if (offset) {
    366     // Return success without appending any data if a chunk beyond the end of
    367     // the file is requested.
    368     if (offset >= FileSize(path)) {
    369       return true;
    370     }
    371     TEST_AND_RETURN_FALSE_ERRNO(fseek(fp.get(), offset, SEEK_SET) == 0);
    372   }
    373   return Read(fp.get(), size, out_p);
    374 }
    375 
    376 // TODO(deymo): This is only used in unittest, but requires the private
    377 // Read<string>() defined here. Expose Read<string>() or move to base/ version.
    378 bool ReadPipe(const string& cmd, string* out_p) {
    379   FILE* fp = popen(cmd.c_str(), "r");
    380   if (!fp)
    381     return false;
    382   bool success = Read(fp, -1, out_p);
    383   return (success && pclose(fp) >= 0);
    384 }
    385 
    386 bool ReadFile(const string& path, brillo::Blob* out_p) {
    387   return ReadFileChunkAndAppend(path, 0, -1, out_p);
    388 }
    389 
    390 bool ReadFile(const string& path, string* out_p) {
    391   return ReadFileChunkAndAppend(path, 0, -1, out_p);
    392 }
    393 
    394 bool ReadFileChunk(const string& path, off_t offset, off_t size,
    395                    brillo::Blob* out_p) {
    396   return ReadFileChunkAndAppend(path, offset, size, out_p);
    397 }
    398 
    399 off_t BlockDevSize(int fd) {
    400   uint64_t dev_size;
    401   int rc = ioctl(fd, BLKGETSIZE64, &dev_size);
    402   if (rc == -1) {
    403     dev_size = -1;
    404     PLOG(ERROR) << "Error running ioctl(BLKGETSIZE64) on " << fd;
    405   }
    406   return dev_size;
    407 }
    408 
    409 off_t FileSize(int fd) {
    410   struct stat stbuf;
    411   int rc = fstat(fd, &stbuf);
    412   CHECK_EQ(rc, 0);
    413   if (rc < 0) {
    414     PLOG(ERROR) << "Error stat-ing " << fd;
    415     return rc;
    416   }
    417   if (S_ISREG(stbuf.st_mode))
    418     return stbuf.st_size;
    419   if (S_ISBLK(stbuf.st_mode))
    420     return BlockDevSize(fd);
    421   LOG(ERROR) << "Couldn't determine the type of " << fd;
    422   return -1;
    423 }
    424 
    425 off_t FileSize(const string& path) {
    426   int fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
    427   if (fd == -1) {
    428     PLOG(ERROR) << "Error opening " << path;
    429     return fd;
    430   }
    431   off_t size = FileSize(fd);
    432   if (size == -1)
    433     PLOG(ERROR) << "Error getting file size of " << path;
    434   close(fd);
    435   return size;
    436 }
    437 
    438 void HexDumpArray(const uint8_t* const arr, const size_t length) {
    439   LOG(INFO) << "Logging array of length: " << length;
    440   const unsigned int bytes_per_line = 16;
    441   for (uint32_t i = 0; i < length; i += bytes_per_line) {
    442     const unsigned int bytes_remaining = length - i;
    443     const unsigned int bytes_per_this_line = min(bytes_per_line,
    444                                                  bytes_remaining);
    445     char header[100];
    446     int r = snprintf(header, sizeof(header), "0x%08x : ", i);
    447     TEST_AND_RETURN(r == 13);
    448     string line = header;
    449     for (unsigned int j = 0; j < bytes_per_this_line; j++) {
    450       char buf[20];
    451       uint8_t c = arr[i + j];
    452       r = snprintf(buf, sizeof(buf), "%02x ", static_cast<unsigned int>(c));
    453       TEST_AND_RETURN(r == 3);
    454       line += buf;
    455     }
    456     LOG(INFO) << line;
    457   }
    458 }
    459 
    460 bool SplitPartitionName(const string& partition_name,
    461                         string* out_disk_name,
    462                         int* out_partition_num) {
    463   if (!base::StartsWith(partition_name, "/dev/",
    464                         base::CompareCase::SENSITIVE)) {
    465     LOG(ERROR) << "Invalid partition device name: " << partition_name;
    466     return false;
    467   }
    468 
    469   size_t last_nondigit_pos = partition_name.find_last_not_of("0123456789");
    470   if (last_nondigit_pos == string::npos ||
    471       (last_nondigit_pos + 1) == partition_name.size()) {
    472     LOG(ERROR) << "Unable to parse partition device name: " << partition_name;
    473     return false;
    474   }
    475 
    476   size_t partition_name_len = string::npos;
    477   if (partition_name[last_nondigit_pos] == '_') {
    478     // NAND block devices have weird naming which could be something
    479     // like "/dev/ubiblock2_0". We discard "_0" in such a case.
    480     size_t prev_nondigit_pos =
    481         partition_name.find_last_not_of("0123456789", last_nondigit_pos - 1);
    482     if (prev_nondigit_pos == string::npos ||
    483         (prev_nondigit_pos + 1) == last_nondigit_pos) {
    484       LOG(ERROR) << "Unable to parse partition device name: " << partition_name;
    485       return false;
    486     }
    487 
    488     partition_name_len = last_nondigit_pos - prev_nondigit_pos;
    489     last_nondigit_pos = prev_nondigit_pos;
    490   }
    491 
    492   if (out_disk_name) {
    493     // Special case for MMC devices which have the following naming scheme:
    494     // mmcblk0p2
    495     size_t disk_name_len = last_nondigit_pos;
    496     if (partition_name[last_nondigit_pos] != 'p' ||
    497         last_nondigit_pos == 0 ||
    498         !isdigit(partition_name[last_nondigit_pos - 1])) {
    499       disk_name_len++;
    500     }
    501     *out_disk_name = partition_name.substr(0, disk_name_len);
    502   }
    503 
    504   if (out_partition_num) {
    505     string partition_str = partition_name.substr(last_nondigit_pos + 1,
    506                                                  partition_name_len);
    507     *out_partition_num = atoi(partition_str.c_str());
    508   }
    509   return true;
    510 }
    511 
    512 string MakePartitionName(const string& disk_name, int partition_num) {
    513   if (partition_num < 1) {
    514     LOG(ERROR) << "Invalid partition number: " << partition_num;
    515     return string();
    516   }
    517 
    518   if (!base::StartsWith(disk_name, "/dev/", base::CompareCase::SENSITIVE)) {
    519     LOG(ERROR) << "Invalid disk name: " << disk_name;
    520     return string();
    521   }
    522 
    523   if (IsMtdDeviceName(disk_name)) {
    524     // Special case for UBI block devices.
    525     //   1. ubiblock is not writable, we need to use plain "ubi".
    526     //   2. There is a "_0" suffix.
    527     return MakeNandPartitionName(partition_num);
    528   }
    529 
    530   string partition_name = disk_name;
    531   if (isdigit(partition_name.back())) {
    532     // Special case for devices with names ending with a digit.
    533     // Add "p" to separate the disk name from partition number,
    534     // e.g. "/dev/loop0p2"
    535     partition_name += 'p';
    536   }
    537 
    538   partition_name += std::to_string(partition_num);
    539 
    540   return partition_name;
    541 }
    542 
    543 string MakePartitionNameForMount(const string& part_name) {
    544   if (IsMtdDeviceName(part_name)) {
    545     int partition_num;
    546     if (!SplitPartitionName(part_name, nullptr, &partition_num)) {
    547       return "";
    548     }
    549     return MakeNandPartitionNameForMount(partition_num);
    550   }
    551   return part_name;
    552 }
    553 
    554 string ErrnoNumberAsString(int err) {
    555   char buf[100];
    556   buf[0] = '\0';
    557   return strerror_r(err, buf, sizeof(buf));
    558 }
    559 
    560 bool FileExists(const char* path) {
    561   struct stat stbuf;
    562   return 0 == lstat(path, &stbuf);
    563 }
    564 
    565 bool IsSymlink(const char* path) {
    566   struct stat stbuf;
    567   return lstat(path, &stbuf) == 0 && S_ISLNK(stbuf.st_mode) != 0;
    568 }
    569 
    570 bool TryAttachingUbiVolume(int volume_num, int timeout) {
    571   const string volume_path = base::StringPrintf("/dev/ubi%d_0", volume_num);
    572   if (FileExists(volume_path.c_str())) {
    573     return true;
    574   }
    575 
    576   int exit_code;
    577   vector<string> cmd = {
    578       "ubiattach",
    579       "-m",
    580       base::StringPrintf("%d", volume_num),
    581       "-d",
    582       base::StringPrintf("%d", volume_num)
    583   };
    584   TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &exit_code, nullptr));
    585   TEST_AND_RETURN_FALSE(exit_code == 0);
    586 
    587   cmd = {
    588       "ubiblock",
    589       "--create",
    590       volume_path
    591   };
    592   TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &exit_code, nullptr));
    593   TEST_AND_RETURN_FALSE(exit_code == 0);
    594 
    595   while (timeout > 0 && !FileExists(volume_path.c_str())) {
    596     sleep(1);
    597     timeout--;
    598   }
    599 
    600   return FileExists(volume_path.c_str());
    601 }
    602 
    603 bool MakeTempFile(const string& base_filename_template,
    604                   string* filename,
    605                   int* fd) {
    606   base::FilePath filename_template;
    607   TEST_AND_RETURN_FALSE(
    608       GetTempName(base_filename_template, &filename_template));
    609   DCHECK(filename || fd);
    610   vector<char> buf(filename_template.value().size() + 1);
    611   memcpy(buf.data(), filename_template.value().data(),
    612          filename_template.value().size());
    613   buf[filename_template.value().size()] = '\0';
    614 
    615   int mkstemp_fd = mkstemp(buf.data());
    616   TEST_AND_RETURN_FALSE_ERRNO(mkstemp_fd >= 0);
    617   if (filename) {
    618     *filename = buf.data();
    619   }
    620   if (fd) {
    621     *fd = mkstemp_fd;
    622   } else {
    623     close(mkstemp_fd);
    624   }
    625   return true;
    626 }
    627 
    628 bool MakeTempDirectory(const string& base_dirname_template,
    629                        string* dirname) {
    630   base::FilePath dirname_template;
    631   TEST_AND_RETURN_FALSE(GetTempName(base_dirname_template, &dirname_template));
    632   DCHECK(dirname);
    633   vector<char> buf(dirname_template.value().size() + 1);
    634   memcpy(buf.data(), dirname_template.value().data(),
    635          dirname_template.value().size());
    636   buf[dirname_template.value().size()] = '\0';
    637 
    638   char* return_code = mkdtemp(buf.data());
    639   TEST_AND_RETURN_FALSE_ERRNO(return_code != nullptr);
    640   *dirname = buf.data();
    641   return true;
    642 }
    643 
    644 bool SetBlockDeviceReadOnly(const string& device, bool read_only) {
    645   int fd = HANDLE_EINTR(open(device.c_str(), O_RDONLY | O_CLOEXEC));
    646   if (fd < 0) {
    647     PLOG(ERROR) << "Opening block device " << device;
    648     return false;
    649   }
    650   ScopedFdCloser fd_closer(&fd);
    651   // We take no action if not needed.
    652   int read_only_flag;
    653   int expected_flag = read_only ? 1 : 0;
    654   int rc = ioctl(fd, BLKROGET, &read_only_flag);
    655   // In case of failure reading the setting we will try to set it anyway.
    656   if (rc == 0 && read_only_flag == expected_flag)
    657     return true;
    658 
    659   rc = ioctl(fd, BLKROSET, &expected_flag);
    660   if (rc != 0) {
    661     PLOG(ERROR) << "Marking block device " << device << " as read_only="
    662                 << expected_flag;
    663     return false;
    664   }
    665   return true;
    666 }
    667 
    668 bool MountFilesystem(const string& device,
    669                      const string& mountpoint,
    670                      unsigned long mountflags,  // NOLINT(runtime/int)
    671                      const string& type,
    672                      const string& fs_mount_options) {
    673   vector<const char*> fstypes;
    674   if (type.empty()) {
    675     fstypes = {"ext2", "ext3", "ext4", "squashfs"};
    676   } else {
    677     fstypes = {type.c_str()};
    678   }
    679   for (const char* fstype : fstypes) {
    680     int rc = mount(device.c_str(), mountpoint.c_str(), fstype, mountflags,
    681                    fs_mount_options.c_str());
    682     if (rc == 0)
    683       return true;
    684 
    685     PLOG(WARNING) << "Unable to mount destination device " << device
    686                   << " on " << mountpoint << " as " << fstype;
    687   }
    688   if (!type.empty()) {
    689     LOG(ERROR) << "Unable to mount " << device << " with any supported type";
    690   }
    691   return false;
    692 }
    693 
    694 bool UnmountFilesystem(const string& mountpoint) {
    695   for (int num_retries = 0; ; ++num_retries) {
    696     if (umount(mountpoint.c_str()) == 0)
    697       break;
    698 
    699     TEST_AND_RETURN_FALSE_ERRNO(errno == EBUSY &&
    700                                 num_retries < kUnmountMaxNumOfRetries);
    701     usleep(kUnmountRetryIntervalInMicroseconds);
    702   }
    703   return true;
    704 }
    705 
    706 bool GetFilesystemSize(const string& device,
    707                        int* out_block_count,
    708                        int* out_block_size) {
    709   int fd = HANDLE_EINTR(open(device.c_str(), O_RDONLY));
    710   TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
    711   ScopedFdCloser fd_closer(&fd);
    712   return GetFilesystemSizeFromFD(fd, out_block_count, out_block_size);
    713 }
    714 
    715 bool GetFilesystemSizeFromFD(int fd,
    716                              int* out_block_count,
    717                              int* out_block_size) {
    718   TEST_AND_RETURN_FALSE(fd >= 0);
    719 
    720   // Determine the filesystem size by directly reading the block count and
    721   // block size information from the superblock. Supported FS are ext3 and
    722   // squashfs.
    723 
    724   // Read from the fd only once and detect in memory. The first 2 KiB is enough
    725   // to read the ext2 superblock (located at offset 1024) and the squashfs
    726   // superblock (located at offset 0).
    727   const ssize_t kBufferSize = 2048;
    728 
    729   uint8_t buffer[kBufferSize];
    730   if (HANDLE_EINTR(pread(fd, buffer, kBufferSize, 0)) != kBufferSize) {
    731     PLOG(ERROR) << "Unable to read the file system header:";
    732     return false;
    733   }
    734 
    735   if (GetSquashfs4Size(buffer, kBufferSize, out_block_count, out_block_size))
    736     return true;
    737   if (GetExt3Size(buffer, kBufferSize, out_block_count, out_block_size))
    738     return true;
    739 
    740   LOG(ERROR) << "Unable to determine file system type.";
    741   return false;
    742 }
    743 
    744 bool GetExt3Size(const uint8_t* buffer, size_t buffer_size,
    745                  int* out_block_count,
    746                  int* out_block_size) {
    747   // See include/linux/ext2_fs.h for more details on the structure. We obtain
    748   // ext2 constants from ext2fs/ext2fs.h header but we don't link with the
    749   // library.
    750   if (buffer_size < SUPERBLOCK_OFFSET + SUPERBLOCK_SIZE)
    751     return false;
    752 
    753   const uint8_t* superblock = buffer + SUPERBLOCK_OFFSET;
    754 
    755   // ext3_fs.h: ext3_super_block.s_blocks_count
    756   uint32_t block_count =
    757       *reinterpret_cast<const uint32_t*>(superblock + 1 * sizeof(int32_t));
    758 
    759   // ext3_fs.h: ext3_super_block.s_log_block_size
    760   uint32_t log_block_size =
    761       *reinterpret_cast<const uint32_t*>(superblock + 6 * sizeof(int32_t));
    762 
    763   // ext3_fs.h: ext3_super_block.s_magic
    764   uint16_t magic =
    765       *reinterpret_cast<const uint16_t*>(superblock + 14 * sizeof(int32_t));
    766 
    767   block_count = le32toh(block_count);
    768   log_block_size = le32toh(log_block_size) + EXT2_MIN_BLOCK_LOG_SIZE;
    769   magic = le16toh(magic);
    770 
    771   // Sanity check the parameters.
    772   TEST_AND_RETURN_FALSE(magic == EXT2_SUPER_MAGIC);
    773   TEST_AND_RETURN_FALSE(log_block_size >= EXT2_MIN_BLOCK_LOG_SIZE &&
    774                         log_block_size <= EXT2_MAX_BLOCK_LOG_SIZE);
    775   TEST_AND_RETURN_FALSE(block_count > 0);
    776 
    777   if (out_block_count)
    778     *out_block_count = block_count;
    779   if (out_block_size)
    780     *out_block_size = 1 << log_block_size;
    781   return true;
    782 }
    783 
    784 bool GetSquashfs4Size(const uint8_t* buffer, size_t buffer_size,
    785                       int* out_block_count,
    786                       int* out_block_size) {
    787   // See fs/squashfs/squashfs_fs.h for format details. We only support
    788   // Squashfs 4.x little endian.
    789 
    790   // sizeof(struct squashfs_super_block)
    791   const size_t kSquashfsSuperBlockSize = 96;
    792   if (buffer_size < kSquashfsSuperBlockSize)
    793     return false;
    794 
    795   // Check magic, squashfs_fs.h: SQUASHFS_MAGIC
    796   if (memcmp(buffer, "hsqs", 4) != 0)
    797     return false;  // Only little endian is supported.
    798 
    799   // squashfs_fs.h: struct squashfs_super_block.s_major
    800   uint16_t s_major = *reinterpret_cast<const uint16_t*>(
    801       buffer + 5 * sizeof(uint32_t) + 4 * sizeof(uint16_t));
    802 
    803   if (s_major != 4) {
    804     LOG(ERROR) << "Found unsupported squashfs major version " << s_major;
    805     return false;
    806   }
    807 
    808   // squashfs_fs.h: struct squashfs_super_block.bytes_used
    809   uint64_t bytes_used = *reinterpret_cast<const int64_t*>(
    810       buffer + 5 * sizeof(uint32_t) + 6 * sizeof(uint16_t) + sizeof(uint64_t));
    811 
    812   const int block_size = 4096;
    813 
    814   // The squashfs' bytes_used doesn't need to be aligned with the block boundary
    815   // so we round up to the nearest blocksize.
    816   if (out_block_count)
    817     *out_block_count = (bytes_used + block_size - 1) / block_size;
    818   if (out_block_size)
    819     *out_block_size = block_size;
    820   return true;
    821 }
    822 
    823 bool IsExtFilesystem(const string& device) {
    824   brillo::Blob header;
    825   // The first 2 KiB is enough to read the ext2 superblock (located at offset
    826   // 1024).
    827   if (!ReadFileChunk(device, 0, 2048, &header))
    828     return false;
    829   return GetExt3Size(header.data(), header.size(), nullptr, nullptr);
    830 }
    831 
    832 bool IsSquashfsFilesystem(const string& device) {
    833   brillo::Blob header;
    834   // The first 96 is enough to read the squashfs superblock.
    835   const ssize_t kSquashfsSuperBlockSize = 96;
    836   if (!ReadFileChunk(device, 0, kSquashfsSuperBlockSize, &header))
    837     return false;
    838   return GetSquashfs4Size(header.data(), header.size(), nullptr, nullptr);
    839 }
    840 
    841 // Tries to parse the header of an ELF file to obtain a human-readable
    842 // description of it on the |output| string.
    843 static bool GetFileFormatELF(const uint8_t* buffer, size_t size,
    844                              string* output) {
    845   // 0x00: EI_MAG - ELF magic header, 4 bytes.
    846   if (size < SELFMAG || memcmp(buffer, ELFMAG, SELFMAG) != 0)
    847     return false;
    848   *output = "ELF";
    849 
    850   // 0x04: EI_CLASS, 1 byte.
    851   if (size < EI_CLASS + 1)
    852     return true;
    853   switch (buffer[EI_CLASS]) {
    854     case ELFCLASS32:
    855       *output += " 32-bit";
    856       break;
    857     case ELFCLASS64:
    858       *output += " 64-bit";
    859       break;
    860     default:
    861       *output += " ?-bit";
    862   }
    863 
    864   // 0x05: EI_DATA, endianness, 1 byte.
    865   if (size < EI_DATA + 1)
    866     return true;
    867   uint8_t ei_data = buffer[EI_DATA];
    868   switch (ei_data) {
    869     case ELFDATA2LSB:
    870       *output += " little-endian";
    871       break;
    872     case ELFDATA2MSB:
    873       *output += " big-endian";
    874       break;
    875     default:
    876       *output += " ?-endian";
    877       // Don't parse anything after the 0x10 offset if endianness is unknown.
    878       return true;
    879   }
    880 
    881   const Elf32_Ehdr* hdr = reinterpret_cast<const Elf32_Ehdr*>(buffer);
    882   // 0x12: e_machine, 2 byte endianness based on ei_data. The position (0x12)
    883   // and size is the same for both 32 and 64 bits.
    884   if (size < offsetof(Elf32_Ehdr, e_machine) + sizeof(hdr->e_machine))
    885     return true;
    886   uint16_t e_machine;
    887   // Fix endianess regardless of the host endianess.
    888   if (ei_data == ELFDATA2LSB)
    889     e_machine = le16toh(hdr->e_machine);
    890   else
    891     e_machine = be16toh(hdr->e_machine);
    892 
    893   switch (e_machine) {
    894     case EM_386:
    895       *output += " x86";
    896       break;
    897     case EM_MIPS:
    898       *output += " mips";
    899       break;
    900     case EM_ARM:
    901       *output += " arm";
    902       break;
    903     case EM_X86_64:
    904       *output += " x86-64";
    905       break;
    906     default:
    907       *output += " unknown-arch";
    908   }
    909   return true;
    910 }
    911 
    912 string GetFileFormat(const string& path) {
    913   brillo::Blob buffer;
    914   if (!ReadFileChunkAndAppend(path, 0, kGetFileFormatMaxHeaderSize, &buffer))
    915     return "File not found.";
    916 
    917   string result;
    918   if (GetFileFormatELF(buffer.data(), buffer.size(), &result))
    919     return result;
    920 
    921   return "data";
    922 }
    923 
    924 namespace {
    925 // Do the actual trigger. We do it as a main-loop callback to (try to) get a
    926 // consistent stack trace.
    927 void TriggerCrashReporterUpload() {
    928   pid_t pid = fork();
    929   CHECK_GE(pid, 0) << "fork failed";  // fork() failed. Something is very wrong.
    930   if (pid == 0) {
    931     // We are the child. Crash.
    932     abort();  // never returns
    933   }
    934   // We are the parent. Wait for child to terminate.
    935   pid_t result = waitpid(pid, nullptr, 0);
    936   LOG_IF(ERROR, result < 0) << "waitpid() failed";
    937 }
    938 }  // namespace
    939 
    940 void ScheduleCrashReporterUpload() {
    941   brillo::MessageLoop::current()->PostTask(
    942       FROM_HERE,
    943       base::Bind(&TriggerCrashReporterUpload));
    944 }
    945 
    946 int FuzzInt(int value, unsigned int range) {
    947   int min = value - range / 2;
    948   int max = value + range - range / 2;
    949   return base::RandInt(min, max);
    950 }
    951 
    952 string FormatSecs(unsigned secs) {
    953   return FormatTimeDelta(TimeDelta::FromSeconds(secs));
    954 }
    955 
    956 string FormatTimeDelta(TimeDelta delta) {
    957   string str;
    958 
    959   // Handle negative durations by prefixing with a minus.
    960   if (delta.ToInternalValue() < 0) {
    961     delta *= -1;
    962     str = "-";
    963   }
    964 
    965   // Canonicalize into days, hours, minutes, seconds and microseconds.
    966   unsigned days = delta.InDays();
    967   delta -= TimeDelta::FromDays(days);
    968   unsigned hours = delta.InHours();
    969   delta -= TimeDelta::FromHours(hours);
    970   unsigned mins = delta.InMinutes();
    971   delta -= TimeDelta::FromMinutes(mins);
    972   unsigned secs = delta.InSeconds();
    973   delta -= TimeDelta::FromSeconds(secs);
    974   unsigned usecs = delta.InMicroseconds();
    975 
    976   if (days)
    977     base::StringAppendF(&str, "%ud", days);
    978   if (days || hours)
    979     base::StringAppendF(&str, "%uh", hours);
    980   if (days || hours || mins)
    981     base::StringAppendF(&str, "%um", mins);
    982   base::StringAppendF(&str, "%u", secs);
    983   if (usecs) {
    984     int width = 6;
    985     while ((usecs / 10) * 10 == usecs) {
    986       usecs /= 10;
    987       width--;
    988     }
    989     base::StringAppendF(&str, ".%0*u", width, usecs);
    990   }
    991   base::StringAppendF(&str, "s");
    992   return str;
    993 }
    994 
    995 string ToString(const Time utc_time) {
    996   Time::Exploded exp_time;
    997   utc_time.UTCExplode(&exp_time);
    998   return base::StringPrintf("%d/%d/%d %d:%02d:%02d GMT",
    999                       exp_time.month,
   1000                       exp_time.day_of_month,
   1001                       exp_time.year,
   1002                       exp_time.hour,
   1003                       exp_time.minute,
   1004                       exp_time.second);
   1005 }
   1006 
   1007 string ToString(bool b) {
   1008   return (b ? "true" : "false");
   1009 }
   1010 
   1011 string ToString(DownloadSource source) {
   1012   switch (source) {
   1013     case kDownloadSourceHttpsServer: return "HttpsServer";
   1014     case kDownloadSourceHttpServer:  return "HttpServer";
   1015     case kDownloadSourceHttpPeer:    return "HttpPeer";
   1016     case kNumDownloadSources:        return "Unknown";
   1017     // Don't add a default case to let the compiler warn about newly added
   1018     // download sources which should be added here.
   1019   }
   1020 
   1021   return "Unknown";
   1022 }
   1023 
   1024 string ToString(PayloadType payload_type) {
   1025   switch (payload_type) {
   1026     case kPayloadTypeDelta:      return "Delta";
   1027     case kPayloadTypeFull:       return "Full";
   1028     case kPayloadTypeForcedFull: return "ForcedFull";
   1029     case kNumPayloadTypes:       return "Unknown";
   1030     // Don't add a default case to let the compiler warn about newly added
   1031     // payload types which should be added here.
   1032   }
   1033 
   1034   return "Unknown";
   1035 }
   1036 
   1037 ErrorCode GetBaseErrorCode(ErrorCode code) {
   1038   // Ignore the higher order bits in the code by applying the mask as
   1039   // we want the enumerations to be in the small contiguous range
   1040   // with values less than ErrorCode::kUmaReportedMax.
   1041   ErrorCode base_code = static_cast<ErrorCode>(
   1042       static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags));
   1043 
   1044   // Make additional adjustments required for UMA and error classification.
   1045   // TODO(jaysri): Move this logic to UeErrorCode.cc when we fix
   1046   // chromium-os:34369.
   1047   if (base_code >= ErrorCode::kOmahaRequestHTTPResponseBase) {
   1048     // Since we want to keep the enums to a small value, aggregate all HTTP
   1049     // errors into this one bucket for UMA and error classification purposes.
   1050     LOG(INFO) << "Converting error code " << base_code
   1051               << " to ErrorCode::kOmahaErrorInHTTPResponse";
   1052     base_code = ErrorCode::kOmahaErrorInHTTPResponse;
   1053   }
   1054 
   1055   return base_code;
   1056 }
   1057 
   1058 bool CreatePowerwashMarkerFile(const char* file_path) {
   1059   const char* marker_file = file_path ? file_path : kPowerwashMarkerFile;
   1060   bool result = utils::WriteFile(marker_file,
   1061                                  kPowerwashCommand,
   1062                                  strlen(kPowerwashCommand));
   1063   if (result) {
   1064     LOG(INFO) << "Created " << marker_file << " to powerwash on next reboot";
   1065   } else {
   1066     PLOG(ERROR) << "Error in creating powerwash marker file: " << marker_file;
   1067   }
   1068 
   1069   return result;
   1070 }
   1071 
   1072 bool DeletePowerwashMarkerFile(const char* file_path) {
   1073   const char* marker_file = file_path ? file_path : kPowerwashMarkerFile;
   1074   const base::FilePath kPowerwashMarkerPath(marker_file);
   1075   bool result = base::DeleteFile(kPowerwashMarkerPath, false);
   1076 
   1077   if (result)
   1078     LOG(INFO) << "Successfully deleted the powerwash marker file : "
   1079               << marker_file;
   1080   else
   1081     PLOG(ERROR) << "Could not delete the powerwash marker file : "
   1082                 << marker_file;
   1083 
   1084   return result;
   1085 }
   1086 
   1087 Time TimeFromStructTimespec(struct timespec *ts) {
   1088   int64_t us = static_cast<int64_t>(ts->tv_sec) * Time::kMicrosecondsPerSecond +
   1089       static_cast<int64_t>(ts->tv_nsec) / Time::kNanosecondsPerMicrosecond;
   1090   return Time::UnixEpoch() + TimeDelta::FromMicroseconds(us);
   1091 }
   1092 
   1093 string StringVectorToString(const vector<string> &vec_str) {
   1094   string str = "[";
   1095   for (vector<string>::const_iterator i = vec_str.begin();
   1096        i != vec_str.end(); ++i) {
   1097     if (i != vec_str.begin())
   1098       str += ", ";
   1099     str += '"';
   1100     str += *i;
   1101     str += '"';
   1102   }
   1103   str += "]";
   1104   return str;
   1105 }
   1106 
   1107 string CalculateP2PFileId(const string& payload_hash, size_t payload_size) {
   1108   string encoded_hash = brillo::data_encoding::Base64Encode(payload_hash);
   1109   return base::StringPrintf("cros_update_size_%" PRIuS "_hash_%s",
   1110                             payload_size,
   1111                             encoded_hash.c_str());
   1112 }
   1113 
   1114 bool DecodeAndStoreBase64String(const string& base64_encoded,
   1115                                 base::FilePath *out_path) {
   1116   brillo::Blob contents;
   1117 
   1118   out_path->clear();
   1119 
   1120   if (base64_encoded.size() == 0) {
   1121     LOG(ERROR) << "Can't decode empty string.";
   1122     return false;
   1123   }
   1124 
   1125   if (!brillo::data_encoding::Base64Decode(base64_encoded, &contents) ||
   1126       contents.size() == 0) {
   1127     LOG(ERROR) << "Error decoding base64.";
   1128     return false;
   1129   }
   1130 
   1131   FILE *file = base::CreateAndOpenTemporaryFile(out_path);
   1132   if (file == nullptr) {
   1133     LOG(ERROR) << "Error creating temporary file.";
   1134     return false;
   1135   }
   1136 
   1137   if (fwrite(contents.data(), 1, contents.size(), file) != contents.size()) {
   1138     PLOG(ERROR) << "Error writing to temporary file.";
   1139     if (fclose(file) != 0)
   1140       PLOG(ERROR) << "Error closing temporary file.";
   1141     if (unlink(out_path->value().c_str()) != 0)
   1142       PLOG(ERROR) << "Error unlinking temporary file.";
   1143     out_path->clear();
   1144     return false;
   1145   }
   1146 
   1147   if (fclose(file) != 0) {
   1148     PLOG(ERROR) << "Error closing temporary file.";
   1149     out_path->clear();
   1150     return false;
   1151   }
   1152 
   1153   return true;
   1154 }
   1155 
   1156 bool ConvertToOmahaInstallDate(Time time, int *out_num_days) {
   1157   time_t unix_time = time.ToTimeT();
   1158   // Output of: date +"%s" --date="Jan 1, 2007 0:00 PST".
   1159   const time_t kOmahaEpoch = 1167638400;
   1160   const int64_t kNumSecondsPerWeek = 7*24*3600;
   1161   const int64_t kNumDaysPerWeek = 7;
   1162 
   1163   time_t omaha_time = unix_time - kOmahaEpoch;
   1164 
   1165   if (omaha_time < 0)
   1166     return false;
   1167 
   1168   // Note, as per the comment in utils.h we are deliberately not
   1169   // handling DST correctly.
   1170 
   1171   int64_t num_weeks_since_omaha_epoch = omaha_time / kNumSecondsPerWeek;
   1172   *out_num_days = num_weeks_since_omaha_epoch * kNumDaysPerWeek;
   1173 
   1174   return true;
   1175 }
   1176 
   1177 bool GetMinorVersion(const brillo::KeyValueStore& store,
   1178                      uint32_t* minor_version) {
   1179   string result;
   1180   if (store.GetString("PAYLOAD_MINOR_VERSION", &result)) {
   1181     if (!base::StringToUint(result, minor_version)) {
   1182       LOG(ERROR) << "StringToUint failed when parsing delta minor version.";
   1183       return false;
   1184     }
   1185     return true;
   1186   }
   1187   return false;
   1188 }
   1189 
   1190 bool IsZlibCompatible(const string& fingerprint) {
   1191   if (fingerprint.size() != sizeof(kCompatibleZlibFingerprint[0]) - 1) {
   1192     LOG(ERROR) << "Invalid fingerprint: " << fingerprint;
   1193     return false;
   1194   }
   1195   for (auto& f : kCompatibleZlibFingerprint) {
   1196     if (base::CompareCaseInsensitiveASCII(fingerprint, f) == 0) {
   1197       return true;
   1198     }
   1199   }
   1200   return false;
   1201 }
   1202 
   1203 bool ReadExtents(const string& path, const vector<Extent>& extents,
   1204                  brillo::Blob* out_data, ssize_t out_data_size,
   1205                  size_t block_size) {
   1206   brillo::Blob data(out_data_size);
   1207   ssize_t bytes_read = 0;
   1208   int fd = open(path.c_str(), O_RDONLY);
   1209   TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
   1210   ScopedFdCloser fd_closer(&fd);
   1211 
   1212   for (const Extent& extent : extents) {
   1213     ssize_t bytes_read_this_iteration = 0;
   1214     ssize_t bytes = extent.num_blocks() * block_size;
   1215     TEST_AND_RETURN_FALSE(bytes_read + bytes <= out_data_size);
   1216     TEST_AND_RETURN_FALSE(utils::PReadAll(fd,
   1217                                           &data[bytes_read],
   1218                                           bytes,
   1219                                           extent.start_block() * block_size,
   1220                                           &bytes_read_this_iteration));
   1221     TEST_AND_RETURN_FALSE(bytes_read_this_iteration == bytes);
   1222     bytes_read += bytes_read_this_iteration;
   1223   }
   1224   TEST_AND_RETURN_FALSE(out_data_size == bytes_read);
   1225   *out_data = data;
   1226   return true;
   1227 }
   1228 
   1229 bool GetBootId(string* boot_id) {
   1230   TEST_AND_RETURN_FALSE(
   1231       base::ReadFileToString(base::FilePath(kBootIdPath), boot_id));
   1232   base::TrimWhitespaceASCII(*boot_id, base::TRIM_TRAILING, boot_id);
   1233   return true;
   1234 }
   1235 
   1236 }  // namespace utils
   1237 
   1238 }  // namespace chromeos_update_engine
   1239