gpted/gpted.c

396 lines
9.9 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <readline/readline.h>
#include <readline/history.h>
#include "util.h"
#include "gpt.h"
#define MAX_ARGS 8
static int cmd_help(struct gpt *gpt, unsigned int argc, const char **argv)
{
printf(" help Show this message\n"
" quit Quit (without saving)\n"
" show Show partition table\n"
" write Write partition table to disk\n"
" part-add <name> ... [follow] Add a partition (NOT IMPLEMENTED)\n"
" part-del <name> [follow] Delete a partition\n"
" part-move <name> <start> [follow] Move a partition\n"
" part-resize <name> <size> [follow] Resize a partition\n"
" part-save <name> <filename> Save a partition\n"
" part-load <name> <filename> Load a partition\n"
"\n"
" <name> is a partition name. Only ASCII names are supported.\n"
"\n"
" <start> is a number, representing the offset from the beginning of the\n"
" device. The default unit is blocks. Multipliers 'k', 'm', 'g'\n"
" may be used.\n"
"\n"
" <size> is a number, representing a partition size. The default unit is\n"
" blocks. Multipliers 'k', 'm', 'g' may be used.\n"
"\n"
" The follow argument indicates that all partitions following the named\n"
" partition are to be moved by the same amount that the end of the current\n"
" partition moves. For example, given partition 'data' of size 1m and\n"
" partition 'extra' following 'data', then 'part-resize data 3m follow'\n"
" would result in partition 'extra' moving by 2m.\n"
"\n"
#if defined(ANDROID) && defined(QCOM)
" firmware-save Save firmware partitions\n"
" firmware-load Load firmware partitions\n"
"\n"
" The firmware commands are equivalent to issuing part-save/part-load for\n"
" for all partitions following 'pad' that may not be reasonably expected to\n"
" be recoverable by the user and/or may be too large to save in RAM (that is,\n"
" everything except: recovery, boot, system, userdata, cache, sdcard). The\n"
" files are saved/loaded from the current directory.\n"
#endif
);
return 0;
}
static int cmd_quit(struct gpt *gpt, unsigned int argc, const char **argv)
{
return 1;
}
static int cmd_show(struct gpt *gpt, unsigned int argc, const char **argv)
{
gpt_show(gpt);
return 0;
}
static int cmd_write(struct gpt *gpt, unsigned int argc, const char **argv)
{
int rc;
rc = gpt_write(gpt);
if (rc != 0) {
printf("E: write failed\n");
return 0;
}
return 0;
}
static int cmd_part_add(struct gpt *gpt, unsigned int argc, const char **argv)
{
printf("E: not implemented\n");
return 0;
}
static int cmd_part_del(struct gpt *gpt, unsigned int argc, const char **argv)
{
int rc;
uint32_t idx;
int follow;
if (argc < 2) {
printf("E: not enough args\n");
return 0;
}
idx = gpt_part_find(gpt, argv[1]);
if (idx == GPT_PART_INVALID) {
printf("E: part %s not found\n", argv[1]);
return 0;
}
follow = (argc > 2 && !strcmp(argv[2], "follow"));
rc = gpt_part_del(gpt, idx, follow);
if (rc != 0) {
printf("E: failed\n");
return 0;
}
return 0;
}
static int cmd_part_move(struct gpt *gpt, unsigned int argc, const char **argv)
{
int rc;
uint32_t idx;
uint64_t lb;
int follow;
if (argc < 3) {
printf("E: not enough args\n");
return 0;
}
idx = gpt_part_find(gpt, argv[1]);
if (idx == GPT_PART_INVALID) {
printf("E: part %s not found\n", argv[1]);
return 0;
}
lb = strtoull_u(argv[2], NULL, 0);
follow = (argc > 3 && !strcmp(argv[3], "follow"));
rc = gpt_part_move(gpt, idx, lb, follow);
if (rc != 0) {
printf("E: failed\n");
return 0;
}
return 0;
}
static int cmd_part_resize(struct gpt *gpt, unsigned int argc, const char **argv)
{
int rc;
uint32_t idx;
uint64_t size;
int follow;
if (argc < 3) {
printf("E: not enough args\n");
return 0;
}
idx = gpt_part_find(gpt, argv[1]);
if (idx == GPT_PART_INVALID) {
printf("E: part %s not found\n", argv[1]);
return 0;
}
follow = (argc > 3 && !strcmp(argv[3], "follow"));
if (!strcmp(argv[2], "max")) {
if (follow) {
struct gpt_partition *endpart;
endpart = gpt->partitions[gpt->last_used_idx];
size = gpt_part_size(gpt, idx) +
(gpt->header.last_usable_lba - endpart->last_lba) * gpt->lbsize;
}
else {
size = strtoull_u(argv[2], NULL, 0);
}
}
else {
size = strtoull_u(argv[2], NULL, 0);
}
rc = gpt_part_resize(gpt, idx, size, follow);
if (rc != 0) {
printf("E: failed\n");
return 0;
}
return 0;
}
static int cmd_part_save(struct gpt *gpt, unsigned int argc, const char **argv)
{
int rc;
uint32_t idx;
if (argc < 3) {
printf("E: not enough args\n");
return 0;
}
idx = gpt_part_find(gpt, argv[1]);
rc = gpt_part_save(gpt, idx, argv[2]);
if (rc != 0) {
printf("E: failed\n");
return 0;
}
return 0;
}
static int cmd_part_load(struct gpt *gpt, unsigned int argc, const char **argv)
{
int rc;
uint32_t idx;
if (argc < 3) {
printf("E: not enough args\n");
return 0;
}
idx = gpt_part_find(gpt, argv[1]);
rc = gpt_part_load(gpt, idx, argv[2]);
if (rc != 0) {
printf("E: failed\n");
return 0;
}
return 0;
}
#if defined(ANDROID) && defined(QCOM)
static const char *non_firmware[] = {
"recovery", "boot",
"system", "userdata", "cache", "sdcard",
/* persist? */
NULL
};
static int cmd_firmware_save(struct gpt *gpt, unsigned int argc, const char **argv)
{
int all = 0;
uint32_t startidx, idx;
if (argc > 1) {
all = !strcmp(argv[1], "all");
}
startidx = (all ? 0 : gpt->last_fw_idx+1);
for (idx = startidx; idx <= gpt->last_used_idx; ++idx) {
char name[72/2+1];
char filename[72/2+4+1];
int skip = 0;
const char **entry;
gpt_part_name(gpt, idx, name);
for (entry = non_firmware; *entry; ++entry) {
if (!strcmp(name, *entry)) {
skip = 1;
}
}
if (skip) {
printf("Skip %s\n", name);
}
else {
printf("Save %s\n", name);
sprintf(filename, "%s.img", name);
gpt_part_save(gpt, idx, filename);
}
}
return 0;
}
static int cmd_firmware_load(struct gpt *gpt, unsigned int argc, const char **argv)
{
int all = 0;
uint32_t startidx, idx;
if (argc > 1) {
all = !strcmp(argv[1], "all");
}
startidx = (all ? 0 : gpt->last_fw_idx+1);
for (idx = startidx; idx <= gpt->last_used_idx; ++idx) {
char name[72/2+1];
char filename[72/2+4+1];
int skip = 0;
const char **entry;
gpt_part_name(gpt, idx, name);
for (entry = non_firmware; *entry; ++entry) {
if (!strcmp(name, *entry)) {
skip = 1;
}
}
if (skip) {
printf("Skip %s\n", name);
}
else {
printf("Load %s\n", name);
sprintf(filename, "%s.img", name);
gpt_part_load(gpt, idx, filename);
}
}
return 0;
}
#endif
struct dispatch_entry
{
const char *cmd;
int (*func)(struct gpt *gpt, unsigned int argc, const char **argv);
};
static struct dispatch_entry dispatch_table[] = {
{ "help", cmd_help },
{ "quit", cmd_quit },
{ "show", cmd_show },
{ "write", cmd_write },
{ "part-add", cmd_part_add },
{ "part-del", cmd_part_del },
{ "part-move", cmd_part_move },
{ "part-resize", cmd_part_resize },
{ "part-load", cmd_part_load },
{ "part-save", cmd_part_save },
#if defined(ANDROID) && defined(QCOM)
{ "firmware-save", cmd_firmware_save },
{ "firmware-load", cmd_firmware_load },
#endif
{ NULL, NULL }
};
static int dispatch(struct gpt *gpt, char *line)
{
char *p;
unsigned int argc;
const char *argv[MAX_ARGS];
struct dispatch_entry *entry;
while (*line == ' ') {
++line;
}
if (*line == '#' || *line == ';') {
return 0;
}
argc = 0;
p = strtok(line, " ");
while (p != NULL) {
argv[argc++] = p;
p = strtok(NULL, " ");
}
if (argc == 0) {
return 0;
}
for (entry = dispatch_table; entry->cmd != NULL; ++entry) {
if (!strcmp(argv[0], entry->cmd)) {
return entry->func(gpt, argc, argv);
}
}
printf("Unknown command %s\n", argv[0]);
return 0;
}
int main(int argc, char** argv)
{
int rc;
struct gpt gpt;
const char* dev;
const char *prompt;
char *line;
if (argc != 2) {
fprintf(stderr, "Usage: %s <device>\n", argv[0]);
exit(1);
}
dev = argv[1];
rc = gpt_open(&gpt, dev);
if (rc != 0) {
fprintf(stderr, "Failed to read gpt\n");
exit(1);
}
prompt = (isatty(STDIN_FILENO) ? "partedit> " : NULL);
while ((line = readline(prompt)) != NULL) {
rc = dispatch(&gpt, line);
free(line);
if (rc != 0) {
break;
}
}
if (prompt) {
printf("\n");
}
gpt_close(&gpt);
return 0;
}