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, &sectors) == 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