fdisk.c 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557
  1. /* fdisk.c - fdisk program to modify partitions on disk.
  2. *
  3. * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
  4. * Copyright 2013 Kyungwan Han <asura321@gmail.com>
  5. *
  6. * No Standard.
  7. USE_FDISK(NEWTOY(fdisk, "C#<0H#<0S#<0b#<512ul", TOYFLAG_SBIN))
  8. config FDISK
  9. bool "fdisk"
  10. default n
  11. help
  12. usage: fdisk [-lu] [-C CYLINDERS] [-H HEADS] [-S SECTORS] [-b SECTSZ] DISK
  13. Change partition table
  14. -u Start and End are in sectors (instead of cylinders)
  15. -l Show partition table for each DISK, then exit
  16. -b size sector size (512, 1024, 2048 or 4096)
  17. -C CYLINDERS Set number of cylinders/heads/sectors
  18. -H HEADS
  19. -S SECTORS
  20. */
  21. #define FOR_fdisk
  22. #include "toys.h"
  23. #include <linux/hdreg.h>
  24. GLOBALS(
  25. long sect_sz;
  26. long sectors;
  27. long heads;
  28. long cylinders;
  29. )
  30. #define EXTENDED 0x05
  31. #define WIN98_EXTENDED 0x0f
  32. #define LINUX_NATIVE 0x83
  33. #define LINUX_EXTENDED 0x85
  34. #define SECTOR_SIZE 512
  35. #define ONE_K 1024
  36. #define PARTITION_MAX 60 //partition max is modifiable
  37. #define IS_EXTENDED(i) ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
  38. #define sector(s) ((s) & 0x3f)
  39. #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
  40. typedef unsigned long long sector_t;
  41. struct partition {
  42. unsigned char boot_ind, head, sector, cyl, sys_ind, end_head,
  43. end_sector, end_cyl, start4[4], size4[4];
  44. };
  45. struct part_entry {
  46. struct partition *part;
  47. char *sec_buffer;
  48. sector_t start_offset;
  49. int modified;
  50. };
  51. struct part_types {
  52. int id;
  53. char type[24];
  54. } sys_types[] = {
  55. {0x00, "Empty"}, {0x01, "FAT12"}, {0x04, "FAT16 <32M"}, {0x05, "Extended"},
  56. {0x06, "FAT16"}, {0x07, "HPFS/NTFS"}, {0x0a, "OS/2 Boot Manager"},
  57. {0x0b, "Win95 FAT32"}, {0x0c, "Win95 FAT32 (LBA)"}, {0x0e, "Win95 FAT16 (LBA)"},
  58. {0x0f, "Win95 Ext'd (LBA)"}, {0x11, "Hidden FAT12"}, {0x12, "Compaq diagnostics"},
  59. {0x14, "Hidden FAT16 <32M"}, {0x16, "Hidden FAT16"}, {0x17, "Hidden HPFS/NTFS"},
  60. {0x1b, "Hidden Win95 FAT32"}, {0x1c, "Hidden W95 FAT32 (LBA)"}, {0x1e, "Hidden W95 FAT16 (LBA)"},
  61. {0x3c, "Part.Magic recovery"}, {0x41, "PPC PReP Boot"}, {0x42, "SFS"},
  62. {0x63, "GNU HURD or SysV"}, {0x80, "Old Minix"}, {0x81, "Minix / old Linux"},
  63. {0x82, "Linux swap"}, {0x83, "Linux"}, {0x84, "OS/2 hidden C: drive"},
  64. {0x85, "Linux extended"}, {0x86, "NTFS volume set"}, {0x87, "NTFS volume set"},
  65. {0x8e, "Linux LVM"}, {0x9f, "BSD/OS"}, {0xa0, "Thinkpad hibernation"},
  66. {0xa5, "FreeBSD"}, {0xa6, "OpenBSD"}, {0xa8, "Darwin UFS"}, {0xa9, "NetBSD"},
  67. {0xab, "Darwin boot"}, {0xb7, "BSDI fs"}, {0xb8, "BSDI swap"},
  68. {0xbe, "Solaris boot"}, {0xeb, "BeOS fs"}, {0xee, "EFI GPT"},
  69. {0xef, "EFI (FAT-12/16/32)"}, {0xf0, "Linux/PA-RISC boot"},
  70. {0xf2, "DOS secondary"}, {0xfd, "Linux raid autodetect"},
  71. };
  72. static int num_parts, disp_unit_cyl, dos_flag, dev_fd = 3;
  73. static long g_cylinders, g_heads, g_sectors, g_sect_size;
  74. static sector_t total_number_sectors, extended_offset;
  75. static char MBRbuf[2048], *disk_device;
  76. struct part_entry partitions[PARTITION_MAX];
  77. static struct partition* part_offset(char *secbuf, int i)
  78. {
  79. return (struct partition*)(secbuf + 0x1be + i*(sizeof(struct partition)));
  80. }
  81. static void set_levalue(unsigned char *cp, sector_t value )
  82. {
  83. uint32_t val = SWAP_LE32(value);
  84. memcpy(cp, (void*)&val, 4);
  85. }
  86. static void set_hsc(struct partition *p, sector_t start, sector_t end)
  87. {
  88. if (dos_flag && (start / (g_sectors * g_heads) > 1023))
  89. start = g_heads * g_sectors * ONE_K - 1;
  90. p->sector = (start % g_sectors) + 1;
  91. start /= g_sectors;
  92. p->head = start % g_heads;
  93. start /= g_heads;
  94. p->cyl = start & 0xFF;
  95. p->sector |= (start >> 2) & 0xc0;
  96. if (dos_flag && (end / (g_sectors * g_heads) > 1023))
  97. end = g_heads * g_sectors * ONE_K - 1;
  98. p->end_sector = (end % g_sectors) + 1;
  99. end /= g_sectors;
  100. p->end_head = end % g_heads;
  101. end /= g_heads;
  102. p->end_cyl = end & 0xFF;
  103. p->end_sector |= (end >> 2) & 0xc0;
  104. }
  105. static int chs_warn(void)
  106. {
  107. if (g_heads && g_sectors && g_cylinders)
  108. return 0;
  109. printf("Unknown value(s) for:");
  110. if (!g_heads) printf(" heads");
  111. if (!g_sectors) printf(" sectors");
  112. if (!g_cylinders) printf(" cylinders");
  113. printf(". can set in the expert menu.\n");
  114. return 1;
  115. }
  116. static void list_types(void)
  117. {
  118. int i, adjust = 0, size = ARRAY_LEN(sys_types);
  119. if(size % 2) adjust = 1;
  120. for (i = 0; i < (size - adjust); i+=2)
  121. xprintf("%2x %-22s\t\t%2x %-22.22s\n", sys_types[i].id, sys_types[i].type,
  122. sys_types[i+1].id, sys_types[i+1].type);
  123. if (adjust) xprintf("%2x %-22s\n",sys_types[size-1].id, sys_types[size-1].type);
  124. xputc('\n');
  125. }
  126. static void read_sec_sz()
  127. {
  128. int arg;
  129. if (ioctl(dev_fd, BLKSSZGET, &arg) == 0) g_sect_size = arg;
  130. if (FLAG(b)) {
  131. if (TT.sect_sz != 512 && TT.sect_sz != 1024 && TT.sect_sz != 2048 &&
  132. TT.sect_sz != 4096)
  133. {
  134. help_exit("bad sector size");
  135. }
  136. g_sect_size = TT.sect_sz;
  137. }
  138. }
  139. static sector_t read_size()
  140. {
  141. uint64_t sec64 = 0;
  142. unsigned long sectors = 0;
  143. if (ioctl(dev_fd, BLKGETSIZE64, &sec64) == 0) {
  144. sec64 = sec64 >> 9; //convert to 512 block size.
  145. if (sec64 != (uint32_t) sec64) {
  146. perror_msg("device has more than 2^32 sectors, can't use all of them");
  147. sec64 = (uint32_t) - 1L;
  148. }
  149. return sec64;
  150. }
  151. if (ioctl(dev_fd, BLKGETSIZE, &sectors) == 0)
  152. if (sizeof(long) > sizeof(sector_t) && sectors != (sector_t)sectors)
  153. sectors = (uint32_t) - 1L;
  154. return sectors;
  155. }
  156. static int validate_part_buff(char *buffer)
  157. {
  158. if ((buffer[510] != 0x55) || (buffer[511] != 0xAA)) return 0;
  159. return 1;
  160. }
  161. static int is_partition_clear(struct partition* p)
  162. {
  163. int i = 0;
  164. unsigned char res = 0;
  165. const char *ptr = (const char*)p;
  166. for (i = 0; i < sizeof(struct partition); i++) res |= (unsigned char)ptr[i];
  167. return (res == 0x00);
  168. }
  169. static uint32_t swap_le32toh(unsigned char *cp)
  170. {
  171. uint32_t val;
  172. memcpy((void*)&val, cp, 4);
  173. return le32toh(val);
  174. }
  175. static int check_order(void)
  176. {
  177. sector_t first[num_parts], last_seen_val = 0;
  178. int i;
  179. struct part_entry *pe;
  180. struct partition *px;
  181. for (i = 0; i < num_parts; i++) {
  182. if (i == 4) last_seen_val = 0;
  183. pe = &partitions[i];
  184. px = pe->part;
  185. if (px->sys_ind) {
  186. first[i] = swap_le32toh(px->start4) + pe->start_offset;
  187. if (last_seen_val > first[i]) return 1;
  188. last_seen_val = first[i];
  189. }
  190. }
  191. return 0;
  192. }
  193. static void read_geometry(struct hd_geometry *disk)
  194. {
  195. struct hd_geometry geometry;
  196. if (ioctl(dev_fd, HDIO_GETGEO, &geometry)) return;
  197. disk->heads = geometry.heads;
  198. disk->sectors = geometry.sectors;
  199. }
  200. /* Read the extended boot record for the
  201. * logical partion details.
  202. */
  203. static void read_ebr(int idx)
  204. {
  205. char *sec_buf = NULL;
  206. sector_t offset = 0, local_start_off = 0;
  207. struct partition *p, *q;
  208. q = p = partitions[idx].part;
  209. local_start_off = swap_le32toh(p->start4);
  210. if (!extended_offset) extended_offset = local_start_off;
  211. do {
  212. if (num_parts >= 60) {
  213. xprintf("Warning: deleting partitions after 60\n");
  214. memset(q, 0, sizeof(struct partition)); //clear_partition
  215. partitions[num_parts-1].modified = 1;
  216. break;
  217. }
  218. sec_buf = xzalloc(g_sect_size);
  219. partitions[num_parts].part = part_offset(sec_buf, 0);
  220. partitions[num_parts].sec_buffer = sec_buf;
  221. offset = swap_le32toh(q->start4);
  222. if (num_parts > 4) offset += local_start_off;
  223. partitions[num_parts].start_offset = offset;
  224. xlseek(dev_fd, (off_t)(offset * g_sect_size), SEEK_SET);
  225. if (g_sect_size != readall(dev_fd, sec_buf, g_sect_size)) {
  226. close(dev_fd);
  227. error_exit("Couldn't read sector zero\n");
  228. }
  229. num_parts++; //extended partions present.
  230. q = part_offset(sec_buf, 1);
  231. } while (!is_partition_clear(q) && IS_EXTENDED(q->sys_ind));
  232. }
  233. static void physical_HS(int* h, int *s)
  234. {
  235. struct partition *p;
  236. int i, end_h, end_s, e_hh = 0, e_ss = 0, ini = 1, dirty = 0;
  237. const unsigned char *bufp = (const unsigned char *)MBRbuf;
  238. if (!(validate_part_buff((char*)bufp))) return;
  239. for (i = 0; i < 4; i++) {
  240. p = part_offset((char*)bufp, i);
  241. if (p->sys_ind) {
  242. end_h = p->end_head + 1;
  243. end_s = (p->end_sector & 077);
  244. if (ini) {
  245. e_hh = end_h;
  246. e_ss = end_s;
  247. ini = 0;
  248. } else if (e_hh !=end_h || e_ss != end_s)
  249. dirty = 1;
  250. }
  251. }
  252. if (!dirty && !ini) {
  253. *h = e_hh;
  254. *s = e_ss;
  255. }
  256. }
  257. //Reset the primary partition table
  258. static void reset_boot(int change)
  259. {
  260. int i;
  261. for(i = 0; i < 4; i++) {
  262. struct part_entry *pe = &partitions[i];
  263. pe->part = part_offset(MBRbuf, i);
  264. pe->start_offset = 0;
  265. pe->sec_buffer = MBRbuf;
  266. pe->modified = change;
  267. }
  268. }
  269. static inline void write_table_flag(char *buf)
  270. {
  271. buf[510] = 0x55;
  272. buf[511] = 0xaa;
  273. }
  274. /* free the buffers used for holding details of
  275. * extended logical partions
  276. */
  277. static void free_bufs(void)
  278. {
  279. int i = 4;
  280. for (; i < num_parts; i++) free(partitions[i].sec_buffer);
  281. }
  282. static void create_empty_doslabel(void)
  283. {
  284. xprintf("Building a new DOS Disklabel. The changes will\n"
  285. "remain in memory only, until you write it.\n");
  286. num_parts = 4;
  287. extended_offset = 0;
  288. memset(&MBRbuf[510 - 4*16], 0, 4*16);
  289. write_table_flag(MBRbuf);
  290. partitions[0].modified = 1;
  291. reset_boot(1);
  292. }
  293. /* Read the Master Boot sector of the device for the
  294. * partition table entries/details.
  295. * If any extended partition is found then read the EBR
  296. * for logical partition details
  297. */
  298. static int read_mbr(char *device, int validate)
  299. {
  300. int fd, sector_fac, i, h = 0, s = 0;
  301. struct hd_geometry disk;
  302. fd = open(device, O_RDWR);
  303. if(fd < 0) {
  304. perror_msg("can't open '%s'",device);
  305. return 1;
  306. }
  307. disk_device = strdup(device);
  308. if(fd != dev_fd) {
  309. if(dup2(fd, dev_fd) != dev_fd) perror_exit("Can't dup2");
  310. close(fd);
  311. }
  312. //read partition table - MBR
  313. if (SECTOR_SIZE != readall(dev_fd, MBRbuf, SECTOR_SIZE)) {
  314. close(dev_fd);
  315. perror_exit("Couldn't read sector zero\n");
  316. }
  317. if (validate && !validate_part_buff(MBRbuf)) {
  318. xprintf("Device contains neither a valid DOS "
  319. "partition table, nor Sun, SGI, OSF or GPT "
  320. "disklabel\n");
  321. create_empty_doslabel();
  322. }
  323. disk.heads = disk.sectors = 0;
  324. read_geometry(&disk); //CHS values
  325. total_number_sectors = read_size(); //Device size
  326. read_sec_sz();
  327. sector_fac = g_sect_size/SECTOR_SIZE; //512 is hardware sector size.
  328. physical_HS(&h, &s); //physical dimensions may be diferent from HDIO_GETGEO
  329. g_sectors = (FLAG(S) && TT.sectors) ? TT.sectors : s ? s : disk.sectors ? disk.sectors : 63;
  330. g_heads = (FLAG(H) && TT.heads) ? TT.heads : h ? h : disk.heads ? disk.heads : 255;
  331. g_cylinders = total_number_sectors/(g_heads * g_sectors * sector_fac);
  332. if (!g_cylinders) g_cylinders = FLAG(C) ? TT.cylinders : 0;
  333. if ((g_cylinders > ONE_K) && !(FLAG(l) || FLAG(S)))
  334. xprintf("\nThe number of cylinders for this disk is set to %lu.\n"
  335. "There is nothing wrong with that, but this is larger than 1024,\n"
  336. "and could in certain setups cause problems.\n", g_cylinders);
  337. for (i = 0; i < num_parts; i++) {
  338. if (IS_EXTENDED(partitions[i].part->sys_ind)) {
  339. read_ebr(i);
  340. break;
  341. }
  342. }
  343. chs_warn();
  344. return 0;
  345. }
  346. static char* get_type(int sys_ind)
  347. {
  348. int i, size = ARRAY_LEN(sys_types);
  349. for (i = 0; i < size; i++)
  350. if (sys_ind == sys_types[i].id)
  351. return sys_types[i].type;
  352. return "Unknown";
  353. }
  354. static void consistency_check(const struct partition *p, int partition)
  355. {
  356. unsigned physbc, physbh, physbs, physec, physeh, physes;
  357. unsigned lbc, lbh, lbs, lec, leh, les;
  358. sector_t start, end;
  359. if (!g_heads || !g_sectors || (partition >= 4)) return;
  360. // physical beginning c, h, s
  361. physbc = cylinder(p->sector,p->cyl);
  362. physbh = p->head;
  363. physbs = sector(p->sector);
  364. // physical ending c, h, s
  365. physec = cylinder(p->end_sector, p->end_cyl);
  366. physeh = p->end_head;
  367. physes = sector(p->end_sector);
  368. // logical begin and end CHS values
  369. start = swap_le32toh((unsigned char*)(p->start4));
  370. end = start + swap_le32toh((unsigned char*)(p->size4)) -1;
  371. lbc = start/(g_sectors * g_heads);
  372. lbh = (start/g_sectors) % g_heads;
  373. lbs = (start % g_sectors) + 1;
  374. lec = end/(g_sectors * g_heads);
  375. leh = (end/g_sectors) % g_heads;
  376. les = (end % g_sectors) + 1;
  377. //Logical and Physical diff
  378. if (g_cylinders <= ONE_K && (physbc != lbc || physbh != lbh || physbs != lbs)) {
  379. xprintf("Partition %u has different physical/logical beginnings (Non-Linux?): \n", partition+1);
  380. xprintf("phys = (%u %u %u) ",physbc, physbh, physbs);
  381. xprintf("logical = (%u %u %u)\n", lbc, lbh, lbs);
  382. }
  383. if (g_cylinders <= ONE_K && (physec != lec || physeh != leh || physes != les)) {
  384. xprintf("Partition %u has different physical/logical endings: \n", partition+1);
  385. xprintf("phys = (%u %u %u) ",physec, physeh, physes);
  386. xprintf("logical = (%u %u %u)\n", lec, leh, les);
  387. }
  388. // Ending on cylinder boundary?
  389. if (physeh != (g_heads - 1) || physes != g_sectors)
  390. xprintf("Partition %u does not end on cylinder boundary\n", partition + 1);
  391. }
  392. // List the partition details
  393. static void list_partitions(int validate)
  394. {
  395. struct partition *p;
  396. uint32_t start_cyl, end_cyl, start_sec, end_sec, blocks, secs;
  397. char boot, lastchar = '\0', *dev = disk_device;
  398. int i = 0, len = strlen(disk_device), odds = 0;
  399. if (validate && !validate_part_buff(MBRbuf)) {
  400. close(dev_fd);
  401. toys.exitval = 1;
  402. xprintf("Device %s: doesn't contain a valid partition table\n", disk_device);
  403. return;
  404. }
  405. if (isdigit(dev[len - 1])) lastchar = 'p';
  406. xprintf("%*s Boot Start End Blocks Id System\n", len+1, "Device");
  407. for (i = 0; i < num_parts; i++) {
  408. p = partitions[i].part;
  409. if (is_partition_clear(p)) continue;
  410. boot = ((p->boot_ind == 0x80)?'*':(!p->boot_ind)?' ':'?');
  411. start_sec = swap_le32toh(p->start4) + partitions[i].start_offset;
  412. secs = swap_le32toh(p->size4);
  413. if ((start_sec + secs) == 0) end_sec = 0;
  414. else end_sec = start_sec + secs -1;
  415. start_cyl = start_sec/(g_heads * g_sectors) + 1;
  416. end_cyl = end_sec/(g_heads * g_sectors) + 1;
  417. blocks = secs;
  418. if (g_sect_size < ONE_K) {
  419. blocks /= (ONE_K/g_sect_size);
  420. odds = secs %(ONE_K/g_sect_size);
  421. } else if (g_sect_size > ONE_K) blocks *= (g_sect_size/ONE_K);
  422. if (lastchar) xprintf("%s%c%d",dev, lastchar, i+1);
  423. else xprintf("%s%d",dev, i+1);
  424. xprintf(" %c %11u %11u %11u%c %2x %s\n",
  425. boot,
  426. disp_unit_cyl == 0? start_sec: start_cyl,
  427. disp_unit_cyl == 0? end_sec: end_cyl,
  428. blocks,odds?'+':' ', p->sys_ind, get_type(p->sys_ind));
  429. consistency_check(p, i);
  430. }
  431. if (check_order()) xprintf("\nPartition table entries are not in disk order");
  432. }
  433. //Print device details
  434. static void print_mbr(int validate)
  435. {
  436. unsigned long long bytes = ((unsigned long long)total_number_sectors << 9);
  437. long mbytes = bytes/1000000;
  438. if (mbytes < 10000) xprintf("Disk %s: %lu MB, %llu bytes\n", disk_device, mbytes, bytes);
  439. else xprintf("Disk %s: %lu.%lu GB, %llu bytes\n", disk_device, mbytes/1000, (mbytes/100)%10, bytes);
  440. xprintf("%ld heads, %ld sectors/track, %ld cylinders", g_heads, g_sectors, g_cylinders);
  441. if (!disp_unit_cyl) {
  442. xprintf(", total %lld sectors\n", total_number_sectors/(g_sect_size/SECTOR_SIZE));
  443. xprintf("Units = sectors of 1 * %ld = %ld bytes\n",g_sect_size, g_sect_size);
  444. } else xprintf("\nUnits = cylinders of %ld * %ld = %ld bytes\n\n",
  445. g_heads * g_sectors, g_sect_size, g_heads * g_sectors * g_sect_size);
  446. list_partitions(validate);
  447. xputc('\n');
  448. }
  449. static void init_members(void)
  450. {
  451. int i = 0;
  452. num_parts = 4; //max of primaries in a part table
  453. disp_unit_cyl = dos_flag = 1;
  454. extended_offset = 0;
  455. g_sect_size = SECTOR_SIZE;
  456. for (i = 0; i < num_parts; i++) {
  457. partitions[i].part = part_offset(MBRbuf, i);
  458. partitions[i].sec_buffer = MBRbuf;
  459. partitions[i].modified = 0;
  460. partitions[i].start_offset = 0;
  461. }
  462. }
  463. static int read_input(char *mesg, char *outp)
  464. {
  465. char *p;
  466. int size = 0;
  467. do {
  468. xprintf("%s", mesg);
  469. p = fgets(toybuf, 80, stdin);
  470. if (!p || !(size = strlen(p))) exit(0);
  471. if (p[size-1] == '\n') p[--size] = '\0';
  472. } while (!size);
  473. while (*p != '\0' && *p <= ' ') p++;
  474. if (outp) memcpy(outp, p, strlen(p) + 1); //1 for nul
  475. return *p;
  476. }
  477. static int read_hex(char *mesg)
  478. {
  479. int val;
  480. char input[80], *endp;
  481. while (1) {
  482. read_input(mesg, input);
  483. if ((*input | 0x20) == 'l') {
  484. list_types();
  485. memset(input, 0, 80);
  486. continue;
  487. }
  488. val = strtoul(input, &endp, 16);
  489. if (endp && *endp) continue;
  490. if (val <= 0xff) return val;
  491. }
  492. }
  493. /* Delete an exiting partition,
  494. * if its primary, then just clear the partition details
  495. * if extended, then clear the partition details, also for logical
  496. * if only logical, then move the later partitions backwards 1 step
  497. */
  498. void delete_partition(int i)
  499. {
  500. int sys_id, looper = 0;
  501. struct partition *p, *q, *ext_p, *ext_q;
  502. sector_t new_start;
  503. struct part_entry *pe = &partitions[i];
  504. if (chs_warn()) return;
  505. p = pe->part;
  506. sys_id = p->sys_ind;
  507. if (!sys_id) xprintf("Partition %u is empty\n", i+1);
  508. if (i < 4 && !IS_EXTENDED(sys_id)) {
  509. memset(p, 0, sizeof(struct partition)); //clear_partition
  510. pe->modified = 1;
  511. } else if (i < 4 && IS_EXTENDED(sys_id)) {
  512. memset(p, 0, sizeof(struct partition)); //clear_partition
  513. pe->modified = 1;
  514. for (looper = 4; looper < num_parts; looper++) {
  515. pe = &partitions[looper];
  516. p = pe->part;
  517. if (is_partition_clear(p)) break;
  518. else {
  519. memset(p, 0, sizeof(struct partition)); //clear_partition
  520. pe->modified = 1;
  521. free(pe->sec_buffer);
  522. }
  523. }
  524. extended_offset = 0;
  525. num_parts = 4;
  526. } else {
  527. //only logical is delete, need to move the rest of them backwards
  528. if (i == 4) { //move partiton# 6 to 5.
  529. partitions[i].modified = 1;
  530. if (num_parts > i+1) {
  531. q = partitions[i + 1].part;
  532. *p = *q; //copy the part table
  533. ext_p = part_offset(partitions[i].sec_buffer, 1);
  534. ext_q = part_offset(partitions[i + 1].sec_buffer, 1);
  535. *ext_p = *ext_q; //copy the extended info pointer
  536. // change the start of the 4th partiton.
  537. new_start = partitions[i + 1].start_offset + swap_le32toh(q->start4) - extended_offset;
  538. new_start = SWAP_LE32(new_start);
  539. memcpy(p->start4, (void *)&new_start, 4);
  540. } else {
  541. memset(partitions[i].part, 0, sizeof(struct partition));
  542. return; //only logical
  543. }
  544. } else if (i > 4) {
  545. ext_p = part_offset(partitions[i-1].sec_buffer, 1);
  546. ext_q = part_offset(partitions[i].sec_buffer, 1);
  547. memcpy((void*)ext_p, (void *)ext_q, sizeof(struct partition));
  548. partitions[i-1].modified = 1;
  549. }
  550. if (i == 4) looper = i+2;
  551. else if (i > 4) looper = i+1;
  552. for (; looper < num_parts; looper++)
  553. partitions[looper-1] = partitions[looper];
  554. num_parts--;
  555. }
  556. }
  557. static int ask_partition(int num_parts)
  558. {
  559. int val;
  560. while (1) {
  561. do {
  562. xprintf("Partition (%u - %u):", 1, num_parts);
  563. fgets(toybuf, 80, stdin);
  564. } while (!isdigit(*toybuf));
  565. val = atoi(toybuf);
  566. if (val > 0 && val <= num_parts) return val;
  567. else xprintf("Invalid number entered\n");
  568. }
  569. }
  570. static void toggle_active_flag(int i)
  571. {
  572. struct partition *p = partitions[i].part;
  573. if (is_partition_clear(p)) xprintf("Partition %u is empty\n", i+1);
  574. if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
  575. xprintf("WARNING: Partition %u is an extended partition\n", i + 1);
  576. p->boot_ind = p->boot_ind == 0x80?0 : 0x80;
  577. partitions[i].modified = 1;
  578. }
  579. //Write the partition details from Buffer to Disk.
  580. void write_table(void)
  581. {
  582. int i =0;
  583. struct part_entry *pe;
  584. sector_t offset;
  585. for (i = 0; i < 4; i++)
  586. if (partitions[i].modified) partitions[3].modified = 1;
  587. for (i = 3; i < num_parts; i++) {
  588. pe = &partitions[i];
  589. write_table_flag(pe->sec_buffer);
  590. offset = pe->start_offset;
  591. if (pe->modified == 1) {
  592. xlseek(dev_fd, offset * g_sect_size, SEEK_SET);
  593. xwrite(dev_fd, pe->sec_buffer, g_sect_size);
  594. }
  595. }
  596. xprintf("The partition table has been altered.\n");
  597. xprintf("Calling ioctl() to re-read partition table\n");
  598. sync();
  599. for (i = 4; i < num_parts; i++) free(partitions[i].sec_buffer);
  600. if(ioctl(dev_fd, BLKRRPART, NULL) < 0)
  601. perror_exit("WARNING: rereading partition table failed, kernel still uses old table");
  602. }
  603. /* try to find a partition for deletion, if only
  604. * one, then select the same, else ask from USER
  605. */
  606. static int get_non_free_partition(int max)
  607. {
  608. int num = -1, i = 0;
  609. for (i = 0; i < max; i++) {
  610. if (!is_partition_clear(partitions[i].part)) {
  611. if (num >= 0)
  612. return ask_partition(num_parts)-1;
  613. num = i;
  614. }
  615. }
  616. (num >= 0) ? xprintf("Selected partition %d\n",num+1):
  617. xprintf("No partition is defined yet!\n");
  618. return num;
  619. }
  620. /* a try at autodetecting an empty partition table entry,
  621. * if multiple options then get USER's choce.
  622. */
  623. static int get_free_partition(int max)
  624. {
  625. int num = -1, i = 0;
  626. for (i = 0; i < max; i++) {
  627. if (is_partition_clear(partitions[i].part)) {
  628. if (num >= 0)
  629. return ask_partition(4)-1;
  630. num = i;
  631. }
  632. }
  633. (num >= 0) ? xprintf("Selected partition %d\n",num+1):
  634. xprintf("All primary partitions have been defined already!\n");
  635. return num;
  636. }
  637. //taking user input for partition start/end sectors/cyinders
  638. static uint32_t ask_value(char *mesg, sector_t left, sector_t right, sector_t defalt)
  639. {
  640. char *str = toybuf;
  641. uint32_t val;
  642. int use_default = 1;
  643. while (1) {
  644. use_default = 1;
  645. do {
  646. xprintf("%s",mesg);
  647. fgets(str, 80, stdin);
  648. } while (!isdigit(*str) && (*str != '\n')
  649. && (*str != '-') && (*str != '+') && (!isblank(*str)));
  650. while (isblank(*str)) str++; //remove leading white spaces
  651. if (*str == '+' || *str == '-') {
  652. int minus = (*str == '-');
  653. int absolute = 0;
  654. val = atoi(str + 1);
  655. while (isdigit(*++str)) use_default = 0;
  656. switch (*str) {
  657. case 'c':
  658. case 'C':
  659. if (!disp_unit_cyl) val *= g_heads * g_sectors;
  660. break;
  661. case 'K':
  662. absolute = ONE_K;
  663. break;
  664. case 'k':
  665. absolute = 1000;
  666. break;
  667. case 'm':
  668. case 'M':
  669. absolute = 1000000;
  670. break;
  671. case 'g':
  672. case 'G':
  673. absolute = 1000000000;
  674. break;
  675. default:
  676. break;
  677. }
  678. if (absolute) {
  679. unsigned long long bytes = (unsigned long long) val * absolute;
  680. unsigned long unit = (disp_unit_cyl && (g_heads * g_sectors))? g_heads * g_sectors : 1;
  681. unit = unit * g_sect_size;
  682. bytes += unit/2; // rounding
  683. bytes /= unit;
  684. val = bytes;
  685. }
  686. if (minus)
  687. val = -val;
  688. val += left;
  689. } else {
  690. val = atoi(str);
  691. while (isdigit(*str)) {
  692. str++;
  693. use_default = 0;
  694. }
  695. }
  696. if(use_default) {
  697. val = defalt;
  698. xprintf("Using default value %lld\n", defalt);
  699. }
  700. if (val >= left && val <= right) return val;
  701. else xprintf("Value out of range\n");
  702. }
  703. }
  704. //validating if the start given falls in a limit or not
  705. static int validate(int start_index, sector_t* begin,sector_t* end, sector_t start
  706. , int asked)
  707. {
  708. int i, valid = 0;
  709. for (i = start_index; i < num_parts; i++) {
  710. if (start >= begin[i] && start <= end[i]) {
  711. if (asked) xprintf("Sector %lld is already allocated\n",start);
  712. valid = 0;
  713. break;
  714. } else valid = 1;
  715. }
  716. return valid;
  717. }
  718. //get the start sector/cylinder of a new partition
  719. static sector_t ask_start_sector(int idx, sector_t* begin, sector_t* end, int ext_idx)
  720. {
  721. sector_t start, limit, temp = 0, start_cyl, limit_cyl, offset = 1;
  722. char mesg[256];
  723. int i, asked = 0, valid = 0, start_index = 0;
  724. if (dos_flag) offset = g_sectors;
  725. start = offset;
  726. if (disp_unit_cyl) limit = (sector_t)g_sectors * g_heads * g_cylinders - 1;
  727. else limit = total_number_sectors - 1;
  728. if (disp_unit_cyl) //make the begin of every partition to cylnder boundary
  729. for (i = 0; i < num_parts; i++)
  730. begin[i] = (begin[i]/(g_heads* g_sectors)) * (g_heads* g_sectors);
  731. if (idx >= 4) {
  732. if (!begin[ext_idx] && extended_offset) begin[ext_idx] = extended_offset;
  733. start = begin[ext_idx] + offset;
  734. limit = end[ext_idx];
  735. start_index = 4;
  736. }
  737. do {
  738. if (asked) valid = validate(start_index, begin, end, start, asked);
  739. if (valid) break;
  740. do {
  741. for (i = start_index; i < num_parts; i++)
  742. if (start >= begin[i] && start <= end[i])
  743. start = end[i] + 1 + ((idx >= 4)? offset : 0);
  744. } while (!validate(start_index, begin, end, start, 0));
  745. start_cyl = start/(g_sectors * g_heads) + 1;
  746. limit_cyl = limit/(g_sectors * g_heads) + 1;
  747. if (start > limit) break;
  748. sprintf(mesg, "First %s (%lld - %lld, default %lld): ", disp_unit_cyl? "cylinder" : "sector",
  749. (long long int)(disp_unit_cyl? start_cyl : start),
  750. (long long int)(disp_unit_cyl? limit_cyl : limit),
  751. (long long int)(disp_unit_cyl? start_cyl : start));
  752. temp = ask_value(mesg, disp_unit_cyl? start_cyl : start,
  753. disp_unit_cyl? limit_cyl : limit, disp_unit_cyl? start_cyl : start);
  754. asked = 1;
  755. if (disp_unit_cyl) {
  756. // point to the cylinder start sector
  757. temp = (temp-1) * g_heads * g_sectors;
  758. if (temp < start) //the boundary is falling in the already used sectors.
  759. temp = start;
  760. }
  761. start = temp;
  762. } while (asked && !valid);
  763. return start;
  764. }
  765. //get the end sector/cylinder of a new partition
  766. static sector_t ask_end_sector(int idx, sector_t* begin, sector_t* end, int ext_idx, sector_t start_sec)
  767. {
  768. sector_t limit, temp = 0, start_cyl, limit_cyl, start = start_sec;
  769. char mesg[256];
  770. int i;
  771. if (disp_unit_cyl) limit = (sector_t)g_sectors * g_heads * g_cylinders - 1;
  772. else limit = total_number_sectors - 1;
  773. if (disp_unit_cyl) //make the begin of every partition to cylnder boundary
  774. for (i = 0; i < num_parts; i++)
  775. begin[i] = (begin[i]/(g_heads* g_sectors)) * (g_heads* g_sectors);
  776. if (idx >= 4) limit = end[ext_idx];
  777. for (i = 0; i < num_parts; i++) {
  778. struct part_entry *pe = &partitions[i];
  779. if (start < pe->start_offset && limit >= pe->start_offset) limit = pe->start_offset - 1;
  780. if (start < begin[i] && limit >= begin[i]) limit = begin[i] - 1;
  781. }
  782. start_cyl = start/(g_sectors * g_heads) + 1;
  783. limit_cyl = limit/(g_sectors * g_heads) + 1;
  784. if (limit < start) { //the boundary is falling in the already used sectors.
  785. xprintf("No Free sectors available\n");
  786. return 0;
  787. }
  788. sprintf(mesg, "Last %s or +size or +sizeM or +sizeK (%lld - %lld, default %lld): ",
  789. disp_unit_cyl? "cylinder" : "sector",
  790. (long long int)(disp_unit_cyl? start_cyl : start),
  791. (long long int)(disp_unit_cyl? limit_cyl : limit),
  792. (long long int)(disp_unit_cyl? limit_cyl : limit));
  793. temp = ask_value(mesg, disp_unit_cyl? start_cyl : start,
  794. disp_unit_cyl? limit_cyl : limit, disp_unit_cyl? limit_cyl : limit);
  795. if (disp_unit_cyl) { // point to the cylinder start sector
  796. temp = temp * g_heads * g_sectors - 1;
  797. if (temp > limit) temp = limit;
  798. }
  799. if (temp < start) { //the boundary is falling in the already used sectors.
  800. xprintf("No Free sectors available\n");
  801. return 0;
  802. }
  803. return temp;
  804. }
  805. // add a new partition to the partition table
  806. static int add_partition(int idx, int sys_id)
  807. {
  808. int i, ext_idx = -1;
  809. sector_t start, end, begin_sec[num_parts], end_sec[num_parts];
  810. struct part_entry *pe = &partitions[idx];
  811. struct partition *p = pe->part;
  812. if (p && !is_partition_clear(p)) {
  813. xprintf("Partition %u is already defined, delete it to re-add\n", idx+1);
  814. return 0;
  815. }
  816. for (i = 0; i < num_parts; i++) {
  817. pe = &partitions[i];
  818. p = pe->part;
  819. if (is_partition_clear(p)) {
  820. begin_sec[i] = 0xffffffff;
  821. end_sec[i] = 0;
  822. } else {
  823. begin_sec[i] = swap_le32toh(p->start4) + pe->start_offset;
  824. end_sec[i] = begin_sec[i] + swap_le32toh(p->size4) - 1;
  825. }
  826. if (IS_EXTENDED(p->sys_ind)) ext_idx = i;
  827. }
  828. start = ask_start_sector(idx, begin_sec, end_sec, ext_idx);
  829. end = ask_end_sector(idx, begin_sec, end_sec, ext_idx, start);
  830. if (!end) return 0;
  831. //Populate partition table entry - 16 bytes
  832. pe = &partitions[idx];
  833. p = pe->part;
  834. if (idx > 4) {
  835. if (dos_flag) pe->start_offset = start - (sector_t)g_sectors;
  836. else pe->start_offset = start - 1;
  837. if (pe->start_offset == extended_offset) pe->start_offset++;
  838. if (!dos_flag) start++;
  839. }
  840. set_levalue(p->start4, start - pe->start_offset);
  841. set_levalue(p->size4, end - start + 1);
  842. set_hsc(p, start, end);
  843. p->boot_ind = 0;
  844. p->sys_ind = sys_id;
  845. pe->modified = 1;
  846. if (idx > 4) {
  847. p = partitions[idx-1].part + 1; //extended pointer for logical partitions
  848. set_levalue(p->start4, pe->start_offset - extended_offset);
  849. set_levalue(p->size4, end - start + 1 + (dos_flag? g_sectors: 1));
  850. set_hsc(p, pe->start_offset, end);
  851. p->boot_ind = 0;
  852. p->sys_ind = EXTENDED;
  853. partitions[idx-1].modified = 1;
  854. }
  855. if (IS_EXTENDED(sys_id)) {
  856. pe = &partitions[4];
  857. pe->modified = 1;
  858. pe->sec_buffer = xzalloc(g_sect_size);
  859. pe->part = part_offset(pe->sec_buffer, 0);
  860. pe->start_offset = extended_offset = start;
  861. num_parts = 5;
  862. }
  863. return 1;
  864. }
  865. static void add_logical_partition(void)
  866. {
  867. struct part_entry *pe;
  868. if (num_parts > 5 || !is_partition_clear(partitions[4].part)) {
  869. pe = &partitions[num_parts];
  870. pe->modified = 1;
  871. pe->sec_buffer = xzalloc(g_sect_size);
  872. pe->part = part_offset(pe->sec_buffer, 0);
  873. pe->start_offset = 0;
  874. num_parts++;
  875. if (!add_partition(num_parts - 1, LINUX_NATIVE)) {
  876. num_parts--;
  877. free(pe->sec_buffer);
  878. }
  879. }
  880. else add_partition(num_parts -1, LINUX_NATIVE);
  881. }
  882. /* Add a new partiton to the partition table.
  883. * MAX partitions limit is taken to be 60, can be changed
  884. */
  885. static void add_new_partition(void)
  886. {
  887. int choice, idx, i, free_part = 0;
  888. char *msg = NULL;
  889. if (chs_warn()) return;
  890. for (i = 0; i < 4; i++) if(is_partition_clear(partitions[i].part)) free_part++;
  891. if (!free_part && num_parts >= 60) {
  892. xprintf("The maximum number of partitions has been created\n");
  893. return;
  894. }
  895. if (!free_part) {
  896. if (extended_offset) add_logical_partition();
  897. else xprintf("You must delete some partition and add "
  898. "an extended partition first\n");
  899. return;
  900. }
  901. msg = xmprintf(" %s\n p primary partition(1-4)\n",
  902. extended_offset? "l logical (5 or over)" : "e extended");
  903. choice = 0x20 | read_input(msg, NULL);
  904. free(msg);
  905. if (choice == 'p') {
  906. idx = get_free_partition(4);
  907. if (idx >= 0) add_partition(idx, LINUX_NATIVE);
  908. return;
  909. }
  910. if (choice =='l' && extended_offset) {
  911. add_logical_partition();
  912. return;
  913. }
  914. if (choice == 'e' && !extended_offset) {
  915. idx = get_free_partition(4);
  916. if (idx >= 0) add_partition(idx, EXTENDED);
  917. return;
  918. }
  919. }
  920. static void change_systype(void )
  921. {
  922. int i, sys_id;
  923. struct partition *p;
  924. struct part_entry *pe;
  925. i = ask_partition(num_parts);
  926. pe = &partitions[i-1];
  927. p = pe->part;
  928. if (is_partition_clear(p)) {
  929. xprintf("Partition %d doesn't exist yet!\n", i);
  930. return;
  931. }
  932. sys_id = read_hex("Hex code (L to list codes): ");
  933. if ((IS_EXTENDED(p->sys_ind) && !IS_EXTENDED(sys_id)) ||
  934. (!IS_EXTENDED(p->sys_ind) && IS_EXTENDED(sys_id))) {
  935. xprintf("you can't change a partition to an extended or vice-versa\n");
  936. return;
  937. }
  938. xprintf("Changed system type of partition %u to %0x (%s)\n",i, sys_id, get_type(sys_id));
  939. p->sys_ind = sys_id;
  940. pe->modified = 1;
  941. }
  942. static void check(int n, unsigned h, unsigned s, unsigned c, sector_t start)
  943. {
  944. sector_t total, real_s, real_c;
  945. real_s = sector(s) - 1;
  946. real_c = cylinder(s, c);
  947. total = (real_c * g_sectors + real_s) * g_heads + h;
  948. if (!total) xprintf("Partition %u contains sector 0\n", n);
  949. if (h >= g_heads)
  950. xprintf("Partition %u: head %u greater than maximum %lu\n", n, h + 1, g_heads);
  951. if (real_s >= g_sectors)
  952. xprintf("Partition %u: sector %u greater than maximum %lu\n", n, s, g_sectors);
  953. if (real_c >= g_cylinders)
  954. xprintf("Partition %u: cylinder %lld greater than maximum %lu\n", n, real_c + 1, g_cylinders);
  955. if (g_cylinders <= ONE_K && start != total)
  956. xprintf("Partition %u: previous sectors %lld disagrees with total %lld\n", n, start, total);
  957. }
  958. static void verify_table(void)
  959. {
  960. int i, j, ext_idx = -1;
  961. sector_t begin_sec[num_parts], end_sec[num_parts], total = 1;
  962. struct part_entry *pe;
  963. struct partition *p;
  964. for (i = 0; i < num_parts; i++) {
  965. pe = &partitions[i];
  966. p = pe->part;
  967. if (is_partition_clear(p) || IS_EXTENDED(p->sys_ind)) {
  968. begin_sec[i] = 0xffffffff;
  969. end_sec[i] = 0;
  970. } else {
  971. begin_sec[i] = swap_le32toh(p->start4) + pe->start_offset;
  972. end_sec[i] = begin_sec[i] + swap_le32toh(p->size4) - 1;
  973. }
  974. if (IS_EXTENDED(p->sys_ind)) ext_idx = i;
  975. }
  976. for (i = 0; i < num_parts; i++) {
  977. pe = &partitions[i];
  978. p = pe->part;
  979. if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
  980. consistency_check(p, i);
  981. if ((swap_le32toh(p->start4) + pe->start_offset) < begin_sec[i])
  982. xprintf("Warning: bad start-of-data in partition %u\n", i + 1);
  983. check(i + 1, p->end_head, p->end_sector, p->end_cyl, end_sec[i]);
  984. total += end_sec[i] + 1 - begin_sec[i];
  985. for (j = 0; j < i; j++) {
  986. if ((begin_sec[i] >= begin_sec[j] && begin_sec[i] <= end_sec[j])
  987. || ((end_sec[i] <= end_sec[j] && end_sec[i] >= begin_sec[j]))) {
  988. xprintf("Warning: partition %u overlaps partition %u\n", j + 1, i + 1);
  989. total += begin_sec[i] >= begin_sec[j] ? begin_sec[i] : begin_sec[j];
  990. total -= end_sec[i] <= end_sec[j] ? end_sec[i] : end_sec[j];
  991. }
  992. }
  993. }
  994. }
  995. if (extended_offset) {
  996. struct part_entry *pex = &partitions[ext_idx];
  997. sector_t e_last = swap_le32toh(pex->part->start4) +
  998. swap_le32toh(pex->part->size4) - 1;
  999. for (i = 4; i < num_parts; i++) {
  1000. total++;
  1001. p = partitions[i].part;
  1002. if (!p->sys_ind) {
  1003. if (i != 4 || i + 1 < num_parts)
  1004. xprintf("Warning: partition %u is empty\n", i + 1);
  1005. } else if (begin_sec[i] < extended_offset || end_sec[i] > e_last)
  1006. xprintf("Logical partition %u not entirely in partition %u\n", i + 1, ext_idx + 1);
  1007. }
  1008. }
  1009. if (total > g_heads * g_sectors * g_cylinders)
  1010. xprintf("Total allocated sectors %lld greater than the maximum "
  1011. "%lu\n", total, g_heads * g_sectors * g_cylinders);
  1012. else {
  1013. total = g_heads * g_sectors * g_cylinders - total;
  1014. if (total) xprintf("%lld unallocated sectors\n", total);
  1015. }
  1016. }
  1017. static void move_begning(int idx)
  1018. {
  1019. sector_t start, num, new_start, end;
  1020. char mesg[256];
  1021. struct part_entry *pe = &partitions[idx];
  1022. struct partition *p = pe->part;
  1023. if (chs_warn()) return;
  1024. start = swap_le32toh(p->start4) + pe->start_offset;
  1025. num = swap_le32toh(p->size4);
  1026. end = start + num -1;
  1027. if (!num || IS_EXTENDED(p->sys_ind)) {
  1028. xprintf("Partition %u doesn't have data area\n", idx+1);
  1029. return;
  1030. }
  1031. sprintf(mesg, "New beginning of data (0 - %lld, default %lld): ",
  1032. (long long int)(end), (long long int)(start));
  1033. new_start = ask_value(mesg, 0, end, start);
  1034. if (new_start != start) {
  1035. set_levalue(p->start4, new_start - pe->start_offset);
  1036. set_levalue(p->size4, end - new_start +1);
  1037. if ((read_input("Recalculate C/H/S (Y/n): ", NULL) | 0x20) == 'y')
  1038. set_hsc(p, new_start, end);
  1039. pe->modified = 1;
  1040. }
  1041. }
  1042. static void print_raw_sectors()
  1043. {
  1044. int i, j;
  1045. struct part_entry *pe;
  1046. xprintf("Device: %s\n", disk_device);
  1047. for (i = 3; i < num_parts; i++) {
  1048. pe = &partitions[i];
  1049. for (j = 0; j < g_sect_size; j++) {
  1050. if (!(j % 16)) xprintf("\n0x%03X: ",j);
  1051. xprintf("%02X ",pe->sec_buffer[j]);
  1052. }
  1053. xputc('\n');
  1054. }
  1055. }
  1056. static void print_partitions_list(int ext)
  1057. {
  1058. int i;
  1059. struct part_entry *pe;
  1060. struct partition *p;
  1061. xprintf("Disk %s: %lu heads, %lu sectors, %lu cylinders\n\n", disk_device, g_heads, g_sectors, g_cylinders);
  1062. xprintf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
  1063. for (i = 0; i < num_parts; i++) {
  1064. pe = &partitions[i];
  1065. p = pe->part;
  1066. if (p) {
  1067. if (ext && (i >= 4)) p = pe->part + 1;
  1068. if(ext && i < 4 && !IS_EXTENDED(p->sys_ind)) continue;
  1069. xprintf("%2u %02x%4u%4u%5u%4u%4u%5u%11u%11u %02x\n",
  1070. i+1, p->boot_ind, p->head,
  1071. sector(p->sector), cylinder(p->sector, p->cyl),
  1072. p->end_head,
  1073. sector(p->end_sector), cylinder(p->end_sector, p->end_cyl),
  1074. swap_le32toh(p->start4),
  1075. swap_le32toh(p->size4),
  1076. p->sys_ind);
  1077. if (p->sys_ind) consistency_check(p, i);
  1078. }
  1079. }
  1080. }
  1081. //fix the partition table order to ascending
  1082. static void fix_order(void)
  1083. {
  1084. sector_t first[num_parts], min;
  1085. int i, j, oj, ojj, sj, sjj;
  1086. struct part_entry *pe;
  1087. struct partition *px, *py, temp, *pj, *pjj, tmp;
  1088. for (i = 0; i < num_parts; i++) {
  1089. pe = &partitions[i];
  1090. px = pe->part;
  1091. if (is_partition_clear(px)) first[i] = 0xffffffff;
  1092. else first[i] = swap_le32toh(px->start4) + pe->start_offset;
  1093. }
  1094. if (!check_order()) {
  1095. xprintf("Ordering is already correct\n\n");
  1096. return;
  1097. }
  1098. for (i = 0; i < 4; i++) {
  1099. for (j = 0; j < 3; j++) {
  1100. if (first[j] > first[j+1]) {
  1101. py = partitions[j+1].part;
  1102. px = partitions[j].part;
  1103. memcpy(&temp, py, sizeof(struct partition));
  1104. memcpy(py, px, sizeof(struct partition));
  1105. memcpy(px, &temp, sizeof(struct partition));
  1106. min = first[j+1];
  1107. first[j+1] = first[j];
  1108. first[j] = min;
  1109. partitions[j].modified = 1;
  1110. }
  1111. }
  1112. }
  1113. for (i = 5; i < num_parts; i++) {
  1114. for (j = 5; j < num_parts - 1; j++) {
  1115. oj = partitions[j].start_offset;
  1116. ojj = partitions[j+1].start_offset;
  1117. if (oj > ojj) {
  1118. partitions[j].start_offset = ojj;
  1119. partitions[j+1].start_offset = oj;
  1120. pj = partitions[j].part;
  1121. set_levalue(pj->start4, swap_le32toh(pj->start4)+oj-ojj);
  1122. pjj = partitions[j+1].part;
  1123. set_levalue(pjj->start4, swap_le32toh(pjj->start4)+ojj-oj);
  1124. set_levalue((partitions[j-1].part+1)->start4, ojj-extended_offset);
  1125. set_levalue((partitions[j].part+1)->start4, oj-extended_offset);
  1126. }
  1127. }
  1128. }
  1129. for (i = 4; i < num_parts; i++) {
  1130. for (j = 4; j < num_parts - 1; j++) {
  1131. pj = partitions[j].part;
  1132. pjj = partitions[j+1].part;
  1133. sj = swap_le32toh(pj->start4);
  1134. sjj = swap_le32toh(pjj->start4);
  1135. oj = partitions[j].start_offset;
  1136. ojj = partitions[j+1].start_offset;
  1137. if (oj+sj > ojj+sjj) {
  1138. tmp = *pj;
  1139. *pj = *pjj;
  1140. *pjj = tmp;
  1141. set_levalue(pj->start4, ojj+sjj-oj);
  1142. set_levalue(pjj->start4, oj+sj-ojj);
  1143. }
  1144. }
  1145. }
  1146. // If anything changed
  1147. for (j = 4; j < num_parts; j++) partitions[j].modified = 1;
  1148. xprintf("Done!\n");
  1149. }
  1150. static void print_menu(void)
  1151. {
  1152. xprintf("a\ttoggle a bootable flag\n"
  1153. "b\tedit bsd disklabel\n"
  1154. "c\ttoggle the dos compatibility flag\n"
  1155. "d\tdelete a partition\n"
  1156. "l\tlist known partition types\n"
  1157. "n\tadd a new partition\n"
  1158. "o\tcreate a new empty DOS partition table\n"
  1159. "p\tprint the partition table\n"
  1160. "q\tquit without saving changes\n"
  1161. "s\tcreate a new empty Sun disklabel\n"
  1162. "t\tchange a partition's system id\n"
  1163. "u\tchange display/entry units\n"
  1164. "v\tverify the partition table\n"
  1165. "w\twrite table to disk and exit\n"
  1166. "x\textra functionality (experts only)\n");
  1167. }
  1168. static void print_xmenu(void)
  1169. {
  1170. xprintf("b\tmove beginning of data in a partition\n"
  1171. "c\tchange number of cylinders\n"
  1172. "d\tprint the raw data in the partition table\n"
  1173. "e\tlist extended partitions\n"
  1174. "f\tfix partition order\n"
  1175. "h\tchange number of heads\n"
  1176. "p\tprint the partition table\n"
  1177. "q\tquit without saving changes\n"
  1178. "r\treturn to main menu\n"
  1179. "s\tchange number of sectors/track\n"
  1180. "v\tverify the partition table\n"
  1181. "w\twrite table to disk and exit\n");
  1182. }
  1183. static void expert_menu(void)
  1184. {
  1185. int choice, idx;
  1186. sector_t value;
  1187. char mesg[256];
  1188. while (1) {
  1189. xputc('\n');
  1190. char *msg = "Expert Command ('m' for help): ";
  1191. choice = 0x20 | read_input(msg, NULL);
  1192. switch (choice) {
  1193. case 'b': //move data beginning in partition
  1194. idx = ask_partition(num_parts);
  1195. move_begning(idx - 1);
  1196. break;
  1197. case 'c': //change cylinders
  1198. sprintf(mesg, "Number of cylinders (1 - 1048576, default %lu): ", g_cylinders);
  1199. value = ask_value(mesg, 1, 1048576, g_cylinders);
  1200. g_cylinders = TT.cylinders = value;
  1201. toys.optflags |= FLAG_C;
  1202. if(g_cylinders > ONE_K)
  1203. xprintf("\nThe number of cylinders for this disk is set to %lu.\n"
  1204. "There is nothing wrong with that, but this is larger than 1024,\n"
  1205. "and could in certain setups cause problems.\n", g_cylinders);
  1206. break;
  1207. case 'd': //print raw data in part tables
  1208. print_raw_sectors();
  1209. break;
  1210. case 'e': //list extended partitions
  1211. print_partitions_list(1);
  1212. break;
  1213. case 'f': //fix part order
  1214. fix_order();
  1215. break;
  1216. case 'h': //change number of heads
  1217. sprintf(mesg, "Number of heads (1 - 256, default %lu): ", g_heads);
  1218. value = ask_value(mesg, 1, 256, g_heads);
  1219. g_heads = TT.heads = value;
  1220. toys.optflags |= FLAG_H;
  1221. break;
  1222. case 'p': //print partition table
  1223. print_partitions_list(0);
  1224. break;
  1225. case 'q':
  1226. free_bufs();
  1227. close(dev_fd);
  1228. xputc('\n');
  1229. exit(0);
  1230. break;
  1231. case 'r':
  1232. return;
  1233. break;
  1234. case 's': //change sector/track
  1235. sprintf(mesg, "Number of sectors (1 - 63, default %lu): ", g_sectors);
  1236. value = ask_value(mesg, 1, 63, g_sectors);
  1237. g_sectors = TT.sectors = value;
  1238. toys.optflags |= FLAG_H;
  1239. break;
  1240. case 'v':
  1241. verify_table();
  1242. break;
  1243. case 'w':
  1244. write_table();
  1245. toys.exitval = 0;
  1246. exit(0);
  1247. break;
  1248. case 'm':
  1249. print_xmenu();
  1250. break;
  1251. default:
  1252. xprintf("Unknown command '%c'\n",choice);
  1253. print_xmenu();
  1254. break;
  1255. }
  1256. } //while(1)
  1257. }
  1258. static int disk_proper(const char *device)
  1259. {
  1260. unsigned length;
  1261. int fd = open(device, O_RDONLY);
  1262. if (fd != -1) {
  1263. struct hd_geometry dev_geo;
  1264. dev_geo.heads = 0;
  1265. dev_geo.sectors = 0;
  1266. int err = ioctl(fd, HDIO_GETGEO, &dev_geo);
  1267. close(fd);
  1268. if (!err) return (dev_geo.start == 0);
  1269. }
  1270. length = strlen(device);
  1271. if (length != 0 && isdigit(device[length - 1])) return 0;
  1272. return 1;
  1273. }
  1274. static void reset_entries()
  1275. {
  1276. int i;
  1277. memset(MBRbuf, 0, sizeof(MBRbuf));
  1278. for (i = 4; i < num_parts; i++)
  1279. memset(&partitions[i], 0, sizeof(struct part_entry));
  1280. }
  1281. //this will keep dev_fd = 3 always alive
  1282. static void move_fd()
  1283. {
  1284. int fd = xopen("/dev/null", O_RDONLY);
  1285. if(fd != dev_fd) {
  1286. if(dup2(fd, dev_fd) != dev_fd) perror_exit("Can't dup2");
  1287. close(fd);
  1288. }
  1289. }
  1290. /* Read proc/partitions and then print the details
  1291. * for partitions on each device
  1292. */
  1293. static void read_and_print_parts()
  1294. {
  1295. unsigned int ma, mi, sz;
  1296. char *name = toybuf, *buffer = toybuf + ONE_K, *device = toybuf + 2048;
  1297. FILE* fp = xfopen("/proc/partitions", "r");
  1298. while (fgets(buffer, ONE_K, fp)) {
  1299. reset_entries();
  1300. num_parts = 4;
  1301. memset(name, 0, sizeof(*name));
  1302. if (sscanf(buffer, " %u %u %u %[^\n ]", &ma, &mi, &sz, name) != 4)
  1303. continue;
  1304. sprintf(device,"/dev/%s",name);
  1305. if (disk_proper(device)) {
  1306. if (read_mbr(device, 0)) continue;
  1307. print_mbr(1);
  1308. move_fd();
  1309. }
  1310. }
  1311. fclose(fp);
  1312. }
  1313. void fdisk_main(void)
  1314. {
  1315. int choice, p;
  1316. init_members();
  1317. move_fd();
  1318. if (TT.heads >= 256) TT.heads = 0;
  1319. if (TT.sectors >= 64) TT.sectors = 0;
  1320. if (FLAG(u)) disp_unit_cyl = 0;
  1321. if (FLAG(l)) {
  1322. if (!toys.optc) read_and_print_parts();
  1323. else {
  1324. while(*toys.optargs){
  1325. if (read_mbr(*toys.optargs, 0)) {
  1326. toys.optargs++;
  1327. continue;
  1328. }
  1329. print_mbr(1);
  1330. move_fd();
  1331. toys.optargs++;
  1332. }
  1333. }
  1334. toys.exitval = 0;
  1335. return;
  1336. } else {
  1337. if (toys.optc != 1) help_exit(0);
  1338. if (read_mbr(toys.optargs[0], 1)) return;
  1339. while (1) {
  1340. xputc('\n');
  1341. char *msg = "Command ('m' for help): ";
  1342. choice = 0x20 | read_input(msg, NULL);
  1343. switch (choice) {
  1344. case 'a':
  1345. p = ask_partition(num_parts);
  1346. toggle_active_flag(p - 1); //partition table index start from 0.
  1347. break;
  1348. case 'b':
  1349. break;
  1350. case 'c':
  1351. dos_flag = !dos_flag;
  1352. xprintf("Dos compatible flag is %s\n", dos_flag?"Set" : "Not set");
  1353. break;
  1354. case 'd':
  1355. p = get_non_free_partition(num_parts); //4 was here
  1356. if(p >= 0) delete_partition(p);
  1357. break;
  1358. case 'l':
  1359. list_types();
  1360. break;
  1361. case 'n': //add new partition
  1362. add_new_partition();
  1363. break;
  1364. case 'o':
  1365. create_empty_doslabel();
  1366. break;
  1367. case 'p':
  1368. print_mbr(0);
  1369. break;
  1370. case 'q':
  1371. free_bufs();
  1372. close(dev_fd);
  1373. xputc('\n');
  1374. exit(0);
  1375. break;
  1376. case 's':
  1377. break;
  1378. case 't':
  1379. change_systype();
  1380. break;
  1381. case 'u':
  1382. disp_unit_cyl = !disp_unit_cyl;
  1383. xprintf("Changing Display/Entry units to %s\n",disp_unit_cyl?"cylinders" : "sectors");
  1384. break;
  1385. case 'v':
  1386. verify_table();
  1387. break;
  1388. case 'w':
  1389. write_table();
  1390. toys.exitval = 0;
  1391. return;
  1392. break;
  1393. case 'x':
  1394. expert_menu();
  1395. break;
  1396. case 'm':
  1397. print_menu();
  1398. break;
  1399. default:
  1400. xprintf("%c: Unknown command\n",choice);
  1401. break;
  1402. }
  1403. } //while(1)
  1404. }
  1405. }