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