PageRenderTime 26ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/f3fix.c

https://gitlab.com/alx741/f3
C | 294 lines | 235 code | 46 blank | 13 comment | 35 complexity | d6efda6229e829acc9cece2467cfc257 MD5 | raw file
  1. #include <stdbool.h>
  2. #include <assert.h>
  3. #include <argp.h>
  4. #include <parted/parted.h>
  5. #include "version.h"
  6. #include "libutils.h"
  7. /* Argp's global variables. */
  8. const char *argp_program_version = "F3 Fix " F3_STR_VERSION;
  9. /* Arguments. */
  10. static char adoc[] = "<DISK_DEV>";
  11. static char doc[] = "F3 Fix -- edit the partition table of "
  12. "a fake flash drive to have a single partition that fully covers "
  13. "the real capacity of the drive";
  14. static struct argp_option options[] = {
  15. {"disk-type", 'd', "TYPE", 0,
  16. "Disk type of the partition table", 2},
  17. {"fs-type", 'f', "TYPE", 0,
  18. "Type of the file system of the partition", 0},
  19. {"boot", 'b', NULL, 0,
  20. "Mark the partition for boot", 0},
  21. {"no-boot", 'n', NULL, 0,
  22. "Do not mark the partition for boot", 0},
  23. {"first-sec", 'a', "SEC-NUM", 0,
  24. "Sector where the partition starts", 0},
  25. {"last-sec", 'l', "SEC-NUM", 0,
  26. "Sector where the partition ends", 0},
  27. {"list-disk-types", 'k', NULL, 0,
  28. "List all supported disk types", 3},
  29. {"list-fs-types", 's', NULL, 0,
  30. "List all supported types of file systems", 0},
  31. { 0 }
  32. };
  33. struct args {
  34. bool list_disk_types;
  35. bool list_fs_types;
  36. bool boot;
  37. /* 29 free bytes. */
  38. const char *dev_filename;
  39. PedDiskType *disk_type;
  40. PedFileSystemType *fs_type;
  41. PedSector first_sec;
  42. PedSector last_sec;
  43. };
  44. static long long arg_to_long_long(const struct argp_state *state,
  45. const char *arg)
  46. {
  47. char *end;
  48. long long ll = strtoll(arg, &end, 0);
  49. if (!arg)
  50. argp_error(state, "An integer must be provided");
  51. if (!*arg || *end)
  52. argp_error(state, "`%s' is not an integer", arg);
  53. return ll;
  54. }
  55. static error_t parse_opt(int key, char *arg, struct argp_state *state)
  56. {
  57. struct args *args = state->input;
  58. long long ll;
  59. switch (key) {
  60. case 'd':
  61. args->disk_type = ped_disk_type_get(arg);
  62. if (!args->disk_type)
  63. argp_error(state,
  64. "Disk type `%s' is not supported; use --list-disk-types to see the supported types");
  65. break;
  66. case 'f':
  67. args->fs_type = ped_file_system_type_get(arg);
  68. if (!args->fs_type)
  69. argp_error(state,
  70. "File system type `%s' is not supported; use --list-fs-types to see the supported types");
  71. break;
  72. case 'b':
  73. args->boot = true;
  74. break;
  75. case 'n':
  76. args->boot = false;
  77. break;
  78. case 'a':
  79. ll = arg_to_long_long(state, arg);
  80. if (ll < 0)
  81. argp_error(state,
  82. "First sector must be greater or equal to 0");
  83. args->first_sec = ll;
  84. break;
  85. case 'l':
  86. ll = arg_to_long_long(state, arg);
  87. if (ll < 0)
  88. argp_error(state,
  89. "Last sector must be greater or equal to 0");
  90. args->last_sec = ll;
  91. break;
  92. case 'k':
  93. args->list_disk_types = true;
  94. break;
  95. case 's':
  96. args->list_fs_types = true;
  97. break;
  98. case ARGP_KEY_INIT:
  99. args->dev_filename = NULL;
  100. args->last_sec = -1;
  101. break;
  102. case ARGP_KEY_ARG:
  103. if (args->dev_filename)
  104. argp_error(state,
  105. "Wrong number of arguments; only one is allowed");
  106. args->dev_filename = arg;
  107. break;
  108. case ARGP_KEY_END:
  109. if (args->list_disk_types || args->list_fs_types)
  110. break;
  111. if (!args->dev_filename)
  112. argp_error(state,
  113. "The disk device was not specified");
  114. if (args->last_sec < 0)
  115. argp_error(state,
  116. "Option --last-sec is required");
  117. if (args->first_sec > args->last_sec)
  118. argp_error(state,
  119. "Option --fist_sec must be less or equal to option --last_sec");
  120. break;
  121. default:
  122. return ARGP_ERR_UNKNOWN;
  123. }
  124. return 0;
  125. }
  126. static struct argp argp = {options, parse_opt, adoc, doc, NULL, NULL, NULL};
  127. static void list_disk_types(void)
  128. {
  129. PedDiskType *type;
  130. int i = 0;
  131. printf("Disk types:\n");
  132. for (type = ped_disk_type_get_next(NULL); type;
  133. type = ped_disk_type_get_next(type)) {
  134. printf("%s\t", type->name);
  135. i++;
  136. if (i == 5) {
  137. printf("\n");
  138. i = 0;
  139. }
  140. }
  141. if (i > 0)
  142. printf("\n");
  143. printf("\n");
  144. }
  145. static void list_fs_types(void)
  146. {
  147. PedFileSystemType *fs_type;
  148. int i = 0;
  149. printf("File system types:\n");
  150. for (fs_type = ped_file_system_type_get_next(NULL); fs_type;
  151. fs_type = ped_file_system_type_get_next(fs_type)) {
  152. printf("%s\t", fs_type->name);
  153. i++;
  154. if (i == 5) {
  155. printf("\n");
  156. i = 0;
  157. }
  158. }
  159. if (i > 0)
  160. printf("\n");
  161. printf("\n");
  162. }
  163. static PedSector map_sector_to_logical_sector(PedSector sector,
  164. int logical_sector_size)
  165. {
  166. assert(logical_sector_size >= 512);
  167. assert(logical_sector_size % 512 == 0);
  168. return sector / (logical_sector_size / 512);
  169. }
  170. /* 0 on failure, 1 otherwise. */
  171. static int fix_disk(PedDevice *dev, PedDiskType *type,
  172. PedFileSystemType *fs_type, int boot, PedSector start, PedSector end)
  173. {
  174. PedDisk *disk;
  175. PedPartition *part;
  176. PedGeometry *geom;
  177. PedConstraint *constraint;
  178. int ret = 0;
  179. disk = ped_disk_new_fresh(dev, type);
  180. if (!disk)
  181. goto out;
  182. start = map_sector_to_logical_sector(start, dev->sector_size);
  183. end = map_sector_to_logical_sector(end, dev->sector_size);
  184. part = ped_partition_new(disk, PED_PARTITION_NORMAL,
  185. fs_type, start, end);
  186. if (!part)
  187. goto disk;
  188. if (boot && !ped_partition_set_flag(part, PED_PARTITION_BOOT, 1))
  189. goto part;
  190. geom = ped_geometry_new(dev, start, end - start + 1);
  191. if (!geom)
  192. goto part;
  193. constraint = ped_constraint_exact(geom);
  194. ped_geometry_destroy(geom);
  195. if (!constraint)
  196. goto part;
  197. ret = ped_disk_add_partition(disk, part, constraint);
  198. ped_constraint_destroy(constraint);
  199. if (!ret)
  200. goto part;
  201. /* ped_disk_print(disk); */
  202. ret = ped_disk_commit(disk);
  203. goto disk;
  204. part:
  205. ped_partition_destroy(part);
  206. disk:
  207. ped_disk_destroy(disk);
  208. out:
  209. return ret;
  210. }
  211. int main (int argc, char *argv[])
  212. {
  213. struct args args = {
  214. /* Defaults. */
  215. .list_disk_types = false,
  216. .list_fs_types = false,
  217. .boot = true,
  218. .disk_type = ped_disk_type_get("msdos"),
  219. .fs_type = ped_file_system_type_get("fat32"),
  220. .first_sec = 2048, /* Skip first 1MB. */
  221. };
  222. PedDevice *dev;
  223. int ret;
  224. /* Read parameters. */
  225. argp_parse(&argp, argc, argv, 0, NULL, &args);
  226. print_header(stdout, "fix");
  227. if (args.list_disk_types)
  228. list_disk_types();
  229. if (args.list_fs_types)
  230. list_fs_types();
  231. if (args.list_disk_types || args.list_fs_types) {
  232. /* If the user has asked for the types,
  233. * she doesn't want to fix the drive yet.
  234. */
  235. return 0;
  236. }
  237. /* XXX If @dev is a partition, refer the user to
  238. * the disk of this partition.
  239. */
  240. dev = ped_device_get(args.dev_filename);
  241. if (!dev)
  242. return 1;
  243. ret = !fix_disk(dev, args.disk_type, args.fs_type, args.boot,
  244. args.first_sec, args.last_sec);
  245. printf("Drive `%s' was successfully fixed\n", args.dev_filename);
  246. ped_device_destroy(dev);
  247. return ret;
  248. }