/f3fix.c
C | 294 lines | 235 code | 46 blank | 13 comment | 35 complexity | d6efda6229e829acc9cece2467cfc257 MD5 | raw file
- #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");
- 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");
- 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;
- }