3 * Copyright (C) 2007-2013 Karel Zak <kzak@redhat.com>
4 * 2012 Davidlohr Bueso <dave@gnu.org>
6 * This is re-written version for libfdisk, the original was fdiskdoslabel.c
7 * from util-linux fdisk.
10 #include "randutils.h"
18 #define MAXIMUM_PARTS 60
19 #define ACTIVE_FLAG 0x80
24 * @short_description: disk label specific functions
29 #define IS_EXTENDED(i) \
30 ((i) == MBR_DOS_EXTENDED_PARTITION \
31 || (i) == MBR_W95_EXTENDED_PARTITION \
32 || (i) == MBR_LINUX_EXTENDED_PARTITION)
35 * per partition table entry data
37 * The four primary partitions have the same sectorbuffer
38 * and have NULL ex_entry.
40 * Each logical partition table entry has two pointers, one for the
41 * partition and one link to the next one.
44 struct dos_partition
*pt_entry
; /* on-disk MBR entry */
45 struct dos_partition
*ex_entry
; /* on-disk EBR entry */
46 fdisk_sector_t offset
; /* disk sector number */
47 unsigned char *sectorbuffer
; /* disk sector contents */
49 unsigned int changed
: 1,
50 private_sectorbuffer
: 1;
54 * in-memory fdisk GPT stuff
56 struct fdisk_dos_label
{
57 struct fdisk_label head
; /* generic part */
59 struct pte ptes
[MAXIMUM_PARTS
]; /* partition */
60 fdisk_sector_t ext_offset
; /* start of the ext.partition */
61 size_t ext_index
; /* ext.partition index (if ext_offset is set) */
62 unsigned int compatible
: 1, /* is DOS compatible? */
63 non_pt_changed
: 1; /* MBR, but no PT changed */
69 static struct fdisk_parttype dos_parttypes
[] = {
70 #include "pt-mbr-partnames.h"
73 #define set_hsc(h,s,c,sector) { \
74 s = sector % cxt->geom.sectors + 1; \
75 sector /= cxt->geom.sectors; \
76 h = sector % cxt->geom.heads; \
77 sector /= cxt->geom.heads; \
79 s |= (sector >> 2) & 0xc0; \
83 #define sector(s) ((s) & 0x3f)
84 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
86 #define alignment_required(_x) ((_x)->grain != (_x)->sector_size)
88 #define is_dos_compatible(_x) \
89 (fdisk_is_label(_x, DOS) && \
90 fdisk_dos_is_compatible(fdisk_get_label(_x, NULL)))
92 #define cround(c, n) fdisk_cround(c, n)
95 static inline struct fdisk_dos_label
*self_label(struct fdisk_context
*cxt
)
99 assert(fdisk_is_label(cxt
, DOS
));
101 return (struct fdisk_dos_label
*) cxt
->label
;
104 static inline struct pte
*self_pte(struct fdisk_context
*cxt
, size_t i
)
106 struct fdisk_dos_label
*l
= self_label(cxt
);
108 if (i
>= ARRAY_SIZE(l
->ptes
))
114 static inline struct dos_partition
*self_partition(
115 struct fdisk_context
*cxt
,
118 struct pte
*pe
= self_pte(cxt
, i
);
119 return pe
? pe
->pt_entry
: NULL
;
122 struct dos_partition
*fdisk_dos_get_partition(
123 struct fdisk_context
*cxt
,
128 assert(fdisk_is_label(cxt
, DOS
));
130 return self_partition(cxt
, i
);
133 static struct fdisk_parttype
*dos_partition_parttype(
134 struct fdisk_context
*cxt
,
135 struct dos_partition
*p
)
137 struct fdisk_parttype
*t
138 = fdisk_label_get_parttype_from_code(cxt
->label
, p
->sys_ind
);
139 return t
? : fdisk_new_unknown_parttype(p
->sys_ind
, NULL
);
143 * Linux kernel cares about partition size only. Things like
144 * partition type or so are completely irrelevant -- kzak Nov-2013
146 static int is_used_partition(struct dos_partition
*p
)
148 return p
&& dos_partition_get_size(p
) != 0;
151 static void partition_set_changed(
152 struct fdisk_context
*cxt
,
156 struct pte
*pe
= self_pte(cxt
, i
);
161 DBG(LABEL
, ul_debug("DOS: setting %zu partition to %s", i
,
162 changed
? "changed" : "unchanged"));
164 pe
->changed
= changed
? 1 : 0;
166 fdisk_label_set_changed(cxt
->label
, 1);
169 static fdisk_sector_t
get_abs_partition_start(struct pte
*pe
)
172 assert(pe
->pt_entry
);
174 return pe
->offset
+ dos_partition_get_start(pe
->pt_entry
);
177 static fdisk_sector_t
get_abs_partition_end(struct pte
*pe
)
182 assert(pe
->pt_entry
);
184 size
= dos_partition_get_size(pe
->pt_entry
);
185 return get_abs_partition_start(pe
) + size
- (size
? 1 : 0);
188 static int is_cleared_partition(struct dos_partition
*p
)
190 return !(!p
|| p
->boot_ind
|| p
->bh
|| p
->bs
|| p
->bc
||
191 p
->sys_ind
|| p
->eh
|| p
->es
|| p
->ec
||
192 dos_partition_get_start(p
) || dos_partition_get_size(p
));
195 static int get_partition_unused_primary(struct fdisk_context
*cxt
,
196 struct fdisk_partition
*pa
,
206 org
= cxt
->label
->nparts_max
;
208 cxt
->label
->nparts_max
= 4;
209 rc
= fdisk_partition_next_partno(pa
, cxt
, &n
);
210 cxt
->label
->nparts_max
= org
;
213 fdisk_info(cxt
, _("All primary partitions have been defined already."));
215 } else if (rc
== -ERANGE
) {
216 fdisk_warnx(cxt
, _("Primary partition not available."));
223 static int seek_sector(struct fdisk_context
*cxt
, fdisk_sector_t secno
)
225 off_t offset
= (off_t
) secno
* cxt
->sector_size
;
227 return lseek(cxt
->dev_fd
, offset
, SEEK_SET
) == (off_t
) -1 ? -errno
: 0;
230 static int read_sector(struct fdisk_context
*cxt
, fdisk_sector_t secno
,
233 int rc
= seek_sector(cxt
, secno
);
239 r
= read(cxt
->dev_fd
, buf
, cxt
->sector_size
);
240 if (r
== (ssize_t
) cxt
->sector_size
)
247 /* Allocate a buffer and read a partition table sector */
248 static int read_pte(struct fdisk_context
*cxt
, size_t pno
, fdisk_sector_t offset
)
252 struct pte
*pe
= self_pte(cxt
, pno
);
257 buf
= calloc(1, cxt
->sector_size
);
261 DBG(LABEL
, ul_debug("DOS: reading EBR %zu: offset=%ju, buffer=%p",
262 pno
, (uintmax_t) offset
, buf
));
265 pe
->sectorbuffer
= buf
;
266 pe
->private_sectorbuffer
= 1;
268 rc
= read_sector(cxt
, offset
, pe
->sectorbuffer
);
270 fdisk_warn(cxt
, _("Failed to read extended partition table "
271 "(offset=%ju)"), (uintmax_t) offset
);
276 pe
->pt_entry
= pe
->ex_entry
= NULL
;
281 static void clear_partition(struct dos_partition
*p
)
293 dos_partition_set_start(p
,0);
294 dos_partition_set_size(p
,0);
297 static void dos_init(struct fdisk_context
*cxt
)
299 struct fdisk_dos_label
*l
= self_label(cxt
);
304 assert(fdisk_is_label(cxt
, DOS
));
306 DBG(LABEL
, ul_debug("DOS: initialize, first sector buffer %p", cxt
->firstsector
));
308 cxt
->label
->nparts_max
= 4; /* default, unlimited number of logical */
312 l
->non_pt_changed
= 0;
314 memset(l
->ptes
, 0, sizeof(l
->ptes
));
316 for (i
= 0; i
< 4; i
++) {
317 struct pte
*pe
= self_pte(cxt
, i
);
320 pe
->pt_entry
= mbr_get_partition(cxt
->firstsector
, i
);
323 pe
->sectorbuffer
= cxt
->firstsector
;
324 pe
->private_sectorbuffer
= 0;
327 DBG(LABEL
, ul_debug("DOS: initialize: #%zu start=%u size=%u sysid=%02x",
329 dos_partition_get_start(pe
->pt_entry
),
330 dos_partition_get_size(pe
->pt_entry
),
331 pe
->pt_entry
->sys_ind
));
334 if (fdisk_is_listonly(cxt
))
337 * Various warnings...
339 if (fdisk_missing_geometry(cxt
))
340 fdisk_warnx(cxt
, _("You can set geometry from the extra functions menu."));
342 if (is_dos_compatible(cxt
)) {
343 fdisk_warnx(cxt
, _("DOS-compatible mode is deprecated."));
345 if (cxt
->sector_size
!= cxt
->phy_sector_size
)
347 "The device presents a logical sector size that is smaller than "
348 "the physical sector size. Aligning to a physical sector (or optimal "
349 "I/O) size boundary is recommended, or performance may be impacted."));
352 if (fdisk_use_cylinders(cxt
))
353 fdisk_warnx(cxt
, _("Cylinders as display units are deprecated."));
355 if (cxt
->total_sectors
> UINT_MAX
) {
356 uint64_t bytes
= cxt
->total_sectors
* cxt
->sector_size
;
357 char *szstr
= size_to_human_string(SIZE_SUFFIX_SPACE
358 | SIZE_SUFFIX_3LETTER
, bytes
);
360 _("The size of this disk is %s (%ju bytes). DOS "
361 "partition table format cannot be used on drives for "
362 "volumes larger than %lu bytes for %lu-byte "
363 "sectors. Use GUID partition table format (GPT)."),
365 UINT_MAX
* cxt
->sector_size
,
371 /* callback called by libfdisk */
372 static void dos_deinit(struct fdisk_label
*lb
)
375 struct fdisk_dos_label
*l
= (struct fdisk_dos_label
*) lb
;
377 for (i
= 0; i
< ARRAY_SIZE(l
->ptes
); i
++) {
378 struct pte
*pe
= &l
->ptes
[i
];
380 if (pe
->private_sectorbuffer
&& pe
->sectorbuffer
) {
381 DBG(LABEL
, ul_debug("DOS: freeing pte %zu sector buffer %p",
382 i
, pe
->sectorbuffer
));
383 free(pe
->sectorbuffer
);
385 pe
->sectorbuffer
= NULL
;
386 pe
->private_sectorbuffer
= 0;
389 memset(l
->ptes
, 0, sizeof(l
->ptes
));
392 static void reset_pte(struct pte
*pe
)
396 if (pe
->private_sectorbuffer
) {
397 DBG(LABEL
, ul_debug(" --> freeing pte sector buffer %p",
399 free(pe
->sectorbuffer
);
401 memset(pe
, 0, sizeof(struct pte
));
404 static int delete_partition(struct fdisk_context
*cxt
, size_t partnum
)
406 struct fdisk_dos_label
*l
;
408 struct dos_partition
*p
;
409 struct dos_partition
*q
;
413 assert(fdisk_is_label(cxt
, DOS
));
415 pe
= self_pte(cxt
, partnum
);
419 DBG(LABEL
, ul_debug("DOS: delete partition %zu (max=%zu)", partnum
,
420 cxt
->label
->nparts_max
));
426 /* Note that for the fifth partition (partnum == 4) we don't actually
427 decrement partitions. */
429 DBG(LABEL
, ul_debug("--> delete primary"));
430 if (IS_EXTENDED(p
->sys_ind
) && partnum
== l
->ext_index
) {
432 DBG(LABEL
, ul_debug(" --> delete extended"));
433 for (i
= 4; i
< cxt
->label
->nparts_max
; i
++) {
434 DBG(LABEL
, ul_debug(" --> delete logical #%zu", i
));
435 reset_pte(&l
->ptes
[i
]);
438 cxt
->label
->nparts_max
= 4;
439 l
->ptes
[l
->ext_index
].ex_entry
= NULL
;
443 partition_set_changed(cxt
, partnum
, 1);
445 } else if (!q
->sys_ind
&& partnum
> 4) {
446 DBG(LABEL
, ul_debug("--> delete logical [last in the chain]"));
447 reset_pte(&l
->ptes
[partnum
]);
448 --cxt
->label
->nparts_max
;
450 /* clear link to deleted partition */
451 clear_partition(l
->ptes
[partnum
].ex_entry
);
452 partition_set_changed(cxt
, partnum
, 1);
454 DBG(LABEL
, ul_debug("--> delete logical [move down]"));
456 DBG(LABEL
, ul_debug(" --> delete %zu logical link", partnum
));
457 p
= l
->ptes
[partnum
- 1].ex_entry
;
459 dos_partition_set_start(p
, dos_partition_get_start(q
));
460 dos_partition_set_size(p
, dos_partition_get_size(q
));
461 partition_set_changed(cxt
, partnum
- 1, 1);
463 } else if (cxt
->label
->nparts_max
> 5) {
464 DBG(LABEL
, ul_debug(" --> delete first logical link"));
465 pe
= &l
->ptes
[5]; /* second logical */
467 if (pe
->pt_entry
) /* prevent SEGFAULT */
468 dos_partition_set_start(pe
->pt_entry
,
469 get_abs_partition_start(pe
) -
471 pe
->offset
= l
->ext_offset
;
472 partition_set_changed(cxt
, 5, 1);
475 if (cxt
->label
->nparts_max
> 5) {
476 DBG(LABEL
, ul_debug(" --> move ptes"));
477 cxt
->label
->nparts_max
--;
478 reset_pte(&l
->ptes
[partnum
]);
479 while (partnum
< cxt
->label
->nparts_max
) {
480 DBG(LABEL
, ul_debug(" --> moving pte %zu <-- %zu", partnum
, partnum
+ 1));
481 l
->ptes
[partnum
] = l
->ptes
[partnum
+ 1];
484 memset(&l
->ptes
[partnum
], 0, sizeof(struct pte
));
486 DBG(LABEL
, ul_debug(" --> the only logical: clear only"));
487 clear_partition(l
->ptes
[partnum
].pt_entry
);
488 cxt
->label
->nparts_max
--;
491 DBG(LABEL
, ul_debug(" --> clear last logical"));
492 reset_pte(&l
->ptes
[partnum
]);
493 partition_set_changed(cxt
, l
->ext_index
, 1);
498 fdisk_label_set_changed(cxt
->label
, 1);
502 static int dos_delete_partition(struct fdisk_context
*cxt
, size_t partnum
)
508 assert(fdisk_is_label(cxt
, DOS
));
510 pe
= self_pte(cxt
, partnum
);
511 if (!pe
|| !is_used_partition(pe
->pt_entry
))
514 return delete_partition(cxt
, partnum
);
517 static void read_extended(struct fdisk_context
*cxt
, size_t ext
)
520 struct pte
*pex
, *pe
;
521 struct dos_partition
*p
, *q
;
522 struct fdisk_dos_label
*l
= self_label(cxt
);
525 pex
= self_pte(cxt
, ext
);
527 DBG(LABEL
, ul_debug("DOS: uninitialized pointer to %zu pex", ext
));
530 pex
->ex_entry
= pex
->pt_entry
;
533 if (!dos_partition_get_start(p
)) {
534 fdisk_warnx(cxt
, _("Bad offset in primary extended partition."));
538 DBG(LABEL
, ul_debug("DOS: Reading extended %zu", ext
));
540 while (IS_EXTENDED (p
->sys_ind
)) {
541 if (cxt
->label
->nparts_max
>= MAXIMUM_PARTS
) {
542 /* This is not a Linux restriction, but
543 this program uses arrays of size MAXIMUM_PARTS.
544 Do not try to `improve' this test. */
545 struct pte
*pre
= self_pte(cxt
,
546 cxt
->label
->nparts_max
- 1);
548 _("Omitting partitions after #%zu. They will be deleted "
549 "if you save this partition table."),
550 cxt
->label
->nparts_max
);
553 clear_partition(pre
->ex_entry
);
554 partition_set_changed(cxt
,
555 cxt
->label
->nparts_max
- 1, 1);
560 pe
= self_pte(cxt
, cxt
->label
->nparts_max
);
564 if (read_pte(cxt
, cxt
->label
->nparts_max
, l
->ext_offset
+
565 dos_partition_get_start(p
)))
569 l
->ext_offset
= dos_partition_get_start(p
);
571 assert(pe
->sectorbuffer
);
572 q
= p
= mbr_get_partition(pe
->sectorbuffer
, 0);
574 for (i
= 0; i
< 4; i
++, p
++) {
575 if (!dos_partition_get_size(p
))
578 if (IS_EXTENDED (p
->sys_ind
)) {
581 "Extra link pointer in partition "
583 cxt
->label
->nparts_max
+ 1);
586 } else if (p
->sys_ind
) {
589 "Ignoring extra data in partition "
591 cxt
->label
->nparts_max
+ 1);
597 /* very strange code here... */
599 if (q
!= pe
->ex_entry
)
602 pe
->pt_entry
= q
+ 1;
605 if (q
!= pe
->pt_entry
)
608 pe
->ex_entry
= q
+ 1;
612 cxt
->label
->nparts_cur
= ++cxt
->label
->nparts_max
;
614 DBG(LABEL
, ul_debug("DOS: EBR[offset=%ju]: link: type=%x, start=%u, size=%u; "
615 " data: type=%x, start=%u, size=%u",
616 (uintmax_t) pe
->offset
,
617 pe
->ex_entry
->sys_ind
,
618 dos_partition_get_start(pe
->ex_entry
),
619 dos_partition_get_size(pe
->ex_entry
),
620 pe
->pt_entry
->sys_ind
,
621 dos_partition_get_start(pe
->pt_entry
),
622 dos_partition_get_size(pe
->pt_entry
)));
626 /* remove last empty EBR */
627 pe
= self_pte(cxt
, cxt
->label
->nparts_max
- 1);
629 is_cleared_partition(pe
->ex_entry
) &&
630 is_cleared_partition(pe
->pt_entry
)) {
631 DBG(LABEL
, ul_debug("DOS: EBR[offset=%ju]: empty, remove", (uintmax_t) pe
->offset
));
633 cxt
->label
->nparts_max
--;
634 cxt
->label
->nparts_cur
--;
637 /* remove empty links */
639 q
= self_partition(cxt
, 4);
640 for (i
= 4; i
< cxt
->label
->nparts_max
; i
++) {
641 p
= self_partition(cxt
, i
);
643 if (p
&& !dos_partition_get_size(p
) &&
644 (cxt
->label
->nparts_max
> 5 || (q
&& q
->sys_ind
))) {
645 fdisk_info(cxt
, _("omitting empty partition (%zu)"), i
+1);
646 delete_partition(cxt
, i
);
647 goto remove
; /* numbering changed */
651 DBG(LABEL
, ul_debug("DOS: nparts_max: %zu", cxt
->label
->nparts_max
));
654 static int dos_create_disklabel(struct fdisk_context
*cxt
)
658 struct fdisk_dos_label
*l
;
662 assert(fdisk_is_label(cxt
, DOS
));
664 DBG(LABEL
, ul_debug("DOS: creating new disklabel"));
668 const char *s
= fdisk_script_get_header(cxt
->script
, "label-id");
672 id
= strtol(s
, &end
, 16);
673 if (!errno
&& end
&& s
< end
) {
675 DBG(LABEL
, ul_debug("DOS: re-use ID from script (0x%08x)", id
));
677 DBG(LABEL
, ul_debug("DOS: failed to parse label=id '%s'", s
));
681 /* random disk signature */
683 DBG(LABEL
, ul_debug("DOS: generate new ID"));
684 random_get_bytes(&id
, sizeof(id
));
687 if (fdisk_has_protected_bootbits(cxt
))
688 rc
= fdisk_init_firstsector_buffer(cxt
, 0, MBR_PT_BOOTBITS_SIZE
);
690 rc
= fdisk_init_firstsector_buffer(cxt
, 0, 0);
697 /* Generate an MBR ID for this disk */
698 mbr_set_id(cxt
->firstsector
, id
);
699 l
->non_pt_changed
= 1;
700 fdisk_label_set_changed(cxt
->label
, 1);
702 /* Put MBR signature */
703 mbr_set_magic(cxt
->firstsector
);
705 fdisk_info(cxt
, _("Created a new DOS disklabel with disk "
706 "identifier 0x%08x."), id
);
710 static int dos_set_disklabel_id(struct fdisk_context
*cxt
)
712 char *end
= NULL
, *str
= NULL
;
713 unsigned int id
, old
;
714 struct fdisk_dos_label
*l
;
719 assert(fdisk_is_label(cxt
, DOS
));
721 DBG(LABEL
, ul_debug("DOS: setting Id"));
724 old
= mbr_get_id(cxt
->firstsector
);
725 rc
= fdisk_ask_string(cxt
,
726 _("Enter the new disk identifier"), &str
);
731 id
= strtoul(str
, &end
, 0);
732 if (errno
|| str
== end
|| (end
&& *end
)) {
733 fdisk_warnx(cxt
, _("Incorrect value."));
738 mbr_set_id(cxt
->firstsector
, id
);
739 l
->non_pt_changed
= 1;
740 fdisk_label_set_changed(cxt
->label
, 1);
742 fdisk_info(cxt
, _("Disk identifier changed from 0x%08x to 0x%08x."),
747 static void get_partition_table_geometry(struct fdisk_context
*cxt
,
748 unsigned int *ph
, unsigned int *ps
)
750 unsigned char *bufp
= cxt
->firstsector
;
751 struct dos_partition
*p
;
757 for (i
= 0; i
< 4; i
++) {
758 p
= mbr_get_partition(bufp
, i
);
759 if (p
->sys_ind
!= 0) {
766 } else if (hh
!= h
|| ss
!= s
)
771 if (!first
&& !bad
) {
776 DBG(LABEL
, ul_debug("DOS PT geometry: heads=%u, sectors=%u", *ph
, *ps
));
779 static int dos_reset_alignment(struct fdisk_context
*cxt
)
783 assert(fdisk_is_label(cxt
, DOS
));
785 /* overwrite necessary stuff by DOS deprecated stuff */
786 if (is_dos_compatible(cxt
)) {
787 DBG(LABEL
, ul_debug("DOS: resetting alignment for DOS-compatible PT"));
788 if (cxt
->geom
.sectors
)
789 cxt
->first_lba
= cxt
->geom
.sectors
; /* usually 63 */
791 cxt
->grain
= cxt
->sector_size
; /* usually 512 */
797 /* TODO: move to include/pt-dos.h and share with libblkid */
798 #define AIX_MAGIC_STRING "\xC9\xC2\xD4\xC1"
799 #define AIX_MAGIC_STRLEN (sizeof(AIX_MAGIC_STRING) - 1)
801 static int dos_probe_label(struct fdisk_context
*cxt
)
804 unsigned int h
= 0, s
= 0;
808 assert(fdisk_is_label(cxt
, DOS
));
810 /* ignore disks with AIX magic number */
811 if (memcmp(cxt
->firstsector
, AIX_MAGIC_STRING
, AIX_MAGIC_STRLEN
) == 0)
814 if (!mbr_is_valid_magic(cxt
->firstsector
))
819 get_partition_table_geometry(cxt
, &h
, &s
);
822 cxt
->geom
.sectors
= s
;
824 if (fdisk_has_user_device_geometry(cxt
))
825 fdisk_apply_user_device_properties(cxt
);
828 for (i
= 0; i
< 4; i
++) {
829 struct pte
*pe
= self_pte(cxt
, i
);
832 if (is_used_partition(pe
->pt_entry
))
833 cxt
->label
->nparts_cur
++;
835 if (IS_EXTENDED (pe
->pt_entry
->sys_ind
)) {
836 if (cxt
->label
->nparts_max
!= 4)
838 "Ignoring extra extended partition %zu"),
841 read_extended(cxt
, i
);
845 for (i
= 3; i
< cxt
->label
->nparts_max
; i
++) {
846 struct pte
*pe
= self_pte(cxt
, i
);
847 struct fdisk_dos_label
*l
= self_label(cxt
);
850 if (!mbr_is_valid_magic(pe
->sectorbuffer
)) {
852 "Invalid flag 0x%02x%02x of EBR (for partition %zu) will "
853 "be corrected by w(rite)."),
854 pe
->sectorbuffer
[510],
855 pe
->sectorbuffer
[511],
857 partition_set_changed(cxt
, i
, 1);
859 /* mark also extended as changed to update the first EBR
860 * in situation that there is no logical partitions at all */
861 partition_set_changed(cxt
, l
->ext_index
, 1);
868 static void set_partition(struct fdisk_context
*cxt
,
869 int i
, int doext
, fdisk_sector_t start
,
870 fdisk_sector_t stop
, int sysid
, int boot
)
872 struct pte
*pe
= self_pte(cxt
, i
);
873 struct dos_partition
*p
;
874 fdisk_sector_t offset
;
876 assert(!FDISK_IS_UNDEF(start
));
877 assert(!FDISK_IS_UNDEF(stop
));
881 struct fdisk_dos_label
*l
= self_label(cxt
);
883 offset
= l
->ext_offset
;
889 DBG(LABEL
, ul_debug("DOS: setting partition %d%s, offset=%zu, start=%zu, size=%zu, sysid=%02x",
890 i
, doext
? " [extended]" : "",
892 (size_t) (start
- offset
),
893 (size_t) (stop
- start
+ 1),
896 p
->boot_ind
= boot
? ACTIVE_FLAG
: 0;
898 dos_partition_set_start(p
, start
- offset
);
899 dos_partition_set_size(p
, stop
- start
+ 1);
901 if (is_dos_compatible(cxt
) && (start
/(cxt
->geom
.sectors
*cxt
->geom
.heads
) > 1023))
902 start
= cxt
->geom
.heads
*cxt
->geom
.sectors
*1024 - 1;
903 set_hsc(p
->bh
, p
->bs
, p
->bc
, start
);
904 if (is_dos_compatible(cxt
) && (stop
/(cxt
->geom
.sectors
*cxt
->geom
.heads
) > 1023))
905 stop
= cxt
->geom
.heads
*cxt
->geom
.sectors
*1024 - 1;
906 set_hsc(p
->eh
, p
->es
, p
->ec
, stop
);
907 partition_set_changed(cxt
, i
, 1);
910 static fdisk_sector_t
get_unused_start(struct fdisk_context
*cxt
,
911 int part_n
, fdisk_sector_t start
,
912 fdisk_sector_t first
[], fdisk_sector_t last
[])
916 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
917 fdisk_sector_t lastplusoff
;
918 struct pte
*pe
= self_pte(cxt
, i
);
921 if (start
== pe
->offset
)
922 start
+= cxt
->first_lba
;
923 lastplusoff
= last
[i
] + ((part_n
< 4) ? 0 : cxt
->first_lba
);
924 if (start
>= first
[i
] && start
<= lastplusoff
)
925 start
= lastplusoff
+ 1;
931 static void fill_bounds(struct fdisk_context
*cxt
,
932 fdisk_sector_t
*first
, fdisk_sector_t
*last
)
935 struct pte
*pe
= self_pte(cxt
, 0);
936 struct dos_partition
*p
;
939 for (i
= 0; i
< cxt
->label
->nparts_max
; pe
++,i
++) {
941 if (is_cleared_partition(p
) || IS_EXTENDED (p
->sys_ind
)) {
942 first
[i
] = 0xffffffff;
945 first
[i
] = get_abs_partition_start(pe
);
946 last
[i
] = get_abs_partition_end(pe
);
951 static int get_start_from_user( struct fdisk_context
*cxt
,
952 fdisk_sector_t
*start
,
955 fdisk_sector_t limit
,
956 struct fdisk_partition
*pa
)
960 /* try to use template from 'pa' */
961 if (pa
&& pa
->start_follow_default
)
964 else if (pa
&& fdisk_partition_has_start(pa
)) {
965 DBG(LABEL
, ul_debug("DOS: start: wanted=%ju, low=%ju, limit=%ju",
966 (uintmax_t) pa
->start
, (uintmax_t) low
, (uintmax_t) limit
));
968 if (*start
< low
|| *start
> limit
) {
969 fdisk_warnx(cxt
, _("Start sector %ju out of range."),
974 /* ask user by dialog */
975 struct fdisk_ask
*ask
= fdisk_new_ask();
980 fdisk_ask_set_query(ask
,
981 fdisk_use_cylinders(cxt
) ?
982 _("First cylinder") : _("First sector"));
983 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_NUMBER
);
984 fdisk_ask_number_set_low(ask
, fdisk_cround(cxt
, low
));
985 fdisk_ask_number_set_default(ask
, fdisk_cround(cxt
, dflt
));
986 fdisk_ask_number_set_high(ask
, fdisk_cround(cxt
, limit
));
988 rc
= fdisk_do_ask(cxt
, ask
);
989 *start
= fdisk_ask_number_get_result(ask
);
990 fdisk_unref_ask(ask
);
993 if (fdisk_use_cylinders(cxt
)) {
994 *start
= (*start
- 1)
995 * fdisk_get_units_per_sector(cxt
);
1001 DBG(LABEL
, ul_debug("DOS: start is %ju", (uintmax_t) *start
));
1005 static fdisk_sector_t
get_possible_last(struct fdisk_context
*cxt
, size_t n
)
1007 fdisk_sector_t limit
;
1010 /* logical partitions */
1011 struct fdisk_dos_label
*l
= self_label(cxt
);
1012 struct pte
*ext_pe
= l
->ext_offset
? self_pte(cxt
, l
->ext_index
) : NULL
;
1016 limit
= get_abs_partition_end(ext_pe
);
1018 /* primary partitions */
1019 if (fdisk_use_cylinders(cxt
) || !cxt
->total_sectors
)
1020 limit
= cxt
->geom
.heads
* cxt
->geom
.sectors
* cxt
->geom
.cylinders
- 1;
1022 limit
= cxt
->total_sectors
- 1;
1024 if (limit
> UINT_MAX
)
1028 DBG(LABEL
, ul_debug("DOS: last possible sector for #%zu is %ju",
1029 n
, (uintmax_t) limit
));
1033 /* returns last free sector for area addressed by @start, the first[] and
1034 * last[] are fill_bounds() results */
1035 static fdisk_sector_t
get_unused_last(struct fdisk_context
*cxt
, size_t n
,
1036 fdisk_sector_t start
,
1037 fdisk_sector_t first
[])
1040 fdisk_sector_t limit
= get_possible_last(cxt
, n
);
1042 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
1043 struct pte
*pe
= self_pte(cxt
, i
);
1046 if (start
< pe
->offset
&& limit
>= pe
->offset
)
1047 limit
= pe
->offset
- 1;
1048 if (start
< first
[i
] && limit
>= first
[i
])
1049 limit
= first
[i
] - 1;
1052 DBG(LABEL
, ul_debug("DOS: unused sector for #%zu is %ju",
1053 n
, (uintmax_t) limit
));
1057 static int add_partition(struct fdisk_context
*cxt
, size_t n
,
1058 struct fdisk_partition
*pa
)
1060 int sys
, read
= 0, rc
, isrel
= 0;
1062 struct fdisk_dos_label
*l
= self_label(cxt
);
1063 struct dos_partition
*p
= self_partition(cxt
, n
);
1064 struct pte
*ext_pe
= l
->ext_offset
? self_pte(cxt
, l
->ext_index
) : NULL
;
1065 struct fdisk_ask
*ask
= NULL
;
1067 fdisk_sector_t start
, stop
= 0, limit
, temp
,
1068 first
[cxt
->label
->nparts_max
],
1069 last
[cxt
->label
->nparts_max
];
1071 DBG(LABEL
, ul_debug("DOS: adding partition %zu", n
));
1073 sys
= pa
&& pa
->type
? pa
->type
->code
: MBR_LINUX_DATA_PARTITION
;
1075 if (p
&& is_used_partition(p
)) {
1076 fdisk_warnx(cxt
, _("Partition %zu is already defined. "
1077 "Delete it before re-adding it."),
1081 fill_bounds(cxt
, first
, last
);
1082 limit
= get_possible_last(cxt
, n
);
1085 if (cxt
->parent
&& fdisk_is_label(cxt
->parent
, GPT
))
1086 start
= 1; /* Bad boy modifies hybrid MBR */
1088 if (cxt
->script
&& pa
&& fdisk_partition_has_start(pa
)
1089 && pa
->start
< cxt
->first_lba
1091 fdisk_set_first_lba(cxt
, 1);
1093 start
= cxt
->first_lba
;
1096 if (l
->ext_offset
) {
1098 first
[l
->ext_index
] = l
->ext_offset
;
1099 last
[l
->ext_index
] = get_abs_partition_end(ext_pe
);
1104 if (cxt
->script
&& pa
&& fdisk_partition_has_start(pa
)
1105 && pa
->start
>= l
->ext_offset
1106 && pa
->start
< l
->ext_offset
+ cxt
->first_lba
)
1107 fdisk_set_first_lba(cxt
, 1);
1109 start
= l
->ext_offset
+ cxt
->first_lba
;
1112 if (fdisk_use_cylinders(cxt
))
1113 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
1114 first
[i
] = (fdisk_cround(cxt
, first
[i
]) - 1)
1115 * fdisk_get_units_per_sector(cxt
);
1119 * Ask for first sector
1122 fdisk_sector_t dflt
, aligned
;
1125 dflt
= start
= get_unused_start(cxt
, n
, start
, first
, last
);
1127 if (n
>= 4 && pa
&& fdisk_partition_has_start(pa
) && cxt
->script
1128 && cxt
->first_lba
> 1
1129 && temp
== start
- cxt
->first_lba
) {
1130 fdisk_set_first_lba(cxt
, 1);
1134 /* the default sector should be aligned and unused */
1136 aligned
= fdisk_align_lba_in_range(cxt
, dflt
, dflt
, limit
);
1137 dflt
= get_unused_start(cxt
, n
, aligned
, first
, last
);
1138 } while (dflt
!= aligned
&& dflt
> aligned
&& dflt
< limit
);
1144 if (start
>= temp
+ fdisk_get_units_per_sector(cxt
)
1146 fdisk_info(cxt
, _("Sector %llu is already allocated."),
1150 if (pa
&& (fdisk_partition_has_start(pa
) ||
1151 pa
->start_follow_default
))
1155 if (!read
&& start
== temp
) {
1156 rc
= get_start_from_user(cxt
, &start
, temp
, dflt
, limit
, pa
);
1161 } while (start
!= temp
|| !read
);
1164 /* The first EBR is stored at begin of the extended partition */
1165 struct pte
*pe
= self_pte(cxt
, n
);
1168 pe
->offset
= l
->ext_offset
;
1170 /* The second (and another) EBR */
1171 struct pte
*pe
= self_pte(cxt
, n
);
1174 pe
->offset
= start
- cxt
->first_lba
;
1175 if (pe
->offset
== l
->ext_offset
) { /* must be corrected */
1177 if (cxt
->first_lba
== 1)
1182 limit
= get_unused_last(cxt
, n
, start
, first
);
1184 if (start
> limit
) {
1185 fdisk_warnx(cxt
, _("No free sectors available."));
1190 * Ask for last sector
1192 if (fdisk_cround(cxt
, start
) == fdisk_cround(cxt
, limit
))
1194 else if (pa
&& pa
->end_follow_default
)
1196 else if (pa
&& fdisk_partition_has_size(pa
)) {
1197 stop
= start
+ pa
->size
;
1198 isrel
= pa
->size_explicit
? 0 : 1;
1199 if ((!isrel
|| !alignment_required(cxt
)) && stop
> start
)
1202 /* ask user by dialog */
1205 ask
= fdisk_new_ask();
1207 fdisk_reset_ask(ask
);
1210 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_OFFSET
);
1212 if (fdisk_use_cylinders(cxt
)) {
1213 fdisk_ask_set_query(ask
, _("Last cylinder, +cylinders or +size{K,M,G,T,P}"));
1214 fdisk_ask_number_set_unit(ask
,
1216 fdisk_get_units_per_sector(cxt
));
1218 fdisk_ask_set_query(ask
, _("Last sector, +sectors or +size{K,M,G,T,P}"));
1219 fdisk_ask_number_set_unit(ask
,cxt
->sector_size
);
1222 fdisk_ask_number_set_low(ask
, fdisk_cround(cxt
, start
));
1223 fdisk_ask_number_set_default(ask
, fdisk_cround(cxt
, limit
));
1224 fdisk_ask_number_set_high(ask
, fdisk_cround(cxt
, limit
));
1225 fdisk_ask_number_set_base(ask
, fdisk_cround(cxt
, start
)); /* base for relative input */
1227 rc
= fdisk_do_ask(cxt
, ask
);
1231 stop
= fdisk_ask_number_get_result(ask
);
1232 isrel
= fdisk_ask_number_is_relative(ask
);
1233 if (fdisk_use_cylinders(cxt
)) {
1234 stop
= stop
* fdisk_get_units_per_sector(cxt
) - 1;
1239 if (stop
>= start
&& stop
<= limit
)
1241 fdisk_warnx(cxt
, _("Value out of range."));
1245 DBG(LABEL
, ul_debug("DOS: raw stop: %ju [limit %ju]", (uintmax_t) stop
, (uintmax_t) limit
));
1250 if (isrel
&& stop
- start
< (cxt
->grain
/ fdisk_get_sector_size(cxt
))) {
1251 /* Don't try to be smart on very small partitions and don't align so small sizes */
1255 DBG(LABEL
, ul_debug("DOS: don't align end of tiny partition [start=%ju, stop=%ju, grain=%lu]",
1256 (uintmax_t)start
, (uintmax_t)stop
, cxt
->grain
));
1259 if (stop
< limit
&& isrel
&& alignment_required(cxt
)) {
1260 /* the last sector has not been exactly requested (but
1261 * defined by +size{K,M,G} convention), so be smart and
1262 * align the end of the partition. The next partition
1263 * will start at phy.block boundary.
1265 stop
= fdisk_align_lba_in_range(cxt
, stop
, start
, limit
);
1270 DBG(LABEL
, ul_debug("DOS: aligned stop: %ju", (uintmax_t) stop
));
1273 set_partition(cxt
, n
, 0, start
, stop
, sys
, fdisk_partition_is_bootable(pa
));
1275 struct pte
*pe
= self_pte(cxt
, n
);
1278 set_partition(cxt
, n
- 1, 1, pe
->offset
, stop
,
1279 MBR_DOS_EXTENDED_PARTITION
, 0);
1284 struct fdisk_parttype
*t
=
1285 fdisk_label_get_parttype_from_code(cxt
->label
, sys
);
1286 fdisk_info_new_partition(cxt
, n
+ 1, start
, stop
, t
);
1287 fdisk_unref_parttype(t
);
1291 if (IS_EXTENDED(sys
)) {
1292 struct pte
*pen
= self_pte(cxt
, n
);
1296 l
->ext_offset
= start
;
1300 fdisk_label_set_changed(cxt
->label
, 1);
1303 fdisk_unref_ask(ask
);
1307 static int add_logical(struct fdisk_context
*cxt
,
1308 struct fdisk_partition
*pa
,
1317 assert(self_label(cxt
)->ext_offset
);
1319 DBG(LABEL
, ul_debug("DOS: nparts max: %zu", cxt
->label
->nparts_max
));
1320 pe
= self_pte(cxt
, cxt
->label
->nparts_max
);
1323 if (!pe
->sectorbuffer
) {
1324 pe
->sectorbuffer
= calloc(1, cxt
->sector_size
);
1325 if (!pe
->sectorbuffer
)
1327 DBG(LABEL
, ul_debug("DOS: logical: %zu: new EBR sector buffer %p",
1328 cxt
->label
->nparts_max
, pe
->sectorbuffer
));
1329 pe
->private_sectorbuffer
= 1;
1331 pe
->pt_entry
= mbr_get_partition(pe
->sectorbuffer
, 0);
1332 pe
->ex_entry
= pe
->pt_entry
+ 1;
1334 partition_set_changed(cxt
, cxt
->label
->nparts_max
, 1);
1336 cxt
->label
->nparts_max
++;
1338 /* this message makes sense only when we use extended/primary/logical
1339 * dialog. The dialog is disable for scripts, see dos_add_partition() */
1341 fdisk_info(cxt
, _("Adding logical partition %zu"),
1342 cxt
->label
->nparts_max
);
1343 *partno
= cxt
->label
->nparts_max
- 1;
1344 rc
= add_partition(cxt
, *partno
, pa
);
1347 /* reset on error */
1348 cxt
->label
->nparts_max
--;
1349 pe
->pt_entry
= NULL
;
1350 pe
->ex_entry
= NULL
;
1358 static void check(struct fdisk_context
*cxt
, size_t n
,
1359 unsigned int h
, unsigned int s
, unsigned int c
,
1362 unsigned int total
, real_s
, real_c
;
1364 if (!is_dos_compatible(cxt
))
1367 real_s
= sector(s
) - 1;
1368 real_c
= cylinder(s
, c
);
1369 total
= (real_c
* cxt
->geom
.heads
+ h
) * cxt
->geom
.sectors
+ real_s
;
1372 fdisk_warnx(cxt
, _("Partition %zu: contains sector 0"), n
);
1373 if (h
>= cxt
->geom
.heads
)
1374 fdisk_warnx(cxt
, _("Partition %zu: head %d greater than "
1375 "maximum %d"), n
, h
+ 1, cxt
->geom
.heads
);
1376 if (real_s
>= cxt
->geom
.sectors
)
1377 fdisk_warnx(cxt
, _("Partition %zu: sector %d greater than "
1378 "maximum %llu"), n
, s
, cxt
->geom
.sectors
);
1379 if (real_c
>= cxt
->geom
.cylinders
)
1380 fdisk_warnx(cxt
, _("Partition %zu: cylinder %d greater than "
1383 cxt
->geom
.cylinders
);
1385 if (cxt
->geom
.cylinders
<= 1024 && start
!= total
)
1386 fdisk_warnx(cxt
, _("Partition %zu: previous sectors %u "
1387 "disagrees with total %u"), n
, start
, total
);
1390 /* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
1391 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1392 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1393 * Lubkin Oct. 1991). */
1396 long2chs(struct fdisk_context
*cxt
, unsigned long ls
,
1397 unsigned int *c
, unsigned int *h
, unsigned int *s
) {
1398 int spc
= cxt
->geom
.heads
* cxt
->geom
.sectors
;
1402 *h
= ls
/ cxt
->geom
.sectors
;
1403 *s
= ls
% cxt
->geom
.sectors
+ 1; /* sectors count from 1 */
1406 static void check_consistency(struct fdisk_context
*cxt
, struct dos_partition
*p
,
1409 unsigned int pbc
, pbh
, pbs
; /* physical beginning c, h, s */
1410 unsigned int pec
, peh
, pes
; /* physical ending c, h, s */
1411 unsigned int lbc
, lbh
, lbs
; /* logical beginning c, h, s */
1412 unsigned int lec
, leh
, les
; /* logical ending c, h, s */
1414 if (!is_dos_compatible(cxt
))
1417 if (!cxt
->geom
.heads
|| !cxt
->geom
.sectors
|| (partition
>= 4))
1418 return; /* do not check extended partitions */
1420 /* physical beginning c, h, s */
1421 pbc
= (p
->bc
& 0xff) | ((p
->bs
<< 2) & 0x300);
1425 /* physical ending c, h, s */
1426 pec
= (p
->ec
& 0xff) | ((p
->es
<< 2) & 0x300);
1430 /* compute logical beginning (c, h, s) */
1431 long2chs(cxt
, dos_partition_get_start(p
), &lbc
, &lbh
, &lbs
);
1433 /* compute logical ending (c, h, s) */
1434 long2chs(cxt
, dos_partition_get_start(p
) + dos_partition_get_size(p
) - 1, &lec
, &leh
, &les
);
1436 /* Same physical / logical beginning? */
1437 if (cxt
->geom
.cylinders
<= 1024
1438 && (pbc
!= lbc
|| pbh
!= lbh
|| pbs
!= lbs
)) {
1439 fdisk_warnx(cxt
, _("Partition %zu: different physical/logical "
1440 "beginnings (non-Linux?): "
1441 "phys=(%d, %d, %d), logical=(%d, %d, %d)"),
1447 /* Same physical / logical ending? */
1448 if (cxt
->geom
.cylinders
<= 1024
1449 && (pec
!= lec
|| peh
!= leh
|| pes
!= les
)) {
1450 fdisk_warnx(cxt
, _("Partition %zu: different physical/logical "
1451 "endings: phys=(%d, %d, %d), logical=(%d, %d, %d)"),
1457 /* Ending on cylinder boundary? */
1458 if (peh
!= (cxt
->geom
.heads
- 1) || pes
!= cxt
->geom
.sectors
) {
1459 fdisk_warnx(cxt
, _("Partition %zu: does not end on "
1460 "cylinder boundary."),
1465 static int dos_verify_disklabel(struct fdisk_context
*cxt
)
1468 fdisk_sector_t total
= 1, n_sectors
= cxt
->total_sectors
;
1469 fdisk_sector_t first
[cxt
->label
->nparts_max
],
1470 last
[cxt
->label
->nparts_max
];
1471 struct dos_partition
*p
;
1472 struct fdisk_dos_label
*l
= self_label(cxt
);
1474 assert(fdisk_is_label(cxt
, DOS
));
1476 fill_bounds(cxt
, first
, last
);
1477 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
1478 struct pte
*pe
= self_pte(cxt
, i
);
1480 p
= self_partition(cxt
, i
);
1481 if (p
&& is_used_partition(p
) && !IS_EXTENDED(p
->sys_ind
)) {
1482 check_consistency(cxt
, p
, i
);
1484 if (get_abs_partition_start(pe
) < first
[i
])
1486 "Partition %zu: bad start-of-data."),
1489 check(cxt
, i
+ 1, p
->eh
, p
->es
, p
->ec
, last
[i
]);
1490 total
+= last
[i
] + 1 - first
[i
];
1493 total
+= get_abs_partition_start(pe
) - 1;
1495 for (j
= 0; j
< i
; j
++) {
1496 if ((first
[i
] >= first
[j
] && first
[i
] <= last
[j
])
1497 || ((last
[i
] <= last
[j
] && last
[i
] >= first
[j
]))) {
1499 fdisk_warnx(cxt
, _("Partition %zu: "
1500 "overlaps partition %zu."),
1503 total
+= first
[i
] >= first
[j
] ?
1504 first
[i
] : first
[j
];
1505 total
-= last
[i
] <= last
[j
] ?
1512 if (l
->ext_offset
) {
1513 fdisk_sector_t e_last
;
1514 struct pte
*ext_pe
= self_pte(cxt
, l
->ext_index
);
1517 e_last
= get_abs_partition_end(ext_pe
);
1519 for (i
= 4; i
< cxt
->label
->nparts_max
; i
++) {
1521 p
= self_partition(cxt
, i
);
1525 if (i
!= 4 || i
+ 1 < cxt
->label
->nparts_max
)
1527 _("Partition %zu: empty."),
1529 } else if (first
[i
] < l
->ext_offset
1530 || last
[i
] > e_last
) {
1532 fdisk_warnx(cxt
, _("Logical partition %zu: "
1533 "not entirely in partition %zu."),
1534 i
+ 1, l
->ext_index
+ 1);
1539 if (total
> n_sectors
)
1540 fdisk_warnx(cxt
, _("Total allocated sectors %llu greater "
1541 "than the maximum %llu."), total
, n_sectors
);
1542 else if (total
< n_sectors
)
1543 fdisk_warnx(cxt
, _("Remaining %lld unallocated %ld-byte "
1544 "sectors."), n_sectors
- total
, cxt
->sector_size
);
1550 * Ask the user for new partition type information (logical, extended).
1551 * This function calls the actual partition adding logic - add_partition.
1555 static int dos_add_partition(struct fdisk_context
*cxt
,
1556 struct fdisk_partition
*pa
,
1559 size_t i
, free_primary
= 0, free_sectors
= 0;
1560 fdisk_sector_t last
= 0, grain
;
1562 struct fdisk_dos_label
*l
;
1564 size_t res
= 0; /* partno */
1568 assert(fdisk_is_label(cxt
, DOS
));
1570 DBG(LABEL
, ul_debug("DOS: new partition wanted"));
1572 l
= self_label(cxt
);
1573 ext_pe
= l
->ext_offset
? self_pte(cxt
, l
->ext_index
) : NULL
;
1576 * partition template (@pa) based partitioning
1579 /* A) template specifies start within extended partition; add logical */
1580 if (pa
&& fdisk_partition_has_start(pa
) && ext_pe
1581 && pa
->start
>= l
->ext_offset
1582 && pa
->start
<= get_abs_partition_end(ext_pe
)) {
1583 DBG(LABEL
, ul_debug("DOS: pa template %p: add logical (by offset)", pa
));
1585 if (fdisk_partition_has_partno(pa
) && fdisk_partition_get_partno(pa
) < 4) {
1586 DBG(LABEL
, ul_debug("DOS: pa template specifies partno<4 for logical partition"));
1589 rc
= add_logical(cxt
, pa
, &res
);
1592 /* B) template specifies start out of extended partition; add primary */
1593 } else if (pa
&& fdisk_partition_has_start(pa
) && ext_pe
) {
1594 DBG(LABEL
, ul_debug("DOS: pa template %p: add primary (by offset)", pa
));
1596 if (fdisk_partition_has_partno(pa
) && fdisk_partition_get_partno(pa
) >= 4) {
1597 DBG(LABEL
, ul_debug("DOS: pa template specifies partno>=4 for primary partition"));
1600 if (ext_pe
&& pa
->type
&& IS_EXTENDED(pa
->type
->code
)) {
1601 fdisk_warnx(cxt
, _("Extended partition already exists."));
1604 rc
= get_partition_unused_primary(cxt
, pa
, &res
);
1606 rc
= add_partition(cxt
, res
, pa
);
1609 /* C) template specifies start (or default), partno < 4; add primary */
1610 } else if (pa
&& (fdisk_partition_start_is_default(pa
) || fdisk_partition_has_start(pa
))
1611 && fdisk_partition_has_partno(pa
)
1612 && pa
->partno
< 4) {
1613 DBG(LABEL
, ul_debug("DOS: pa template %p: add primary (by partno)", pa
));
1615 if (ext_pe
&& pa
->type
&& IS_EXTENDED(pa
->type
->code
)) {
1616 fdisk_warnx(cxt
, _("Extended partition already exists."));
1619 rc
= get_partition_unused_primary(cxt
, pa
, &res
);
1621 rc
= add_partition(cxt
, res
, pa
);
1624 /* D) template specifies start (or default), partno >= 4; add logical */
1625 } else if (pa
&& (fdisk_partition_start_is_default(pa
) || fdisk_partition_has_start(pa
))
1626 && fdisk_partition_has_partno(pa
)
1627 && pa
->partno
>= 4) {
1628 DBG(LABEL
, ul_debug("DOS: pa template %p: add logical (by partno)", pa
));
1631 fdisk_warnx(cxt
, _("Extended partition does not exists. Failed to add logical partition."));
1633 } else if (fdisk_partition_has_start(pa
)
1634 && pa
->start
< l
->ext_offset
1635 && pa
->start
> get_abs_partition_end(ext_pe
)) {
1636 DBG(LABEL
, ul_debug("DOS: pa template specifies partno>=4, but start out of extended"));
1640 rc
= add_logical(cxt
, pa
, &res
);
1644 DBG(LABEL
, ul_debug("DOS: dialog driven partitioning"));
1645 /* Note @pa may be still used for things like partition type, etc */
1647 /* check if there is space for primary partition */
1648 grain
= cxt
->grain
> cxt
->sector_size
? cxt
->grain
/ cxt
->sector_size
: 1;
1649 last
= cxt
->first_lba
;
1651 for (i
= 0; i
< 4; i
++) {
1652 struct dos_partition
*p
= self_partition(cxt
, i
);
1655 if (is_used_partition(p
)) {
1656 fdisk_sector_t start
= dos_partition_get_start(p
);
1657 if (last
+ grain
<= start
)
1659 last
= start
+ dos_partition_get_size(p
);
1663 if (last
+ grain
< cxt
->total_sectors
- 1)
1666 if (!free_primary
&& cxt
->label
->nparts_max
>= MAXIMUM_PARTS
) {
1667 fdisk_info(cxt
, _("The maximum number of partitions has "
1673 if (!free_primary
|| !free_sectors
) {
1674 DBG(LABEL
, ul_debug("DOS: primary impossible, add logical"));
1675 if (l
->ext_offset
) {
1676 if (!pa
|| fdisk_partition_has_start(pa
)) {
1677 /* See above case A); here we have start, but
1678 * out of extended partition */
1681 msg
= _("All primary partitions are in use.");
1683 msg
= _("All space for primary partitions is in use.");
1685 if (pa
&& fdisk_partition_has_start(pa
)) {
1686 fdisk_warnx(cxt
, msg
);
1689 fdisk_info(cxt
, msg
);
1691 rc
= add_logical(cxt
, pa
, &res
);
1694 fdisk_info(cxt
, _("All space for primary partitions is in use."));
1696 /* TRANSLATORS: Try to keep this within 80 characters. */
1697 fdisk_info(cxt
, _("To create more partitions, first replace "
1698 "a primary with an extended partition."));
1701 } else if (cxt
->label
->nparts_max
>= MAXIMUM_PARTS
) {
1702 fdisk_info(cxt
, _("All logical partitions are in use. "
1703 "Adding a primary partition."));
1704 rc
= get_partition_unused_primary(cxt
, pa
, &res
);
1706 rc
= add_partition(cxt
, res
, pa
);
1709 struct fdisk_ask
*ask
;
1712 /* the default layout for scripts is to create primary partitions */
1713 if (cxt
->script
|| !fdisk_has_dialogs(cxt
)) {
1714 rc
= get_partition_unused_primary(cxt
, pa
, &res
);
1716 rc
= add_partition(cxt
, res
, pa
);
1720 ask
= fdisk_new_ask();
1723 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_MENU
);
1724 fdisk_ask_set_query(ask
, _("Partition type"));
1725 fdisk_ask_menu_set_default(ask
, free_primary
== 1
1726 && !l
->ext_offset
? 'e' : 'p');
1727 snprintf(hint
, sizeof(hint
),
1728 _("%zu primary, %d extended, %zu free"),
1729 4 - (l
->ext_offset
? 1 : 0) - free_primary
,
1730 l
->ext_offset
? 1 : 0,
1733 fdisk_ask_menu_add_item(ask
, 'p', _("primary"), hint
);
1735 fdisk_ask_menu_add_item(ask
, 'e', _("extended"), _("container for logical partitions"));
1737 fdisk_ask_menu_add_item(ask
, 'l', _("logical"), _("numbered from 5"));
1739 rc
= fdisk_do_ask(cxt
, ask
);
1741 fdisk_ask_menu_get_result(ask
, &c
);
1742 fdisk_unref_ask(ask
);
1747 rc
= get_partition_unused_primary(cxt
, pa
, &res
);
1749 rc
= add_partition(cxt
, res
, pa
);
1751 } else if (c
== 'l' && l
->ext_offset
) {
1752 rc
= add_logical(cxt
, pa
, &res
);
1754 } else if (c
== 'e' && !l
->ext_offset
) {
1755 rc
= get_partition_unused_primary(cxt
, pa
, &res
);
1757 struct fdisk_partition
*xpa
= NULL
;
1758 struct fdisk_parttype
*t
;
1760 t
= fdisk_label_get_parttype_from_code(cxt
->label
,
1761 MBR_DOS_EXTENDED_PARTITION
);
1763 pa
= xpa
= fdisk_new_partition();
1767 fdisk_partition_set_type(pa
, t
);
1768 rc
= add_partition(cxt
, res
, pa
);
1770 fdisk_unref_partition(xpa
);
1776 fdisk_warnx(cxt
, _("Invalid partition type `%c'."), c
);
1780 cxt
->label
->nparts_cur
++;
1787 static int write_sector(struct fdisk_context
*cxt
, fdisk_sector_t secno
,
1792 rc
= seek_sector(cxt
, secno
);
1794 fdisk_warn(cxt
, _("Cannot write sector %jd: seek failed"),
1799 DBG(LABEL
, ul_debug("DOS: writing to sector %ju", (uintmax_t) secno
));
1801 if (write(cxt
->dev_fd
, buf
, cxt
->sector_size
) != (ssize_t
) cxt
->sector_size
)
1806 static int dos_write_disklabel(struct fdisk_context
*cxt
)
1808 struct fdisk_dos_label
*l
= self_label(cxt
);
1810 int rc
= 0, mbr_changed
= 0;
1814 assert(fdisk_is_label(cxt
, DOS
));
1816 DBG(LABEL
, ul_debug("DOS: write PT requested [label-changed: %d, non-pt-changed: %d]",
1817 cxt
->label
->changed
, l
->non_pt_changed
));
1819 mbr_changed
= l
->non_pt_changed
;
1821 /* MBR (primary partitions) */
1823 for (i
= 0; i
< 4; i
++) {
1824 struct pte
*pe
= self_pte(cxt
, i
);
1832 DBG(LABEL
, ul_debug("DOS: MBR changed, writing"));
1833 mbr_set_magic(cxt
->firstsector
);
1834 rc
= write_sector(cxt
, 0, cxt
->firstsector
);
1839 if (cxt
->label
->nparts_max
<= 4 && l
->ext_offset
) {
1840 /* we have empty extended partition, check if the partition has
1841 * been modified and then cleanup possible remaining EBR */
1842 struct pte
*pe
= self_pte(cxt
, l
->ext_index
);
1843 unsigned char empty
[512] = { 0 };
1844 fdisk_sector_t off
= pe
? get_abs_partition_start(pe
) : 0;
1846 if (off
&& pe
->changed
) {
1847 mbr_set_magic(empty
);
1848 write_sector(cxt
, off
, empty
);
1852 /* EBR (logical partitions) */
1853 for (i
= 4; i
< cxt
->label
->nparts_max
; i
++) {
1854 struct pte
*pe
= self_pte(cxt
, i
);
1857 if (!pe
->changed
|| !pe
->offset
|| !pe
->sectorbuffer
)
1860 mbr_set_magic(pe
->sectorbuffer
);
1861 rc
= write_sector(cxt
, pe
->offset
, pe
->sectorbuffer
);
1870 static int dos_locate_disklabel(struct fdisk_context
*cxt
, int n
,
1871 const char **name
, uint64_t *offset
, size_t *size
)
1886 /* extended partitions */
1887 if ((size_t)n
- 1 + 4 < cxt
->label
->nparts_max
) {
1888 struct pte
*pe
= self_pte(cxt
, n
- 1 + 4);
1891 assert(pe
->private_sectorbuffer
);
1894 *offset
= (uint64_t) pe
->offset
* cxt
->sector_size
;
1905 * Check whether partition entries are ordered by their starting positions.
1906 * Return 0 if OK. Return i if partition i should have been earlier.
1907 * Two separate checks: primary and logical partitions.
1909 static int wrong_p_order(struct fdisk_context
*cxt
, size_t *prev
)
1911 size_t last_p_start_pos
= 0, p_start_pos
;
1912 size_t i
, last_i
= 0;
1914 for (i
= 0 ; i
< cxt
->label
->nparts_max
; i
++) {
1916 struct pte
*pe
= self_pte(cxt
, i
);
1917 struct dos_partition
*p
;
1924 last_p_start_pos
= 0;
1926 if (is_used_partition(p
)) {
1927 p_start_pos
= get_abs_partition_start(pe
);
1929 if (last_p_start_pos
> p_start_pos
) {
1935 last_p_start_pos
= p_start_pos
;
1942 static int dos_get_disklabel_item(struct fdisk_context
*cxt
, struct fdisk_labelitem
*item
)
1948 assert(fdisk_is_label(cxt
, DOS
));
1951 case FDISK_LABELITEM_ID
:
1953 unsigned int num
= mbr_get_id(cxt
->firstsector
);
1954 item
->name
= _("Disk identifier");
1956 if (asprintf(&item
->data
.str
, "0x%08x", num
) < 0)
1961 if (item
->id
< __FDISK_NLABELITEMS
)
1962 rc
= 1; /* unsupported generic item */
1964 rc
= 2; /* out of range */
1972 static int dos_get_partition(struct fdisk_context
*cxt
, size_t n
,
1973 struct fdisk_partition
*pa
)
1975 struct dos_partition
*p
;
1977 struct fdisk_dos_label
*lb
;
1982 assert(fdisk_is_label(cxt
, DOS
));
1984 lb
= self_label(cxt
);
1986 pe
= self_pte(cxt
, n
);
1990 pa
->used
= !is_cleared_partition(p
);
1994 pa
->type
= dos_partition_parttype(cxt
, p
);
1995 pa
->boot
= p
->boot_ind
== ACTIVE_FLAG
? 1 : 0;
1996 pa
->start
= get_abs_partition_start(pe
);
1997 pa
->size
= dos_partition_get_size(p
);
1998 pa
->container
= lb
->ext_offset
&& n
== lb
->ext_index
;
2001 pa
->parent_partno
= lb
->ext_index
;
2003 if (p
->boot_ind
&& asprintf(&pa
->attrs
, "%02x", p
->boot_ind
) < 0)
2007 if (asprintf(&pa
->start_chs
, "%d/%d/%d",
2008 cylinder(p
->bs
, p
->bc
),
2014 if (asprintf(&pa
->end_chs
, "%d/%d/%d",
2015 cylinder(p
->es
, p
->ec
),
2023 static int has_logical(struct fdisk_context
*cxt
)
2026 struct fdisk_dos_label
*l
= self_label(cxt
);
2028 for (i
= 4; i
< cxt
->label
->nparts_max
; i
++) {
2029 if (l
->ptes
[i
].pt_entry
)
2035 static int dos_set_partition(struct fdisk_context
*cxt
, size_t n
,
2036 struct fdisk_partition
*pa
)
2038 struct fdisk_dos_label
*l
;
2039 struct dos_partition
*p
;
2042 fdisk_sector_t start
, size
;
2047 assert(fdisk_is_label(cxt
, DOS
));
2049 if (n
>= cxt
->label
->nparts_max
)
2052 l
= self_label(cxt
);
2053 p
= self_partition(cxt
, n
);
2055 pe
= self_pte(cxt
, n
);
2059 orgtype
= p
->sys_ind
;
2062 if (IS_EXTENDED(pa
->type
->code
) && l
->ext_offset
&& l
->ext_index
!= n
) {
2063 fdisk_warnx(cxt
, _("Extended partition already exists."));
2067 if (!pa
->type
->code
)
2068 fdisk_warnx(cxt
, _("Type 0 means free space to many systems. "
2069 "Having partitions of type 0 is probably unwise."));
2071 if (IS_EXTENDED(p
->sys_ind
) && !IS_EXTENDED(pa
->type
->code
) && has_logical(cxt
)) {
2073 "Cannot change type of the extended partition which is "
2074 "already used by logical partitions. Delete logical "
2075 "partitions first."));
2080 FDISK_INIT_UNDEF(start
);
2081 FDISK_INIT_UNDEF(size
);
2083 if (fdisk_partition_has_start(pa
))
2085 if (fdisk_partition_has_size(pa
))
2088 if (!FDISK_IS_UNDEF(start
) || !FDISK_IS_UNDEF(size
)) {
2089 DBG(LABEL
, ul_debug("DOS: resize partition"));
2091 if (FDISK_IS_UNDEF(start
))
2092 start
= get_abs_partition_start(pe
);
2093 if (FDISK_IS_UNDEF(size
))
2094 size
= dos_partition_get_size(p
);
2096 set_partition(cxt
, n
, 0, start
, start
+ size
- 1,
2097 pa
->type
? pa
->type
->code
: p
->sys_ind
,
2098 FDISK_IS_UNDEF(pa
->boot
) ?
2099 p
->boot_ind
== ACTIVE_FLAG
:
2100 fdisk_partition_is_bootable(pa
));
2102 DBG(LABEL
, ul_debug("DOS: keep size, modify properties"));
2104 p
->sys_ind
= pa
->type
->code
;
2105 if (!FDISK_IS_UNDEF(pa
->boot
))
2106 p
->boot_ind
= fdisk_partition_is_bootable(pa
) ? ACTIVE_FLAG
: 0;
2110 if (IS_EXTENDED(pa
->type
->code
) && !IS_EXTENDED(orgtype
)) {
2111 /* new extended partition - create a reference */
2113 l
->ext_offset
= dos_partition_get_start(p
);
2115 } else if (IS_EXTENDED(orgtype
)) {
2116 /* remove extended partition */
2117 cxt
->label
->nparts_max
= 4;
2118 l
->ptes
[l
->ext_index
].ex_entry
= NULL
;
2124 partition_set_changed(cxt
, n
, 1);
2128 static void print_chain_of_logicals(struct fdisk_context
*cxt
)
2131 struct fdisk_dos_label
*l
= self_label(cxt
);
2133 fputc('\n', stdout
);
2135 for (i
= 4; i
< cxt
->label
->nparts_max
; i
++) {
2136 struct pte
*pe
= self_pte(cxt
, i
);
2139 fprintf(stderr
, "#%02zu EBR [%10ju], "
2140 "data[start=%10ju (%10ju), size=%10ju], "
2141 "link[start=%10ju (%10ju), size=%10ju]\n",
2142 i
, (uintmax_t) pe
->offset
,
2144 (uintmax_t) dos_partition_get_start(pe
->pt_entry
),
2145 (uintmax_t) get_abs_partition_start(pe
),
2146 (uintmax_t) dos_partition_get_size(pe
->pt_entry
),
2148 (uintmax_t) dos_partition_get_start(pe
->ex_entry
),
2149 (uintmax_t) l
->ext_offset
+ dos_partition_get_start(pe
->ex_entry
),
2150 (uintmax_t) dos_partition_get_size(pe
->ex_entry
));
2154 static int cmp_ebr_offsets(const void *a
, const void *b
)
2156 struct pte
*ae
= (struct pte
*) a
,
2157 *be
= (struct pte
*) b
;
2159 if (ae
->offset
== 0 && be
->offset
== 0)
2161 if (ae
->offset
== 0)
2163 if (be
->offset
== 0)
2166 return cmp_numbers(ae
->offset
, be
->offset
);
2170 * Fix the chain of logicals.
2172 * The function does not modify data partitions within EBR tables
2173 * (pte->pt_entry). It sorts the chain by EBR offsets and then update links
2174 * (pte->ex_entry) between EBR tables.
2177 static void fix_chain_of_logicals(struct fdisk_context
*cxt
)
2179 struct fdisk_dos_label
*l
= self_label(cxt
);
2183 DBG(LABEL
, print_chain_of_logicals(cxt
));
2185 /* Sort chain by EBR offsets */
2186 qsort(&l
->ptes
[4], cxt
->label
->nparts_max
- 4, sizeof(struct pte
),
2190 /* Sort data partitions by start */
2191 for (i
= 4; i
< cxt
->label
->nparts_max
- 1; i
++) {
2192 struct pte
*cur
= self_pte(cxt
, i
),
2193 *nxt
= self_pte(cxt
, i
+ 1);
2198 if (get_abs_partition_start(cur
) >
2199 get_abs_partition_start(nxt
)) {
2201 struct dos_partition tmp
= *cur
->pt_entry
;
2202 fdisk_sector_t cur_start
= get_abs_partition_start(cur
),
2203 nxt_start
= get_abs_partition_start(nxt
);
2205 /* swap data partitions */
2206 *cur
->pt_entry
= *nxt
->pt_entry
;
2207 *nxt
->pt_entry
= tmp
;
2209 /* Recount starts according to EBR offsets, the absolute
2210 * address still has to be the same! */
2211 dos_partition_set_start(cur
->pt_entry
, nxt_start
- cur
->offset
);
2212 dos_partition_set_start(nxt
->pt_entry
, cur_start
- nxt
->offset
);
2214 partition_set_changed(cxt
, i
, 1);
2215 partition_set_changed(cxt
, i
+ 1, 1);
2220 /* Update EBR links */
2221 for (i
= 4; i
< cxt
->label
->nparts_max
- 1; i
++) {
2222 struct pte
*cur
= self_pte(cxt
, i
),
2223 *nxt
= self_pte(cxt
, i
+ 1);
2228 fdisk_sector_t noff
= nxt
->offset
- l
->ext_offset
,
2229 ooff
= dos_partition_get_start(cur
->ex_entry
);
2234 DBG(LABEL
, ul_debug("DOS: fix EBR [%10ju] link %ju -> %ju",
2235 (uintmax_t) cur
->offset
,
2236 (uintmax_t) ooff
, (uintmax_t) noff
));
2238 set_partition(cxt
, i
, 1, nxt
->offset
,
2239 get_abs_partition_end(nxt
),
2240 MBR_DOS_EXTENDED_PARTITION
, 0);
2243 /* always terminate the chain ! */
2244 last
= self_pte(cxt
, cxt
->label
->nparts_max
- 1);
2246 clear_partition(last
->ex_entry
);
2247 partition_set_changed(cxt
, cxt
->label
->nparts_max
- 1, 1);
2250 DBG(LABEL
, print_chain_of_logicals(cxt
));
2253 static int dos_reorder(struct fdisk_context
*cxt
)
2255 struct pte
*pei
, *pek
;
2258 if (!wrong_p_order(cxt
, NULL
)) {
2259 fdisk_info(cxt
, _("Nothing to do. Ordering is correct already."));
2263 while ((i
= wrong_p_order(cxt
, &k
)) != 0 && i
< 4) {
2264 /* partition i should have come earlier, move it */
2265 /* We have to move data in the MBR */
2266 struct dos_partition
*pi
, *pk
, *pe
, pbuf
;
2267 pei
= self_pte(cxt
, i
);
2268 pek
= self_pte(cxt
, k
);
2274 pei
->ex_entry
= pek
->ex_entry
;
2280 memmove(&pbuf
, pi
, sizeof(struct dos_partition
));
2281 memmove(pi
, pk
, sizeof(struct dos_partition
));
2282 memmove(pk
, &pbuf
, sizeof(struct dos_partition
));
2284 partition_set_changed(cxt
, i
, 1);
2285 partition_set_changed(cxt
, k
, 1);
2289 fix_chain_of_logicals(cxt
);
2294 /* TODO: use fdisk_set_partition() API */
2295 int fdisk_dos_move_begin(struct fdisk_context
*cxt
, size_t i
)
2298 struct dos_partition
*p
;
2299 unsigned int new, free_start
, curr_start
, last
;
2305 assert(fdisk_is_label(cxt
, DOS
));
2307 pe
= self_pte(cxt
, i
);
2313 if (!is_used_partition(p
) || IS_EXTENDED (p
->sys_ind
)) {
2314 fdisk_warnx(cxt
, _("Partition %zu: no data area."), i
+ 1);
2318 /* the default start is at the second sector of the disk or at the
2319 * second sector of the extended partition
2321 free_start
= pe
->offset
? pe
->offset
+ 1 : 1;
2323 curr_start
= get_abs_partition_start(pe
);
2325 /* look for a free space before the current start of the partition */
2326 for (x
= 0; x
< cxt
->label
->nparts_max
; x
++) {
2328 struct pte
*prev_pe
= self_pte(cxt
, x
);
2329 struct dos_partition
*prev_p
;
2333 prev_p
= prev_pe
->pt_entry
;
2336 end
= get_abs_partition_start(prev_pe
)
2337 + dos_partition_get_size(prev_p
);
2339 if (is_used_partition(prev_p
) &&
2340 end
> free_start
&& end
<= curr_start
)
2344 last
= get_abs_partition_end(pe
);
2346 rc
= fdisk_ask_number(cxt
, free_start
, curr_start
, last
,
2347 _("New beginning of data"), &res
);
2351 new = res
- pe
->offset
;
2353 if (new != dos_partition_get_size(p
)) {
2354 unsigned int sects
= dos_partition_get_size(p
)
2355 + dos_partition_get_start(p
) - new;
2357 dos_partition_set_size(p
, sects
);
2358 dos_partition_set_start(p
, new);
2360 partition_set_changed(cxt
, i
, 1);
2366 static int dos_partition_is_used(
2367 struct fdisk_context
*cxt
,
2370 struct dos_partition
*p
;
2374 assert(fdisk_is_label(cxt
, DOS
));
2376 if (i
>= cxt
->label
->nparts_max
)
2379 p
= self_partition(cxt
, i
);
2381 return p
&& !is_cleared_partition(p
);
2384 static int dos_toggle_partition_flag(
2385 struct fdisk_context
*cxt
,
2389 struct dos_partition
*p
;
2393 assert(fdisk_is_label(cxt
, DOS
));
2395 if (i
>= cxt
->label
->nparts_max
)
2398 p
= self_partition(cxt
, i
);
2401 case DOS_FLAG_ACTIVE
:
2402 if (IS_EXTENDED(p
->sys_ind
) && !p
->boot_ind
)
2403 fdisk_warnx(cxt
, _("Partition %zu: is an extended "
2404 "partition."), i
+ 1);
2406 p
->boot_ind
= (p
->boot_ind
? 0 : ACTIVE_FLAG
);
2407 partition_set_changed(cxt
, i
, 1);
2408 fdisk_info(cxt
, p
->boot_ind
?
2409 _("The bootable flag on partition %zu is enabled now.") :
2410 _("The bootable flag on partition %zu is disabled now."),
2420 static const struct fdisk_field dos_fields
[] =
2423 { FDISK_FIELD_DEVICE
, N_("Device"), 10, 0 },
2424 { FDISK_FIELD_BOOT
, N_("Boot"), 1, 0 },
2425 { FDISK_FIELD_START
, N_("Start"), 5, FDISK_FIELDFL_NUMBER
},
2426 { FDISK_FIELD_END
, N_("End"), 5, FDISK_FIELDFL_NUMBER
},
2427 { FDISK_FIELD_SECTORS
, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER
},
2428 { FDISK_FIELD_CYLINDERS
,N_("Cylinders"), 5, FDISK_FIELDFL_NUMBER
},
2429 { FDISK_FIELD_SIZE
, N_("Size"), 5, FDISK_FIELDFL_NUMBER
| FDISK_FIELDFL_EYECANDY
},
2430 { FDISK_FIELD_TYPEID
, N_("Id"), 2, FDISK_FIELDFL_NUMBER
},
2431 { FDISK_FIELD_TYPE
, N_("Type"), 0.1, 0 },
2434 { FDISK_FIELD_SADDR
, N_("Start-C/H/S"), 1, FDISK_FIELDFL_NUMBER
| FDISK_FIELDFL_DETAIL
},
2435 { FDISK_FIELD_EADDR
, N_("End-C/H/S"), 1, FDISK_FIELDFL_NUMBER
| FDISK_FIELDFL_DETAIL
},
2436 { FDISK_FIELD_ATTR
, N_("Attrs"), 2, FDISK_FIELDFL_NUMBER
| FDISK_FIELDFL_DETAIL
}
2440 static const struct fdisk_label_operations dos_operations
=
2442 .probe
= dos_probe_label
,
2443 .write
= dos_write_disklabel
,
2444 .verify
= dos_verify_disklabel
,
2445 .create
= dos_create_disklabel
,
2446 .locate
= dos_locate_disklabel
,
2447 .get_item
= dos_get_disklabel_item
,
2448 .set_id
= dos_set_disklabel_id
,
2450 .get_part
= dos_get_partition
,
2451 .set_part
= dos_set_partition
,
2452 .add_part
= dos_add_partition
,
2453 .del_part
= dos_delete_partition
,
2454 .reorder
= dos_reorder
,
2456 .part_toggle_flag
= dos_toggle_partition_flag
,
2457 .part_is_used
= dos_partition_is_used
,
2459 .reset_alignment
= dos_reset_alignment
,
2461 .deinit
= dos_deinit
,
2465 * allocates DOS in-memory stuff
2467 struct fdisk_label
*fdisk_new_dos_label(struct fdisk_context
*cxt
__attribute__ ((__unused__
)))
2469 struct fdisk_label
*lb
;
2470 struct fdisk_dos_label
*dos
;
2472 dos
= calloc(1, sizeof(*dos
));
2476 /* initialize generic part of the driver */
2477 lb
= (struct fdisk_label
*) dos
;
2479 lb
->id
= FDISK_DISKLABEL_DOS
;
2480 lb
->op
= &dos_operations
;
2481 lb
->parttypes
= dos_parttypes
;
2482 lb
->nparttypes
= ARRAY_SIZE(dos_parttypes
) - 1;
2483 lb
->fields
= dos_fields
;
2484 lb
->nfields
= ARRAY_SIZE(dos_fields
);
2486 lb
->geom_min
.sectors
= 1;
2487 lb
->geom_min
.heads
= 1;
2488 lb
->geom_min
.cylinders
= 1;
2490 lb
->geom_max
.sectors
= 63;
2491 lb
->geom_max
.heads
= 255;
2492 lb
->geom_max
.cylinders
= 1048576;
2498 * fdisk_dos_enable_compatible:
2499 * @lb: DOS label (see fdisk_get_label())
2502 * Enables deprecated DOS compatible mode, in this mode library checks for
2503 * cylinders boundary, cases about CHS addressing and another obscure things.
2505 * Returns: 0 on success, <0 on error.
2507 int fdisk_dos_enable_compatible(struct fdisk_label
*lb
, int enable
)
2509 struct fdisk_dos_label
*dos
= (struct fdisk_dos_label
*) lb
;
2514 dos
->compatible
= enable
;
2516 lb
->flags
|= FDISK_LABEL_FL_REQUIRE_GEOMETRY
;
2521 * fdisk_dos_is_compatible:
2524 * Returns: 0 if DOS compatibility disabled, 1 if enabled
2526 int fdisk_dos_is_compatible(struct fdisk_label
*lb
)
2528 return ((struct fdisk_dos_label
*) lb
)->compatible
;