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