f3/f3fix.c
Michel Machado 88c03dea90 f3fix: add missing parameter in argp_error() calls
@pbludov reported and fixed this bug in the following issue:
https://github.com/AltraMayor/f3/issues/26
2015-11-10 14:00:47 -05:00

297 lines
6.4 KiB
C

#include <stdbool.h>
#include <assert.h>
#include <argp.h>
#include <parted/parted.h>
#include "version.h"
#include "libutils.h"
/* Argp's global variables. */
const char *argp_program_version = "F3 Fix " F3_STR_VERSION;
/* Arguments. */
static char adoc[] = "<DISK_DEV>";
static char doc[] = "F3 Fix -- edit the partition table of "
"a fake flash drive to have a single partition that fully covers "
"the real capacity of the drive";
static struct argp_option options[] = {
{"disk-type", 'd', "TYPE", 0,
"Disk type of the partition table", 2},
{"fs-type", 'f', "TYPE", 0,
"Type of the file system of the partition", 0},
{"boot", 'b', NULL, 0,
"Mark the partition for boot", 0},
{"no-boot", 'n', NULL, 0,
"Do not mark the partition for boot", 0},
{"first-sec", 'a', "SEC-NUM", 0,
"Sector where the partition starts", 0},
{"last-sec", 'l', "SEC-NUM", 0,
"Sector where the partition ends", 0},
{"list-disk-types", 'k', NULL, 0,
"List all supported disk types", 3},
{"list-fs-types", 's', NULL, 0,
"List all supported types of file systems", 0},
{ 0 }
};
struct args {
bool list_disk_types;
bool list_fs_types;
bool boot;
/* 29 free bytes. */
const char *dev_filename;
PedDiskType *disk_type;
PedFileSystemType *fs_type;
PedSector first_sec;
PedSector last_sec;
};
static long long arg_to_long_long(const struct argp_state *state,
const char *arg)
{
char *end;
long long ll = strtoll(arg, &end, 0);
if (!arg)
argp_error(state, "An integer must be provided");
if (!*arg || *end)
argp_error(state, "`%s' is not an integer", arg);
return ll;
}
static error_t parse_opt(int key, char *arg, struct argp_state *state)
{
struct args *args = state->input;
long long ll;
switch (key) {
case 'd':
args->disk_type = ped_disk_type_get(arg);
if (!args->disk_type)
argp_error(state,
"Disk type `%s' is not supported; use --list-disk-types to see the supported types",
arg);
break;
case 'f':
args->fs_type = ped_file_system_type_get(arg);
if (!args->fs_type)
argp_error(state,
"File system type `%s' is not supported; use --list-fs-types to see the supported types",
arg);
break;
case 'b':
args->boot = true;
break;
case 'n':
args->boot = false;
break;
case 'a':
ll = arg_to_long_long(state, arg);
if (ll < 0)
argp_error(state,
"First sector must be greater or equal to 0");
args->first_sec = ll;
break;
case 'l':
ll = arg_to_long_long(state, arg);
if (ll < 0)
argp_error(state,
"Last sector must be greater or equal to 0");
args->last_sec = ll;
break;
case 'k':
args->list_disk_types = true;
break;
case 's':
args->list_fs_types = true;
break;
case ARGP_KEY_INIT:
args->dev_filename = NULL;
args->last_sec = -1;
break;
case ARGP_KEY_ARG:
if (args->dev_filename)
argp_error(state,
"Wrong number of arguments; only one is allowed");
args->dev_filename = arg;
break;
case ARGP_KEY_END:
if (args->list_disk_types || args->list_fs_types)
break;
if (!args->dev_filename)
argp_error(state,
"The disk device was not specified");
if (args->last_sec < 0)
argp_error(state,
"Option --last-sec is required");
if (args->first_sec > args->last_sec)
argp_error(state,
"Option --fist_sec must be less or equal to option --last_sec");
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
static struct argp argp = {options, parse_opt, adoc, doc, NULL, NULL, NULL};
static void list_disk_types(void)
{
PedDiskType *type;
int i = 0;
printf("Disk types:\n");
for (type = ped_disk_type_get_next(NULL); type;
type = ped_disk_type_get_next(type)) {
printf("%s\t", type->name);
i++;
if (i == 5) {
printf("\n");
i = 0;
}
}
if (i > 0)
printf("\n");
printf("\n");
}
static void list_fs_types(void)
{
PedFileSystemType *fs_type;
int i = 0;
printf("File system types:\n");
for (fs_type = ped_file_system_type_get_next(NULL); fs_type;
fs_type = ped_file_system_type_get_next(fs_type)) {
printf("%s\t", fs_type->name);
i++;
if (i == 5) {
printf("\n");
i = 0;
}
}
if (i > 0)
printf("\n");
printf("\n");
}
static PedSector map_sector_to_logical_sector(PedSector sector,
int logical_sector_size)
{
assert(logical_sector_size >= 512);
assert(logical_sector_size % 512 == 0);
return sector / (logical_sector_size / 512);
}
/* 0 on failure, 1 otherwise. */
static int fix_disk(PedDevice *dev, PedDiskType *type,
PedFileSystemType *fs_type, int boot, PedSector start, PedSector end)
{
PedDisk *disk;
PedPartition *part;
PedGeometry *geom;
PedConstraint *constraint;
int ret = 0;
disk = ped_disk_new_fresh(dev, type);
if (!disk)
goto out;
start = map_sector_to_logical_sector(start, dev->sector_size);
end = map_sector_to_logical_sector(end, dev->sector_size);
part = ped_partition_new(disk, PED_PARTITION_NORMAL,
fs_type, start, end);
if (!part)
goto disk;
if (boot && !ped_partition_set_flag(part, PED_PARTITION_BOOT, 1))
goto part;
geom = ped_geometry_new(dev, start, end - start + 1);
if (!geom)
goto part;
constraint = ped_constraint_exact(geom);
ped_geometry_destroy(geom);
if (!constraint)
goto part;
ret = ped_disk_add_partition(disk, part, constraint);
ped_constraint_destroy(constraint);
if (!ret)
goto part;
/* ped_disk_print(disk); */
ret = ped_disk_commit(disk);
goto disk;
part:
ped_partition_destroy(part);
disk:
ped_disk_destroy(disk);
out:
return ret;
}
int main (int argc, char *argv[])
{
struct args args = {
/* Defaults. */
.list_disk_types = false,
.list_fs_types = false,
.boot = true,
.disk_type = ped_disk_type_get("msdos"),
.fs_type = ped_file_system_type_get("fat32"),
.first_sec = 2048, /* Skip first 1MB. */
};
PedDevice *dev;
int ret;
/* Read parameters. */
argp_parse(&argp, argc, argv, 0, NULL, &args);
print_header(stdout, "fix");
if (args.list_disk_types)
list_disk_types();
if (args.list_fs_types)
list_fs_types();
if (args.list_disk_types || args.list_fs_types) {
/* If the user has asked for the types,
* she doesn't want to fix the drive yet.
*/
return 0;
}
/* XXX If @dev is a partition, refer the user to
* the disk of this partition.
*/
dev = ped_device_get(args.dev_filename);
if (!dev)
return 1;
ret = !fix_disk(dev, args.disk_type, args.fs_type, args.boot,
args.first_sec, args.last_sec);
printf("Drive `%s' was successfully fixed\n", args.dev_filename);
ped_device_destroy(dev);
return ret;
}