OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "update_engine/set_bootable_flag_action.h" |
| 6 #include <sys/stat.h> |
| 7 #include <sys/types.h> |
| 8 #include <errno.h> |
| 9 #include <fcntl.h> |
| 10 #include <string> |
| 11 #include "update_engine/utils.h" |
| 12 |
| 13 using std::string; |
| 14 |
| 15 namespace chromeos_update_engine { |
| 16 |
| 17 void SetBootableFlagAction::PerformAction() { |
| 18 ScopedActionCompleter completer(processor_, this); |
| 19 |
| 20 if (!HasInputObject() || GetInputObject().empty()) { |
| 21 LOG(ERROR) << "SetBootableFlagAction: No input object."; |
| 22 return; |
| 23 } |
| 24 string device = GetInputObject(); |
| 25 |
| 26 if (device.size() < 2) { |
| 27 LOG(ERROR) << "Device name too short: " << device; |
| 28 return; |
| 29 } |
| 30 |
| 31 // Make sure device is valid. |
| 32 const char last_char = device[device.size() - 1]; |
| 33 if ((last_char < '1') || (last_char > '4')) { |
| 34 LOG(ERROR) << "Bad device:" << device; |
| 35 return; |
| 36 } |
| 37 |
| 38 // We were passed the partition_number'th partition; indexed from 1, not 0 |
| 39 int partition_number = last_char - '0'; |
| 40 |
| 41 const char second_to_last_char = device[device.size() - 2]; |
| 42 if ((second_to_last_char >= '0') && (second_to_last_char <= '9')) { |
| 43 LOG(ERROR) << "Bad device:" << device; |
| 44 return; |
| 45 } |
| 46 |
| 47 // Strip trailing 1-4 off end of device |
| 48 device.resize(device.size() - 1); |
| 49 |
| 50 char mbr[512]; // MBR is the first 512 bytes of the device |
| 51 if (!ReadMbr(mbr, sizeof(mbr), device.c_str())) |
| 52 return; |
| 53 |
| 54 // Check MBR. Verify that last two byes are 0x55aa. This is the MBR signature. |
| 55 if ((mbr[510] != static_cast<char>(0x55)) || |
| 56 (mbr[511] != static_cast<char>(0xaa))) { |
| 57 LOG(ERROR) << "Bad MBR signature"; |
| 58 return; |
| 59 } |
| 60 |
| 61 // Mark partition passed in bootable and all other partitions non bootable. |
| 62 // There are 4 partition table entries, each 16 bytes, stored consecutively |
| 63 // beginning at byte 446. Within each entry, the first byte is the |
| 64 // bootable flag. It's set to 0x80 (bootable) or 0x00 (not bootable). |
| 65 for (int i = 0; i < 4; i++) { |
| 66 int offset = 446 + 16 * i; |
| 67 |
| 68 // partition_number is indexed from 1, not 0 |
| 69 if ((i + 1) == partition_number) |
| 70 mbr[offset] = 0x80; |
| 71 else |
| 72 mbr[offset] = '\0'; |
| 73 } |
| 74 |
| 75 // Write MBR back to disk |
| 76 bool success = WriteMbr(mbr, sizeof(mbr), device.c_str()); |
| 77 if (success) { |
| 78 completer.set_success(true); |
| 79 if (HasOutputPipe()) { |
| 80 SetOutputObject(GetInputObject()); |
| 81 } |
| 82 } |
| 83 } |
| 84 |
| 85 bool SetBootableFlagAction::ReadMbr(char* buffer, |
| 86 int buffer_len, |
| 87 const char* device) { |
| 88 int fd = open(device, O_RDONLY, 0); |
| 89 TEST_AND_RETURN_FALSE(fd >= 0); |
| 90 |
| 91 ssize_t r = read(fd, buffer, buffer_len); |
| 92 close(fd); |
| 93 TEST_AND_RETURN_FALSE(r == buffer_len); |
| 94 |
| 95 return true; |
| 96 } |
| 97 |
| 98 bool SetBootableFlagAction::WriteMbr(const char* buffer, |
| 99 int buffer_len, |
| 100 const char* device) { |
| 101 int fd = open(device, O_WRONLY, 0666); |
| 102 TEST_AND_RETURN_FALSE(fd >= 0); |
| 103 ScopedFdCloser fd_closer(&fd); |
| 104 |
| 105 ssize_t bytes_written = 0; |
| 106 while (bytes_written < buffer_len) { |
| 107 ssize_t r = write(fd, buffer + bytes_written, buffer_len - bytes_written); |
| 108 TEST_AND_RETURN_FALSE_ERRNO(r >= 0); |
| 109 bytes_written += r; |
| 110 } |
| 111 TEST_AND_RETURN_FALSE(bytes_written == buffer_len); |
| 112 |
| 113 return true; |
| 114 } |
| 115 |
| 116 |
| 117 } // namespace chromeos_update_engine |
OLD | NEW |