utils.cc revision a918f9daede277d043e5b3b8443d712c88c949da
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
66using base::Time;
67using base::TimeDelta;
68using std::min;
69using std::pair;
70using std::string;
71using std::vector;
72
73namespace chromeos_update_engine {
74
75namespace {
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.
80const int kUnmountMaxNumOfRetries = 5;
81const 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.
85const int kGetFileFormatMaxHeaderSize = 32;
86
87// The path to the kernel's boot_id.
88const 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.
92bool 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.
100string 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).
115string 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.
137bool 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
159namespace utils {
160
161string 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
182bool 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
192bool 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
221bool 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
232bool 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
252bool 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
263bool 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
272bool 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
289bool 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|.
309static 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}
315static 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.
326template <class T>
327static 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.
355template <class T>
356static 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.
378bool 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
386bool ReadFile(const string& path, brillo::Blob* out_p) {
387  return ReadFileChunkAndAppend(path, 0, -1, out_p);
388}
389
390bool ReadFile(const string& path, string* out_p) {
391  return ReadFileChunkAndAppend(path, 0, -1, out_p);
392}
393
394bool 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
399off_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
409off_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
425off_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
438void 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
460bool 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
512string 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
543string 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
554string ErrnoNumberAsString(int err) {
555  char buf[100];
556  buf[0] = '\0';
557  return strerror_r(err, buf, sizeof(buf));
558}
559
560bool FileExists(const char* path) {
561  struct stat stbuf;
562  return 0 == lstat(path, &stbuf);
563}
564
565bool IsSymlink(const char* path) {
566  struct stat stbuf;
567  return lstat(path, &stbuf) == 0 && S_ISLNK(stbuf.st_mode) != 0;
568}
569
570bool 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
603bool 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
628bool 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
644bool 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
668bool 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
694bool 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
706bool 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
715bool 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
744bool 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
784bool 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
823bool 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
832bool 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.
843static 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
912string 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
924namespace {
925// Do the actual trigger. We do it as a main-loop callback to (try to) get a
926// consistent stack trace.
927void 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
940void ScheduleCrashReporterUpload() {
941  brillo::MessageLoop::current()->PostTask(
942      FROM_HERE,
943      base::Bind(&TriggerCrashReporterUpload));
944}
945
946int 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
952string FormatSecs(unsigned secs) {
953  return FormatTimeDelta(TimeDelta::FromSeconds(secs));
954}
955
956string 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
995string 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
1007string ToString(bool b) {
1008  return (b ? "true" : "false");
1009}
1010
1011string 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
1024string 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
1037ErrorCode 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
1058Time TimeFromStructTimespec(struct timespec *ts) {
1059  int64_t us = static_cast<int64_t>(ts->tv_sec) * Time::kMicrosecondsPerSecond +
1060      static_cast<int64_t>(ts->tv_nsec) / Time::kNanosecondsPerMicrosecond;
1061  return Time::UnixEpoch() + TimeDelta::FromMicroseconds(us);
1062}
1063
1064string StringVectorToString(const vector<string> &vec_str) {
1065  string str = "[";
1066  for (vector<string>::const_iterator i = vec_str.begin();
1067       i != vec_str.end(); ++i) {
1068    if (i != vec_str.begin())
1069      str += ", ";
1070    str += '"';
1071    str += *i;
1072    str += '"';
1073  }
1074  str += "]";
1075  return str;
1076}
1077
1078string CalculateP2PFileId(const string& payload_hash, size_t payload_size) {
1079  string encoded_hash = brillo::data_encoding::Base64Encode(payload_hash);
1080  return base::StringPrintf("cros_update_size_%" PRIuS "_hash_%s",
1081                            payload_size,
1082                            encoded_hash.c_str());
1083}
1084
1085bool DecodeAndStoreBase64String(const string& base64_encoded,
1086                                base::FilePath *out_path) {
1087  brillo::Blob contents;
1088
1089  out_path->clear();
1090
1091  if (base64_encoded.size() == 0) {
1092    LOG(ERROR) << "Can't decode empty string.";
1093    return false;
1094  }
1095
1096  if (!brillo::data_encoding::Base64Decode(base64_encoded, &contents) ||
1097      contents.size() == 0) {
1098    LOG(ERROR) << "Error decoding base64.";
1099    return false;
1100  }
1101
1102  FILE *file = base::CreateAndOpenTemporaryFile(out_path);
1103  if (file == nullptr) {
1104    LOG(ERROR) << "Error creating temporary file.";
1105    return false;
1106  }
1107
1108  if (fwrite(contents.data(), 1, contents.size(), file) != contents.size()) {
1109    PLOG(ERROR) << "Error writing to temporary file.";
1110    if (fclose(file) != 0)
1111      PLOG(ERROR) << "Error closing temporary file.";
1112    if (unlink(out_path->value().c_str()) != 0)
1113      PLOG(ERROR) << "Error unlinking temporary file.";
1114    out_path->clear();
1115    return false;
1116  }
1117
1118  if (fclose(file) != 0) {
1119    PLOG(ERROR) << "Error closing temporary file.";
1120    out_path->clear();
1121    return false;
1122  }
1123
1124  return true;
1125}
1126
1127bool ConvertToOmahaInstallDate(Time time, int *out_num_days) {
1128  time_t unix_time = time.ToTimeT();
1129  // Output of: date +"%s" --date="Jan 1, 2007 0:00 PST".
1130  const time_t kOmahaEpoch = 1167638400;
1131  const int64_t kNumSecondsPerWeek = 7*24*3600;
1132  const int64_t kNumDaysPerWeek = 7;
1133
1134  time_t omaha_time = unix_time - kOmahaEpoch;
1135
1136  if (omaha_time < 0)
1137    return false;
1138
1139  // Note, as per the comment in utils.h we are deliberately not
1140  // handling DST correctly.
1141
1142  int64_t num_weeks_since_omaha_epoch = omaha_time / kNumSecondsPerWeek;
1143  *out_num_days = num_weeks_since_omaha_epoch * kNumDaysPerWeek;
1144
1145  return true;
1146}
1147
1148bool GetMinorVersion(const brillo::KeyValueStore& store,
1149                     uint32_t* minor_version) {
1150  string result;
1151  if (store.GetString("PAYLOAD_MINOR_VERSION", &result)) {
1152    if (!base::StringToUint(result, minor_version)) {
1153      LOG(ERROR) << "StringToUint failed when parsing delta minor version.";
1154      return false;
1155    }
1156    return true;
1157  }
1158  return false;
1159}
1160
1161bool IsZlibCompatible(const string& fingerprint) {
1162  if (fingerprint.size() != sizeof(kCompatibleZlibFingerprint[0]) - 1) {
1163    LOG(ERROR) << "Invalid fingerprint: " << fingerprint;
1164    return false;
1165  }
1166  for (auto& f : kCompatibleZlibFingerprint) {
1167    if (base::CompareCaseInsensitiveASCII(fingerprint, f) == 0) {
1168      return true;
1169    }
1170  }
1171  return false;
1172}
1173
1174bool ReadExtents(const string& path, const vector<Extent>& extents,
1175                 brillo::Blob* out_data, ssize_t out_data_size,
1176                 size_t block_size) {
1177  brillo::Blob data(out_data_size);
1178  ssize_t bytes_read = 0;
1179  int fd = open(path.c_str(), O_RDONLY);
1180  TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
1181  ScopedFdCloser fd_closer(&fd);
1182
1183  for (const Extent& extent : extents) {
1184    ssize_t bytes_read_this_iteration = 0;
1185    ssize_t bytes = extent.num_blocks() * block_size;
1186    TEST_AND_RETURN_FALSE(bytes_read + bytes <= out_data_size);
1187    TEST_AND_RETURN_FALSE(utils::PReadAll(fd,
1188                                          &data[bytes_read],
1189                                          bytes,
1190                                          extent.start_block() * block_size,
1191                                          &bytes_read_this_iteration));
1192    TEST_AND_RETURN_FALSE(bytes_read_this_iteration == bytes);
1193    bytes_read += bytes_read_this_iteration;
1194  }
1195  TEST_AND_RETURN_FALSE(out_data_size == bytes_read);
1196  *out_data = data;
1197  return true;
1198}
1199
1200bool GetBootId(string* boot_id) {
1201  TEST_AND_RETURN_FALSE(
1202      base::ReadFileToString(base::FilePath(kBootIdPath), boot_id));
1203  base::TrimWhitespaceASCII(*boot_id, base::TRIM_TRAILING, boot_id);
1204  return true;
1205}
1206
1207}  // namespace utils
1208
1209}  // namespace chromeos_update_engine
1210