| Index: src/platform/vboot_reference/utility/cgpt/cgpt.c
|
| diff --git a/src/platform/vboot_reference/utility/cgpt/cgpt.c b/src/platform/vboot_reference/utility/cgpt/cgpt.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e20a2d2640013e770d420fb206ed678fe1b5f717
|
| --- /dev/null
|
| +++ b/src/platform/vboot_reference/utility/cgpt/cgpt.c
|
| @@ -0,0 +1,246 @@
|
| +/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
| + * Use of this source code is governed by a BSD-style license that can be
|
| + * found in the LICENSE file.
|
| + *
|
| + * Utility for ChromeOS-specific GPT partitions, Please see corresponding .c
|
| + * files for more details.
|
| + */
|
| +#include "cgpt.h"
|
| +#include <errno.h>
|
| +#include <fcntl.h>
|
| +#include <getopt.h>
|
| +#include <stdint.h>
|
| +#include <stdio.h>
|
| +#include <stdlib.h>
|
| +#include <string.h>
|
| +#include <sys/ioctl.h>
|
| +#include <sys/mount.h>
|
| +#include <sys/stat.h>
|
| +#include <sys/types.h>
|
| +#include <unistd.h>
|
| +#include "utility.h"
|
| +
|
| +/* For usage print */
|
| +const char* progname;
|
| +
|
| +/* Lists all command here. */
|
| +struct {
|
| + const char *name;
|
| + int (*fp)(int argc, char *argv[]);
|
| + const char *comment;
|
| +} cmds[] = {
|
| + {"attribute", CgptAttribute, "Update GPT attribute bits "
|
| + "(for ChromeOS kernel entry only)"},
|
| + {"show", CgptShow, "Show partition details"},
|
| +};
|
| +
|
| +/* Shows main menu. If 'message' is non-NULL, shows it as header. Then, this
|
| + * traverses cmds[] and shows supported commands and their comments. */
|
| +void Usage(const char *message) {
|
| + int i;
|
| +
|
| + if (message) printf("%s\n", message);
|
| + printf("Usage: %s COMMAND [OPTIONS]\n\n"
|
| + "Supported commands:\n\n",
|
| + progname);
|
| + for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) {
|
| + printf(" %-10s %s\n", cmds[i].name, cmds[i].comment);
|
| + }
|
| + printf("\nFor more detailed usage, use %s COMMAND --help.\n\n", progname);
|
| +}
|
| +
|
| +/* Loads sectors from 'fd'.
|
| + * *buf is pointed to an allocated memory when returned, and should be
|
| + * freed by cgpt_close().
|
| + *
|
| + * fd -- file descriptot.
|
| + * buf -- pointer to buffer pointer
|
| + * sector -- offset of starting sector (in sectors)
|
| + * sector_bytes -- bytes per sector
|
| + * sector_count -- number of sectors to load
|
| + *
|
| + * Returns CGPT_OK for successful. Aborts if any error occurs.
|
| + */
|
| +int Load(const int fd, uint8_t **buf,
|
| + const uint64_t sector,
|
| + const uint64_t sector_bytes,
|
| + const uint64_t sector_count) {
|
| + int count; /* byte count to read */
|
| + int nread;
|
| +
|
| + assert(buf);
|
| + count = sector_bytes * sector_count;
|
| + *buf = Malloc(count);
|
| + assert(*buf);
|
| +
|
| + if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET))
|
| + goto error_free;
|
| +
|
| + nread = read(fd, *buf, count);
|
| + if (nread < count)
|
| + goto error_free;
|
| +
|
| + return CGPT_OK;
|
| +
|
| +error_free:
|
| + Free(*buf);
|
| + *buf = 0;
|
| + abort();
|
| +}
|
| +
|
| +/* Saves sectors to 'fd'.
|
| + *
|
| + * fd -- file descriptot.
|
| + * buf -- pointer to buffer
|
| + * sector -- starting sector offset
|
| + * sector_bytes -- bytes per sector
|
| + * sector_count -- number of sector to save
|
| + *
|
| + * Returns CGPT_OK for successful, CGPT_FAILED for failed.
|
| + */
|
| +int Save(const int fd, const uint8_t *buf,
|
| + const uint64_t sector,
|
| + const uint64_t sector_bytes,
|
| + const uint64_t sector_count) {
|
| + int count; /* byte count to write */
|
| + int nwrote;
|
| +
|
| + assert(buf);
|
| + count = sector_bytes * sector_count;
|
| +
|
| + if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET))
|
| + return CGPT_FAILED;
|
| +
|
| + nwrote = write(fd, buf, count);
|
| + if (nwrote < count)
|
| + return CGPT_FAILED;
|
| +
|
| + return CGPT_OK;
|
| +}
|
| +
|
| +/* Opens a block device (a regular file works well too).
|
| + *
|
| + * Returns CGPT_FAILED if any error happens.
|
| + * Returns CGPT_OK if success and information are stored in 'drive'. */
|
| +int DriveOpen(const char *drive_path, struct drive *drive) {
|
| + struct stat stat;
|
| + int gpt_retval;
|
| +
|
| + assert(drive_path);
|
| + assert(drive);
|
| +
|
| + Memset(drive, 0, sizeof(struct drive));
|
| + drive->fd = open(drive_path, O_RDWR);
|
| + if (drive->fd == -1) {
|
| + printf("[ERROR] Cannot open drive file [%s]: %s\n",
|
| + drive_path, strerror(errno));
|
| + return CGPT_FAILED;
|
| + }
|
| +
|
| + if (fstat(drive->fd, &stat) == -1) {
|
| + goto error_close;
|
| + }
|
| + if ((stat.st_mode & S_IFMT) != S_IFREG) {
|
| + if (ioctl(drive->fd, BLKGETSIZE64, &drive->size) < 0) {
|
| + printf("[ERROR] Cannot get sector size from drive file [%s]: %s\n",
|
| + drive_path, strerror(errno));
|
| + goto error_close;
|
| + }
|
| + if (ioctl(drive->fd, BLKSSZGET, &drive->gpt.sector_bytes) < 0) {
|
| + printf("[ERROR] Cannot get drive size from drive file [%s]: %s\n",
|
| + drive_path, strerror(errno));
|
| + goto error_close;
|
| + }
|
| + } else {
|
| + drive->gpt.sector_bytes = 512; /* bytes */
|
| + drive->size = stat.st_size;
|
| + }
|
| + if (drive->size % drive->gpt.sector_bytes) {
|
| + printf("[ERROR] Media size (%llu) is not the multiple of sector size(%d)\n",
|
| + (long long unsigned int)drive->size, drive->gpt.sector_bytes);
|
| + goto error_close;
|
| + }
|
| + drive->gpt.drive_sectors = drive->size / drive->gpt.sector_bytes;
|
| + debug("drive: size:%llu sector_size:%d num_sector:%llu\n",
|
| + (long long unsigned int)drive->size, drive->gpt.sector_bytes,
|
| + (long long unsigned int)drive->gpt.drive_sectors);
|
| +
|
| + Load(drive->fd, &drive->gpt.primary_header, GPT_PMBR_SECTOR,
|
| + drive->gpt.sector_bytes, GPT_HEADER_SECTOR);
|
| + Load(drive->fd, &drive->gpt.secondary_header,
|
| + drive->gpt.drive_sectors - GPT_PMBR_SECTOR,
|
| + drive->gpt.sector_bytes, GPT_HEADER_SECTOR);
|
| + Load(drive->fd, &drive->gpt.primary_entries,
|
| + GPT_PMBR_SECTOR + GPT_HEADER_SECTOR,
|
| + drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS);
|
| + Load(drive->fd, &drive->gpt.secondary_entries,
|
| + drive->gpt.drive_sectors - GPT_HEADER_SECTOR - GPT_ENTRIES_SECTORS,
|
| + drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS);
|
| +
|
| + if (GPT_SUCCESS != (gpt_retval = GptInit(&drive->gpt))) {
|
| + printf("[ERROR] GptInit(): %s\n", GptError(gpt_retval));
|
| + goto error_close;
|
| + }
|
| +
|
| + drive->inited = 1;
|
| +
|
| + return CGPT_OK;
|
| +
|
| +error_close:
|
| + close(drive->fd);
|
| + return CGPT_FAILED;
|
| +}
|
| +
|
| +int DriveClose(struct drive *drive) {
|
| + if (drive->inited) {
|
| + if (drive->gpt.modified & GPT_MODIFIED_HEADER1)
|
| + assert(CGPT_OK ==
|
| + Save(drive->fd, drive->gpt.primary_header, GPT_PMBR_SECTOR,
|
| + drive->gpt.sector_bytes, GPT_HEADER_SECTOR));
|
| + if (drive->gpt.modified & GPT_MODIFIED_HEADER2)
|
| + assert(CGPT_OK ==
|
| + Save(drive->fd, drive->gpt.secondary_header,
|
| + drive->gpt.drive_sectors - GPT_PMBR_SECTOR,
|
| + drive->gpt.sector_bytes, GPT_HEADER_SECTOR));
|
| + if (drive->gpt.modified & GPT_MODIFIED_ENTRIES1)
|
| + assert(CGPT_OK ==
|
| + Save(drive->fd, drive->gpt.primary_entries,
|
| + GPT_PMBR_SECTOR + GPT_HEADER_SECTOR,
|
| + drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS));
|
| + if (drive->gpt.modified & GPT_MODIFIED_ENTRIES2)
|
| + assert(CGPT_OK ==
|
| + Save(drive->fd, drive->gpt.secondary_entries,
|
| + drive->gpt.drive_sectors - GPT_HEADER_SECTOR -
|
| + GPT_ENTRIES_SECTORS,
|
| + drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS));
|
| +
|
| + close(drive->fd);
|
| + }
|
| +
|
| + Free(drive->gpt.primary_header);
|
| + drive->gpt.primary_header = 0;
|
| + Free(drive->gpt.primary_entries);
|
| + drive->gpt.primary_entries = 0;
|
| + Free(drive->gpt.secondary_header);
|
| + drive->gpt.secondary_header = 0;
|
| + Free(drive->gpt.secondary_entries);
|
| + drive->gpt.secondary_entries = 0;
|
| +
|
| + drive->inited = 0;
|
| + return CGPT_OK;
|
| +}
|
| +
|
| +int main(int argc, char *argv[]) {
|
| + char *cmd;
|
| + int i;
|
| +
|
| + progname = argv[0];
|
| + cmd = argv[optind++];
|
| + for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) {
|
| + if (cmd && !strcmp(cmds[i].name, cmd))
|
| + return cmds[i].fp(argc, argv);
|
| + }
|
| +
|
| + Usage(0);
|
| + return CGPT_FAILED;
|
| +}
|
|
|