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