Upload Tizen:Base source
[framework/base/util-linux-ng.git] / fdisk / fdisk.c
1 /* fdisk.c -- Partition table manipulator for Linux.
2  *
3  * Copyright (C) 1992  A. V. Le Blanc (LeBlanc@mcc.ac.uk)
4  *
5  * This program is free software.  You can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation: either version 1 or
8  * (at your option) any later version.
9  */
10
11 #include <unistd.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <fcntl.h>
16 #include <ctype.h>
17 #include <setjmp.h>
18 #include <errno.h>
19 #include <getopt.h>
20 #include <sys/stat.h>
21 #include <sys/time.h>
22 #include <time.h>
23 #include <limits.h>
24
25 #include "nls.h"
26 #include "blkdev.h"
27 #include "common.h"
28 #include "fdisk.h"
29 #include "wholedisk.h"
30
31 #include "fdisksunlabel.h"
32 #include "fdisksgilabel.h"
33 #include "fdiskaixlabel.h"
34 #include "fdiskmaclabel.h"
35
36 #ifdef HAVE_LINUX_COMPILER_H
37 #include <linux/compiler.h>
38 #endif
39 #ifdef HAVE_LINUX_BLKPG_H
40 #include <linux/blkpg.h>
41 #endif
42
43 #include "gpt.h"
44
45 static void delete_partition(int i);
46
47 #define hex_val(c)      ({ \
48                                 char _c = (c); \
49                                 isdigit(_c) ? _c - '0' : \
50                                 tolower(_c) + 10 - 'a'; \
51                         })
52
53
54 #define LINE_LENGTH     800
55 #define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
56                                 (n) * sizeof(struct partition)))
57 #define sector(s)       ((s) & 0x3f)
58 #define cylinder(s, c)  ((c) | (((s) & 0xc0) << 2))
59
60 #define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
61                                 ((h) + heads * cylinder(s,c)))
62 #define set_hsc(h,s,c,sector) { \
63                                 s = sector % sectors + 1;       \
64                                 sector /= sectors;      \
65                                 h = sector % heads;     \
66                                 sector /= heads;        \
67                                 c = sector & 0xff;      \
68                                 s |= (sector >> 2) & 0xc0;      \
69                         }
70
71 /* A valid partition table sector ends in 0x55 0xaa */
72 static unsigned int
73 part_table_flag(unsigned char *b) {
74         return ((unsigned int) b[510]) + (((unsigned int) b[511]) << 8);
75 }
76
77 int
78 valid_part_table_flag(unsigned char *b) {
79         return (b[510] == 0x55 && b[511] == 0xaa);
80 }
81
82 static void
83 write_part_table_flag(unsigned char *b) {
84         b[510] = 0x55;
85         b[511] = 0xaa;
86 }
87
88 /* start_sect and nr_sects are stored little endian on all machines */
89 /* moreover, they are not aligned correctly */
90 static void
91 store4_little_endian(unsigned char *cp, unsigned int val) {
92         cp[0] = (val & 0xff);
93         cp[1] = ((val >> 8) & 0xff);
94         cp[2] = ((val >> 16) & 0xff);
95         cp[3] = ((val >> 24) & 0xff);
96 }
97
98 static unsigned int
99 read4_little_endian(const unsigned char *cp) {
100         return (unsigned int)(cp[0]) + ((unsigned int)(cp[1]) << 8)
101                 + ((unsigned int)(cp[2]) << 16)
102                 + ((unsigned int)(cp[3]) << 24);
103 }
104
105 static void
106 set_start_sect(struct partition *p, unsigned int start_sect) {
107         store4_little_endian(p->start4, start_sect);
108 }
109
110 unsigned long long
111 get_start_sect(struct partition *p) {
112         return read4_little_endian(p->start4);
113 }
114
115 static void
116 set_nr_sects(struct partition *p, unsigned long long nr_sects) {
117         store4_little_endian(p->size4, nr_sects);
118 }
119
120 unsigned long long
121 get_nr_sects(struct partition *p) {
122         return read4_little_endian(p->size4);
123 }
124
125 static ssize_t
126 xread(int fd, void *buf, size_t count) {
127         char *p = buf;
128         ssize_t out = 0;
129         ssize_t rv;
130
131         while (count) {
132                 rv = read(fd, p, count);
133                 if (rv == -1) {
134                         if (errno == EINTR || errno == EAGAIN)
135                                 continue;
136                         return out ? out : -1; /* Error */
137                 } else if (rv == 0) {
138                         return out; /* EOF */
139                 }
140
141                 p += rv;
142                 out += rv;
143                 count -= rv;
144         }
145
146         return out;
147 }
148
149 static unsigned int
150 get_random_id(void) {
151         int fd;
152         unsigned int v;
153         ssize_t rv = -1;
154         struct timeval tv;
155
156         fd = open("/dev/urandom", O_RDONLY);
157         if (fd >= 0) {
158                 rv = xread(fd, &v, sizeof v);
159                 close(fd);
160         }
161
162         if (rv == sizeof v)
163                 return v;
164
165         /* Fallback: sucks, but better than nothing */
166         gettimeofday(&tv, NULL);
167         return (unsigned int)(tv.tv_sec + (tv.tv_usec << 12) + getpid());
168 }
169
170 /* normally O_RDWR, -l option gives O_RDONLY */
171 static int type_open = O_RDWR;
172
173 /*
174  * Raw disk label. For DOS-type partition tables the MBR,
175  * with descriptions of the primary partitions.
176  */
177 unsigned char MBRbuffer[MAX_SECTOR_SIZE];
178
179 /*
180  * per partition table entry data
181  *
182  * The four primary partitions have the same sectorbuffer (MBRbuffer)
183  * and have NULL ext_pointer.
184  * Each logical partition table entry has two pointers, one for the
185  * partition and one link to the next one.
186  */
187 struct pte {
188         struct partition *part_table;   /* points into sectorbuffer */
189         struct partition *ext_pointer;  /* points into sectorbuffer */
190         char changed;                   /* boolean */
191         unsigned long long offset;      /* disk sector number */
192         unsigned char *sectorbuffer;    /* disk sector contents */
193 } ptes[MAXIMUM_PARTS];
194
195 char    *disk_device,                   /* must be specified */
196         *line_ptr,                      /* interactive input */
197         line_buffer[LINE_LENGTH];
198
199 int     fd,                             /* the disk */
200         ext_index,                      /* the prime extended partition */
201         listing = 0,                    /* no aborts for fdisk -l */
202         nowarn = 0,                     /* no warnings for fdisk -l/-s */
203         dos_compatible_flag = ~0,
204         dos_changed = 0,
205         partitions = 4;                 /* maximum partition + 1 */
206
207 unsigned int    user_cylinders, user_heads, user_sectors;
208 unsigned int    pt_heads, pt_sectors;
209 unsigned int    kern_heads, kern_sectors;
210
211 unsigned long long sector_offset = 1, extended_offset = 0, sectors;
212
213 unsigned int    heads,
214         cylinders,
215         sector_size = DEFAULT_SECTOR_SIZE,
216         sector_factor = 1,
217         user_set_sector_size = 0,
218         units_per_sector = 1,
219         display_in_cyl_units = 1;
220
221 unsigned long long total_number_of_sectors;     /* (!) 512-byte sectors */
222
223 #define dos_label (!sun_label && !sgi_label && !aix_label && !mac_label && !osf_label)
224 int     sun_label = 0;                  /* looking at sun disklabel */
225 int     sgi_label = 0;                  /* looking at sgi disklabel */
226 int     aix_label = 0;                  /* looking at aix disklabel */
227 int     osf_label = 0;                  /* looking at OSF/1 disklabel */
228 int     mac_label = 0;                  /* looking at mac disklabel */
229 int     possibly_osf_label = 0;
230
231 jmp_buf listingbuf;
232
233 void fatal(enum failure why) {
234         char    error[LINE_LENGTH],
235                 *message = error;
236
237         if (listing) {
238                 close(fd);
239                 longjmp(listingbuf, 1);
240         }
241
242         switch (why) {
243                 case usage: message = _(
244 "Usage: fdisk [-b SSZ] [-u] DISK     Change partition table\n"
245 "       fdisk -l [-b SSZ] [-u] DISK  List partition table(s)\n"
246 "       fdisk -s PARTITION           Give partition size(s) in blocks\n"
247 "       fdisk -v                     Give fdisk version\n"
248 "Here DISK is something like /dev/hdb or /dev/sda\n"
249 "and PARTITION is something like /dev/hda7\n"
250 "-u: give Start and End in sector (instead of cylinder) units\n"
251 "-b 2048: (for certain MO disks) use 2048-byte sectors\n");
252                         break;
253                 case usage2:
254                   /* msg in cases where fdisk used to probe */
255                         message = _(
256 "Usage: fdisk [-l] [-b SSZ] [-u] device\n"
257 "E.g.: fdisk /dev/hda  (for the first IDE disk)\n"
258 "  or: fdisk /dev/sdc  (for the third SCSI disk)\n"
259 "  or: fdisk /dev/eda  (for the first PS/2 ESDI drive)\n"
260 "  or: fdisk /dev/rd/c0d0  or: fdisk /dev/ida/c0d0  (for RAID devices)\n"
261 "  ...\n");
262                         break;
263                 case unable_to_open:
264                         snprintf(error, sizeof(error),
265                                  _("Unable to open %s\n"), disk_device);
266                         break;
267                 case unable_to_read:
268                         snprintf(error, sizeof(error),
269                                  _("Unable to read %s\n"), disk_device);
270                         break;
271                 case unable_to_seek:
272                         snprintf(error, sizeof(error),
273                                 _("Unable to seek on %s\n"),disk_device);
274                         break;
275                 case unable_to_write:
276                         snprintf(error, sizeof(error),
277                                 _("Unable to write %s\n"), disk_device);
278                         break;
279                 case ioctl_error:
280                         snprintf(error, sizeof(error),
281                                  _("BLKGETSIZE ioctl failed on %s\n"),
282                                 disk_device);
283                         break;
284                 case out_of_memory:
285                         message = _("Unable to allocate any more memory\n");
286                         break;
287                 default:
288                         message = _("Fatal error\n");
289         }
290
291         fputc('\n', stderr);
292         fputs(message, stderr);
293         exit(1);
294 }
295
296 static void
297 seek_sector(int fd, unsigned long long secno) {
298         off_t offset = (off_t) secno * sector_size;
299         if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
300                 fatal(unable_to_seek);
301 }
302
303 static void
304 read_sector(int fd, unsigned long long secno, unsigned char *buf) {
305         seek_sector(fd, secno);
306         if (read(fd, buf, sector_size) != sector_size)
307                 fatal(unable_to_read);
308 }
309
310 static void
311 write_sector(int fd, unsigned long long secno, unsigned char *buf) {
312         seek_sector(fd, secno);
313         if (write(fd, buf, sector_size) != sector_size)
314                 fatal(unable_to_write);
315 }
316
317 /* Allocate a buffer and read a partition table sector */
318 static void
319 read_pte(int fd, int pno, unsigned long long offset) {
320         struct pte *pe = &ptes[pno];
321
322         pe->offset = offset;
323         pe->sectorbuffer = malloc(sector_size);
324         if (!pe->sectorbuffer)
325                 fatal(out_of_memory);
326         read_sector(fd, offset, pe->sectorbuffer);
327         pe->changed = 0;
328         pe->part_table = pe->ext_pointer = NULL;
329 }
330
331 static unsigned long long
332 get_partition_start(struct pte *pe) {
333         return pe->offset + get_start_sect(pe->part_table);
334 }
335
336 struct partition *
337 get_part_table(int i) {
338         return ptes[i].part_table;
339 }
340
341 void
342 set_all_unchanged(void) {
343         int i;
344
345         for (i = 0; i < MAXIMUM_PARTS; i++)
346                 ptes[i].changed = 0;
347 }
348
349 void
350 set_changed(int i) {
351         ptes[i].changed = 1;
352 }
353
354 static int
355 is_garbage_table(void) {
356         int i;
357
358         for (i = 0; i < 4; i++) {
359                 struct pte *pe = &ptes[i];
360                 struct partition *p = pe->part_table;
361
362                 if (p->boot_ind != 0 && p->boot_ind != 0x80)
363                         return 1;
364         }
365         return 0;
366 }
367
368 /*
369  * Avoid warning about DOS partitions when no DOS partition was changed.
370  * Here a heuristic "is probably dos partition".
371  * We might also do the opposite and warn in all cases except
372  * for "is probably nondos partition".
373  */
374 static int
375 is_dos_partition(int t) {
376         return (t == 1 || t == 4 || t == 6 ||
377                 t == 0x0b || t == 0x0c || t == 0x0e ||
378                 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
379                 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
380                 t == 0xc1 || t == 0xc4 || t == 0xc6);
381 }
382
383 static void
384 menu(void) {
385         if (sun_label) {
386            puts(_("Command action"));
387            puts(_("   a   toggle a read only flag"));           /* sun */
388            puts(_("   b   edit bsd disklabel"));
389            puts(_("   c   toggle the mountable flag"));         /* sun */
390            puts(_("   d   delete a partition"));
391            puts(_("   l   list known partition types"));
392            puts(_("   m   print this menu"));
393            puts(_("   n   add a new partition"));
394            puts(_("   o   create a new empty DOS partition table"));
395            puts(_("   p   print the partition table"));
396            puts(_("   q   quit without saving changes"));
397            puts(_("   s   create a new empty Sun disklabel"));  /* sun */
398            puts(_("   t   change a partition's system id"));
399            puts(_("   u   change display/entry units"));
400            puts(_("   v   verify the partition table"));
401            puts(_("   w   write table to disk and exit"));
402            puts(_("   x   extra functionality (experts only)"));
403         }
404         else if (sgi_label) {
405            puts(_("Command action"));
406            puts(_("   a   select bootable partition"));    /* sgi flavour */
407            puts(_("   b   edit bootfile entry"));          /* sgi */
408            puts(_("   c   select sgi swap partition"));    /* sgi flavour */
409            puts(_("   d   delete a partition"));
410            puts(_("   l   list known partition types"));
411            puts(_("   m   print this menu"));
412            puts(_("   n   add a new partition"));
413            puts(_("   o   create a new empty DOS partition table"));
414            puts(_("   p   print the partition table"));
415            puts(_("   q   quit without saving changes"));
416            puts(_("   s   create a new empty Sun disklabel"));  /* sun */
417            puts(_("   t   change a partition's system id"));
418            puts(_("   u   change display/entry units"));
419            puts(_("   v   verify the partition table"));
420            puts(_("   w   write table to disk and exit"));
421         }
422         else if (aix_label || mac_label) {
423            puts(_("Command action"));
424            puts(_("   m   print this menu"));
425            puts(_("   o   create a new empty DOS partition table"));
426            puts(_("   q   quit without saving changes"));
427            puts(_("   s   create a new empty Sun disklabel"));  /* sun */
428         }
429         else {
430            puts(_("Command action"));
431            puts(_("   a   toggle a bootable flag"));
432            puts(_("   b   edit bsd disklabel"));
433            puts(_("   c   toggle the dos compatibility flag"));
434            puts(_("   d   delete a partition"));
435            puts(_("   l   list known partition types"));
436            puts(_("   m   print this menu"));
437            puts(_("   n   add a new partition"));
438            puts(_("   o   create a new empty DOS partition table"));
439            puts(_("   p   print the partition table"));
440            puts(_("   q   quit without saving changes"));
441            puts(_("   s   create a new empty Sun disklabel"));  /* sun */
442            puts(_("   t   change a partition's system id"));
443            puts(_("   u   change display/entry units"));
444            puts(_("   v   verify the partition table"));
445            puts(_("   w   write table to disk and exit"));
446            puts(_("   x   extra functionality (experts only)"));
447         }
448 }
449
450 static void
451 xmenu(void) {
452         if (sun_label) {
453            puts(_("Command action"));
454            puts(_("   a   change number of alternate cylinders"));      /*sun*/
455            puts(_("   c   change number of cylinders"));
456            puts(_("   d   print the raw data in the partition table"));
457            puts(_("   e   change number of extra sectors per cylinder"));/*sun*/
458            puts(_("   h   change number of heads"));
459            puts(_("   i   change interleave factor"));                  /*sun*/
460            puts(_("   o   change rotation speed (rpm)"));               /*sun*/
461            puts(_("   m   print this menu"));
462            puts(_("   p   print the partition table"));
463            puts(_("   q   quit without saving changes"));
464            puts(_("   r   return to main menu"));
465            puts(_("   s   change number of sectors/track"));
466            puts(_("   v   verify the partition table"));
467            puts(_("   w   write table to disk and exit"));
468            puts(_("   y   change number of physical cylinders"));       /*sun*/
469         }
470         else if (sgi_label) {
471            puts(_("Command action"));
472            puts(_("   b   move beginning of data in a partition")); /* !sun */
473            puts(_("   c   change number of cylinders"));
474            puts(_("   d   print the raw data in the partition table"));
475            puts(_("   e   list extended partitions"));          /* !sun */
476            puts(_("   g   create an IRIX (SGI) partition table"));/* sgi */
477            puts(_("   h   change number of heads"));
478            puts(_("   m   print this menu"));
479            puts(_("   p   print the partition table"));
480            puts(_("   q   quit without saving changes"));
481            puts(_("   r   return to main menu"));
482            puts(_("   s   change number of sectors/track"));
483            puts(_("   v   verify the partition table"));
484            puts(_("   w   write table to disk and exit"));
485         }
486         else if (aix_label || mac_label) {
487            puts(_("Command action"));
488            puts(_("   b   move beginning of data in a partition")); /* !sun */
489            puts(_("   c   change number of cylinders"));
490            puts(_("   d   print the raw data in the partition table"));
491            puts(_("   e   list extended partitions"));          /* !sun */
492            puts(_("   g   create an IRIX (SGI) partition table"));/* sgi */
493            puts(_("   h   change number of heads"));
494            puts(_("   m   print this menu"));
495            puts(_("   p   print the partition table"));
496            puts(_("   q   quit without saving changes"));
497            puts(_("   r   return to main menu"));
498            puts(_("   s   change number of sectors/track"));
499            puts(_("   v   verify the partition table"));
500            puts(_("   w   write table to disk and exit"));
501         }
502         else {
503            puts(_("Command action"));
504            puts(_("   b   move beginning of data in a partition")); /* !sun */
505            puts(_("   c   change number of cylinders"));
506            puts(_("   d   print the raw data in the partition table"));
507            puts(_("   e   list extended partitions"));          /* !sun */
508            puts(_("   f   fix partition order"));               /* !sun, !aix, !sgi */
509            puts(_("   g   create an IRIX (SGI) partition table"));/* sgi */
510            puts(_("   h   change number of heads"));
511            puts(_("   i   change the disk identifier")); /* dos only */
512            puts(_("   m   print this menu"));
513            puts(_("   p   print the partition table"));
514            puts(_("   q   quit without saving changes"));
515            puts(_("   r   return to main menu"));
516            puts(_("   s   change number of sectors/track"));
517            puts(_("   v   verify the partition table"));
518            puts(_("   w   write table to disk and exit"));
519         }
520 }
521
522 static int
523 get_sysid(int i) {
524         return (
525                 sun_label ? sun_get_sysid(i) :
526                 sgi_label ? sgi_get_sysid(i) :
527                 ptes[i].part_table->sys_ind);
528 }
529
530 static struct systypes *
531 get_sys_types(void) {
532         return (
533                 sun_label ? sun_sys_types :
534                 sgi_label ? sgi_sys_types :
535                 i386_sys_types);
536 }
537
538 char *partition_type(unsigned char type)
539 {
540         int i;
541         struct systypes *types = get_sys_types();
542
543         for (i=0; types[i].name; i++)
544                 if (types[i].type == type)
545                         return _(types[i].name);
546
547         return NULL;
548 }
549
550 void list_types(struct systypes *sys)
551 {
552         unsigned int last[4], done = 0, next = 0, size;
553         int i;
554
555         for (i = 0; sys[i].name; i++);
556         size = i;
557
558         for (i = 3; i >= 0; i--)
559                 last[3 - i] = done += (size + i - done) / (i + 1);
560         i = done = 0;
561
562         do {
563                 printf("%c%2x  %-15.15s", i ? ' ' : '\n',
564                         sys[next].type, _(sys[next].name));
565                 next = last[i++] + done;
566                 if (i > 3 || next >= last[i]) {
567                         i = 0;
568                         next = ++done;
569                 }
570         } while (done < last[0]);
571         putchar('\n');
572 }
573
574 static int
575 is_cleared_partition(struct partition *p) {
576         return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
577                  p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
578                  get_start_sect(p) || get_nr_sects(p));
579 }
580
581 static void
582 clear_partition(struct partition *p) {
583         if (!p)
584                 return;
585         p->boot_ind = 0;
586         p->head = 0;
587         p->sector = 0;
588         p->cyl = 0;
589         p->sys_ind = 0;
590         p->end_head = 0;
591         p->end_sector = 0;
592         p->end_cyl = 0;
593         set_start_sect(p,0);
594         set_nr_sects(p,0);
595 }
596
597 static void
598 set_partition(int i, int doext, unsigned long long start,
599               unsigned long long stop, int sysid) {
600         struct partition *p;
601         unsigned long long offset;
602
603         if (doext) {
604                 p = ptes[i].ext_pointer;
605                 offset = extended_offset;
606         } else {
607                 p = ptes[i].part_table;
608                 offset = ptes[i].offset;
609         }
610         p->boot_ind = 0;
611         p->sys_ind = sysid;
612         set_start_sect(p, start - offset);
613         set_nr_sects(p, stop - start + 1);
614         if (dos_compatible_flag && (start/(sectors*heads) > 1023))
615                 start = heads*sectors*1024 - 1;
616         set_hsc(p->head, p->sector, p->cyl, start);
617         if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
618                 stop = heads*sectors*1024 - 1;
619         set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
620         ptes[i].changed = 1;
621 }
622
623 static int
624 test_c(char **m, char *mesg) {
625         int val = 0;
626         if (!*m)
627                 fprintf(stderr, _("You must set"));
628         else {
629                 fprintf(stderr, " %s", *m);
630                 val = 1;
631         }
632         *m = mesg;
633         return val;
634 }
635
636 static int
637 warn_geometry(void) {
638         char *m = NULL;
639         int prev = 0;
640
641         if (sgi_label)  /* cannot set cylinders etc anyway */
642                 return 0;
643         if (!heads)
644                 prev = test_c(&m, _("heads"));
645         if (!sectors)
646                 prev = test_c(&m, _("sectors"));
647         if (!cylinders)
648                 prev = test_c(&m, _("cylinders"));
649         if (!m)
650                 return 0;
651         fprintf(stderr,
652                 _("%s%s.\nYou can do this from the extra functions menu.\n"),
653                 prev ? _(" and ") : " ", m);
654         return 1;
655 }
656
657 void update_units(void)
658 {
659         int cyl_units = heads * sectors;
660
661         if (display_in_cyl_units && cyl_units)
662                 units_per_sector = cyl_units;
663         else
664                 units_per_sector = 1;   /* in sectors */
665 }
666
667 static void
668 warn_cylinders(void) {
669         if (dos_label && cylinders > 1024 && !nowarn)
670                 fprintf(stderr, _("\n"
671 "The number of cylinders for this disk is set to %d.\n"
672 "There is nothing wrong with that, but this is larger than 1024,\n"
673 "and could in certain setups cause problems with:\n"
674 "1) software that runs at boot time (e.g., old versions of LILO)\n"
675 "2) booting and partitioning software from other OSs\n"
676 "   (e.g., DOS FDISK, OS/2 FDISK)\n"),
677                         cylinders);
678
679         if (total_number_of_sectors > UINT_MAX) {
680                 int giga = (total_number_of_sectors << 9) / 1000000000;
681                 int hectogiga = (giga + 50) / 100;
682
683                 fprintf(stderr, _("\n"
684 "WARNING: The size of this disk is %d.%d TB (%llu bytes).\n"
685 "DOS partition table format can not be used on drives for volumes\n"
686 "larger than (%llu bytes) for %d-byte sectors. Use parted(1) and GUID \n"
687 "partition table format (GPT).\n\n"),
688                         hectogiga / 10, hectogiga % 10,
689                         total_number_of_sectors << 9,
690                         (unsigned long long ) UINT_MAX * sector_size,
691                         sector_size);
692         }
693 }
694
695 static void
696 read_extended(int ext) {
697         int i;
698         struct pte *pex;
699         struct partition *p, *q;
700
701         ext_index = ext;
702         pex = &ptes[ext];
703         pex->ext_pointer = pex->part_table;
704
705         p = pex->part_table;
706         if (!get_start_sect(p)) {
707                 fprintf(stderr,
708                         _("Bad offset in primary extended partition\n"));
709                 return;
710         }
711
712         while (IS_EXTENDED (p->sys_ind)) {
713                 struct pte *pe = &ptes[partitions];
714
715                 if (partitions >= MAXIMUM_PARTS) {
716                         /* This is not a Linux restriction, but
717                            this program uses arrays of size MAXIMUM_PARTS.
718                            Do not try to `improve' this test. */
719                         struct pte *pre = &ptes[partitions-1];
720
721                         fprintf(stderr,
722                                 _("Warning: omitting partitions after #%d.\n"
723                                   "They will be deleted "
724                                   "if you save this partition table.\n"),
725                                 partitions);
726                         clear_partition(pre->ext_pointer);
727                         pre->changed = 1;
728                         return;
729                 }
730
731                 read_pte(fd, partitions, extended_offset + get_start_sect(p));
732
733                 if (!extended_offset)
734                         extended_offset = get_start_sect(p);
735
736                 q = p = pt_offset(pe->sectorbuffer, 0);
737                 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
738                         if (IS_EXTENDED (p->sys_ind)) {
739                                 if (pe->ext_pointer)
740                                         fprintf(stderr,
741                                                 _("Warning: extra link "
742                                                   "pointer in partition table"
743                                                   " %d\n"), partitions + 1);
744                                 else
745                                         pe->ext_pointer = p;
746                         } else if (p->sys_ind) {
747                                 if (pe->part_table)
748                                         fprintf(stderr,
749                                                 _("Warning: ignoring extra "
750                                                   "data in partition table"
751                                                   " %d\n"), partitions + 1);
752                                 else
753                                         pe->part_table = p;
754                         }
755                 }
756
757                 /* very strange code here... */
758                 if (!pe->part_table) {
759                         if (q != pe->ext_pointer)
760                                 pe->part_table = q;
761                         else
762                                 pe->part_table = q + 1;
763                 }
764                 if (!pe->ext_pointer) {
765                         if (q != pe->part_table)
766                                 pe->ext_pointer = q;
767                         else
768                                 pe->ext_pointer = q + 1;
769                 }
770
771                 p = pe->ext_pointer;
772                 partitions++;
773         }
774
775         /* remove empty links */
776  remove:
777         for (i = 4; i < partitions; i++) {
778                 struct pte *pe = &ptes[i];
779
780                 if (!get_nr_sects(pe->part_table) &&
781                     (partitions > 5 || ptes[4].part_table->sys_ind)) {
782                         printf(_("omitting empty partition (%d)\n"), i+1);
783                         delete_partition(i);
784                         goto remove;    /* numbering changed */
785                 }
786         }
787 }
788
789 static void
790 dos_write_mbr_id(unsigned char *b, unsigned int id) {
791         store4_little_endian(&b[440], id);
792 }
793
794 static unsigned int
795 dos_read_mbr_id(const unsigned char *b) {
796         return read4_little_endian(&b[440]);
797 }
798
799 static void
800 dos_print_mbr_id(void) {
801         printf(_("Disk identifier: 0x%08x\n"), dos_read_mbr_id(MBRbuffer));
802 }
803
804 static void
805 dos_set_mbr_id(void) {
806         unsigned long new_id;
807         char *ep;
808         char ps[64];
809
810         snprintf(ps, sizeof ps, _("New disk identifier (current 0x%08x): "),
811                  dos_read_mbr_id(MBRbuffer));
812
813         if (read_chars(ps) == '\n')
814                 return;
815
816         new_id = strtoul(line_ptr, &ep, 0);
817         if (*ep != '\n')
818                 return;
819
820         dos_write_mbr_id(MBRbuffer, new_id);
821         dos_print_mbr_id();
822 }
823
824 static void
825 create_doslabel(void) {
826         unsigned int id = get_random_id();
827
828         fprintf(stderr,
829         _("Building a new DOS disklabel with disk identifier 0x%08x.\n"
830           "Changes will remain in memory only, until you decide to write them.\n"
831           "After that, of course, the previous content won't be recoverable.\n\n"),
832                 id);
833         sun_nolabel();  /* otherwise always recognised as sun */
834         sgi_nolabel();  /* otherwise always recognised as sgi */
835         mac_label = aix_label = osf_label = possibly_osf_label = 0;
836         partitions = 4;
837
838         /* Zero out the MBR buffer */
839         extended_offset = 0;
840         set_all_unchanged();
841         set_changed(0);
842         get_boot(create_empty_dos);
843
844         /* Generate an MBR ID for this disk */
845         dos_write_mbr_id(MBRbuffer, id);
846
847         /* Mark it bootable (unfortunately required) */
848         write_part_table_flag(MBRbuffer);
849 }
850
851 static void
852 get_sectorsize(int fd) {
853         int arg;
854
855         if (user_set_sector_size)
856                 return;
857
858         if (blkdev_get_sector_size(fd, &arg) == 0)
859                 sector_size = arg;
860         if (sector_size != DEFAULT_SECTOR_SIZE)
861                 printf(_("Note: sector size is %d (not %d)\n"),
862                        sector_size, DEFAULT_SECTOR_SIZE);
863 }
864
865 static void
866 get_kernel_geometry(int fd) {
867 #ifdef HDIO_GETGEO
868         struct hd_geometry geometry;
869
870         if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
871                 kern_heads = geometry.heads;
872                 kern_sectors = geometry.sectors;
873                 /* never use geometry.cylinders - it is truncated */
874         }
875 #endif
876 }
877
878 static void
879 get_partition_table_geometry(void) {
880         unsigned char *bufp = MBRbuffer;
881         struct partition *p;
882         int i, h, s, hh, ss;
883         int first = 1;
884         int bad = 0;
885
886         if (!(valid_part_table_flag(bufp)))
887                 return;
888
889         hh = ss = 0;
890         for (i=0; i<4; i++) {
891                 p = pt_offset(bufp, i);
892                 if (p->sys_ind != 0) {
893                         h = p->end_head + 1;
894                         s = (p->end_sector & 077);
895                         if (first) {
896                                 hh = h;
897                                 ss = s;
898                                 first = 0;
899                         } else if (hh != h || ss != s)
900                                 bad = 1;
901                 }
902         }
903
904         if (!first && !bad) {
905                 pt_heads = hh;
906                 pt_sectors = ss;
907         }
908 }
909
910 void
911 get_geometry(int fd, struct geom *g) {
912         unsigned long long llcyls;
913
914         get_sectorsize(fd);
915         sector_factor = sector_size / 512;
916         guess_device_type(fd);
917         heads = cylinders = sectors = 0;
918         kern_heads = kern_sectors = 0;
919         pt_heads = pt_sectors = 0;
920
921         get_kernel_geometry(fd);
922         get_partition_table_geometry();
923
924         heads = user_heads ? user_heads :
925                 pt_heads ? pt_heads :
926                 kern_heads ? kern_heads : 255;
927         sectors = user_sectors ? user_sectors :
928                 pt_sectors ? pt_sectors :
929                 kern_sectors ? kern_sectors : 63;
930
931         if (blkdev_get_sectors(fd, &total_number_of_sectors) == -1)
932                 total_number_of_sectors = 0;
933
934         sector_offset = 1;
935         if (dos_compatible_flag)
936                 sector_offset = sectors;
937
938         llcyls = total_number_of_sectors / (heads * sectors * sector_factor);
939         cylinders = llcyls;
940         if (cylinders != llcyls)        /* truncated? */
941                 cylinders = ~0;
942         if (!cylinders)
943                 cylinders = user_cylinders;
944
945         if (g) {
946                 g->heads = heads;
947                 g->sectors = sectors;
948                 g->cylinders = cylinders;
949         }
950 }
951
952 /*
953  * Read MBR.  Returns:
954  *   -1: no 0xaa55 flag present (possibly entire disk BSD)
955  *    0: found or created label
956  *    1: I/O error
957  */
958 int
959 get_boot(enum action what) {
960         int i;
961
962         partitions = 4;
963         ext_index = 0;
964         extended_offset = 0;
965
966         for (i = 0; i < 4; i++) {
967                 struct pte *pe = &ptes[i];
968
969                 pe->part_table = pt_offset(MBRbuffer, i);
970                 pe->ext_pointer = NULL;
971                 pe->offset = 0;
972                 pe->sectorbuffer = MBRbuffer;
973                 pe->changed = (what == create_empty_dos);
974         }
975
976         if (what == create_empty_sun && check_sun_label())
977                 return 0;
978
979         memset(MBRbuffer, 0, 512);
980
981         if (what == create_empty_dos)
982                 goto got_dos_table;             /* skip reading disk */
983
984         if ((fd = open(disk_device, type_open)) < 0) {
985             if ((fd = open(disk_device, O_RDONLY)) < 0) {
986                 if (what == try_only)
987                     return 1;
988                 fatal(unable_to_open);
989             } else
990                 printf(_("You will not be able to write "
991                          "the partition table.\n"));
992         }
993
994         if (512 != read(fd, MBRbuffer, 512)) {
995                 if (what == try_only)
996                         return 1;
997                 fatal(unable_to_read);
998         }
999
1000         get_geometry(fd, NULL);
1001
1002         update_units();
1003
1004         if (check_sun_label())
1005                 return 0;
1006
1007         if (check_sgi_label())
1008                 return 0;
1009
1010         if (check_aix_label())
1011                 return 0;
1012
1013         if (check_mac_label())
1014                 return 0;
1015
1016         if (check_osf_label()) {
1017                 possibly_osf_label = 1;
1018                 if (!valid_part_table_flag(MBRbuffer)) {
1019                         osf_label = 1;
1020                         return 0;
1021                 }
1022                 printf(_("This disk has both DOS and BSD magic.\n"
1023                          "Give the 'b' command to go to BSD mode.\n"));
1024         }
1025
1026 got_dos_table:
1027
1028         if (!valid_part_table_flag(MBRbuffer)) {
1029                 switch(what) {
1030                 case fdisk:
1031                         fprintf(stderr,
1032                                 _("Device contains neither a valid DOS "
1033                                   "partition table, nor Sun, SGI or OSF "
1034                                   "disklabel\n"));
1035 #ifdef __sparc__
1036                         create_sunlabel();
1037 #else
1038                         create_doslabel();
1039 #endif
1040                         return 0;
1041                 case require:
1042                         return -1;
1043                 case try_only:
1044                         return -1;
1045                 case create_empty_dos:
1046                 case create_empty_sun:
1047                         break;
1048                 default:
1049                         fprintf(stderr, _("Internal error\n"));
1050                         exit(1);
1051                 }
1052         }
1053
1054         warn_cylinders();
1055         warn_geometry();
1056
1057         for (i = 0; i < 4; i++) {
1058                 struct pte *pe = &ptes[i];
1059
1060                 if (IS_EXTENDED (pe->part_table->sys_ind)) {
1061                         if (partitions != 4)
1062                                 fprintf(stderr, _("Ignoring extra extended "
1063                                         "partition %d\n"), i + 1);
1064                         else
1065                                 read_extended(i);
1066                 }
1067         }
1068
1069         for (i = 3; i < partitions; i++) {
1070                 struct pte *pe = &ptes[i];
1071
1072                 if (!valid_part_table_flag(pe->sectorbuffer)) {
1073                         fprintf(stderr,
1074                                 _("Warning: invalid flag 0x%04x of partition "
1075                                 "table %d will be corrected by w(rite)\n"),
1076                                 part_table_flag(pe->sectorbuffer), i + 1);
1077                         pe->changed = 1;
1078                 }
1079         }
1080
1081         return 0;
1082 }
1083
1084 /* read line; return 0 or first char */
1085 int
1086 read_line(void)
1087 {
1088         static int got_eof = 0;
1089
1090         line_ptr = line_buffer;
1091         if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
1092                 if (feof(stdin))
1093                         got_eof++;      /* user typed ^D ? */
1094                 if (got_eof >= 3) {
1095                         fflush(stdout);
1096                         fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
1097                         exit(1);
1098                 }
1099                 return 0;
1100         }
1101         while (*line_ptr && !isgraph(*line_ptr))
1102                 line_ptr++;
1103         return *line_ptr;
1104 }
1105
1106 char
1107 read_char(char *mesg)
1108 {
1109         do {
1110                 fputs(mesg, stdout);
1111                 fflush (stdout);         /* requested by niles@scyld.com */
1112         } while (!read_line());
1113         return *line_ptr;
1114 }
1115
1116 char
1117 read_chars(char *mesg)
1118 {
1119         fputs(mesg, stdout);
1120         fflush (stdout);        /* niles@scyld.com */
1121         if (!read_line()) {
1122                 *line_ptr = '\n';
1123                 line_ptr[1] = 0;
1124         }
1125         return *line_ptr;
1126 }
1127
1128 int
1129 read_hex(struct systypes *sys)
1130 {
1131         int hex;
1132
1133         while (1)
1134         {
1135            read_char(_("Hex code (type L to list codes): "));
1136            if (tolower(*line_ptr) == 'l')
1137                list_types(sys);
1138            else if (isxdigit (*line_ptr))
1139            {
1140               hex = 0;
1141               do
1142                  hex = hex << 4 | hex_val(*line_ptr++);
1143               while (isxdigit(*line_ptr));
1144               return hex;
1145            }
1146         }
1147 }
1148
1149 /*
1150  * Print the message MESG, then read an integer in LOW..HIGH.
1151  * If the user hits Enter, DFLT is returned, provided that is in LOW..HIGH.
1152  * Answers like +10 are interpreted as offsets from BASE.
1153  *
1154  * There is no default if DFLT is not between LOW and HIGH.
1155  */
1156 unsigned int
1157 read_int(unsigned int low, unsigned int dflt, unsigned int high,
1158          unsigned int base, char *mesg)
1159 {
1160         unsigned int i;
1161         int default_ok = 1;
1162         static char *ms = NULL;
1163         static int mslen = 0;
1164
1165         if (!ms || strlen(mesg)+100 > mslen) {
1166                 mslen = strlen(mesg)+200;
1167                 if (!(ms = realloc(ms,mslen)))
1168                         fatal(out_of_memory);
1169         }
1170
1171         if (dflt < low || dflt > high)
1172                 default_ok = 0;
1173
1174         if (default_ok)
1175                 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
1176                          mesg, low, high, dflt);
1177         else
1178                 snprintf(ms, mslen, "%s (%u-%u): ",
1179                          mesg, low, high);
1180
1181         while (1) {
1182                 int use_default = default_ok;
1183
1184                 /* ask question and read answer */
1185                 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
1186                        && *line_ptr != '-' && *line_ptr != '+')
1187                         continue;
1188
1189                 if (*line_ptr == '+' || *line_ptr == '-') {
1190                         int minus = (*line_ptr == '-');
1191                         int absolute = 0;
1192                         int suflen;
1193
1194                         i = atoi(line_ptr+1);
1195
1196                         while (isdigit(*++line_ptr))
1197                                 use_default = 0;
1198
1199                         suflen = strlen(line_ptr) - 1;
1200
1201                         while(isspace(*(line_ptr + suflen)))
1202                                 *(line_ptr + suflen--) = '\0';
1203
1204                         if ((*line_ptr == 'C' || *line_ptr == 'c') &&
1205                             *(line_ptr + 1) == '\0') {
1206                                 /*
1207                                  * Cylinders
1208                                  */
1209                                 if (!display_in_cyl_units)
1210                                         i *= heads * sectors;
1211                         } else if (*line_ptr &&
1212                                    *(line_ptr + 1) == 'B' &&
1213                                    *(line_ptr + 2) == '\0') {
1214                                 /*
1215                                  * 10^N
1216                                  */
1217                                 if (*line_ptr == 'K')
1218                                         absolute = 1000;
1219                                 else if (*line_ptr == 'M')
1220                                         absolute = 1000000;
1221                                 else if (*line_ptr == 'G')
1222                                         absolute = 1000000000;
1223                                 else
1224                                         absolute = -1;
1225                         } else if (*line_ptr &&
1226                                    *(line_ptr + 1) == '\0') {
1227                                 /*
1228                                  * 2^N
1229                                  */
1230                                 if (*line_ptr == 'K')
1231                                         absolute = 1 << 10;
1232                                 else if (*line_ptr == 'M')
1233                                         absolute = 1 << 20;
1234                                 else if (*line_ptr == 'G')
1235                                         absolute = 1 << 30;
1236                                 else
1237                                         absolute = -1;
1238                         } else if (*line_ptr != '\0')
1239                                 absolute = -1;
1240
1241                         if (absolute == -1)  {
1242                                 printf(_("Unsupported suffix: '%s'.\n"), line_ptr);
1243                                 printf(_("Supported: 10^N: KB (KiloByte), MB (MegaByte), GB (GigaByte)\n"
1244                                          "            2^N: K  (KibiByte), M  (MebiByte), G  (GibiByte)\n"));
1245                                 continue;
1246                         }
1247
1248                         if (absolute && i) {
1249                                 unsigned long long bytes;
1250                                 unsigned long unit;
1251
1252                                 bytes = (unsigned long long) i * absolute;
1253                                 unit = sector_size * units_per_sector;
1254                                 bytes += unit/2;        /* round */
1255                                 bytes /= unit;
1256                                 i = bytes;
1257                         }
1258                         if (minus)
1259                                 i = -i;
1260                         i += base;
1261                 } else {
1262                         i = atoi(line_ptr);
1263                         while (isdigit(*line_ptr)) {
1264                                 line_ptr++;
1265                                 use_default = 0;
1266                         }
1267                 }
1268                 if (use_default)
1269                         printf(_("Using default value %u\n"), i = dflt);
1270                 if (i >= low && i <= high)
1271                         break;
1272                 else
1273                         printf(_("Value out of range.\n"));
1274         }
1275         return i;
1276 }
1277
1278 int
1279 get_partition(int warn, int max) {
1280         struct pte *pe;
1281         int i;
1282
1283         i = read_int(1, 0, max, 0, _("Partition number")) - 1;
1284         pe = &ptes[i];
1285
1286         if (warn) {
1287                 if ((!sun_label && !sgi_label && !pe->part_table->sys_ind)
1288                     || (sun_label &&
1289                         (!sunlabel->partitions[i].num_sectors ||
1290                          !sunlabel->part_tags[i].tag))
1291                     || (sgi_label && (!sgi_get_num_sectors(i)))
1292                    )
1293                         fprintf(stderr,
1294                                 _("Warning: partition %d has empty type\n"),
1295                                 i+1);
1296         }
1297         return i;
1298 }
1299
1300 static int
1301 get_existing_partition(int warn, int max) {
1302         int pno = -1;
1303         int i;
1304
1305         for (i = 0; i < max; i++) {
1306                 struct pte *pe = &ptes[i];
1307                 struct partition *p = pe->part_table;
1308
1309                 if (p && !is_cleared_partition(p)) {
1310                         if (pno >= 0)
1311                                 goto not_unique;
1312                         pno = i;
1313                 }
1314         }
1315         if (pno >= 0) {
1316                 printf(_("Selected partition %d\n"), pno+1);
1317                 return pno;
1318         }
1319         printf(_("No partition is defined yet!\n"));
1320         return -1;
1321
1322  not_unique:
1323         return get_partition(warn, max);
1324 }
1325
1326 static int
1327 get_nonexisting_partition(int warn, int max) {
1328         int pno = -1;
1329         int i;
1330
1331         for (i = 0; i < max; i++) {
1332                 struct pte *pe = &ptes[i];
1333                 struct partition *p = pe->part_table;
1334
1335                 if (p && is_cleared_partition(p)) {
1336                         if (pno >= 0)
1337                                 goto not_unique;
1338                         pno = i;
1339                 }
1340         }
1341         if (pno >= 0) {
1342                 printf(_("Selected partition %d\n"), pno+1);
1343                 return pno;
1344         }
1345         printf(_("All primary partitions have been defined already!\n"));
1346         return -1;
1347
1348  not_unique:
1349         return get_partition(warn, max);
1350 }
1351
1352 const char *
1353 str_units(int n) {      /* n==1: use singular */
1354         if (n == 1)
1355                 return display_in_cyl_units ? _("cylinder") : _("sector");
1356         else
1357                 return display_in_cyl_units ? _("cylinders") : _("sectors");
1358 }
1359
1360 void change_units(void)
1361 {
1362         display_in_cyl_units = !display_in_cyl_units;
1363         update_units();
1364         printf(_("Changing display/entry units to %s\n"),
1365                 str_units(PLURAL));
1366 }
1367
1368 static void
1369 toggle_active(int i) {
1370         struct pte *pe = &ptes[i];
1371         struct partition *p = pe->part_table;
1372
1373         if (IS_EXTENDED (p->sys_ind) && !p->boot_ind)
1374                 fprintf(stderr,
1375                         _("WARNING: Partition %d is an extended partition\n"),
1376                         i + 1);
1377         p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1378         pe->changed = 1;
1379 }
1380
1381 static void
1382 toggle_dos_compatibility_flag(void) {
1383         dos_compatible_flag = ~dos_compatible_flag;
1384         if (dos_compatible_flag) {
1385                 sector_offset = sectors;
1386                 printf(_("DOS Compatibility flag is set\n"));
1387         }
1388         else {
1389                 sector_offset = 1;
1390                 printf(_("DOS Compatibility flag is not set\n"));
1391         }
1392 }
1393
1394 static void
1395 delete_partition(int i) {
1396         struct pte *pe = &ptes[i];
1397         struct partition *p = pe->part_table;
1398         struct partition *q = pe->ext_pointer;
1399
1400 /* Note that for the fifth partition (i == 4) we don't actually
1401  * decrement partitions.
1402  */
1403
1404         if (warn_geometry())
1405                 return;         /* C/H/S not set */
1406         pe->changed = 1;
1407
1408         if (sun_label) {
1409                 sun_delete_partition(i);
1410                 return;
1411         }
1412
1413         if (sgi_label) {
1414                 sgi_delete_partition(i);
1415                 return;
1416         }
1417
1418         if (i < 4) {
1419                 if (IS_EXTENDED (p->sys_ind) && i == ext_index) {
1420                         partitions = 4;
1421                         ptes[ext_index].ext_pointer = NULL;
1422                         extended_offset = 0;
1423                 }
1424                 clear_partition(p);
1425                 return;
1426         }
1427
1428         if (!q->sys_ind && i > 4) {
1429                 /* the last one in the chain - just delete */
1430                 --partitions;
1431                 --i;
1432                 clear_partition(ptes[i].ext_pointer);
1433                 ptes[i].changed = 1;
1434         } else {
1435                 /* not the last one - further ones will be moved down */
1436                 if (i > 4) {
1437                         /* delete this link in the chain */
1438                         p = ptes[i-1].ext_pointer;
1439                         *p = *q;
1440                         set_start_sect(p, get_start_sect(q));
1441                         set_nr_sects(p, get_nr_sects(q));
1442                         ptes[i-1].changed = 1;
1443                 } else if (partitions > 5) {    /* 5 will be moved to 4 */
1444                         /* the first logical in a longer chain */
1445                         struct pte *pe = &ptes[5];
1446
1447                         if (pe->part_table) /* prevent SEGFAULT */
1448                                 set_start_sect(pe->part_table,
1449                                                get_partition_start(pe) -
1450                                                extended_offset);
1451                         pe->offset = extended_offset;
1452                         pe->changed = 1;
1453                 }
1454
1455                 if (partitions > 5) {
1456                         partitions--;
1457                         while (i < partitions) {
1458                                 ptes[i] = ptes[i+1];
1459                                 i++;
1460                         }
1461                 } else
1462                         /* the only logical: clear only */
1463                         clear_partition(ptes[i].part_table);
1464         }
1465 }
1466
1467 static void
1468 change_sysid(void) {
1469         char *temp;
1470         int i, sys, origsys;
1471         struct partition *p;
1472
1473         /* If sgi_label then don't use get_existing_partition,
1474            let the user select a partition, since get_existing_partition()
1475            only works for Linux like partition tables. */
1476         if (!sgi_label) {
1477                 i = get_existing_partition(0, partitions);
1478         } else {
1479                 i = get_partition(0, partitions);
1480         }
1481
1482         if (i == -1)
1483                 return;
1484         p = ptes[i].part_table;
1485         origsys = sys = get_sysid(i);
1486
1487         /* if changing types T to 0 is allowed, then
1488            the reverse change must be allowed, too */
1489         if (!sys && !sgi_label && !sun_label && !get_nr_sects(p))
1490                 printf(_("Partition %d does not exist yet!\n"), i + 1);
1491         else while (1) {
1492                 sys = read_hex (get_sys_types());
1493
1494                 if (!sys && !sgi_label && !sun_label) {
1495                         printf(_("Type 0 means free space to many systems\n"
1496                                "(but not to Linux). Having partitions of\n"
1497                                "type 0 is probably unwise. You can delete\n"
1498                                "a partition using the `d' command.\n"));
1499                         /* break; */
1500                 }
1501
1502                 if (!sun_label && !sgi_label) {
1503                         if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) {
1504                                 printf(_("You cannot change a partition into"
1505                                        " an extended one or vice versa\n"
1506                                        "Delete it first.\n"));
1507                                 break;
1508                         }
1509                 }
1510
1511                 if (sys < 256) {
1512                         if (sun_label && i == 2 && sys != SUN_TAG_BACKUP)
1513                                 printf(_("Consider leaving partition 3 "
1514                                        "as Whole disk (5),\n"
1515                                        "as SunOS/Solaris expects it and "
1516                                        "even Linux likes it.\n\n"));
1517                         if (sgi_label && ((i == 10 && sys != ENTIRE_DISK)
1518                                           || (i == 8 && sys != 0)))
1519                                 printf(_("Consider leaving partition 9 "
1520                                        "as volume header (0),\nand "
1521                                        "partition 11 as entire volume (6), "
1522                                        "as IRIX expects it.\n\n"));
1523                         if (sys == origsys)
1524                                 break;
1525                         if (sun_label) {
1526                                 ptes[i].changed = sun_change_sysid(i, sys);
1527                         } else
1528                         if (sgi_label) {
1529                                 ptes[i].changed = sgi_change_sysid(i, sys);
1530                         } else {
1531                                 p->sys_ind = sys;
1532                                 ptes[i].changed = 1;
1533                         }
1534                         temp = partition_type(sys) ? : _("Unknown");
1535                         if (ptes[i].changed)
1536                                 printf (_("Changed system type of partition %d "
1537                                         "to %x (%s)\n"), i + 1, sys, temp);
1538                         else
1539                                 printf (_("System type of partition %d is unchanged: "
1540                                         "%x (%s)\n"), i + 1, sys, temp);
1541                         if (is_dos_partition(origsys) ||
1542                             is_dos_partition(sys))
1543                                 dos_changed = 1;
1544                         break;
1545                 }
1546         }
1547 }
1548
1549 /* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
1550  * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1551  * Jan.  1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1552  * Lubkin Oct.  1991). */
1553
1554 static void
1555 long2chs(ulong ls, unsigned int *c, unsigned int *h, unsigned int *s) {
1556         int spc = heads * sectors;
1557
1558         *c = ls / spc;
1559         ls = ls % spc;
1560         *h = ls / sectors;
1561         *s = ls % sectors + 1;  /* sectors count from 1 */
1562 }
1563
1564 static void check_consistency(struct partition *p, int partition) {
1565         unsigned int pbc, pbh, pbs;     /* physical beginning c, h, s */
1566         unsigned int pec, peh, pes;     /* physical ending c, h, s */
1567         unsigned int lbc, lbh, lbs;     /* logical beginning c, h, s */
1568         unsigned int lec, leh, les;     /* logical ending c, h, s */
1569
1570         if (!heads || !sectors || (partition >= 4))
1571                 return;         /* do not check extended partitions */
1572
1573 /* physical beginning c, h, s */
1574         pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1575         pbh = p->head;
1576         pbs = p->sector & 0x3f;
1577
1578 /* physical ending c, h, s */
1579         pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1580         peh = p->end_head;
1581         pes = p->end_sector & 0x3f;
1582
1583 /* compute logical beginning (c, h, s) */
1584         long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1585
1586 /* compute logical ending (c, h, s) */
1587         long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1588
1589 /* Same physical / logical beginning? */
1590         if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1591                 printf(_("Partition %d has different physical/logical "
1592                         "beginnings (non-Linux?):\n"), partition + 1);
1593                 printf(_("     phys=(%d, %d, %d) "), pbc, pbh, pbs);
1594                 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
1595         }
1596
1597 /* Same physical / logical ending? */
1598         if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1599                 printf(_("Partition %d has different physical/logical "
1600                         "endings:\n"), partition + 1);
1601                 printf(_("     phys=(%d, %d, %d) "), pec, peh, pes);
1602                 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
1603         }
1604
1605 #if 0
1606 /* Beginning on cylinder boundary? */
1607         if (pbh != !pbc || pbs != 1) {
1608                 printf(_("Partition %i does not start on cylinder "
1609                         "boundary:\n"), partition + 1);
1610                 printf(_("     phys=(%d, %d, %d) "), pbc, pbh, pbs);
1611                 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
1612         }
1613 #endif
1614
1615 /* Ending on cylinder boundary? */
1616         if (peh != (heads - 1) || pes != sectors) {
1617                 printf(_("Partition %i does not end on cylinder boundary.\n"),
1618                         partition + 1);
1619 #if 0
1620                 printf(_("     phys=(%d, %d, %d) "), pec, peh, pes);
1621                 printf(_("should be (%d, %d, %d)\n"),
1622                 pec, heads - 1, sectors);
1623 #endif
1624         }
1625 }
1626
1627 static void
1628 list_disk_geometry(void) {
1629         long long bytes = (total_number_of_sectors << 9);
1630         long megabytes = bytes/1000000;
1631
1632         if (megabytes < 10000)
1633                 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
1634                        disk_device, megabytes, bytes);
1635         else {
1636                 long hectomega = (megabytes + 50) / 100;
1637                 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
1638                        disk_device, hectomega / 10, hectomega % 10, bytes);
1639         }
1640         printf(_("%d heads, %llu sectors/track, %d cylinders"),
1641                heads, sectors, cylinders);
1642         if (units_per_sector == 1)
1643                 printf(_(", total %llu sectors"),
1644                        total_number_of_sectors / sector_factor);
1645         printf("\n");
1646         printf(_("Units = %s of %d * %d = %d bytes\n"),
1647                str_units(PLURAL),
1648                units_per_sector, sector_size, units_per_sector * sector_size);
1649         if (dos_label)
1650                 dos_print_mbr_id();
1651         printf("\n");
1652 }
1653
1654 /*
1655  * Check whether partition entries are ordered by their starting positions.
1656  * Return 0 if OK. Return i if partition i should have been earlier.
1657  * Two separate checks: primary and logical partitions.
1658  */
1659 static int
1660 wrong_p_order(int *prev) {
1661         struct pte *pe;
1662         struct partition *p;
1663         unsigned int last_p_start_pos = 0, p_start_pos;
1664         int i, last_i = 0;
1665
1666         for (i = 0 ; i < partitions; i++) {
1667                 if (i == 4) {
1668                         last_i = 4;
1669                         last_p_start_pos = 0;
1670                 }
1671                 pe = &ptes[i];
1672                 if ((p = pe->part_table)->sys_ind) {
1673                         p_start_pos = get_partition_start(pe);
1674
1675                         if (last_p_start_pos > p_start_pos) {
1676                                 if (prev)
1677                                         *prev = last_i;
1678                                 return i;
1679                         }
1680
1681                         last_p_start_pos = p_start_pos;
1682                         last_i = i;
1683                 }
1684         }
1685         return 0;
1686 }
1687
1688 /*
1689  * Fix the chain of logicals.
1690  * extended_offset is unchanged, the set of sectors used is unchanged
1691  * The chain is sorted so that sectors increase, and so that
1692  * starting sectors increase.
1693  *
1694  * After this it may still be that cfdisk doesnt like the table.
1695  * (This is because cfdisk considers expanded parts, from link to
1696  * end of partition, and these may still overlap.)
1697  * Now
1698  *   sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1699  * may help.
1700  */
1701 static void
1702 fix_chain_of_logicals(void) {
1703         int j, oj, ojj, sj, sjj;
1704         struct partition *pj,*pjj,tmp;
1705
1706         /* Stage 1: sort sectors but leave sector of part 4 */
1707         /* (Its sector is the global extended_offset.) */
1708  stage1:
1709         for (j = 5; j < partitions-1; j++) {
1710                 oj = ptes[j].offset;
1711                 ojj = ptes[j+1].offset;
1712                 if (oj > ojj) {
1713                         ptes[j].offset = ojj;
1714                         ptes[j+1].offset = oj;
1715                         pj = ptes[j].part_table;
1716                         set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1717                         pjj = ptes[j+1].part_table;
1718                         set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1719                         set_start_sect(ptes[j-1].ext_pointer,
1720                                        ojj-extended_offset);
1721                         set_start_sect(ptes[j].ext_pointer,
1722                                        oj-extended_offset);
1723                         goto stage1;
1724                 }
1725         }
1726
1727         /* Stage 2: sort starting sectors */
1728  stage2:
1729         for (j = 4; j < partitions-1; j++) {
1730                 pj = ptes[j].part_table;
1731                 pjj = ptes[j+1].part_table;
1732                 sj = get_start_sect(pj);
1733                 sjj = get_start_sect(pjj);
1734                 oj = ptes[j].offset;
1735                 ojj = ptes[j+1].offset;
1736                 if (oj+sj > ojj+sjj) {
1737                         tmp = *pj;
1738                         *pj = *pjj;
1739                         *pjj = tmp;
1740                         set_start_sect(pj, ojj+sjj-oj);
1741                         set_start_sect(pjj, oj+sj-ojj);
1742                         goto stage2;
1743                 }
1744         }
1745
1746         /* Probably something was changed */
1747         for (j = 4; j < partitions; j++)
1748                 ptes[j].changed = 1;
1749 }
1750
1751 static void
1752 fix_partition_table_order(void) {
1753         struct pte *pei, *pek;
1754         int i,k;
1755
1756         if (!wrong_p_order(NULL)) {
1757                 printf(_("Nothing to do. Ordering is correct already.\n\n"));
1758                 return;
1759         }
1760
1761         while ((i = wrong_p_order(&k)) != 0 && i < 4) {
1762                 /* partition i should have come earlier, move it */
1763                 /* We have to move data in the MBR */
1764                 struct partition *pi, *pk, *pe, pbuf;
1765                 pei = &ptes[i];
1766                 pek = &ptes[k];
1767
1768                 pe = pei->ext_pointer;
1769                 pei->ext_pointer = pek->ext_pointer;
1770                 pek->ext_pointer = pe;
1771
1772                 pi = pei->part_table;
1773                 pk = pek->part_table;
1774
1775                 memmove(&pbuf, pi, sizeof(struct partition));
1776                 memmove(pi, pk, sizeof(struct partition));
1777                 memmove(pk, &pbuf, sizeof(struct partition));
1778
1779                 pei->changed = pek->changed = 1;
1780         }
1781
1782         if (i)
1783                 fix_chain_of_logicals();
1784
1785         printf(_("Done.\n"));
1786
1787 }
1788
1789 static void
1790 list_table(int xtra) {
1791         struct partition *p;
1792         char *type;
1793         int i, w;
1794
1795         if (sun_label) {
1796                 sun_list_table(xtra);
1797                 return;
1798         }
1799
1800         if (sgi_label) {
1801                 sgi_list_table(xtra);
1802                 return;
1803         }
1804
1805         list_disk_geometry();
1806
1807         if (osf_label) {
1808                 xbsd_print_disklabel(xtra);
1809                 return;
1810         }
1811
1812         if (is_garbage_table()) {
1813                 printf(_("This doesn't look like a partition table\n"
1814                          "Probably you selected the wrong device.\n\n"));
1815         }
1816
1817         /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
1818            but if the device name ends in a digit, say /dev/foo1,
1819            then the partition is called /dev/foo1p3. */
1820         w = strlen(disk_device);
1821         if (w && isdigit(disk_device[w-1]))
1822                 w++;
1823         if (w < 5)
1824                 w = 5;
1825
1826         printf(_("%*s Boot      Start         End      Blocks   Id  System\n"),
1827                w+1, _("Device"));
1828
1829         for (i = 0; i < partitions; i++) {
1830                 struct pte *pe = &ptes[i];
1831
1832                 p = pe->part_table;
1833                 if (p && !is_cleared_partition(p)) {
1834                         unsigned int psects = get_nr_sects(p);
1835                         unsigned int pblocks = psects;
1836                         unsigned int podd = 0;
1837
1838                         if (sector_size < 1024) {
1839                                 pblocks /= (1024 / sector_size);
1840                                 podd = psects % (1024 / sector_size);
1841                         }
1842                         if (sector_size > 1024)
1843                                 pblocks *= (sector_size / 1024);
1844                         printf(
1845                             "%s  %c %11lu %11lu %11lu%c  %2x  %s\n",
1846                         partname(disk_device, i+1, w+2),
1847 /* boot flag */         !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
1848                         ? '*' : '?',
1849 /* start */             (unsigned long) cround(get_partition_start(pe)),
1850 /* end */               (unsigned long) cround(get_partition_start(pe) + psects
1851                                 - (psects ? 1 : 0)),
1852 /* odd flag on end */   (unsigned long) pblocks, podd ? '+' : ' ',
1853 /* type id */           p->sys_ind,
1854 /* type name */         (type = partition_type(p->sys_ind)) ?
1855                         type : _("Unknown"));
1856                         check_consistency(p, i);
1857                 }
1858         }
1859
1860         /* Is partition table in disk order? It need not be, but... */
1861         /* partition table entries are not checked for correct order if this
1862            is a sgi, sun or aix labeled disk... */
1863         if (dos_label && wrong_p_order(NULL)) {
1864                 printf(_("\nPartition table entries are not in disk order\n"));
1865         }
1866 }
1867
1868 static void
1869 x_list_table(int extend) {
1870         struct pte *pe;
1871         struct partition *p;
1872         int i;
1873
1874         printf(_("\nDisk %s: %d heads, %llu sectors, %d cylinders\n\n"),
1875                 disk_device, heads, sectors, cylinders);
1876         printf(_("Nr AF  Hd Sec  Cyl  Hd Sec  Cyl     Start      Size ID\n"));
1877         for (i = 0 ; i < partitions; i++) {
1878                 pe = &ptes[i];
1879                 p = (extend ? pe->ext_pointer : pe->part_table);
1880                 if (p != NULL) {
1881                         printf("%2d %02x%4d%4d%5d%4d%4d%5d%11lu%11lu %02x\n",
1882                                 i + 1, p->boot_ind, p->head,
1883                                 sector(p->sector),
1884                                 cylinder(p->sector, p->cyl), p->end_head,
1885                                 sector(p->end_sector),
1886                                 cylinder(p->end_sector, p->end_cyl),
1887                                 (unsigned long) get_start_sect(p),
1888                                 (unsigned long) get_nr_sects(p), p->sys_ind);
1889                         if (p->sys_ind)
1890                                 check_consistency(p, i);
1891                 }
1892         }
1893 }
1894
1895 static void
1896 fill_bounds(unsigned long long *first, unsigned long long *last) {
1897         int i;
1898         struct pte *pe = &ptes[0];
1899         struct partition *p;
1900
1901         for (i = 0; i < partitions; pe++,i++) {
1902                 p = pe->part_table;
1903                 if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) {
1904                         first[i] = 0xffffffff;
1905                         last[i] = 0;
1906                 } else {
1907                         first[i] = get_partition_start(pe);
1908                         last[i] = first[i] + get_nr_sects(p) - 1;
1909                 }
1910         }
1911 }
1912
1913 static void
1914 check(int n, unsigned int h, unsigned int s, unsigned int c,
1915       unsigned int start) {
1916         unsigned int total, real_s, real_c;
1917
1918         real_s = sector(s) - 1;
1919         real_c = cylinder(s, c);
1920         total = (real_c * sectors + real_s) * heads + h;
1921         if (!total)
1922                 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
1923         if (h >= heads)
1924                 fprintf(stderr,
1925                         _("Partition %d: head %d greater than maximum %d\n"),
1926                         n, h + 1, heads);
1927         if (real_s >= sectors)
1928                 fprintf(stderr, _("Partition %d: sector %d greater than "
1929                         "maximum %llu\n"), n, s, sectors);
1930         if (real_c >= cylinders)
1931                 fprintf(stderr, _("Partitions %d: cylinder %d greater than "
1932                         "maximum %d\n"), n, real_c + 1, cylinders);
1933         if (cylinders <= 1024 && start != total)
1934                 fprintf(stderr,
1935                         _("Partition %d: previous sectors %d disagrees with "
1936                         "total %d\n"), n, start, total);
1937 }
1938
1939 static void
1940 verify(void) {
1941         int i, j;
1942         unsigned long long total = 1;
1943         unsigned long long n_sectors = (total_number_of_sectors / sector_factor);
1944         unsigned long long first[partitions], last[partitions];
1945         struct partition *p;
1946
1947         if (warn_geometry())
1948                 return;
1949
1950         if (sun_label) {
1951                 verify_sun();
1952                 return;
1953         }
1954
1955         if (sgi_label) {
1956                 verify_sgi(1);
1957                 return;
1958         }
1959
1960         fill_bounds(first, last);
1961         for (i = 0; i < partitions; i++) {
1962                 struct pte *pe = &ptes[i];
1963
1964                 p = pe->part_table;
1965                 if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) {
1966                         check_consistency(p, i);
1967                         if (get_partition_start(pe) < first[i])
1968                                 printf(_("Warning: bad start-of-data in "
1969                                         "partition %d\n"), i + 1);
1970                         check(i + 1, p->end_head, p->end_sector, p->end_cyl,
1971                                 last[i]);
1972                         total += last[i] + 1 - first[i];
1973                         for (j = 0; j < i; j++)
1974                         if ((first[i] >= first[j] && first[i] <= last[j])
1975                          || ((last[i] <= last[j] && last[i] >= first[j]))) {
1976                                 printf(_("Warning: partition %d overlaps "
1977                                         "partition %d.\n"), j + 1, i + 1);
1978                                 total += first[i] >= first[j] ?
1979                                         first[i] : first[j];
1980                                 total -= last[i] <= last[j] ?
1981                                         last[i] : last[j];
1982                         }
1983                 }
1984         }
1985
1986         if (extended_offset) {
1987                 struct pte *pex = &ptes[ext_index];
1988                 unsigned long long e_last = get_start_sect(pex->part_table) +
1989                         get_nr_sects(pex->part_table) - 1;
1990
1991                 for (i = 4; i < partitions; i++) {
1992                         total++;
1993                         p = ptes[i].part_table;
1994                         if (!p->sys_ind) {
1995                                 if (i != 4 || i + 1 < partitions)
1996                                         printf(_("Warning: partition %d "
1997                                                 "is empty\n"), i + 1);
1998                         }
1999                         else if (first[i] < extended_offset ||
2000                                         last[i] > e_last)
2001                                 printf(_("Logical partition %d not entirely in "
2002                                         "partition %d\n"), i + 1, ext_index + 1);
2003                 }
2004         }
2005
2006         if (total > n_sectors)
2007                 printf(_("Total allocated sectors %llu greater than the maximum"
2008                         " %llu\n"), total, n_sectors);
2009         else if (total < n_sectors)
2010                 printf(_("%lld unallocated %d-byte sectors\n"),
2011                        n_sectors - total, sector_size);
2012 }
2013
2014 static void
2015 add_partition(int n, int sys) {
2016         char mesg[256];         /* 48 does not suffice in Japanese */
2017         int i, read = 0;
2018         struct partition *p = ptes[n].part_table;
2019         struct partition *q = ptes[ext_index].part_table;
2020         long long llimit;
2021         unsigned long long start, stop = 0, limit, temp,
2022                 first[partitions], last[partitions];
2023
2024         if (p && p->sys_ind) {
2025                 printf(_("Partition %d is already defined.  Delete "
2026                          "it before re-adding it.\n"), n + 1);
2027                 return;
2028         }
2029         fill_bounds(first, last);
2030         if (n < 4) {
2031                 start = sector_offset;
2032                 if (display_in_cyl_units || !total_number_of_sectors)
2033                         llimit = heads * sectors * cylinders - 1;
2034                 else
2035                         llimit = (total_number_of_sectors / sector_factor) - 1;
2036                 limit = llimit;
2037                 if (limit != llimit)
2038                         limit = 0x7fffffff;
2039                 if (extended_offset) {
2040                         first[ext_index] = extended_offset;
2041                         last[ext_index] = get_start_sect(q) +
2042                                 get_nr_sects(q) - 1;
2043                 }
2044         } else {
2045                 start = extended_offset + sector_offset;
2046                 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2047         }
2048         if (display_in_cyl_units)
2049                 for (i = 0; i < partitions; i++)
2050                         first[i] = (cround(first[i]) - 1) * units_per_sector;
2051
2052         snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2053         do {
2054                 temp = start;
2055                 for (i = 0; i < partitions; i++) {
2056                         unsigned long long lastplusoff;
2057
2058                         if (start == ptes[i].offset)
2059                                 start += sector_offset;
2060                         lastplusoff = last[i] + ((n<4) ? 0 : sector_offset);
2061                         if (start >= first[i] && start <= lastplusoff)
2062                                 start = lastplusoff + 1;
2063                 }
2064                 if (start > limit)
2065                         break;
2066                 if (start >= temp+units_per_sector && read) {
2067                         printf(_("Sector %llu is already allocated\n"), temp);
2068                         temp = start;
2069                         read = 0;
2070                 }
2071                 if (!read && start == temp) {
2072                         unsigned long long i = start;
2073
2074                         start = read_int(cround(i), cround(i), cround(limit),
2075                                          0, mesg);
2076                         if (display_in_cyl_units) {
2077                                 start = (start - 1) * units_per_sector;
2078                                 if (start < i) start = i;
2079                         }
2080                         read = 1;
2081                 }
2082         } while (start != temp || !read);
2083         if (n > 4) {                    /* NOT for fifth partition */
2084                 struct pte *pe = &ptes[n];
2085
2086                 pe->offset = start - sector_offset;
2087                 if (pe->offset == extended_offset) { /* must be corrected */
2088                         pe->offset++;
2089                         if (sector_offset == 1)
2090                                 start++;
2091                 }
2092         }
2093
2094         for (i = 0; i < partitions; i++) {
2095                 struct pte *pe = &ptes[i];
2096
2097                 if (start < pe->offset && limit >= pe->offset)
2098                         limit = pe->offset - 1;
2099                 if (start < first[i] && limit >= first[i])
2100                         limit = first[i] - 1;
2101         }
2102         if (start > limit) {
2103                 printf(_("No free sectors available\n"));
2104                 if (n > 4)
2105                         partitions--;
2106                 return;
2107         }
2108         if (cround(start) == cround(limit)) {
2109                 stop = limit;
2110         } else {
2111                 snprintf(mesg, sizeof(mesg),
2112                         _("Last %1$s, +%2$s or +size{K,M,G}"),
2113                          str_units(SINGULAR), str_units(PLURAL));
2114
2115                 stop = read_int(cround(start), cround(limit), cround(limit),
2116                                 cround(start), mesg);
2117                 if (display_in_cyl_units) {
2118                         stop = stop * units_per_sector - 1;
2119                         if (stop >limit)
2120                                 stop = limit;
2121                 }
2122         }
2123
2124         set_partition(n, 0, start, stop, sys);
2125         if (n > 4)
2126                 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2127
2128         if (IS_EXTENDED (sys)) {
2129                 struct pte *pe4 = &ptes[4];
2130                 struct pte *pen = &ptes[n];
2131
2132                 ext_index = n;
2133                 pen->ext_pointer = p;
2134                 pe4->offset = extended_offset = start;
2135                 if (!(pe4->sectorbuffer = calloc(1, sector_size)))
2136                         fatal(out_of_memory);
2137                 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2138                 pe4->ext_pointer = pe4->part_table + 1;
2139                 pe4->changed = 1;
2140                 partitions = 5;
2141         }
2142 }
2143
2144 static void
2145 add_logical(void) {
2146         if (partitions > 5 || ptes[4].part_table->sys_ind) {
2147                 struct pte *pe = &ptes[partitions];
2148
2149                 if (!(pe->sectorbuffer = calloc(1, sector_size)))
2150                         fatal(out_of_memory);
2151                 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2152                 pe->ext_pointer = pe->part_table + 1;
2153                 pe->offset = 0;
2154                 pe->changed = 1;
2155                 partitions++;
2156         }
2157         add_partition(partitions - 1, LINUX_NATIVE);
2158 }
2159
2160 static void
2161 new_partition(void) {
2162         int i, free_primary = 0;
2163
2164         if (warn_geometry())
2165                 return;
2166
2167         if (sun_label) {
2168                 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
2169                 return;
2170         }
2171
2172         if (sgi_label) {
2173                 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
2174                 return;
2175         }
2176
2177         if (aix_label) {
2178                 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
2179                          "\n\tIf you want to add DOS-type partitions, create"
2180                          "\n\ta new empty DOS partition table first. (Use o.)"
2181                          "\n\tWARNING: "
2182                          "This will destroy the present disk contents.\n"));
2183                 return;
2184         }
2185
2186         if (mac_label) {
2187                 printf(_("\tSorry - this fdisk cannot handle Mac disk labels."
2188                          "\n\tIf you want to add DOS-type partitions, create"
2189                          "\n\ta new empty DOS partition table first. (Use o.)"
2190                          "\n\tWARNING: "
2191                          "This will destroy the present disk contents.\n"));
2192                  return;
2193         }
2194
2195         for (i = 0; i < 4; i++)
2196                 free_primary += !ptes[i].part_table->sys_ind;
2197
2198         if (!free_primary && partitions >= MAXIMUM_PARTS) {
2199                 printf(_("The maximum number of partitions has been created\n"));
2200                 return;
2201         }
2202
2203         if (!free_primary) {
2204                 if (extended_offset)
2205                         add_logical();
2206                 else
2207                         printf(_("You must delete some partition and add "
2208                                  "an extended partition first\n"));
2209         } else if (partitions >= MAXIMUM_PARTS) {
2210                 printf(_("All logical partitions are in use\n"));
2211                 printf(_("Adding a primary partition\n"));
2212                 add_partition(get_partition(0, 4), LINUX_NATIVE);
2213         } else {
2214                 char c, line[LINE_LENGTH];
2215                 snprintf(line, sizeof(line),
2216                          _("Command action\n   %s\n   p   primary "
2217                            "partition (1-4)\n"), extended_offset ?
2218                          _("l   logical (5 or over)") : _("e   extended"));
2219                 while (1) {
2220                         if ((c = tolower(read_char(line))) == 'p') {
2221                                 int i = get_nonexisting_partition(0, 4);
2222                                 if (i >= 0)
2223                                         add_partition(i, LINUX_NATIVE);
2224                                 return;
2225                         }
2226                         else if (c == 'l' && extended_offset) {
2227                                 add_logical();
2228                                 return;
2229                         }
2230                         else if (c == 'e' && !extended_offset) {
2231                                 int i = get_nonexisting_partition(0, 4);
2232                                 if (i >= 0)
2233                                         add_partition(i, EXTENDED);
2234                                 return;
2235                         }
2236                         else
2237                                 printf(_("Invalid partition number "
2238                                          "for type `%c'\n"), c);
2239                 }
2240         }
2241 }
2242
2243 static void
2244 write_table(void) {
2245         int i;
2246
2247         if (dos_label) {
2248                 for (i=0; i<3; i++)
2249                         if (ptes[i].changed)
2250                                 ptes[3].changed = 1;
2251                 for (i = 3; i < partitions; i++) {
2252                         struct pte *pe = &ptes[i];
2253
2254                         if (pe->changed) {
2255                                 write_part_table_flag(pe->sectorbuffer);
2256                                 write_sector(fd, pe->offset, pe->sectorbuffer);
2257                         }
2258                 }
2259         }
2260         else if (sgi_label) {
2261                 /* no test on change? the printf below might be mistaken */
2262                 sgi_write_table();
2263         } else if (sun_label) {
2264                 int needw = 0;
2265
2266                 for (i=0; i<8; i++)
2267                         if (ptes[i].changed)
2268                                 needw = 1;
2269                 if (needw)
2270                         sun_write_table();
2271         }
2272
2273         printf(_("The partition table has been altered!\n\n"));
2274         reread_partition_table(1);
2275 }
2276
2277 void
2278 reread_partition_table(int leave) {
2279         int i;
2280         struct stat statbuf;
2281
2282         i = fstat(fd, &statbuf);
2283         if (i == 0 && S_ISBLK(statbuf.st_mode)) {
2284                 sync();
2285                 sleep(2);
2286 #ifdef BLKRRPART
2287                 printf(_("Calling ioctl() to re-read partition table.\n"));
2288                 i = ioctl(fd, BLKRRPART);
2289 #else
2290                 errno = ENOSYS;
2291                 i = 1;
2292 #endif
2293         }
2294
2295         if (i) {
2296                 printf(_("\nWARNING: Re-reading the partition table failed with error %d: %s.\n"
2297                          "The kernel still uses the old table. The new table will be used at\n"
2298                          "the next reboot or after you run partprobe(8) or kpartx(8)\n"),
2299                         errno, strerror(errno));
2300         }
2301
2302         if (dos_changed)
2303             printf(
2304                 _("\nWARNING: If you have created or modified any DOS 6.x\n"
2305                 "partitions, please see the fdisk manual page for additional\n"
2306                 "information.\n"));
2307
2308         if (leave) {
2309                 if (fsync(fd) || close(fd)) {
2310                         fprintf(stderr, _("\nError closing file\n"));
2311                         exit(1);
2312                 }
2313
2314                 printf(_("Syncing disks.\n"));
2315                 sync();
2316                 sleep(4);               /* for sync() */
2317                 exit(!!i);
2318         }
2319 }
2320
2321 #define MAX_PER_LINE    16
2322 static void
2323 print_buffer(unsigned char pbuffer[]) {
2324         int     i,
2325                 l;
2326
2327         for (i = 0, l = 0; i < sector_size; i++, l++) {
2328                 if (l == 0)
2329                         printf("0x%03X:", i);
2330                 printf(" %02X", pbuffer[i]);
2331                 if (l == MAX_PER_LINE - 1) {
2332                         printf("\n");
2333                         l = -1;
2334                 }
2335         }
2336         if (l > 0)
2337                 printf("\n");
2338         printf("\n");
2339 }
2340
2341 static void
2342 print_raw(void) {
2343         int i;
2344
2345         printf(_("Device: %s\n"), disk_device);
2346         if (sun_label || sgi_label)
2347                 print_buffer(MBRbuffer);
2348         else for (i = 3; i < partitions; i++)
2349                 print_buffer(ptes[i].sectorbuffer);
2350 }
2351
2352 static void
2353 move_begin(int i) {
2354         struct pte *pe = &ptes[i];
2355         struct partition *p = pe->part_table;
2356         unsigned int new, first;
2357
2358         if (warn_geometry())
2359                 return;
2360         if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED (p->sys_ind)) {
2361                 printf(_("Partition %d has no data area\n"), i + 1);
2362                 return;
2363         }
2364         first = get_partition_start(pe);
2365         new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2366                        _("New beginning of data")) - pe->offset;
2367
2368         if (new != get_nr_sects(p)) {
2369                 first = get_nr_sects(p) + get_start_sect(p) - new;
2370                 set_nr_sects(p, first);
2371                 set_start_sect(p, new);
2372                 pe->changed = 1;
2373         }
2374 }
2375
2376 static void
2377 xselect(void) {
2378         char c;
2379
2380         while(1) {
2381                 putchar('\n');
2382                 c = tolower(read_char(_("Expert command (m for help): ")));
2383                 switch (c) {
2384                 case 'a':
2385                         if (sun_label)
2386                                 sun_set_alt_cyl();
2387                         break;
2388                 case 'b':
2389                         if (dos_label)
2390                                 move_begin(get_partition(0, partitions));
2391                         break;
2392                 case 'c':
2393                         user_cylinders = cylinders =
2394                                 read_int(1, cylinders, 1048576, 0,
2395                                          _("Number of cylinders"));
2396                         if (sun_label)
2397                                 sun_set_ncyl(cylinders);
2398                         if (dos_label)
2399                                 warn_cylinders();
2400                         break;
2401                 case 'd':
2402                         print_raw();
2403                         break;
2404                 case 'e':
2405                         if (sgi_label)
2406                                 sgi_set_xcyl();
2407                         else if (sun_label)
2408                                 sun_set_xcyl();
2409                         else
2410                         if (dos_label)
2411                                 x_list_table(1);
2412                         break;
2413                 case 'f':
2414                         if (dos_label)
2415                                 fix_partition_table_order();
2416                         break;
2417                 case 'g':
2418                         create_sgilabel();
2419                         break;
2420                 case 'h':
2421                         user_heads = heads = read_int(1, heads, 256, 0,
2422                                          _("Number of heads"));
2423                         update_units();
2424                         break;
2425                 case 'i':
2426                         if (sun_label)
2427                                 sun_set_ilfact();
2428                         if (dos_label)
2429                                 dos_set_mbr_id();
2430                         break;
2431                 case 'o':
2432                         if (sun_label)
2433                                 sun_set_rspeed();
2434                         break;
2435                 case 'p':
2436                         if (sun_label)
2437                                 list_table(1);
2438                         else
2439                                 x_list_table(0);
2440                         break;
2441                 case 'q':
2442                         close(fd);
2443                         printf("\n");
2444                         exit(0);
2445                 case 'r':
2446                         return;
2447                 case 's':
2448                         user_sectors = sectors = read_int(1, sectors, 63, 0,
2449                                            _("Number of sectors"));
2450                         if (dos_compatible_flag) {
2451                                 sector_offset = sectors;
2452                                 fprintf(stderr, _("Warning: setting "
2453                                         "sector offset for DOS "
2454                                         "compatiblity\n"));
2455                         }
2456                         update_units();
2457                         break;
2458                 case 'v':
2459                         verify();
2460                         break;
2461                 case 'w':
2462                         write_table();  /* does not return */
2463                         break;
2464                 case 'y':
2465                         if (sun_label)
2466                                 sun_set_pcylcount();
2467                         break;
2468                 default:
2469                         xmenu();
2470                 }
2471         }
2472 }
2473
2474 static int
2475 is_ide_cdrom_or_tape(char *device) {
2476         FILE *procf;
2477         char buf[100];
2478         struct stat statbuf;
2479         int is_ide = 0;
2480
2481         /* No device was given explicitly, and we are trying some
2482            likely things.  But opening /dev/hdc may produce errors like
2483            "hdc: tray open or drive not ready"
2484            if it happens to be a CD-ROM drive. It even happens that
2485            the process hangs on the attempt to read a music CD.
2486            So try to be careful. This only works since 2.1.73. */
2487
2488         if (strncmp("/dev/hd", device, 7))
2489                 return 0;
2490
2491         snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2492         procf = fopen(buf, "r");
2493         if (procf != NULL && fgets(buf, sizeof(buf), procf))
2494                 is_ide = (!strncmp(buf, "cdrom", 5) ||
2495                           !strncmp(buf, "tape", 4));
2496         else
2497                 /* Now when this proc file does not exist, skip the
2498                    device when it is read-only. */
2499                 if (stat(device, &statbuf) == 0)
2500                         is_ide = ((statbuf.st_mode & 0222) == 0);
2501
2502         if (procf)
2503                 fclose(procf);
2504         return is_ide;
2505 }
2506
2507 static void
2508 gpt_warning(char *dev)
2509 {
2510         if (dev && gpt_probe_signature_devname(dev))
2511                 fprintf(stderr, _("\nWARNING: GPT (GUID Partition Table) detected on '%s'! "
2512                         "The util fdisk doesn't support GPT. Use GNU Parted.\n\n"), dev);
2513 }
2514
2515 static void
2516 try(char *device, int user_specified) {
2517         int gb;
2518
2519         disk_device = device;
2520         if (setjmp(listingbuf))
2521                 return;
2522         if (!user_specified)
2523                 if (is_ide_cdrom_or_tape(device))
2524                         return;
2525         gpt_warning(device);
2526         if ((fd = open(disk_device, type_open)) >= 0) {
2527                 gb = get_boot(try_only);
2528                 if (gb > 0) { /* I/O error */
2529                 } else if (gb < 0) { /* no DOS signature */
2530                         list_disk_geometry();
2531                         if (!aix_label && !mac_label && btrydev(device) < 0)
2532                                 fprintf(stderr,
2533                                         _("Disk %s doesn't contain a valid "
2534                                           "partition table\n"), device);
2535                 } else {
2536                         list_table(0);
2537                 }
2538                 close(fd);
2539         } else {
2540                 /* Ignore other errors, since we try IDE
2541                    and SCSI hard disks which may not be
2542                    installed on the system. */
2543                 if (errno == EACCES) {
2544                         fprintf(stderr, _("Cannot open %s\n"), device);
2545                         return;
2546                 }
2547         }
2548 }
2549
2550 /*
2551  * for fdisk -l:
2552  * try all things in /proc/partitions that look like a full disk
2553  */
2554 static void
2555 tryprocpt(void) {
2556         FILE *procpt;
2557         char line[128], ptname[128], devname[256];
2558         int ma, mi;
2559         unsigned long long sz;
2560
2561         procpt = fopen(PROC_PARTITIONS, "r");
2562         if (procpt == NULL) {
2563                 fprintf(stderr, _("cannot open %s\n"), PROC_PARTITIONS);
2564                 return;
2565         }
2566
2567         while (fgets(line, sizeof(line), procpt)) {
2568                 if (sscanf (line, " %d %d %llu %128[^\n ]",
2569                             &ma, &mi, &sz, ptname) != 4)
2570                         continue;
2571                 snprintf(devname, sizeof(devname), "/dev/%s", ptname);
2572                 if (is_whole_disk(devname))
2573                         try(devname, 0);
2574         }
2575         fclose(procpt);
2576 }
2577
2578 static void
2579 dummy(int *kk) {}
2580
2581 static void
2582 unknown_command(int c) {
2583         printf(_("%c: unknown command\n"), c);
2584 }
2585
2586
2587
2588 int
2589 main(int argc, char **argv) {
2590         int j, c;
2591         int optl = 0, opts = 0;
2592
2593         setlocale(LC_ALL, "");
2594         bindtextdomain(PACKAGE, LOCALEDIR);
2595         textdomain(PACKAGE);
2596
2597         /*
2598          * Calls:
2599          *  fdisk -v
2600          *  fdisk -l [-b sectorsize] [-u] device ...
2601          *  fdisk -s [partition] ...
2602          *  fdisk [-b sectorsize] [-u] device
2603          *
2604          * Options -C, -H, -S set the geometry.
2605          *
2606          */
2607         while ((c = getopt(argc, argv, "b:C:H:lsS:uvV")) != -1) {
2608                 switch (c) {
2609                 case 'b':
2610                         /* Ugly: this sector size is really per device,
2611                            so cannot be combined with multiple disks,
2612                            and te same goes for the C/H/S options.
2613                         */
2614                         sector_size = atoi(optarg);
2615                         if (sector_size != 512 && sector_size != 1024 &&
2616                             sector_size != 2048 && sector_size != 4096)
2617                                 fatal(usage);
2618                         sector_offset = 2;
2619                         user_set_sector_size = 1;
2620                         break;
2621                 case 'C':
2622                         user_cylinders = atoi(optarg);
2623                         break;
2624                 case 'H':
2625                         user_heads = atoi(optarg);
2626                         if (user_heads <= 0 || user_heads > 256)
2627                                 user_heads = 0;
2628                         break;
2629                 case 'S':
2630                         user_sectors = atoi(optarg);
2631                         if (user_sectors <= 0 || user_sectors >= 64)
2632                                 user_sectors = 0;
2633                         break;
2634                 case 'l':
2635                         optl = 1;
2636                         break;
2637                 case 's':
2638                         opts = 1;
2639                         break;
2640                 case 'u':
2641                         display_in_cyl_units = 0;
2642                         break;
2643                 case 'V':
2644                 case 'v':
2645                         printf("fdisk (%s)\n", PACKAGE_STRING);
2646                         exit(0);
2647                 default:
2648                         fatal(usage);
2649                 }
2650         }
2651
2652 #if 0
2653         printf(_("This kernel finds the sector size itself - "
2654                  "-b option ignored\n"));
2655 #else
2656         if (user_set_sector_size && argc-optind != 1)
2657                 printf(_("Warning: the -b (set sector size) option should"
2658                          " be used with one specified device\n"));
2659 #endif
2660
2661         if (optl) {
2662                 nowarn = 1;
2663                 type_open = O_RDONLY;
2664                 if (argc > optind) {
2665                         int k;
2666                         /* avoid gcc warning:
2667                            variable `k' might be clobbered by `longjmp' */
2668                         dummy(&k);
2669                         listing = 1;
2670                         for (k = optind; k < argc; k++)
2671                                 try(argv[k], 1);
2672                 } else {
2673                         /* we no longer have default device names */
2674                         /* but we can use /proc/partitions instead */
2675                         tryprocpt();
2676                 }
2677                 exit(0);
2678         }
2679
2680         if (opts) {
2681                 unsigned long long size;
2682
2683                 nowarn = 1;
2684                 type_open = O_RDONLY;
2685
2686                 opts = argc - optind;
2687                 if (opts <= 0)
2688                         fatal(usage);
2689
2690                 for (j = optind; j < argc; j++) {
2691                         disk_device = argv[j];
2692                         if ((fd = open(disk_device, type_open)) < 0)
2693                                 fatal(unable_to_open);
2694                         if (blkdev_get_sectors(fd, &size) == -1)
2695                                 fatal(ioctl_error);
2696                         close(fd);
2697                         if (opts == 1)
2698                                 printf("%llu\n", size/2);
2699                         else
2700                                 printf("%s: %llu\n", argv[j], size/2);
2701                 }
2702                 exit(0);
2703         }
2704
2705         if (argc-optind == 1)
2706                 disk_device = argv[optind];
2707         else if (argc-optind != 0)
2708                 fatal(usage);
2709         else
2710                 fatal(usage2);
2711
2712         gpt_warning(disk_device);
2713         get_boot(fdisk);
2714
2715         if (osf_label) {
2716                 /* OSF label, and no DOS label */
2717                 printf(_("Detected an OSF/1 disklabel on %s, entering "
2718                          "disklabel mode.\n"),
2719                        disk_device);
2720                 bselect();
2721                 osf_label = 0;
2722                 /* If we return we may want to make an empty DOS label? */
2723         }
2724
2725         while (1) {
2726                 putchar('\n');
2727                 c = tolower(read_char(_("Command (m for help): ")));
2728                 switch (c) {
2729                 case 'a':
2730                         if (dos_label)
2731                                 toggle_active(get_partition(1, partitions));
2732                         else if (sun_label)
2733                                 toggle_sunflags(get_partition(1, partitions),
2734                                                 SUN_FLAG_UNMNT);
2735                         else if (sgi_label)
2736                                 sgi_set_bootpartition(
2737                                         get_partition(1, partitions));
2738                         else
2739                                 unknown_command(c);
2740                         break;
2741                 case 'b':
2742                         if (sgi_label) {
2743                                 printf(_("\nThe current boot file is: %s\n"),
2744                                        sgi_get_bootfile());
2745                                 if (read_chars(_("Please enter the name of the "
2746                                                "new boot file: ")) == '\n')
2747                                         printf(_("Boot file unchanged\n"));
2748                                 else
2749                                         sgi_set_bootfile(line_ptr);
2750                         } else
2751                                 bselect();
2752                         break;
2753                 case 'c':
2754                         if (dos_label)
2755                                 toggle_dos_compatibility_flag();
2756                         else if (sun_label)
2757                                 toggle_sunflags(get_partition(1, partitions),
2758                                                 SUN_FLAG_RONLY);
2759                         else if (sgi_label)
2760                                 sgi_set_swappartition(
2761                                                 get_partition(1, partitions));
2762                         else
2763                                 unknown_command(c);
2764                         break;
2765                 case 'd':
2766                         /* If sgi_label then don't use get_existing_partition,
2767                            let the user select a partition, since
2768                            get_existing_partition() only works for Linux-like
2769                            partition tables */
2770                         if (!sgi_label) {
2771                                 j = get_existing_partition(1, partitions);
2772                         } else {
2773                                 j = get_partition(1, partitions);
2774                         }
2775                         if (j >= 0)
2776                                 delete_partition(j);
2777                         break;
2778                 case 'i':
2779                         if (sgi_label)
2780                                 create_sgiinfo();
2781                         else
2782                                 unknown_command(c);
2783                 case 'l':
2784                         list_types(get_sys_types());
2785                         break;
2786                 case 'm':
2787                         menu();
2788                         break;
2789                 case 'n':
2790                         new_partition();
2791                         break;
2792                 case 'o':
2793                         create_doslabel();
2794                         break;
2795                 case 'p':
2796                         list_table(0);
2797                         break;
2798                 case 'q':
2799                         close(fd);
2800                         printf("\n");
2801                         exit(0);
2802                 case 's':
2803                         create_sunlabel();
2804                         break;
2805                 case 't':
2806                         change_sysid();
2807                         break;
2808                 case 'u':
2809                         change_units();
2810                         break;
2811                 case 'v':
2812                         verify();
2813                         break;
2814                 case 'w':
2815                         write_table();          /* does not return */
2816                         break;
2817                 case 'x':
2818                         if (sgi_label) {
2819                                 fprintf(stderr,
2820                                         _("\n\tSorry, no experts menu for SGI "
2821                                         "partition tables available.\n\n"));
2822                         } else
2823                                 xselect();
2824                         break;
2825                 default:
2826                         unknown_command(c);
2827                         menu();
2828                 }
2829         }
2830         return 0;
2831 }