]> git.ipfire.org Git - thirdparty/util-linux.git/blame - fdisks/fdisk.c
fdisk: (bds) use nested partition table
[thirdparty/util-linux.git] / fdisks / fdisk.c
CommitLineData
6dbe3af9
KZ
1/* fdisk.c -- Partition table manipulator for Linux.
2 *
3 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
38b36353 4 * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org>
6dbe3af9
KZ
5 *
6 * This program is free software. You can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation: either version 1 or
9 * (at your option) any later version.
6dbe3af9
KZ
10 */
11
6dbe3af9
KZ
12#include <unistd.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <fcntl.h>
17#include <ctype.h>
6dbe3af9 18#include <errno.h>
2b6fc908 19#include <getopt.h>
2b6fc908 20#include <sys/stat.h>
f26873dc 21#include <sys/time.h>
bb6aacfe 22#include <time.h>
ee5355e0 23#include <limits.h>
6dbe3af9 24
52b38677 25#include "xalloc.h"
22853e4a 26#include "nls.h"
e66ac5d3 27#include "rpmatch.h"
810f986b 28#include "blkdev.h"
7eda085c 29#include "common.h"
b8d22034 30#include "mbsalign.h"
726f69e2 31#include "fdisk.h"
929f243f 32#include "wholedisk.h"
6bec8710
KZ
33#include "pathnames.h"
34#include "canonicalize.h"
20aa2570 35#include "strutils.h"
b2d28533 36#include "closestream.h"
5c36a0eb 37
2b6fc908 38#include "fdisksunlabel.h"
5c36a0eb
KZ
39#include "fdisksgilabel.h"
40#include "fdiskaixlabel.h"
e7fa917a 41#include "fdiskmaclabel.h"
e2ee9178 42#include "fdiskdoslabel.h"
37eadc17 43#include "fdiskbsdlabel.h"
5c36a0eb 44
48d7b13a
KZ
45#ifdef HAVE_LINUX_COMPILER_H
46#include <linux/compiler.h>
47#endif
48#ifdef HAVE_LINUX_BLKPG_H
7eda085c
KZ
49#include <linux/blkpg.h>
50#endif
6dbe3af9 51
c482303e
FC
52/* menu list description */
53
54struct menulist_descr {
55 char command; /* command key */
56 char *description; /* command description */
79c8a145 57 enum fdisk_labeltype label[2]; /* disklabel types associated with main and expert menu */
c482303e
FC
58};
59
60static const struct menulist_descr menulist[] = {
bbc41eeb
KZ
61 {'a', N_("change number of alternate cylinders"), {0, FDISK_DISKLABEL_SUN}},
62 {'a', N_("select bootable partition"), {FDISK_DISKLABEL_SGI, 0}},
ff5775bd
DB
63 {'a', N_("toggle a bootable flag"), {FDISK_DISKLABEL_DOS, 0}},
64 {'a', N_("toggle a read only flag"), {FDISK_DISKLABEL_SUN, 0}},
ff5775bd 65 {'b', N_("edit bootfile entry"), {FDISK_DISKLABEL_SGI, 0}},
bbc41eeb 66 {'b', N_("edit bsd disklabel"), {FDISK_DISKLABEL_DOS, 0}},
ff5775bd 67 {'b', N_("move beginning of data in a partition"), {0, FDISK_DISKLABEL_DOS}},
bbc41eeb
KZ
68 {'c', N_("change number of cylinders"), {0, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN}},
69 {'c', N_("select sgi swap partition"), {FDISK_DISKLABEL_SGI, 0}},
ff5775bd
DB
70 {'c', N_("toggle the dos compatibility flag"), {FDISK_DISKLABEL_DOS, 0}},
71 {'c', N_("toggle the mountable flag"), {FDISK_DISKLABEL_SUN, 0}},
ff5775bd
DB
72 {'d', N_("delete a partition"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF | FDISK_DISKLABEL_GPT, 0}},
73 {'d', N_("print the raw data in the partition table"), {0, FDISK_DISKLABEL_ANY}},
74 {'e', N_("change number of extra sectors per cylinder"), {0, FDISK_DISKLABEL_SUN}},
ff5775bd 75 {'e', N_("edit drive data"), {FDISK_DISKLABEL_OSF, 0}},
bbc41eeb 76 {'e', N_("list extended partitions"), {0, FDISK_DISKLABEL_DOS}},
ff5775bd 77 {'f', N_("fix partition order"), {0, FDISK_DISKLABEL_DOS}},
ff5775bd 78 {'g', N_("create a new empty GPT partition table"), {~FDISK_DISKLABEL_OSF, 0}},
bbc41eeb
KZ
79 {'g', N_("create an IRIX (SGI) partition table"), {0, FDISK_DISKLABEL_ANY}}, /* for backward compatibility only */
80 {'G', N_("create an IRIX (SGI) partition table"), {~FDISK_DISKLABEL_OSF, 0}},
ff5775bd
DB
81 {'h', N_("change number of heads"), {0, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN}},
82 {'i', N_("change interleave factor"), {0, FDISK_DISKLABEL_SUN}},
83 {'i', N_("change the disk identifier"), {0, FDISK_DISKLABEL_DOS}},
84 {'i', N_("install bootstrap"), {FDISK_DISKLABEL_OSF, 0}},
85 {'l', N_("list known partition types"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF | FDISK_DISKLABEL_GPT, 0}},
86 {'m', N_("print this menu"), {FDISK_DISKLABEL_ANY, FDISK_DISKLABEL_ANY}},
87 {'n', N_("add a new partition"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF | FDISK_DISKLABEL_GPT, 0}},
ff5775bd 88 {'o', N_("change rotation speed (rpm)"), {0, FDISK_DISKLABEL_SUN}},
bbc41eeb 89 {'o', N_("create a new empty DOS partition table"), {~FDISK_DISKLABEL_OSF, 0}},
ff5775bd
DB
90 {'p', N_("print the partition table"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN}},
91 {'q', N_("quit without saving changes"), {FDISK_DISKLABEL_ANY, FDISK_DISKLABEL_ANY}},
92 {'r', N_("return to main menu"), {FDISK_DISKLABEL_OSF, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF}},
ff5775bd 93 {'s', N_("change number of sectors/track"), {0, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN}},
bbc41eeb 94 {'s', N_("create a new empty Sun disklabel"), {~FDISK_DISKLABEL_OSF, 0}},
ff5775bd
DB
95 {'s', N_("show complete disklabel"), {FDISK_DISKLABEL_OSF, 0}},
96 {'t', N_("change a partition's system id"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF, 0}},
97 {'u', N_("change display/entry units"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF, 0}},
98 {'v', N_("verify the partition table"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI}},
ff5775bd 99 {'w', N_("write disklabel to disk"), {FDISK_DISKLABEL_OSF, 0}},
bbc41eeb 100 {'w', N_("write table to disk and exit"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_GPT, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI}},
ff5775bd 101 {'x', N_("extra functionality (experts only)"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI, 0}},
c482303e 102#if !defined (__alpha__)
ff5775bd 103 {'x', N_("link BSD partition to non-BSD partition"), {FDISK_DISKLABEL_OSF, 0}},
c482303e 104#endif
ff5775bd 105 {'y', N_("change number of physical cylinders"), {0, FDISK_DISKLABEL_SUN}},
c482303e
FC
106};
107
749af4b6
KZ
108
109
50dec1eb 110sector_t get_nr_sects(struct partition *p) {
2b6fc908
KZ
111 return read4_little_endian(p->size4);
112}
113
823f0fd1 114char *line_ptr, /* interactive input */
22853e4a 115 line_buffer[LINE_LENGTH];
6dbe3af9 116
e3661531 117int nowarn = 0; /* no warnings for fdisk -l/-s */
6dbe3af9 118
df1dddf9 119unsigned int user_cylinders, user_heads, user_sectors;
365acc97 120
ec10aa67
KZ
121void toggle_units(struct fdisk_context *cxt)
122{
123 fdisk_context_set_unit(cxt,
124 fdisk_context_use_cylinders(cxt) ? "sectors" :
125 "cylinders");
126 if (fdisk_context_use_cylinders(cxt))
127 fdisk_info(cxt, _("Changing display/entry units to cylinders (DEPRECATED!)."));
128 else
129 fdisk_info(cxt, _("Changing display/entry units to sectors."));
130}
131
132
7c1db6b4
FC
133static void __attribute__ ((__noreturn__)) usage(FILE *out)
134{
135 fprintf(out, _("Usage:\n"
136 " %1$s [options] <disk> change partition table\n"
137 " %1$s [options] -l <disk> list partition table(s)\n"
138 " %1$s -s <partition> give partition size(s) in blocks\n"
139 "\nOptions:\n"
140 " -b <size> sector size (512, 1024, 2048 or 4096)\n"
141 " -c[=<mode>] compatible mode: 'dos' or 'nondos' (default)\n"
142 " -h print this help text\n"
143 " -u[=<unit>] display units: 'cylinders' or 'sectors' (default)\n"
144 " -v print program version\n"
145 " -C <number> specify the number of cylinders\n"
146 " -H <number> specify the number of heads\n"
147 " -S <number> specify the number of sectors per track\n"
148 "\n"), program_invocation_short_name);
149 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
150}
151
888a2e1c
SK
152void __attribute__((__noreturn__))
153fatal(struct fdisk_context *cxt, enum failure why)
9f6c866f 154{
823f0fd1 155 close(cxt->dev_fd);
6dbe3af9 156 switch (why) {
6dbe3af9 157 case unable_to_read:
823f0fd1 158 err(EXIT_FAILURE, _("unable to read %s"), cxt->dev_path);
c845f12c 159
6dbe3af9 160 case unable_to_seek:
823f0fd1 161 err(EXIT_FAILURE, _("unable to seek on %s"), cxt->dev_path);
c845f12c 162
6dbe3af9 163 case unable_to_write:
823f0fd1 164 err(EXIT_FAILURE, _("unable to write %s"), cxt->dev_path);
c845f12c 165
7eda085c 166 case ioctl_error:
823f0fd1 167 err(EXIT_FAILURE, _("BLKGETSIZE ioctl failed on %s"), cxt->dev_path);
c845f12c 168
c07ebfa1 169 default:
c845f12c 170 err(EXIT_FAILURE, _("fatal error"));
6dbe3af9 171 }
6dbe3af9
KZ
172}
173
22853e4a
KZ
174struct partition *
175get_part_table(int i) {
176 return ptes[i].part_table;
177}
178
ff5775bd 179void print_menu(struct fdisk_context *cxt, enum menutype menu)
c482303e
FC
180{
181 size_t i;
53b422ab 182 int id;
6dbe3af9 183
c482303e
FC
184 puts(_("Command action"));
185
53b422ab
KZ
186 id = cxt && cxt->label ? cxt->label->id : FDISK_DISKLABEL_ANY;
187
c482303e 188 for (i = 0; i < ARRAY_SIZE(menulist); i++)
53b422ab 189 if (menulist[i].label[menu] & id)
c482303e 190 printf(" %c %s\n", menulist[i].command, menulist[i].description);
6dbe3af9
KZ
191}
192
7b575fcc 193void list_partition_types(struct fdisk_context *cxt)
6dbe3af9 194{
7b575fcc 195 struct fdisk_parttype *types;
6dbe3af9
KZ
196 int i;
197
7b575fcc
KZ
198 if (!cxt || !cxt->label || !cxt->label->parttypes)
199 return;
2b6fc908 200
7b575fcc 201 types = cxt->label->parttypes;
6dbe3af9 202
7b575fcc
KZ
203 if (types[0].typestr == NULL) {
204 /*
205 * Prints in 4 columns in format <hex> <name>
206 */
207 unsigned int last[4], done = 0, next = 0, size;
b8d22034 208
7b575fcc
KZ
209 for (i = 0; types[i].name; i++);
210 size = i;
211
212 for (i = 3; i >= 0; i--)
213 last[3 - i] = done += (size + i - done) / (i + 1);
214 i = done = 0;
215
216 do {
217 #define NAME_WIDTH 15
218 char name[NAME_WIDTH * MB_LEN_MAX];
219 size_t width = NAME_WIDTH;
220 struct fdisk_parttype *t = &types[next];
221 size_t ret;
222
223 printf("%c%2x ", i ? ' ' : '\n', t->type);
224 ret = mbsalign(_(t->name), name, sizeof(name),
225 &width, MBS_ALIGN_LEFT, 0);
226
227 if (ret == (size_t)-1 || ret >= sizeof(name))
228 printf("%-15.15s", _(t->name));
229 else
230 fputs(name, stdout);
231
232 next = last[i++] + done;
233 if (i > 3 || next >= last[i]) {
234 i = 0;
235 next = ++done;
236 }
237 } while (done < last[0]);
238
239 } else {
240 /*
241 * Prints 1 column in format <idx> <name> <typestr>
242 */
243 struct fdisk_parttype *t;
244
245 for (i = 0, t = types; t->name; t++, i++)
246 printf("%3d %-30s %s\n", i + 1, t->name, t->typestr);
247 }
6dbe3af9
KZ
248 putchar('\n');
249}
250
22853e4a
KZ
251static int
252test_c(char **m, char *mesg) {
6dbe3af9
KZ
253 int val = 0;
254 if (!*m)
7eda085c 255 fprintf(stderr, _("You must set"));
6dbe3af9
KZ
256 else {
257 fprintf(stderr, " %s", *m);
258 val = 1;
259 }
260 *m = mesg;
261 return val;
262}
263
24cd580b 264int warn_geometry(struct fdisk_context *cxt)
e2ee9178 265{
6dbe3af9
KZ
266 char *m = NULL;
267 int prev = 0;
a47f2e66 268
ff5775bd 269 if (fdisk_is_disklabel(cxt, SGI)) /* cannot set cylinders etc anyway */
a47f2e66 270 return 0;
24cd580b 271 if (!cxt->geom.heads)
7eda085c 272 prev = test_c(&m, _("heads"));
24cd580b 273 if (!cxt->geom.sectors)
7eda085c 274 prev = test_c(&m, _("sectors"));
24cd580b 275 if (!cxt->geom.cylinders)
7eda085c 276 prev = test_c(&m, _("cylinders"));
6dbe3af9
KZ
277 if (!m)
278 return 0;
279 fprintf(stderr,
7eda085c
KZ
280 _("%s%s.\nYou can do this from the extra functions menu.\n"),
281 prev ? _(" and ") : " ", m);
6dbe3af9
KZ
282 return 1;
283}
284
e53ced85 285void warn_limits(struct fdisk_context *cxt)
e2ee9178 286{
618882d6
DB
287 if (cxt->total_sectors > UINT_MAX && !nowarn) {
288 unsigned long long bytes = cxt->total_sectors * cxt->sector_size;
06023c2e 289 int giga = bytes / 1000000000;
32b40fec
KZ
290 int hectogiga = (giga + 50) / 100;
291
ee5355e0
KZ
292 fprintf(stderr, _("\n"
293"WARNING: The size of this disk is %d.%d TB (%llu bytes).\n"
32b40fec 294"DOS partition table format can not be used on drives for volumes\n"
e53ced85 295"larger than (%llu bytes) for %ld-byte sectors. Use parted(1) and GUID \n"
ee5355e0 296"partition table format (GPT).\n\n"),
32b40fec 297 hectogiga / 10, hectogiga % 10,
06023c2e 298 bytes,
e53ced85
DB
299 (sector_t ) UINT_MAX * cxt->sector_size,
300 cxt->sector_size);
ee5355e0 301 }
6dbe3af9
KZ
302}
303
bddd84e7 304static void maybe_exit(struct fdisk_context *cxt, int rc, int *asked)
aead9d13
FC
305{
306 char line[LINE_LENGTH];
307
bddd84e7
KZ
308 assert(cxt);
309 assert(cxt->label);
310
aead9d13 311 putchar('\n');
8feb31e5
KZ
312 if (asked)
313 *asked = 0;
aead9d13 314
bddd84e7 315 if (fdisk_label_is_changed(cxt->label)) {
aead9d13
FC
316 fprintf(stderr, _("Do you really want to quit? "));
317
318 if (!fgets(line, LINE_LENGTH, stdin) || rpmatch(line) == 1)
bddd84e7 319 goto leave;
8feb31e5
KZ
320 if (asked)
321 *asked = 1;
bddd84e7
KZ
322 return;
323 }
324leave:
325 fdisk_free_context(cxt);
326 exit(rc);
aead9d13
FC
327}
328
5c36a0eb 329/* read line; return 0 or first char */
bddd84e7 330int read_line(struct fdisk_context *cxt, int *asked)
6dbe3af9 331{
5c36a0eb 332 line_ptr = line_buffer;
7eda085c 333 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
bddd84e7 334 maybe_exit(cxt, 1, asked);
6dbe3af9 335 return 0;
7eda085c 336 }
8feb31e5
KZ
337 if (asked)
338 *asked = 0;
6dbe3af9
KZ
339 while (*line_ptr && !isgraph(*line_ptr))
340 line_ptr++;
341 return *line_ptr;
342}
343
bddd84e7 344char read_char(struct fdisk_context *cxt, char *mesg)
6dbe3af9 345{
2b6fc908 346 do {
6dbe3af9 347 fputs(mesg, stdout);
66ee8158 348 fflush (stdout); /* requested by niles@scyld.com */
bddd84e7
KZ
349
350 } while (!read_line(cxt, NULL));
351
6dbe3af9
KZ
352 return *line_ptr;
353}
354
bddd84e7 355char read_chars(struct fdisk_context *cxt, char *mesg)
2b6fc908 356{
8feb31e5
KZ
357 int rc, asked = 0;
358
359 do {
360 fputs(mesg, stdout);
361 fflush (stdout); /* niles@scyld.com */
bddd84e7 362 rc = read_line(cxt, &asked);
8feb31e5
KZ
363 } while (asked);
364
365 if (!rc) {
2b6fc908 366 *line_ptr = '\n';
5c36a0eb
KZ
367 line_ptr[1] = 0;
368 }
369 return *line_ptr;
2b6fc908
KZ
370}
371
559d921e 372struct fdisk_parttype *read_partition_type(struct fdisk_context *cxt)
6dbe3af9 373{
559d921e
KZ
374 if (!cxt || !cxt->label || !cxt->label->nparttypes)
375 return NULL;
376
377 do {
378 size_t sz;
379
380 if (cxt->label->parttypes[0].typestr)
bddd84e7 381 read_chars(cxt, _("Partition type (type L to list all types): "));
559d921e 382 else
bddd84e7 383 read_chars(cxt, _("Hex code (type L to list all codes): "));
559d921e
KZ
384
385 sz = strlen(line_ptr);
386 if (!sz || line_ptr[sz - 1] != '\n' || sz == 1)
387 continue;
388 line_ptr[sz - 1] = '\0';
389
390 if (tolower(*line_ptr) == 'l')
391 list_partition_types(cxt);
392 else
393 return fdisk_parse_parttype(cxt, line_ptr);
394 } while (1);
395
396 return NULL;
726f69e2
KZ
397}
398
559d921e 399
9dea2923 400unsigned int
e53ced85
DB
401read_int_with_suffix(struct fdisk_context *cxt,
402 unsigned int low, unsigned int dflt, unsigned int high,
2c911261 403 unsigned int base, char *mesg, int *is_suffix_used)
726f69e2 404{
2c911261 405 unsigned int res;
5c36a0eb 406 int default_ok = 1;
0c381880 407 int absolute = 0;
5c36a0eb 408 static char *ms = NULL;
e99da659 409 static size_t mslen = 0;
5c36a0eb 410
c07ebfa1
KZ
411 if (!ms || strlen(mesg)+100 > mslen) {
412 mslen = strlen(mesg)+200;
52b38677 413 ms = xrealloc(ms,mslen);
726f69e2 414 }
6dbe3af9 415
5c36a0eb
KZ
416 if (dflt < low || dflt > high)
417 default_ok = 0;
418
419 if (default_ok)
df1dddf9 420 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
c07ebfa1 421 mesg, low, high, dflt);
5c36a0eb 422 else
df1dddf9 423 snprintf(ms, mslen, "%s (%u-%u): ",
c07ebfa1 424 mesg, low, high);
5c36a0eb 425
6dbe3af9 426 while (1) {
5c36a0eb
KZ
427 int use_default = default_ok;
428
429 /* ask question and read answer */
bddd84e7 430 while (read_chars(cxt, ms) != '\n' && !isdigit(*line_ptr)
5c36a0eb
KZ
431 && *line_ptr != '-' && *line_ptr != '+')
432 continue;
433
726f69e2 434 if (*line_ptr == '+' || *line_ptr == '-') {
a5a16c68 435 int minus = (*line_ptr == '-');
b1edb510 436 int suflen;
a5a16c68 437
0c381880 438 absolute = 0;
2c911261 439 res = atoi(line_ptr + 1);
a5a16c68 440
b1edb510 441 while (isdigit(*++line_ptr))
726f69e2 442 use_default = 0;
a5a16c68 443
74396048
FC
444 while (isspace(*line_ptr))
445 line_ptr++;
446
b1edb510
KZ
447 suflen = strlen(line_ptr) - 1;
448
449 while(isspace(*(line_ptr + suflen)))
450 *(line_ptr + suflen--) = '\0';
451
452 if ((*line_ptr == 'C' || *line_ptr == 'c') &&
453 *(line_ptr + 1) == '\0') {
454 /*
455 * Cylinders
456 */
ec10aa67 457 if (fdisk_context_use_cylinders(cxt))
24cd580b 458 res *= cxt->geom.heads * cxt->geom.sectors;
5ea8931c
KZ
459 } else if (*line_ptr &&
460 *(line_ptr + 1) == 'B' &&
b1edb510
KZ
461 *(line_ptr + 2) == '\0') {
462 /*
463 * 10^N
464 */
465 if (*line_ptr == 'K')
a5a16c68 466 absolute = 1000;
b1edb510 467 else if (*line_ptr == 'M')
a5a16c68 468 absolute = 1000000;
b1edb510 469 else if (*line_ptr == 'G')
a5a16c68 470 absolute = 1000000000;
b1edb510
KZ
471 else
472 absolute = -1;
5ea8931c
KZ
473 } else if (*line_ptr &&
474 *(line_ptr + 1) == '\0') {
b1edb510
KZ
475 /*
476 * 2^N
477 */
478 if (*line_ptr == 'K')
479 absolute = 1 << 10;
480 else if (*line_ptr == 'M')
481 absolute = 1 << 20;
482 else if (*line_ptr == 'G')
483 absolute = 1 << 30;
484 else
485 absolute = -1;
486 } else if (*line_ptr != '\0')
487 absolute = -1;
488
489 if (absolute == -1) {
490 printf(_("Unsupported suffix: '%s'.\n"), line_ptr);
491 printf(_("Supported: 10^N: KB (KiloByte), MB (MegaByte), GB (GigaByte)\n"
492 " 2^N: K (KibiByte), M (MebiByte), G (GibiByte)\n"));
493 continue;
726f69e2 494 }
b1edb510 495
2c911261 496 if (absolute && res) {
a5a16c68
KZ
497 unsigned long long bytes;
498 unsigned long unit;
499
2c911261 500 bytes = (unsigned long long) res * absolute;
ec10aa67 501 unit = cxt->sector_size * fdisk_context_get_units_per_sector(cxt);
a5a16c68
KZ
502 bytes += unit/2; /* round */
503 bytes /= unit;
2c911261 504 res = bytes;
a5a16c68
KZ
505 }
506 if (minus)
2c911261
FC
507 res = -res;
508 res += base;
5c36a0eb 509 } else {
2c911261 510 res = atoi(line_ptr);
5c36a0eb 511 while (isdigit(*line_ptr)) {
726f69e2
KZ
512 line_ptr++;
513 use_default = 0;
514 }
515 }
0c381880
FC
516 if (use_default) {
517 printf(_("Using default value %u\n"), dflt);
518 return dflt;
519 }
2c911261 520 if (res >= low && res <= high)
6dbe3af9 521 break;
726f69e2 522 else
7eda085c 523 printf(_("Value out of range.\n"));
6dbe3af9 524 }
0c381880
FC
525 if (is_suffix_used)
526 *is_suffix_used = absolute > 0;
2c911261 527 return res;
6dbe3af9
KZ
528}
529
b7e76f8e
KZ
530/*
531 * Print the message MESG, then read an integer in LOW..HIGH.
532 * If the user hits Enter, DFLT is returned, provided that is in LOW..HIGH.
533 * Answers like +10 are interpreted as offsets from BASE.
534 *
535 * There is no default if DFLT is not between LOW and HIGH.
536 */
537unsigned int
e53ced85
DB
538read_int(struct fdisk_context *cxt,
539 unsigned int low, unsigned int dflt, unsigned int high,
b7e76f8e
KZ
540 unsigned int base, char *mesg)
541{
e53ced85 542 return read_int_with_suffix(cxt, low, dflt, high, base, mesg, NULL);
b7e76f8e
KZ
543}
544
22853e4a 545int
225592d4
KZ
546get_partition_dflt(struct fdisk_context *cxt, int warn, int max, int dflt)
547{
22853e4a
KZ
548 int i;
549
e53ced85 550 i = read_int(cxt, 1, dflt, max, 0, _("Partition number")) - 1;
225592d4
KZ
551
552 if (warn && !fdisk_partition_is_used(cxt, i))
553 fdisk_warnx(cxt, _("Warning: partition %d is unused"), i + 1);
554
6dbe3af9
KZ
555 return i;
556}
557
147e1e73 558int
e53ced85
DB
559get_partition(struct fdisk_context *cxt, int warn, int max) {
560 return get_partition_dflt(cxt, warn, max, 0);
147e1e73
KZ
561}
562
b152082d
FC
563/* User partition selection unless one partition only is available */
564
24f4bbff 565static int
e53ced85 566get_existing_partition(struct fdisk_context *cxt, int warn, int max) {
24f4bbff
KZ
567 int pno = -1;
568 int i;
569
ff5775bd 570 if (!fdisk_is_disklabel(cxt, DOS))
b152082d
FC
571 goto not_implemented;
572
24f4bbff
KZ
573 for (i = 0; i < max; i++) {
574 struct pte *pe = &ptes[i];
575 struct partition *p = pe->part_table;
576
577 if (p && !is_cleared_partition(p)) {
578 if (pno >= 0)
579 goto not_unique;
580 pno = i;
581 }
582 }
365acc97 583
24f4bbff
KZ
584 if (pno >= 0) {
585 printf(_("Selected partition %d\n"), pno+1);
586 return pno;
587 }
588 printf(_("No partition is defined yet!\n"));
589 return -1;
590
b152082d
FC
591not_implemented:
592not_unique:
e53ced85 593 return get_partition(cxt, warn, max);
24f4bbff
KZ
594}
595
852ce62b
KZ
596static void toggle_dos_compatibility_flag(struct fdisk_context *cxt)
597{
598 struct fdisk_label *lb = fdisk_context_get_label(cxt, "dos");
599 int flag;
600
601 if (!lb)
602 return;
603
604 flag = !fdisk_dos_is_compatible(lb);
605
606 if (flag)
278f63c0 607 printf(_("DOS Compatibility flag is set (DEPRECATED!)\n"));
edd7b958 608 else
7eda085c 609 printf(_("DOS Compatibility flag is not set\n"));
edd7b958 610
852ce62b
KZ
611 fdisk_dos_enable_compatible(lb, flag);
612
613 if (fdisk_is_disklabel(cxt, DOS))
614 fdisk_reset_alignment(cxt);
6dbe3af9
KZ
615}
616
61c4cb85 617static void delete_partition(struct fdisk_context *cxt, int partnum)
47104bae 618{
61c4cb85 619 if (partnum < 0 || warn_geometry(cxt))
4a96a62a
FC
620 return;
621
61c4cb85 622 ptes[partnum].changed = 1;
1f5eb51b
DB
623 if (fdisk_delete_partition(cxt, partnum) != 0)
624 printf(_("Could not delete partition %d\n"), partnum + 1);
625 else
626 printf(_("Partition %d is deleted\n"), partnum + 1);
6dbe3af9
KZ
627}
628
02460b8a 629static void change_partition_type(struct fdisk_context *cxt)
e53ced85 630{
559d921e
KZ
631 int i;
632 struct fdisk_parttype *t, *org_t;
6dbe3af9 633
e3661531
KZ
634 assert(cxt);
635 assert(cxt->label);
636
637 i = get_existing_partition(cxt, 0, cxt->label->nparts_max);
24f4bbff
KZ
638 if (i == -1)
639 return;
2b6fc908 640
010186f2
KZ
641 org_t = t = fdisk_get_partition_type(cxt, i);
642 if (!t)
7eda085c 643 printf(_("Partition %d does not exist yet!\n"), i + 1);
010186f2 644
02460b8a 645 else do {
559d921e 646 t = read_partition_type(cxt);
559d921e
KZ
647 if (!t)
648 continue;
649
02460b8a
KZ
650 if (fdisk_set_partition_type(cxt, i, t) == 0) {
651 ptes[i].changed = 1;
652 printf (_("Changed type of partition '%s' to '%s'\n"),
653 org_t ? org_t->name : _("Unknown"),
654 t ? t->name : _("Unknown"));
655 } else {
656 printf (_("Type of partition %d is unchanged: %s\n"),
657 i + 1,
658 org_t ? org_t->name : _("Unknown"));
6dbe3af9 659 }
02460b8a
KZ
660 break;
661 } while (1);
559d921e
KZ
662
663 fdisk_free_parttype(t);
664 fdisk_free_parttype(org_t);
6dbe3af9
KZ
665}
666
22853e4a 667static void
7737f698 668list_disk_geometry(struct fdisk_context *cxt) {
618882d6 669 unsigned long long bytes = cxt->total_sectors * cxt->sector_size;
24f4bbff
KZ
670 long megabytes = bytes/1000000;
671
672 if (megabytes < 10000)
f8527f4b 673 printf(_("\nDisk %s: %ld MB, %lld bytes"),
823f0fd1 674 cxt->dev_path, megabytes, bytes);
32b40fec
KZ
675 else {
676 long hectomega = (megabytes + 50) / 100;
f8527f4b 677 printf(_("\nDisk %s: %ld.%ld GB, %llu bytes"),
823f0fd1 678 cxt->dev_path, hectomega / 10, hectomega % 10, bytes);
32b40fec 679 }
f8527f4b 680 printf(_(", %llu sectors\n"), cxt->total_sectors);
852ce62b 681 if (is_dos_compatible(cxt))
a7a6f7d2
PU
682 printf(_("%d heads, %llu sectors/track, %llu cylinders\n"),
683 cxt->geom.heads, cxt->geom.sectors, cxt->geom.cylinders);
e53ced85 684 printf(_("Units = %s of %d * %ld = %ld bytes\n"),
ec10aa67
KZ
685 fdisk_context_get_unit(cxt, PLURAL),
686 fdisk_context_get_units_per_sector(cxt),
687 cxt->sector_size,
688 fdisk_context_get_units_per_sector(cxt) * cxt->sector_size);
05dc9645 689
e53ced85
DB
690 printf(_("Sector size (logical/physical): %lu bytes / %lu bytes\n"),
691 cxt->sector_size, cxt->phy_sector_size);
a8a86a1c 692 printf(_("I/O size (minimum/optimal): %lu bytes / %lu bytes\n"),
e53ced85
DB
693 cxt->min_io_size, cxt->io_size);
694 if (cxt->alignment_offset)
695 printf(_("Alignment offset: %lu bytes\n"), cxt->alignment_offset);
b546d442
KZ
696 if (fdisk_dev_has_disklabel(cxt))
697 printf(_("Disk label type: %s\n"), cxt->label->name);
ff5775bd 698 if (fdisk_is_disklabel(cxt, DOS))
38b36353 699 dos_print_mbr_id(cxt);
bb6aacfe 700 printf("\n");
5c36a0eb
KZ
701}
702
766d5156
DB
703static void list_table(struct fdisk_context *cxt, int xtra)
704{
ff5775bd 705 if (fdisk_is_disklabel(cxt, SUN)) {
7737f698 706 sun_list_table(cxt, xtra);
5c36a0eb
KZ
707 return;
708 }
709
ff5775bd 710 if (fdisk_is_disklabel(cxt, SGI)) {
7737f698 711 sgi_list_table(cxt, xtra);
5c36a0eb
KZ
712 return;
713 }
2b6fc908 714
7737f698 715 list_disk_geometry(cxt);
22853e4a 716
ff5775bd 717 if (fdisk_is_disklabel(cxt, GPT)) {
766d5156
DB
718 gpt_list_table(cxt, xtra);
719 return;
720 }
721
ff5775bd 722 if (fdisk_is_disklabel(cxt, OSF)) {
7737f698 723 xbsd_print_disklabel(cxt, xtra);
22853e4a
KZ
724 return;
725 }
726
6d864a49
KZ
727 if (fdisk_is_disklabel(cxt, DOS))
728 dos_list_table(cxt, xtra);
6dbe3af9
KZ
729}
730
2ca61a61
DB
731static void verify(struct fdisk_context *cxt)
732{
24cd580b 733 if (warn_geometry(cxt))
6dbe3af9
KZ
734 return;
735
2ca61a61 736 fdisk_verify_disklabel(cxt);
6dbe3af9
KZ
737}
738
e53ced85
DB
739void print_partition_size(struct fdisk_context *cxt,
740 int num, sector_t start, sector_t stop, int sysid)
20aa2570
FC
741{
742 char *str = size_to_human_string(SIZE_SUFFIX_3LETTER | SIZE_SUFFIX_SPACE,
7e6e9c70 743 (uint64_t)(stop - start + 1) * cxt->sector_size);
559d921e
KZ
744 struct fdisk_parttype *t = fdisk_get_parttype_from_code(cxt, sysid);
745
746 printf(_("Partition %d of type %s and of size %s is set\n"),
747 num, t ? t->name : _("Unknown"), str);
20aa2570
FC
748 free(str);
749}
750
e53ced85 751static void new_partition(struct fdisk_context *cxt)
9dea2923 752{
9fcd49d5
KZ
753 assert(cxt);
754 assert(cxt->label);
755
0f639e54 756 if (warn_geometry(cxt))
e8f26419 757 return;
e8f26419 758
416c43a9 759 fdisk_add_partition(cxt, NULL);
6dbe3af9
KZ
760}
761
fae7b1bc
DB
762static void write_table(struct fdisk_context *cxt)
763{
764 int rc;
6dbe3af9 765
fae7b1bc
DB
766 rc = fdisk_write_disklabel(cxt);
767 if (rc)
768 err(EXIT_FAILURE, _("cannot write disk label"));
6dbe3af9 769
7eda085c 770 printf(_("The partition table has been altered!\n\n"));
7737f698 771 reread_partition_table(cxt, 1);
eb63b9b8
KZ
772}
773
774void
7737f698 775reread_partition_table(struct fdisk_context *cxt, int leave) {
eb63b9b8 776 int i;
edd867fa 777 struct stat statbuf;
6dbe3af9 778
823f0fd1 779 i = fstat(cxt->dev_fd, &statbuf);
edd867fa 780 if (i == 0 && S_ISBLK(statbuf.st_mode)) {
edd867fa 781 sync();
6b0054a2
ST
782#ifdef BLKRRPART
783 printf(_("Calling ioctl() to re-read partition table.\n"));
823f0fd1 784 i = ioctl(cxt->dev_fd, BLKRRPART);
6b0054a2
ST
785#else
786 errno = ENOSYS;
787 i = 1;
788#endif
726f69e2
KZ
789 }
790
e8f26419 791 if (i) {
960cf573 792 printf(_("\nWARNING: Re-reading the partition table failed with error %d: %m.\n"
c64061c9
VD
793 "The kernel still uses the old table. The new table will be used at\n"
794 "the next reboot or after you run partprobe(8) or kpartx(8)\n"),
960cf573 795 errno);
e8f26419 796 }
6dbe3af9 797
eb63b9b8 798 if (leave) {
823f0fd1 799 if (fsync(cxt->dev_fd) || close(cxt->dev_fd)) {
a47f2e66
KZ
800 fprintf(stderr, _("\nError closing file\n"));
801 exit(1);
802 }
eb63b9b8
KZ
803
804 printf(_("Syncing disks.\n"));
805 sync();
eb63b9b8
KZ
806 exit(!!i);
807 }
6dbe3af9
KZ
808}
809
810#define MAX_PER_LINE 16
22853e4a 811static void
e53ced85 812print_buffer(struct fdisk_context *cxt, unsigned char pbuffer[]) {
e99da659 813 unsigned int i, l;
6dbe3af9 814
e53ced85 815 for (i = 0, l = 0; i < cxt->sector_size; i++, l++) {
6dbe3af9
KZ
816 if (l == 0)
817 printf("0x%03X:", i);
be97c5f3 818 printf(" %02X", pbuffer[i]);
6dbe3af9
KZ
819 if (l == MAX_PER_LINE - 1) {
820 printf("\n");
821 l = -1;
822 }
823 }
824 if (l > 0)
825 printf("\n");
826 printf("\n");
827}
828
e53ced85
DB
829static void print_raw(struct fdisk_context *cxt)
830{
e3661531
KZ
831 size_t i;
832
833 assert(cxt);
834 assert(cxt->label);
6dbe3af9 835
e53ced85 836 printf(_("Device: %s\n"), cxt->dev_path);
ff5775bd
DB
837 if (fdisk_is_disklabel(cxt, SUN) ||
838 fdisk_is_disklabel(cxt, SGI) ||
839 fdisk_is_disklabel(cxt, GPT))
67987b47 840 print_buffer(cxt, cxt->firstsector);
e3661531
KZ
841
842 else for (i = 3; i < cxt->label->nparts_max; i++)
e53ced85 843 print_buffer(cxt, ptes[i].sectorbuffer);
6dbe3af9
KZ
844}
845
823f0fd1 846static void __attribute__ ((__noreturn__)) handle_quit(struct fdisk_context *cxt)
365f01fc 847{
823f0fd1 848 fdisk_free_context(cxt);
365f01fc
DB
849 printf("\n");
850 exit(EXIT_SUCCESS);
851}
852
22853e4a 853static void
7737f698 854expert_command_prompt(struct fdisk_context *cxt)
e97a991a 855{
22853e4a
KZ
856 char c;
857
e3661531
KZ
858 assert(cxt);
859
6dbe3af9 860 while(1) {
e3661531
KZ
861 assert(cxt->label);
862
6dbe3af9 863 putchar('\n');
bddd84e7 864 c = tolower(read_char(cxt, _("Expert command (m for help): ")));
22853e4a 865 switch (c) {
2b6fc908 866 case 'a':
ff5775bd 867 if (fdisk_is_disklabel(cxt, SUN))
2b0bc17b 868 fdisk_sun_set_alt_cyl(cxt);
2b6fc908 869 break;
2b6fc908 870 case 'b':
ff5775bd 871 if (fdisk_is_disklabel(cxt, DOS))
e3661531
KZ
872 dos_move_begin(cxt, get_partition(cxt, 0,
873 cxt->label->nparts_max));
2b6fc908
KZ
874 break;
875 case 'c':
cf3808e4 876 user_cylinders = read_int(cxt, 1, cxt->geom.cylinders, 1048576, 0,
22853e4a 877 _("Number of cylinders"));
aa42788d 878 fdisk_override_geometry(cxt, user_cylinders, user_heads, user_sectors);
ff5775bd 879 if (fdisk_is_disklabel(cxt, SUN))
2b0bc17b 880 fdisk_sun_set_ncyl(cxt, cxt->geom.cylinders);
2b6fc908
KZ
881 break;
882 case 'd':
e53ced85 883 print_raw(cxt);
2b6fc908
KZ
884 break;
885 case 'e':
ff5775bd 886 if (fdisk_is_disklabel(cxt, SGI))
5c36a0eb 887 sgi_set_xcyl();
ff5775bd 888 else if (fdisk_is_disklabel(cxt, SUN))
2b0bc17b 889 fdisk_sun_set_xcyl(cxt);
a2c5f3ca 890 else
ff5775bd 891 if (fdisk_is_disklabel(cxt, DOS))
5dfca634 892 dos_list_table_expert(cxt, 1);
5c36a0eb 893 break;
22853e4a 894 case 'f':
ff5775bd 895 if (fdisk_is_disklabel(cxt, DOS))
e3661531 896 dos_fix_partition_table_order(cxt);
22853e4a 897 break;
5c36a0eb 898 case 'g':
de3d6c93 899 fdisk_create_disklabel(cxt, "sgi");
2b6fc908
KZ
900 break;
901 case 'h':
cf3808e4 902 user_heads = read_int(cxt, 1, cxt->geom.heads, 256, 0,
7eda085c 903 _("Number of heads"));
aa42788d 904 fdisk_override_geometry(cxt, user_cylinders, user_heads, user_sectors);
2b6fc908 905 break;
2b6fc908 906 case 'i':
ff5775bd 907 if (fdisk_is_disklabel(cxt, SUN))
2b0bc17b 908 fdisk_sun_set_ilfact(cxt);
ff5775bd 909 else if (fdisk_is_disklabel(cxt, DOS))
38b36353 910 dos_set_mbr_id(cxt);
2b6fc908
KZ
911 break;
912 case 'o':
ff5775bd 913 if (fdisk_is_disklabel(cxt, SUN))
2b0bc17b 914 fdisk_sun_set_rspeed(cxt);
2b6fc908 915 break;
2b6fc908 916 case 'p':
ff5775bd 917 if (fdisk_is_disklabel(cxt, SUN))
7737f698 918 list_table(cxt, 1);
2b6fc908 919 else
5dfca634 920 dos_list_table_expert(cxt, 0);
2b6fc908
KZ
921 break;
922 case 'q':
823f0fd1 923 handle_quit(cxt);
2b6fc908
KZ
924 case 'r':
925 return;
926 case 's':
cf3808e4 927 user_sectors = read_int(cxt, 1, cxt->geom.sectors, 63, 0,
7eda085c 928 _("Number of sectors"));
852ce62b 929 if (is_dos_compatible(cxt))
7eda085c 930 fprintf(stderr, _("Warning: setting "
2b6fc908 931 "sector offset for DOS "
6a95c736 932 "compatibility\n"));
aa42788d 933 fdisk_override_geometry(cxt, user_cylinders, user_heads, user_sectors);
2b6fc908
KZ
934 break;
935 case 'v':
e53ced85 936 verify(cxt);
2b6fc908
KZ
937 break;
938 case 'w':
d8de0955 939 write_table(cxt);
2b6fc908 940 break;
2b6fc908 941 case 'y':
ff5775bd 942 if (fdisk_is_disklabel(cxt, SUN))
2b0bc17b 943 fdisk_sun_set_pcylcount(cxt);
2b6fc908 944 break;
2b6fc908 945 default:
ff5775bd 946 print_menu(cxt, EXPERT_MENU);
6dbe3af9
KZ
947 }
948 }
949}
950
3b622ddd
DB
951static int is_ide_cdrom_or_tape(char *device)
952{
953 int fd, ret;
2b6fc908 954
1c6b3378 955 if ((fd = open(device, O_RDONLY)) < 0)
e8f26419 956 return 0;
3b622ddd 957 ret = blkdev_is_cdrom(fd);
2b6fc908 958
3b622ddd
DB
959 close(fd);
960 return ret;
2b6fc908
KZ
961}
962
ea4824f1 963/* Print disk geometry and partition table of a specified device (-l option) */
4e0e8253
KZ
964static void print_partition_table_from_option(struct fdisk_context *cxt,
965 char *device, unsigned long sector_size)
e27b42d5 966{
4e0e8253 967 if (fdisk_context_assign_device(cxt, device, 1) != 0) /* read-only */
289dcc90 968 err(EXIT_FAILURE, _("cannot open %s"), device);
823f0fd1 969
759d093f 970 if (sector_size) /* passed -b option, override autodiscovery */
aa42788d 971 fdisk_override_sector_size(cxt, sector_size);
759d093f 972
9a5e29e9 973 if (user_cylinders || user_heads || user_sectors)
aa42788d 974 fdisk_override_geometry(cxt, user_cylinders,
759d093f 975 user_heads, user_sectors);
84e18f76
KZ
976
977 if (!fdisk_dev_has_disklabel(cxt)) {
978 /*
979 * Try BSD -- TODO: move to list_table() too
980 */
7737f698 981 list_disk_geometry(cxt);
ff5775bd
DB
982 if (!fdisk_is_disklabel(cxt, AIX) &&
983 !fdisk_is_disklabel(cxt, MAC))
7737f698 984 btrydev(cxt);
ff5775bd 985 } else
7737f698 986 list_table(cxt, 0);
6dbe3af9
KZ
987}
988
c129767e
KZ
989/*
990 * for fdisk -l:
991 * try all things in /proc/partitions that look like a full disk
992 */
22853e4a 993static void
4e0e8253
KZ
994print_all_partition_table_from_option(struct fdisk_context *cxt,
995 unsigned long sector_size)
ea4824f1 996{
eb63b9b8 997 FILE *procpt;
657d9adb 998 char line[128 + 1], ptname[128 + 1], devname[256];
981b80b7
KZ
999 int ma, mi;
1000 unsigned long long sz;
eb63b9b8 1001
6bec8710 1002 procpt = fopen(_PATH_PROC_PARTITIONS, "r");
eb63b9b8 1003 if (procpt == NULL) {
6bec8710 1004 fprintf(stderr, _("cannot open %s\n"), _PATH_PROC_PARTITIONS);
eb63b9b8
KZ
1005 return;
1006 }
1007
1008 while (fgets(line, sizeof(line), procpt)) {
bb662090 1009 if (sscanf (line, " %d %d %llu %128[^\n ]",
eb63b9b8
KZ
1010 &ma, &mi, &sz, ptname) != 4)
1011 continue;
c07ebfa1 1012 snprintf(devname, sizeof(devname), "/dev/%s", ptname);
6bec8710
KZ
1013 if (is_whole_disk(devname)) {
1014 char *cn = canonicalize_path(devname);
1015 if (cn) {
0c48d371 1016 if (!is_ide_cdrom_or_tape(cn))
4e0e8253 1017 print_partition_table_from_option(cxt, cn, sector_size);
6bec8710
KZ
1018 free(cn);
1019 }
1020 }
eb63b9b8 1021 }
e8f26419 1022 fclose(procpt);
eb63b9b8
KZ
1023}
1024
22853e4a
KZ
1025static void
1026unknown_command(int c) {
1027 printf(_("%c: unknown command\n"), c);
7eda085c
KZ
1028}
1029
89fd812f
DB
1030static void print_welcome(void)
1031{
1032 printf(_("Welcome to fdisk (%s).\n\n"
1033 "Changes will remain in memory only, until you decide to write them.\n"
1034 "Be careful before using the write command.\n\n"), PACKAGE_STRING);
1035
1036 fflush(stdout);
1037}
1038
7737f698 1039static void command_prompt(struct fdisk_context *cxt)
56c07b96 1040{
4a96a62a 1041 int c;
5dbff4c0 1042
e3661531
KZ
1043 assert(cxt);
1044
ff5775bd 1045 if (fdisk_is_disklabel(cxt, OSF)) {
56c07b96
FC
1046 putchar('\n');
1047 /* OSF label, and no DOS label */
1048 printf(_("Detected an OSF/1 disklabel on %s, entering "
1049 "disklabel mode.\n"),
823f0fd1 1050 cxt->dev_path);
7737f698 1051 bsd_command_prompt(cxt);
53b422ab 1052
56c07b96 1053 /* If we return we may want to make an empty DOS label? */
53b422ab 1054 fdisk_context_switch_label(cxt, "dos");
56c07b96
FC
1055 }
1056
1057 while (1) {
e3661531
KZ
1058
1059 assert(cxt->label);
1060
56c07b96 1061 putchar('\n');
bddd84e7 1062 c = tolower(read_char(cxt, _("Command (m for help): ")));
56c07b96
FC
1063 switch (c) {
1064 case 'a':
ff5775bd 1065 if (fdisk_is_disklabel(cxt, DOS))
fb1caca7
KZ
1066 fdisk_partition_toggle_flag(cxt,
1067 get_partition(cxt, 1, cxt->label->nparts_max),
1068 DOS_FLAG_ACTIVE);
ff5775bd 1069 else if (fdisk_is_disklabel(cxt, SUN))
fb1caca7 1070 fdisk_partition_toggle_flag(cxt,
e3661531
KZ
1071 get_partition(cxt, 1, cxt->label->nparts_max),
1072 SUN_FLAG_UNMNT);
ff5775bd 1073 else if (fdisk_is_disklabel(cxt, SGI))
fb1caca7
KZ
1074 fdisk_partition_toggle_flag(cxt,
1075 get_partition(cxt, 1, cxt->label->nparts_max),
1076 SGI_FLAG_BOOT);
56c07b96
FC
1077 else
1078 unknown_command(c);
1079 break;
1080 case 'b':
53b422ab
KZ
1081 /*
1082 * TODO: create child context for nexted partition tables
1083 */
ff5775bd 1084 if (fdisk_is_disklabel(cxt, SGI))
38b36353 1085 sgi_set_bootfile(cxt);
ff5775bd 1086 else if (fdisk_is_disklabel(cxt, DOS)) {
e09435aa
KZ
1087
1088 struct fdisk_context *bsd;
1089
1090 bsd = fdisk_new_nested_context(cxt, "bsd");
1091 if (bsd)
1092 bsd_command_prompt(bsd);
1093 fdisk_free_context(bsd);
c482303e
FC
1094 } else
1095 unknown_command(c);
56c07b96
FC
1096 break;
1097 case 'c':
ff5775bd 1098 if (fdisk_is_disklabel(cxt, DOS))
e53ced85 1099 toggle_dos_compatibility_flag(cxt);
ff5775bd 1100 else if (fdisk_is_disklabel(cxt, SUN))
fb1caca7 1101 fdisk_partition_toggle_flag(cxt,
e3661531
KZ
1102 get_partition(cxt, 1, cxt->label->nparts_max),
1103 SUN_FLAG_RONLY);
ff5775bd 1104 else if (fdisk_is_disklabel(cxt, SGI))
fb1caca7
KZ
1105 fdisk_partition_toggle_flag(cxt,
1106 get_partition(cxt, 1, cxt->label->nparts_max),
1107 SGI_FLAG_SWAP);
56c07b96
FC
1108 else
1109 unknown_command(c);
1110 break;
1111 case 'd':
e3661531
KZ
1112 delete_partition(cxt,
1113 get_existing_partition(cxt, 1, cxt->label->nparts_max));
56c07b96 1114 break;
3f731001
DB
1115 case 'g':
1116 fdisk_create_disklabel(cxt, "gpt");
1117 break;
7375423c
KZ
1118 case 'G':
1119 fdisk_create_disklabel(cxt, "sgi");
1120 break;
56c07b96 1121 case 'i':
ff5775bd 1122 if (fdisk_is_disklabel(cxt, SGI))
38b36353 1123 create_sgiinfo(cxt);
56c07b96
FC
1124 else
1125 unknown_command(c);
099c7a94 1126 break;
56c07b96 1127 case 'l':
7b575fcc 1128 list_partition_types(cxt);
56c07b96
FC
1129 break;
1130 case 'm':
ff5775bd 1131 print_menu(cxt, MAIN_MENU);
56c07b96
FC
1132 break;
1133 case 'n':
e53ced85 1134 new_partition(cxt);
56c07b96
FC
1135 break;
1136 case 'o':
de3d6c93 1137 fdisk_create_disklabel(cxt, "dos");
56c07b96
FC
1138 break;
1139 case 'p':
7737f698 1140 list_table(cxt, 0);
56c07b96
FC
1141 break;
1142 case 'q':
823f0fd1 1143 handle_quit(cxt);
56c07b96 1144 case 's':
de3d6c93 1145 fdisk_create_disklabel(cxt, "sun");
56c07b96
FC
1146 break;
1147 case 't':
02460b8a 1148 change_partition_type(cxt);
56c07b96
FC
1149 break;
1150 case 'u':
ec10aa67 1151 toggle_units(cxt);
56c07b96
FC
1152 break;
1153 case 'v':
e53ced85 1154 verify(cxt);
56c07b96
FC
1155 break;
1156 case 'w':
d8de0955 1157 write_table(cxt);
56c07b96
FC
1158 break;
1159 case 'x':
7737f698 1160 expert_command_prompt(cxt);
56c07b96
FC
1161 break;
1162 default:
1163 unknown_command(c);
ff5775bd 1164 print_menu(cxt, MAIN_MENU);
56c07b96
FC
1165 }
1166 }
1167}
5dbff4c0 1168
50dec1eb 1169static sector_t get_dev_blocks(char *dev)
6da365de
DB
1170{
1171 int fd;
50dec1eb 1172 sector_t size;
6da365de
DB
1173
1174 if ((fd = open(dev, O_RDONLY)) < 0)
289dcc90 1175 err(EXIT_FAILURE, _("cannot open %s"), dev);
7737f698
DB
1176 if (blkdev_get_sectors(fd, &size) == -1) {
1177 close(fd);
1178 err(EXIT_FAILURE, _("BLKGETSIZE ioctl failed on %s"), dev);
1179 }
6da365de
DB
1180 close(fd);
1181 return size/2;
1182}
1183
e1144767
DB
1184int main(int argc, char **argv)
1185{
6da365de 1186 int c, optl = 0, opts = 0;
e53ced85 1187 unsigned long sector_size = 0;
4e0e8253 1188 struct fdisk_context *cxt;
852ce62b 1189 struct fdisk_label *lb;
2b6fc908 1190
7eda085c
KZ
1191 setlocale(LC_ALL, "");
1192 bindtextdomain(PACKAGE, LOCALEDIR);
1193 textdomain(PACKAGE);
b2d28533 1194 atexit(close_stdout);
2b6fc908 1195
4e0e8253
KZ
1196 fdisk_init_debug(0);
1197 cxt = fdisk_new_context();
1198 if (!cxt)
1199 err(EXIT_FAILURE, _("failed to allocate libfdisk context"));
1200
416c43a9
KZ
1201 fdisk_context_set_ask(cxt, ask_callback, NULL);
1202
278f63c0 1203 while ((c = getopt(argc, argv, "b:c::C:hH:lsS:u::vV")) != -1) {
2b6fc908
KZ
1204 switch (c) {
1205 case 'b':
0e6f4a20
KZ
1206 /* Ugly: this sector size is really per device,
1207 so cannot be combined with multiple disks,
1208 and te same goes for the C/H/S options.
1209 */
00695059 1210 sector_size = strtou32_or_err(optarg, _("invalid sector size argument"));
5c36a0eb 1211 if (sector_size != 512 && sector_size != 1024 &&
8905beda 1212 sector_size != 2048 && sector_size != 4096)
7c1db6b4 1213 usage(stderr);
2b6fc908 1214 break;
0e6f4a20 1215 case 'C':
00695059 1216 user_cylinders = strtou32_or_err(optarg, _("invalid cylinders argument"));
0e6f4a20 1217 break;
78498b7b 1218 case 'c':
852ce62b 1219 if (optarg) {
2b0bc17b
KZ
1220 /* this setting is independent on the current
1221 * actively used label */
852ce62b
KZ
1222 lb = fdisk_context_get_label(cxt, "dos");
1223 if (!lb)
1224 err(EXIT_FAILURE, _("not found DOS label driver"));
1225 if (strcmp(optarg, "=dos") == 0)
1226 fdisk_dos_enable_compatible(lb, TRUE);
1227 else if (strcmp(optarg, "=nondos") == 0)
1228 fdisk_dos_enable_compatible(lb, FALSE);
1229 else
1230 usage(stderr);
1231 }
1232 /* use default if no optarg specified */
78498b7b 1233 break;
0e6f4a20 1234 case 'H':
00695059
KZ
1235 user_heads = strtou32_or_err(optarg, _("invalid heads argument"));
1236 if (user_heads > 256)
0e6f4a20
KZ
1237 user_heads = 0;
1238 break;
1239 case 'S':
00695059
KZ
1240 user_sectors = strtou32_or_err(optarg, _("invalid sectors argument"));
1241 if (user_sectors >= 64)
0e6f4a20
KZ
1242 user_sectors = 0;
1243 break;
2b6fc908
KZ
1244 case 'l':
1245 optl = 1;
1246 break;
1247 case 's':
1248 opts = 1;
1249 break;
1250 case 'u':
ec10aa67
KZ
1251 if (optarg && *optarg == '=')
1252 optarg++;
1253 if (fdisk_context_set_unit(cxt, optarg) != 0)
7c1db6b4 1254 usage(stderr);
2b6fc908 1255 break;
22853e4a 1256 case 'V':
2b6fc908 1257 case 'v':
a2482eb3
DB
1258 printf(UTIL_LINUX_VERSION);
1259 return EXIT_SUCCESS;
e1144767
DB
1260 case 'h':
1261 usage(stdout);
2b6fc908 1262 default:
7c1db6b4 1263 usage(stderr);
2b6fc908 1264 }
6dbe3af9 1265 }
2b6fc908 1266
f7b1f75e 1267
14e93ff3 1268 if (sector_size && argc-optind != 1)
7eda085c
KZ
1269 printf(_("Warning: the -b (set sector size) option should"
1270 " be used with one specified device\n"));
7eda085c 1271
2b6fc908 1272 if (optl) {
2b6fc908 1273 nowarn = 1;
2b6fc908
KZ
1274 if (argc > optind) {
1275 int k;
c129767e 1276 for (k = optind; k < argc; k++)
4e0e8253 1277 print_partition_table_from_option(cxt, argv[k], sector_size);
ea4824f1 1278 } else
4e0e8253 1279 print_all_partition_table_from_option(cxt, sector_size);
3e3de41a 1280 exit(EXIT_SUCCESS);
2b6fc908
KZ
1281 }
1282
1283 if (opts) {
6da365de
DB
1284 /* print partition size for one or more devices */
1285 int i, ndevs = argc - optind;
1286 if (ndevs <= 0)
7c1db6b4 1287 usage(stderr);
2b6fc908 1288
6da365de
DB
1289 for (i = optind; i < argc; i++) {
1290 if (ndevs == 1)
1291 printf("%llu\n", get_dev_blocks(argv[i]));
2b6fc908 1292 else
6da365de 1293 printf("%s: %llu\n", argv[i], get_dev_blocks(argv[i]));
6dbe3af9 1294 }
6da365de 1295 exit(EXIT_SUCCESS);
6dbe3af9 1296 }
6dbe3af9 1297
7d2ba340 1298 if (argc-optind != 1)
7c1db6b4 1299 usage(stderr);
7eda085c 1300
4e0e8253 1301 if (fdisk_context_assign_device(cxt, argv[optind], 0) != 0)
289dcc90 1302 err(EXIT_FAILURE, _("cannot open %s"), argv[optind]);
759d093f 1303
7d2ba340 1304 if (sector_size) /* passed -b option, override autodiscovery */
aa42788d 1305 fdisk_override_sector_size(cxt, sector_size);
759d093f 1306
9a5e29e9 1307 if (user_cylinders || user_heads || user_sectors)
aa42788d 1308 fdisk_override_geometry(cxt, user_cylinders,
9a5e29e9 1309 user_heads, user_sectors);
7d2ba340 1310
89fd812f 1311 print_welcome();
56c07b96 1312
a71601af
KZ
1313 if (!fdisk_dev_has_disklabel(cxt)) {
1314 fprintf(stderr,
1315 _("Device does not contain a recognized partition table\n"));
639f1d56 1316 fdisk_create_disklabel(cxt, NULL);
a71601af 1317 }
6dbe3af9 1318
7737f698 1319 command_prompt(cxt);
9777759a 1320
4e0e8253 1321 fdisk_free_context(cxt);
5c36a0eb 1322 return 0;
6dbe3af9 1323}