]> git.ipfire.org Git - thirdparty/util-linux.git/blame - fdisks/fdiskdoslabel.c
docs: update deprecated file
[thirdparty/util-linux.git] / fdisks / fdiskdoslabel.c
CommitLineData
e2ee9178
DB
1/*
2 * Many, many hands.
3 * Specific DOS label file - Davidlohr Bueso <dave@gnu.org>
4 */
5
6#include <unistd.h>
9dea2923 7#include <ctype.h>
e2ee9178
DB
8
9#include "nls.h"
10#include "xalloc.h"
11#include "randutils.h"
12#include "common.h"
13#include "fdisk.h"
14#include "fdiskdoslabel.h"
15
749af4b6
KZ
16static struct fdisk_parttype dos_parttypes[] = {
17 #include "dos_part_types.h"
18};
19
9dea2923 20#define set_hsc(h,s,c,sector) { \
24cd580b
DB
21 s = sector % cxt->geom.sectors + 1; \
22 sector /= cxt->geom.sectors; \
23 h = sector % cxt->geom.heads; \
24 sector /= cxt->geom.heads; \
25 c = sector & 0xff; \
26 s |= (sector >> 2) & 0xc0; \
9dea2923
DB
27 }
28
b29ce87b 29#define alignment_required (cxt->grain != cxt->sector_size)
9dea2923 30
96f817fb 31struct pte ptes[MAXIMUM_PARTS];
24def09d 32sector_t extended_offset;
96f817fb
KZ
33int ext_index;
34
e53ced85 35static int get_nonexisting_partition(struct fdisk_context *cxt, int warn, int max)
9dea2923
DB
36{
37 int pno = -1;
38 int i;
39 int dflt = 0;
40
41 for (i = 0; i < max; i++) {
42 struct pte *pe = &ptes[i];
43 struct partition *p = pe->part_table;
44
45 if (p && is_cleared_partition(p)) {
46 if (pno >= 0) {
47 dflt = pno + 1;
48 goto not_unique;
49 }
50 pno = i;
51 }
52 }
53 if (pno >= 0) {
54 printf(_("Selected partition %d\n"), pno+1);
55 return pno;
56 }
57 printf(_("All primary partitions have been defined already!\n"));
58 return -1;
59
60 not_unique:
e53ced85 61 return get_partition_dflt(cxt, warn, max, dflt);
9dea2923
DB
62}
63
64
e2ee9178 65/* Allocate a buffer and read a partition table sector */
24def09d 66static void read_pte(struct fdisk_context *cxt, int pno, sector_t offset)
e2ee9178
DB
67{
68 struct pte *pe = &ptes[pno];
69
70 pe->offset = offset;
e53ced85 71 pe->sectorbuffer = xmalloc(cxt->sector_size);
7737f698 72 read_sector(cxt, offset, pe->sectorbuffer);
e2ee9178
DB
73 pe->changed = 0;
74 pe->part_table = pe->ext_pointer = NULL;
75}
76
87a97832 77static void mbr_set_id(unsigned char *b, unsigned int id)
e2ee9178
DB
78{
79 store4_little_endian(&b[440], id);
80}
81
87a97832
KZ
82static void mbr_set_magic(unsigned char *b)
83{
84 b[510] = 0x55;
85 b[511] = 0xaa;
86}
87
67188340
KZ
88int mbr_is_valid_magic(unsigned char *b)
89{
90 return (b[510] == 0x55 && b[511] == 0xaa);
91}
92
87a97832 93static unsigned int mbr_get_id(const unsigned char *b)
e2ee9178
DB
94{
95 return read4_little_endian(&b[440]);
96}
97
98static void clear_partition(struct partition *p)
99{
100 if (!p)
101 return;
102 p->boot_ind = 0;
103 p->head = 0;
104 p->sector = 0;
105 p->cyl = 0;
106 p->sys_ind = 0;
107 p->end_head = 0;
108 p->end_sector = 0;
109 p->end_cyl = 0;
110 set_start_sect(p,0);
111 set_nr_sects(p,0);
112}
113
e53ced85 114void dos_init(struct fdisk_context *cxt)
e2ee9178
DB
115{
116 int i;
117
118 disklabel = DOS_LABEL;
119 partitions = 4;
120 ext_index = 0;
121 extended_offset = 0;
122
123 for (i = 0; i < 4; i++) {
124 struct pte *pe = &ptes[i];
125
67987b47 126 pe->part_table = pt_offset(cxt->firstsector, i);
e2ee9178
DB
127 pe->ext_pointer = NULL;
128 pe->offset = 0;
67987b47 129 pe->sectorbuffer = cxt->firstsector;
e2ee9178
DB
130 pe->changed = 0;
131 }
132
24cd580b 133 warn_geometry(cxt);
e53ced85
DB
134 warn_limits(cxt);
135 warn_alignment(cxt);
e2ee9178
DB
136}
137
43b382e6
KZ
138static void dos_delete_partition(
139 struct fdisk_context *cxt __attribute__ ((__unused__)),
140 int partnum)
61c4cb85
DB
141{
142 struct pte *pe = &ptes[partnum];
143 struct partition *p = pe->part_table;
144 struct partition *q = pe->ext_pointer;
145
146 /* Note that for the fifth partition (partnum == 4) we don't actually
147 decrement partitions. */
148
149 if (partnum < 4) {
150 if (IS_EXTENDED (p->sys_ind) && partnum == ext_index) {
151 partitions = 4;
152 ptes[ext_index].ext_pointer = NULL;
153 extended_offset = 0;
154 }
155 clear_partition(p);
156 } else if (!q->sys_ind && partnum > 4) {
157 /* the last one in the chain - just delete */
158 --partitions;
159 --partnum;
160 clear_partition(ptes[partnum].ext_pointer);
161 ptes[partnum].changed = 1;
162 } else {
163 /* not the last one - further ones will be moved down */
164 if (partnum > 4) {
165 /* delete this link in the chain */
166 p = ptes[partnum-1].ext_pointer;
167 *p = *q;
168 set_start_sect(p, get_start_sect(q));
169 set_nr_sects(p, get_nr_sects(q));
170 ptes[partnum-1].changed = 1;
171 } else if (partitions > 5) { /* 5 will be moved to 4 */
172 /* the first logical in a longer chain */
173 struct pte *pe = &ptes[5];
174
175 if (pe->part_table) /* prevent SEGFAULT */
176 set_start_sect(pe->part_table,
177 get_partition_start(pe) -
178 extended_offset);
179 pe->offset = extended_offset;
180 pe->changed = 1;
181 }
182
183 if (partitions > 5) {
184 partitions--;
185 while (partnum < partitions) {
186 ptes[partnum] = ptes[partnum+1];
187 partnum++;
188 }
189 } else
190 /* the only logical: clear only */
191 clear_partition(ptes[partnum].part_table);
192 }
193}
194
7737f698 195static void read_extended(struct fdisk_context *cxt, int ext)
e2ee9178
DB
196{
197 int i;
198 struct pte *pex;
199 struct partition *p, *q;
200
201 ext_index = ext;
202 pex = &ptes[ext];
203 pex->ext_pointer = pex->part_table;
204
205 p = pex->part_table;
206 if (!get_start_sect(p)) {
207 fprintf(stderr,
208 _("Bad offset in primary extended partition\n"));
209 return;
210 }
211
212 while (IS_EXTENDED (p->sys_ind)) {
213 struct pte *pe = &ptes[partitions];
214
215 if (partitions >= MAXIMUM_PARTS) {
216 /* This is not a Linux restriction, but
217 this program uses arrays of size MAXIMUM_PARTS.
218 Do not try to `improve' this test. */
219 struct pte *pre = &ptes[partitions-1];
220
221 fprintf(stderr,
222 _("Warning: omitting partitions after #%d.\n"
223 "They will be deleted "
224 "if you save this partition table.\n"),
225 partitions);
226 clear_partition(pre->ext_pointer);
227 pre->changed = 1;
228 return;
229 }
230
7737f698 231 read_pte(cxt, partitions, extended_offset + get_start_sect(p));
e2ee9178
DB
232
233 if (!extended_offset)
234 extended_offset = get_start_sect(p);
235
236 q = p = pt_offset(pe->sectorbuffer, 0);
237 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
238 if (IS_EXTENDED (p->sys_ind)) {
239 if (pe->ext_pointer)
240 fprintf(stderr,
241 _("Warning: extra link "
242 "pointer in partition table"
243 " %d\n"), partitions + 1);
244 else
245 pe->ext_pointer = p;
246 } else if (p->sys_ind) {
247 if (pe->part_table)
248 fprintf(stderr,
249 _("Warning: ignoring extra "
250 "data in partition table"
251 " %d\n"), partitions + 1);
252 else
253 pe->part_table = p;
254 }
255 }
256
257 /* very strange code here... */
258 if (!pe->part_table) {
259 if (q != pe->ext_pointer)
260 pe->part_table = q;
261 else
262 pe->part_table = q + 1;
263 }
264 if (!pe->ext_pointer) {
265 if (q != pe->part_table)
266 pe->ext_pointer = q;
267 else
268 pe->ext_pointer = q + 1;
269 }
270
271 p = pe->ext_pointer;
272 partitions++;
273 }
274
275 /* remove empty links */
276 remove:
277 for (i = 4; i < partitions; i++) {
278 struct pte *pe = &ptes[i];
279
280 if (!get_nr_sects(pe->part_table) &&
281 (partitions > 5 || ptes[4].part_table->sys_ind)) {
282 printf(_("omitting empty partition (%d)\n"), i+1);
61c4cb85 283 dos_delete_partition(cxt, i);
e2ee9178
DB
284 goto remove; /* numbering changed */
285 }
286 }
287}
288
38b36353 289void dos_print_mbr_id(struct fdisk_context *cxt)
e2ee9178 290{
67987b47 291 printf(_("Disk identifier: 0x%08x\n"), mbr_get_id(cxt->firstsector));
e2ee9178
DB
292}
293
639f1d56 294static int dos_create_disklabel(struct fdisk_context *cxt)
e2ee9178
DB
295{
296 unsigned int id;
297
298 /* random disk signature */
c544aa2c 299 random_get_bytes(&id, sizeof(id));
e2ee9178
DB
300
301 fprintf(stderr, _("Building a new DOS disklabel with disk identifier 0x%08x.\n"), id);
302
e53ced85 303 dos_init(cxt);
67987b47 304 fdisk_zeroize_firstsector(cxt);
e2ee9178
DB
305 set_all_unchanged();
306 set_changed(0);
307
308 /* Generate an MBR ID for this disk */
67987b47 309 mbr_set_id(cxt->firstsector, id);
e2ee9178
DB
310
311 /* Put MBR signature */
67987b47 312 mbr_set_magic(cxt->firstsector);
a71601af 313 return 0;
e2ee9178
DB
314}
315
38b36353 316void dos_set_mbr_id(struct fdisk_context *cxt)
e2ee9178
DB
317{
318 unsigned long new_id;
319 char *ep;
320 char ps[64];
321
322 snprintf(ps, sizeof ps, _("New disk identifier (current 0x%08x): "),
67987b47 323 mbr_get_id(cxt->firstsector));
e2ee9178
DB
324
325 if (read_chars(ps) == '\n')
326 return;
327
328 new_id = strtoul(line_ptr, &ep, 0);
329 if (*ep != '\n')
330 return;
331
67987b47 332 mbr_set_id(cxt->firstsector, new_id);
e2ee9178 333 MBRbuffer_changed = 1;
38b36353 334 dos_print_mbr_id(cxt);
e2ee9178
DB
335}
336
9a5e29e9
KZ
337static void get_partition_table_geometry(struct fdisk_context *cxt,
338 unsigned int *ph, unsigned int *ps)
339{
67987b47 340 unsigned char *bufp = cxt->firstsector;
9a5e29e9
KZ
341 struct partition *p;
342 int i, h, s, hh, ss;
343 int first = 1;
344 int bad = 0;
345
346 hh = ss = 0;
347 for (i=0; i<4; i++) {
348 p = pt_offset(bufp, i);
349 if (p->sys_ind != 0) {
350 h = p->end_head + 1;
351 s = (p->end_sector & 077);
352 if (first) {
353 hh = h;
354 ss = s;
355 first = 0;
356 } else if (hh != h || ss != s)
357 bad = 1;
358 }
359 }
360
361 if (!first && !bad) {
362 *ph = hh;
363 *ps = ss;
364 }
365}
366
367
da4ea9f5 368static int dos_probe_label(struct fdisk_context *cxt)
e2ee9178
DB
369{
370 int i;
9a5e29e9 371 unsigned int h = 0, s = 0;
e2ee9178 372
67987b47 373 if (!mbr_is_valid_magic(cxt->firstsector))
e2ee9178
DB
374 return 0;
375
e53ced85 376 dos_init(cxt);
e2ee9178 377
9a5e29e9
KZ
378 get_partition_table_geometry(cxt, &h, &s);
379 if (h && s) {
380 cxt->geom.heads = h;
381 cxt->geom.sectors = s;
382 }
383
e2ee9178
DB
384 for (i = 0; i < 4; i++) {
385 struct pte *pe = &ptes[i];
386
387 if (IS_EXTENDED (pe->part_table->sys_ind)) {
388 if (partitions != 4)
389 fprintf(stderr, _("Ignoring extra extended "
390 "partition %d\n"), i + 1);
391 else
7737f698 392 read_extended(cxt, i);
e2ee9178
DB
393 }
394 }
395
396 for (i = 3; i < partitions; i++) {
397 struct pte *pe = &ptes[i];
398
67188340 399 if (!mbr_is_valid_magic(pe->sectorbuffer)) {
e2ee9178
DB
400 fprintf(stderr,
401 _("Warning: invalid flag 0x%04x of partition "
402 "table %d will be corrected by w(rite)\n"),
403 part_table_flag(pe->sectorbuffer), i + 1);
404 pe->changed = 1;
405 }
406 }
407
408 return 1;
409}
410
411/*
412 * Avoid warning about DOS partitions when no DOS partition was changed.
413 * Here a heuristic "is probably dos partition".
414 * We might also do the opposite and warn in all cases except
415 * for "is probably nondos partition".
416 */
02460b8a 417static int is_dos_partition(int t)
e2ee9178
DB
418{
419 return (t == 1 || t == 4 || t == 6 ||
420 t == 0x0b || t == 0x0c || t == 0x0e ||
421 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
422 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
423 t == 0xc1 || t == 0xc4 || t == 0xc6);
424}
9dea2923 425
e53ced85
DB
426static void set_partition(struct fdisk_context *cxt,
427 int i, int doext, sector_t start,
24def09d 428 sector_t stop, int sysid)
9dea2923
DB
429{
430 struct partition *p;
24def09d 431 sector_t offset;
9dea2923
DB
432
433 if (doext) {
434 p = ptes[i].ext_pointer;
435 offset = extended_offset;
436 } else {
437 p = ptes[i].part_table;
438 offset = ptes[i].offset;
439 }
440 p->boot_ind = 0;
441 p->sys_ind = sysid;
442 set_start_sect(p, start - offset);
443 set_nr_sects(p, stop - start + 1);
444
445 if (!doext)
e53ced85 446 print_partition_size(cxt, i + 1, start, stop, sysid);
9dea2923 447
24cd580b
DB
448 if (dos_compatible_flag && (start/(cxt->geom.sectors*cxt->geom.heads) > 1023))
449 start = cxt->geom.heads*cxt->geom.sectors*1024 - 1;
9dea2923 450 set_hsc(p->head, p->sector, p->cyl, start);
24cd580b
DB
451 if (dos_compatible_flag && (stop/(cxt->geom.sectors*cxt->geom.heads) > 1023))
452 stop = cxt->geom.heads*cxt->geom.sectors*1024 - 1;
9dea2923
DB
453 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
454 ptes[i].changed = 1;
455}
456
24def09d
DB
457static sector_t get_unused_start(int part_n, sector_t start,
458 sector_t first[], sector_t last[])
9dea2923
DB
459{
460 int i;
461
462 for (i = 0; i < partitions; i++) {
24def09d 463 sector_t lastplusoff;
9dea2923
DB
464
465 if (start == ptes[i].offset)
466 start += sector_offset;
467 lastplusoff = last[i] + ((part_n < 4) ? 0 : sector_offset);
468 if (start >= first[i] && start <= lastplusoff)
469 start = lastplusoff + 1;
470 }
471
472 return start;
473}
474
e53ced85
DB
475static sector_t align_lba_in_range(struct fdisk_context *cxt,
476 sector_t lba, sector_t start, sector_t stop)
9dea2923 477{
e53ced85
DB
478 start = align_lba(cxt, start, ALIGN_UP);
479 stop = align_lba(cxt, stop, ALIGN_DOWN);
9dea2923 480
e53ced85 481 lba = align_lba(cxt, lba, ALIGN_NEAREST);
9dea2923
DB
482
483 if (lba < start)
484 return start;
485 else if (lba > stop)
486 return stop;
487 return lba;
488}
489
ed470672 490static void add_partition(struct fdisk_context *cxt, int n, struct fdisk_parttype *t)
9dea2923
DB
491{
492 char mesg[256]; /* 48 does not suffice in Japanese */
ed470672 493 int i, sys, read = 0;
9dea2923
DB
494 struct partition *p = ptes[n].part_table;
495 struct partition *q = ptes[ext_index].part_table;
24def09d 496 sector_t start, stop = 0, limit, temp,
9dea2923
DB
497 first[partitions], last[partitions];
498
ed470672
KZ
499 sys = t ? t->type : LINUX_NATIVE;
500
9dea2923
DB
501 if (p && p->sys_ind) {
502 printf(_("Partition %d is already defined. Delete "
503 "it before re-adding it.\n"), n + 1);
504 return;
505 }
506 fill_bounds(first, last);
507 if (n < 4) {
508 start = sector_offset;
618882d6 509 if (display_in_cyl_units || !cxt->total_sectors)
24cd580b 510 limit = cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders - 1;
9dea2923 511 else
618882d6 512 limit = cxt->total_sectors - 1;
9dea2923
DB
513
514 if (limit > UINT_MAX)
515 limit = UINT_MAX;
516
517 if (extended_offset) {
518 first[ext_index] = extended_offset;
519 last[ext_index] = get_start_sect(q) +
520 get_nr_sects(q) - 1;
521 }
522 } else {
523 start = extended_offset + sector_offset;
524 limit = get_start_sect(q) + get_nr_sects(q) - 1;
525 }
526 if (display_in_cyl_units)
527 for (i = 0; i < partitions; i++)
528 first[i] = (cround(first[i]) - 1) * units_per_sector;
529
530 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
531 do {
24def09d 532 sector_t dflt, aligned;
9dea2923
DB
533
534 temp = start;
535 dflt = start = get_unused_start(n, start, first, last);
536
537 /* the default sector should be aligned and unused */
538 do {
e53ced85 539 aligned = align_lba_in_range(cxt, dflt, dflt, limit);
9dea2923
DB
540 dflt = get_unused_start(n, aligned, first, last);
541 } while (dflt != aligned && dflt > aligned && dflt < limit);
542
543 if (dflt >= limit)
544 dflt = start;
545 if (start > limit)
546 break;
547 if (start >= temp+units_per_sector && read) {
548 printf(_("Sector %llu is already allocated\n"), temp);
549 temp = start;
550 read = 0;
551 }
552 if (!read && start == temp) {
24def09d 553 sector_t i = start;
9dea2923 554
e53ced85 555 start = read_int(cxt, cround(i), cround(dflt), cround(limit),
9dea2923
DB
556 0, mesg);
557 if (display_in_cyl_units) {
558 start = (start - 1) * units_per_sector;
559 if (start < i) start = i;
560 }
561 read = 1;
562 }
563 } while (start != temp || !read);
564 if (n > 4) { /* NOT for fifth partition */
565 struct pte *pe = &ptes[n];
566
567 pe->offset = start - sector_offset;
568 if (pe->offset == extended_offset) { /* must be corrected */
569 pe->offset++;
570 if (sector_offset == 1)
571 start++;
572 }
573 }
574
575 for (i = 0; i < partitions; i++) {
576 struct pte *pe = &ptes[i];
577
578 if (start < pe->offset && limit >= pe->offset)
579 limit = pe->offset - 1;
580 if (start < first[i] && limit >= first[i])
581 limit = first[i] - 1;
582 }
583 if (start > limit) {
584 printf(_("No free sectors available\n"));
585 if (n > 4)
586 partitions--;
587 return;
588 }
589 if (cround(start) == cround(limit)) {
590 stop = limit;
591 } else {
592 int is_suffix_used = 0;
593
594 snprintf(mesg, sizeof(mesg),
595 _("Last %1$s, +%2$s or +size{K,M,G}"),
596 str_units(SINGULAR), str_units(PLURAL));
597
e53ced85
DB
598 stop = read_int_with_suffix(cxt,
599 cround(start), cround(limit), cround(limit),
600 cround(start), mesg, &is_suffix_used);
9dea2923
DB
601 if (display_in_cyl_units) {
602 stop = stop * units_per_sector - 1;
603 if (stop >limit)
604 stop = limit;
605 }
606
607 if (is_suffix_used && alignment_required) {
608 /* the last sector has not been exactly requested (but
609 * defined by +size{K,M,G} convention), so be smart
610 * and align the end of the partition. The next
611 * partition will start at phy.block boundary.
612 */
e53ced85 613 stop = align_lba_in_range(cxt, stop, start, limit) - 1;
9dea2923
DB
614 if (stop > limit)
615 stop = limit;
616 }
617 }
618
e53ced85 619 set_partition(cxt, n, 0, start, stop, sys);
9dea2923 620 if (n > 4)
e53ced85 621 set_partition(cxt, n - 1, 1, ptes[n].offset, stop, EXTENDED);
9dea2923
DB
622
623 if (IS_EXTENDED (sys)) {
624 struct pte *pe4 = &ptes[4];
625 struct pte *pen = &ptes[n];
626
627 ext_index = n;
628 pen->ext_pointer = p;
629 pe4->offset = extended_offset = start;
e53ced85 630 pe4->sectorbuffer = xcalloc(1, cxt->sector_size);
9dea2923
DB
631 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
632 pe4->ext_pointer = pe4->part_table + 1;
633 pe4->changed = 1;
634 partitions = 5;
635 }
636}
637
e53ced85 638static void add_logical(struct fdisk_context *cxt)
9dea2923
DB
639{
640 if (partitions > 5 || ptes[4].part_table->sys_ind) {
641 struct pte *pe = &ptes[partitions];
642
e53ced85 643 pe->sectorbuffer = xcalloc(1, cxt->sector_size);
9dea2923
DB
644 pe->part_table = pt_offset(pe->sectorbuffer, 0);
645 pe->ext_pointer = pe->part_table + 1;
646 pe->offset = 0;
647 pe->changed = 1;
648 partitions++;
649 }
650 printf(_("Adding logical partition %d\n"), partitions);
ed470672 651 add_partition(cxt, partitions - 1, NULL);
9dea2923
DB
652}
653
2ca61a61
DB
654static int dos_verify_disklabel(struct fdisk_context *cxt)
655{
656 int i, j;
657 sector_t total = 1, n_sectors = cxt->total_sectors;
658 unsigned long long first[partitions], last[partitions];
659 struct partition *p;
660
661 fill_bounds(first, last);
662 for (i = 0; i < partitions; i++) {
663 struct pte *pe = &ptes[i];
664
665 p = pe->part_table;
666 if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) {
667 check_consistency(cxt, p, i);
668 check_alignment(cxt, get_partition_start(pe), i);
669 if (get_partition_start(pe) < first[i])
670 printf(_("Warning: bad start-of-data in "
671 "partition %d\n"), i + 1);
672 check(cxt, i + 1, p->end_head, p->end_sector, p->end_cyl,
673 last[i]);
674 total += last[i] + 1 - first[i];
675 for (j = 0; j < i; j++)
676 if ((first[i] >= first[j] && first[i] <= last[j])
677 || ((last[i] <= last[j] && last[i] >= first[j]))) {
678 printf(_("Warning: partition %d overlaps "
679 "partition %d.\n"), j + 1, i + 1);
680 total += first[i] >= first[j] ?
681 first[i] : first[j];
682 total -= last[i] <= last[j] ?
683 last[i] : last[j];
684 }
685 }
686 }
687
688 if (extended_offset) {
689 struct pte *pex = &ptes[ext_index];
690 sector_t e_last = get_start_sect(pex->part_table) +
691 get_nr_sects(pex->part_table) - 1;
692
693 for (i = 4; i < partitions; i++) {
694 total++;
695 p = ptes[i].part_table;
696 if (!p->sys_ind) {
697 if (i != 4 || i + 1 < partitions)
698 printf(_("Warning: partition %d "
699 "is empty\n"), i + 1);
700 }
701 else if (first[i] < extended_offset ||
702 last[i] > e_last)
703 printf(_("Logical partition %d not entirely in "
704 "partition %d\n"), i + 1, ext_index + 1);
705 }
706 }
707
708 if (total > n_sectors)
709 printf(_("Total allocated sectors %llu greater than the maximum"
710 " %llu\n"), total, n_sectors);
711 else if (total < n_sectors)
712 printf(_("Remaining %lld unallocated %ld-byte sectors\n"),
713 n_sectors - total, cxt->sector_size);
714
715 return 0;
716}
717
9dea2923
DB
718/*
719 * Ask the user for new partition type information (logical, extended).
0f639e54
DB
720 * This function calls the actual partition adding logic - add_partition.
721 *
722 * API callback.
9dea2923 723 */
43b382e6
KZ
724static void dos_add_partition(
725 struct fdisk_context *cxt,
726 int partnum __attribute__ ((__unused__)),
ed470672 727 struct fdisk_parttype *t)
9dea2923
DB
728{
729 int i, free_primary = 0;
730
731 for (i = 0; i < 4; i++)
732 free_primary += !ptes[i].part_table->sys_ind;
733
734 if (!free_primary && partitions >= MAXIMUM_PARTS) {
735 printf(_("The maximum number of partitions has been created\n"));
736 return;
737 }
738
739 if (!free_primary) {
740 if (extended_offset) {
741 printf(_("All primary partitions are in use\n"));
e53ced85 742 add_logical(cxt);
9dea2923
DB
743 } else
744 printf(_("If you want to create more than four partitions, you must replace a\n"
745 "primary partition with an extended partition first.\n"));
746 } else if (partitions >= MAXIMUM_PARTS) {
747 printf(_("All logical partitions are in use\n"));
748 printf(_("Adding a primary partition\n"));
ed470672 749 add_partition(cxt, get_partition(cxt, 0, 4), t);
9dea2923
DB
750 } else {
751 char c, dflt, line[LINE_LENGTH];
752
753 dflt = (free_primary == 1 && !extended_offset) ? 'e' : 'p';
754 snprintf(line, sizeof(line),
755 _("Partition type:\n"
756 " p primary (%d primary, %d extended, %d free)\n"
757 "%s\n"
758 "Select (default %c): "),
759 4 - (extended_offset ? 1 : 0) - free_primary, extended_offset ? 1 : 0, free_primary,
760 extended_offset ? _(" l logical (numbered from 5)") : _(" e extended"),
761 dflt);
762
763 c = tolower(read_chars(line));
764 if (c == '\n') {
765 c = dflt;
766 printf(_("Using default response %c\n"), c);
767 }
768 if (c == 'p') {
e53ced85 769 int i = get_nonexisting_partition(cxt, 0, 4);
9dea2923 770 if (i >= 0)
ed470672 771 add_partition(cxt, i, t);
9dea2923
DB
772 return;
773 } else if (c == 'l' && extended_offset) {
e53ced85 774 add_logical(cxt);
9dea2923
DB
775 return;
776 } else if (c == 'e' && !extended_offset) {
e53ced85 777 int i = get_nonexisting_partition(cxt, 0, 4);
ed470672
KZ
778 if (i >= 0) {
779 t = fdisk_get_parttype_from_code(cxt, EXTENDED);
780 add_partition(cxt, i, t);
781 }
9dea2923
DB
782 return;
783 } else
784 printf(_("Invalid partition type `%c'\n"), c);
785 }
786}
0dc13a38 787
fae7b1bc
DB
788static int write_sector(struct fdisk_context *cxt, sector_t secno,
789 unsigned char *buf)
0dc13a38 790{
fae7b1bc
DB
791 seek_sector(cxt, secno);
792 if (write(cxt->dev_fd, buf, cxt->sector_size) != (ssize_t) cxt->sector_size)
793 return -errno;
794 return 0;
795}
796
797static int dos_write_disklabel(struct fdisk_context *cxt)
798{
799 int i, rc = 0;
0dc13a38
DB
800
801 /* MBR (primary partitions) */
802 if (!MBRbuffer_changed) {
803 for (i = 0; i < 4; i++)
804 if (ptes[i].changed)
805 MBRbuffer_changed = 1;
806 }
807 if (MBRbuffer_changed) {
67987b47 808 mbr_set_magic(cxt->firstsector);
fae7b1bc
DB
809 rc = write_sector(cxt, 0, cxt->firstsector);
810 if (rc)
811 goto done;
0dc13a38
DB
812 }
813 /* EBR (logical partitions) */
814 for (i = 4; i < partitions; i++) {
815 struct pte *pe = &ptes[i];
816
817 if (pe->changed) {
87a97832 818 mbr_set_magic(pe->sectorbuffer);
fae7b1bc
DB
819 rc = write_sector(cxt, pe->offset, pe->sectorbuffer);
820 if (rc)
821 goto done;
0dc13a38
DB
822 }
823 }
fae7b1bc
DB
824
825done:
826 return rc;
0dc13a38 827}
b8855c86 828
010186f2
KZ
829static struct fdisk_parttype *dos_get_parttype(struct fdisk_context *cxt, int partnum)
830{
831 struct fdisk_parttype *t;
832 struct partition *p;
833
834 if (partnum >= partitions)
835 return NULL;
836
837 p = ptes[partnum].part_table;
838 t = fdisk_get_parttype_from_code(cxt, p->sys_ind);
839 if (!t)
840 t = fdisk_new_unknown_parttype(p->sys_ind, NULL);
841 return t;
842}
843
02460b8a
KZ
844static int dos_set_parttype(struct fdisk_context *cxt, int partnum,
845 struct fdisk_parttype *t)
846{
847 struct partition *p;
848
849 if (partnum >= partitions || !t || t->type > UINT8_MAX)
850 return -EINVAL;
851
852 p = ptes[partnum].part_table;
853 if (t->type == p->sys_ind)
854 return 0;
855
856 if (IS_EXTENDED(p->sys_ind) || IS_EXTENDED(t->type)) {
857 printf(_("\nYou cannot change a partition into an extended one "
858 "or vice versa.\nDelete it first.\n\n"));
859 return -EINVAL;
860 }
861
862 if (is_dos_partition(t->type) || is_dos_partition(p->sys_ind))
863 printf(
864 _("\nWARNING: If you have created or modified any DOS 6.x"
865 "partitions, please see the fdisk manual page for additional"
866 "information.\n\n"));
867
868 p->sys_ind = t->type;
869 return 0;
870}
871
b8855c86
DB
872const struct fdisk_label dos_label =
873{
874 .name = "dos",
749af4b6 875 .parttypes = dos_parttypes,
559d921e
KZ
876 .nparttypes = ARRAY_SIZE(dos_parttypes),
877
da4ea9f5 878 .probe = dos_probe_label,
fae7b1bc 879 .write = dos_write_disklabel,
2ca61a61 880 .verify = dos_verify_disklabel,
639f1d56 881 .create = dos_create_disklabel,
0f639e54 882 .part_add = dos_add_partition,
61c4cb85 883 .part_delete = dos_delete_partition,
010186f2 884 .part_get_type = dos_get_parttype,
02460b8a 885 .part_set_type = dos_set_parttype,
b8855c86 886};