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.
IsMtdDeviceName(const string & disk_name)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.
MakeNandPartitionName(int partition_num)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).
MakeNandPartitionNameForMount(int partition_num)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.
GetTempName(const string & path,base::FilePath * template_path)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 
ParseECVersion(string input_line)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 
WriteFile(const char * path,const void * data,int data_len)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 
ReadAll(int fd,void * buf,size_t count,size_t * out_bytes_read,bool * eof)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 
WriteAll(int fd,const void * buf,size_t count)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 
PWriteAll(int fd,const void * buf,size_t count,off_t offset)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 
WriteAll(FileDescriptorPtr fd,const void * buf,size_t count)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 
PWriteAll(FileDescriptorPtr fd,const void * buf,size_t count,off_t offset)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 
PReadAll(int fd,void * buf,size_t count,off_t offset,ssize_t * out_bytes_read)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 
PReadAll(FileDescriptorPtr fd,void * buf,size_t count,off_t offset,ssize_t * out_bytes_read)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|.
AppendBytes(const uint8_t * buf,size_t nbytes,brillo::Blob * vec_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 }
AppendBytes(const uint8_t * buf,size_t nbytes,string * str_p)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>
Read(FILE * fp,off_t size,T * out_p)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>
ReadFileChunkAndAppend(const string & path,off_t offset,off_t size,T * out_p)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.
ReadPipe(const string & cmd,string * out_p)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 
ReadFile(const string & path,brillo::Blob * out_p)386 bool ReadFile(const string& path, brillo::Blob* out_p) {
387   return ReadFileChunkAndAppend(path, 0, -1, out_p);
388 }
389 
ReadFile(const string & path,string * out_p)390 bool ReadFile(const string& path, string* out_p) {
391   return ReadFileChunkAndAppend(path, 0, -1, out_p);
392 }
393 
ReadFileChunk(const string & path,off_t offset,off_t size,brillo::Blob * out_p)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 
BlockDevSize(int fd)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 
FileSize(int fd)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 
FileSize(const string & path)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 
HexDumpArray(const uint8_t * const arr,const size_t length)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 
SplitPartitionName(const string & partition_name,string * out_disk_name,int * out_partition_num)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 
MakePartitionName(const string & disk_name,int partition_num)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 
MakePartitionNameForMount(const string & part_name)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 
ErrnoNumberAsString(int err)554 string ErrnoNumberAsString(int err) {
555   char buf[100];
556   buf[0] = '\0';
557   return strerror_r(err, buf, sizeof(buf));
558 }
559 
FileExists(const char * path)560 bool FileExists(const char* path) {
561   struct stat stbuf;
562   return 0 == lstat(path, &stbuf);
563 }
564 
IsSymlink(const char * path)565 bool IsSymlink(const char* path) {
566   struct stat stbuf;
567   return lstat(path, &stbuf) == 0 && S_ISLNK(stbuf.st_mode) != 0;
568 }
569 
TryAttachingUbiVolume(int volume_num,int timeout)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 
MakeTempFile(const string & base_filename_template,string * filename,int * fd)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 
MakeTempDirectory(const string & base_dirname_template,string * dirname)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 
SetBlockDeviceReadOnly(const string & device,bool read_only)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 
MountFilesystem(const string & device,const string & mountpoint,unsigned long mountflags,const string & type,const string & fs_mount_options)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 
UnmountFilesystem(const string & mountpoint)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 
GetFilesystemSize(const string & device,int * out_block_count,int * out_block_size)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 
GetFilesystemSizeFromFD(int fd,int * out_block_count,int * out_block_size)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 
GetExt3Size(const uint8_t * buffer,size_t buffer_size,int * out_block_count,int * out_block_size)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 
GetSquashfs4Size(const uint8_t * buffer,size_t buffer_size,int * out_block_count,int * out_block_size)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 
IsExtFilesystem(const string & device)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 
IsSquashfsFilesystem(const string & device)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.
GetFileFormatELF(const uint8_t * buffer,size_t size,string * output)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 
GetFileFormat(const string & path)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.
TriggerCrashReporterUpload()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 
ScheduleCrashReporterUpload()940 void ScheduleCrashReporterUpload() {
941   brillo::MessageLoop::current()->PostTask(
942       FROM_HERE,
943       base::Bind(&TriggerCrashReporterUpload));
944 }
945 
FuzzInt(int value,unsigned int range)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 
FormatSecs(unsigned secs)952 string FormatSecs(unsigned secs) {
953   return FormatTimeDelta(TimeDelta::FromSeconds(secs));
954 }
955 
FormatTimeDelta(TimeDelta delta)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 
ToString(const Time utc_time)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 
ToString(bool b)1007 string ToString(bool b) {
1008   return (b ? "true" : "false");
1009 }
1010 
ToString(DownloadSource source)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 
ToString(PayloadType payload_type)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 
GetBaseErrorCode(ErrorCode code)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 
CreatePowerwashMarkerFile(const char * file_path)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 
DeletePowerwashMarkerFile(const char * file_path)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 
TimeFromStructTimespec(struct timespec * ts)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 
StringVectorToString(const vector<string> & vec_str)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 
CalculateP2PFileId(const string & payload_hash,size_t payload_size)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 
DecodeAndStoreBase64String(const string & base64_encoded,base::FilePath * out_path)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 
ConvertToOmahaInstallDate(Time time,int * out_num_days)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 
GetMinorVersion(const brillo::KeyValueStore & store,uint32_t * minor_version)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 
IsZlibCompatible(const string & fingerprint)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 
ReadExtents(const string & path,const vector<Extent> & extents,brillo::Blob * out_data,ssize_t out_data_size,size_t block_size)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 
GetBootId(string * boot_id)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