mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-27 11:44:02 +00:00
248 lines
7.2 KiB
C
248 lines
7.2 KiB
C
/* 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)"},
|
|
{"repair", CgptRepair, "Repair primary and secondary headers and tables"},
|
|
{"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;
|
|
}
|