OLD | NEW |
(Empty) | |
| 1 /* Copyright (c) 2010 The Chromium OS 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 * Utility for ChromeOS-specific GPT partitions, Please see corresponding .c |
| 6 * files for more details. |
| 7 */ |
| 8 #include "cgpt.h" |
| 9 #include <errno.h> |
| 10 #include <fcntl.h> |
| 11 #include <getopt.h> |
| 12 #include <stdint.h> |
| 13 #include <stdio.h> |
| 14 #include <stdlib.h> |
| 15 #include <string.h> |
| 16 #include <sys/ioctl.h> |
| 17 #include <sys/mount.h> |
| 18 #include <sys/stat.h> |
| 19 #include <sys/types.h> |
| 20 #include <unistd.h> |
| 21 #include "utility.h" |
| 22 |
| 23 /* For usage print */ |
| 24 const char* progname; |
| 25 |
| 26 /* Lists all command here. */ |
| 27 struct { |
| 28 const char *name; |
| 29 int (*fp)(int argc, char *argv[]); |
| 30 const char *comment; |
| 31 } cmds[] = { |
| 32 {"attribute", CgptAttribute, "Update GPT attribute bits " |
| 33 "(for ChromeOS kernel entry only)"}, |
| 34 {"show", CgptShow, "Show partition details"}, |
| 35 }; |
| 36 |
| 37 /* Shows main menu. If 'message' is non-NULL, shows it as header. Then, this |
| 38 * traverses cmds[] and shows supported commands and their comments. */ |
| 39 void Usage(const char *message) { |
| 40 int i; |
| 41 |
| 42 if (message) printf("%s\n", message); |
| 43 printf("Usage: %s COMMAND [OPTIONS]\n\n" |
| 44 "Supported commands:\n\n", |
| 45 progname); |
| 46 for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) { |
| 47 printf(" %-10s %s\n", cmds[i].name, cmds[i].comment); |
| 48 } |
| 49 printf("\nFor more detailed usage, use %s COMMAND --help.\n\n", progname); |
| 50 } |
| 51 |
| 52 /* Loads sectors from 'fd'. |
| 53 * *buf is pointed to an allocated memory when returned, and should be |
| 54 * freed by cgpt_close(). |
| 55 * |
| 56 * fd -- file descriptot. |
| 57 * buf -- pointer to buffer pointer |
| 58 * sector -- offset of starting sector (in sectors) |
| 59 * sector_bytes -- bytes per sector |
| 60 * sector_count -- number of sectors to load |
| 61 * |
| 62 * Returns CGPT_OK for successful. Aborts if any error occurs. |
| 63 */ |
| 64 int Load(const int fd, uint8_t **buf, |
| 65 const uint64_t sector, |
| 66 const uint64_t sector_bytes, |
| 67 const uint64_t sector_count) { |
| 68 int count; /* byte count to read */ |
| 69 int nread; |
| 70 |
| 71 assert(buf); |
| 72 count = sector_bytes * sector_count; |
| 73 *buf = Malloc(count); |
| 74 assert(*buf); |
| 75 |
| 76 if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET)) |
| 77 goto error_free; |
| 78 |
| 79 nread = read(fd, *buf, count); |
| 80 if (nread < count) |
| 81 goto error_free; |
| 82 |
| 83 return CGPT_OK; |
| 84 |
| 85 error_free: |
| 86 Free(*buf); |
| 87 *buf = 0; |
| 88 abort(); |
| 89 } |
| 90 |
| 91 /* Saves sectors to 'fd'. |
| 92 * |
| 93 * fd -- file descriptot. |
| 94 * buf -- pointer to buffer |
| 95 * sector -- starting sector offset |
| 96 * sector_bytes -- bytes per sector |
| 97 * sector_count -- number of sector to save |
| 98 * |
| 99 * Returns CGPT_OK for successful, CGPT_FAILED for failed. |
| 100 */ |
| 101 int Save(const int fd, const uint8_t *buf, |
| 102 const uint64_t sector, |
| 103 const uint64_t sector_bytes, |
| 104 const uint64_t sector_count) { |
| 105 int count; /* byte count to write */ |
| 106 int nwrote; |
| 107 |
| 108 assert(buf); |
| 109 count = sector_bytes * sector_count; |
| 110 |
| 111 if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET)) |
| 112 return CGPT_FAILED; |
| 113 |
| 114 nwrote = write(fd, buf, count); |
| 115 if (nwrote < count) |
| 116 return CGPT_FAILED; |
| 117 |
| 118 return CGPT_OK; |
| 119 } |
| 120 |
| 121 /* Opens a block device (a regular file works well too). |
| 122 * |
| 123 * Returns CGPT_FAILED if any error happens. |
| 124 * Returns CGPT_OK if success and information are stored in 'drive'. */ |
| 125 int DriveOpen(const char *drive_path, struct drive *drive) { |
| 126 struct stat stat; |
| 127 int gpt_retval; |
| 128 |
| 129 assert(drive_path); |
| 130 assert(drive); |
| 131 |
| 132 Memset(drive, 0, sizeof(struct drive)); |
| 133 drive->fd = open(drive_path, O_RDWR); |
| 134 if (drive->fd == -1) { |
| 135 printf("[ERROR] Cannot open drive file [%s]: %s\n", |
| 136 drive_path, strerror(errno)); |
| 137 return CGPT_FAILED; |
| 138 } |
| 139 |
| 140 if (fstat(drive->fd, &stat) == -1) { |
| 141 goto error_close; |
| 142 } |
| 143 if ((stat.st_mode & S_IFMT) != S_IFREG) { |
| 144 if (ioctl(drive->fd, BLKGETSIZE64, &drive->size) < 0) { |
| 145 printf("[ERROR] Cannot get sector size from drive file [%s]: %s\n", |
| 146 drive_path, strerror(errno)); |
| 147 goto error_close; |
| 148 } |
| 149 if (ioctl(drive->fd, BLKSSZGET, &drive->gpt.sector_bytes) < 0) { |
| 150 printf("[ERROR] Cannot get drive size from drive file [%s]: %s\n", |
| 151 drive_path, strerror(errno)); |
| 152 goto error_close; |
| 153 } |
| 154 } else { |
| 155 drive->gpt.sector_bytes = 512; /* bytes */ |
| 156 drive->size = stat.st_size; |
| 157 } |
| 158 if (drive->size % drive->gpt.sector_bytes) { |
| 159 printf("[ERROR] Media size (%llu) is not the multiple of sector size(%d)\n", |
| 160 (long long unsigned int)drive->size, drive->gpt.sector_bytes); |
| 161 goto error_close; |
| 162 } |
| 163 drive->gpt.drive_sectors = drive->size / drive->gpt.sector_bytes; |
| 164 debug("drive: size:%llu sector_size:%d num_sector:%llu\n", |
| 165 (long long unsigned int)drive->size, drive->gpt.sector_bytes, |
| 166 (long long unsigned int)drive->gpt.drive_sectors); |
| 167 |
| 168 Load(drive->fd, &drive->gpt.primary_header, GPT_PMBR_SECTOR, |
| 169 drive->gpt.sector_bytes, GPT_HEADER_SECTOR); |
| 170 Load(drive->fd, &drive->gpt.secondary_header, |
| 171 drive->gpt.drive_sectors - GPT_PMBR_SECTOR, |
| 172 drive->gpt.sector_bytes, GPT_HEADER_SECTOR); |
| 173 Load(drive->fd, &drive->gpt.primary_entries, |
| 174 GPT_PMBR_SECTOR + GPT_HEADER_SECTOR, |
| 175 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS); |
| 176 Load(drive->fd, &drive->gpt.secondary_entries, |
| 177 drive->gpt.drive_sectors - GPT_HEADER_SECTOR - GPT_ENTRIES_SECTORS, |
| 178 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS); |
| 179 |
| 180 if (GPT_SUCCESS != (gpt_retval = GptInit(&drive->gpt))) { |
| 181 printf("[ERROR] GptInit(): %s\n", GptError(gpt_retval)); |
| 182 goto error_close; |
| 183 } |
| 184 |
| 185 drive->inited = 1; |
| 186 |
| 187 return CGPT_OK; |
| 188 |
| 189 error_close: |
| 190 close(drive->fd); |
| 191 return CGPT_FAILED; |
| 192 } |
| 193 |
| 194 int DriveClose(struct drive *drive) { |
| 195 if (drive->inited) { |
| 196 if (drive->gpt.modified & GPT_MODIFIED_HEADER1) |
| 197 assert(CGPT_OK == |
| 198 Save(drive->fd, drive->gpt.primary_header, GPT_PMBR_SECTOR, |
| 199 drive->gpt.sector_bytes, GPT_HEADER_SECTOR)); |
| 200 if (drive->gpt.modified & GPT_MODIFIED_HEADER2) |
| 201 assert(CGPT_OK == |
| 202 Save(drive->fd, drive->gpt.secondary_header, |
| 203 drive->gpt.drive_sectors - GPT_PMBR_SECTOR, |
| 204 drive->gpt.sector_bytes, GPT_HEADER_SECTOR)); |
| 205 if (drive->gpt.modified & GPT_MODIFIED_ENTRIES1) |
| 206 assert(CGPT_OK == |
| 207 Save(drive->fd, drive->gpt.primary_entries, |
| 208 GPT_PMBR_SECTOR + GPT_HEADER_SECTOR, |
| 209 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)); |
| 210 if (drive->gpt.modified & GPT_MODIFIED_ENTRIES2) |
| 211 assert(CGPT_OK == |
| 212 Save(drive->fd, drive->gpt.secondary_entries, |
| 213 drive->gpt.drive_sectors - GPT_HEADER_SECTOR - |
| 214 GPT_ENTRIES_SECTORS, |
| 215 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)); |
| 216 |
| 217 close(drive->fd); |
| 218 } |
| 219 |
| 220 Free(drive->gpt.primary_header); |
| 221 drive->gpt.primary_header = 0; |
| 222 Free(drive->gpt.primary_entries); |
| 223 drive->gpt.primary_entries = 0; |
| 224 Free(drive->gpt.secondary_header); |
| 225 drive->gpt.secondary_header = 0; |
| 226 Free(drive->gpt.secondary_entries); |
| 227 drive->gpt.secondary_entries = 0; |
| 228 |
| 229 drive->inited = 0; |
| 230 return CGPT_OK; |
| 231 } |
| 232 |
| 233 int main(int argc, char *argv[]) { |
| 234 char *cmd; |
| 235 int i; |
| 236 |
| 237 progname = argv[0]; |
| 238 cmd = argv[optind++]; |
| 239 for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) { |
| 240 if (cmd && !strcmp(cmds[i].name, cmd)) |
| 241 return cmds[i].fp(argc, argv); |
| 242 } |
| 243 |
| 244 Usage(0); |
| 245 return CGPT_FAILED; |
| 246 } |
OLD | NEW |