]>
Commit | Line | Data |
---|---|---|
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 | ||
54 | struct 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 | ||
60 | static 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 | 110 | sector_t get_nr_sects(struct partition *p) { |
2b6fc908 KZ |
111 | return read4_little_endian(p->size4); |
112 | } | |
113 | ||
823f0fd1 | 114 | char *line_ptr, /* interactive input */ |
22853e4a | 115 | line_buffer[LINE_LENGTH]; |
6dbe3af9 | 116 | |
e3661531 | 117 | int nowarn = 0; /* no warnings for fdisk -l/-s */ |
6dbe3af9 | 118 | |
df1dddf9 | 119 | unsigned int user_cylinders, user_heads, user_sectors; |
365acc97 | 120 | |
ec10aa67 KZ |
121 | void 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 |
133 | static 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 |
152 | void __attribute__((__noreturn__)) |
153 | fatal(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 |
174 | struct partition * |
175 | get_part_table(int i) { | |
176 | return ptes[i].part_table; | |
177 | } | |
178 | ||
ff5775bd | 179 | void 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 | 193 | void 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 |
251 | static int |
252 | test_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 | 264 | int 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 | 285 | void 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 | 304 | static 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 | } | |
324 | leave: | |
325 | fdisk_free_context(cxt); | |
326 | exit(rc); | |
aead9d13 FC |
327 | } |
328 | ||
5c36a0eb | 329 | /* read line; return 0 or first char */ |
bddd84e7 | 330 | int 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 | 344 | char 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 | 355 | char 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 | 372 | struct 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 | 400 | unsigned int |
e53ced85 DB |
401 | read_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 | */ | |
537 | unsigned int | |
e53ced85 DB |
538 | read_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 | 545 | int |
e53ced85 | 546 | get_partition_dflt(struct fdisk_context *cxt, int warn, int max, int dflt) { |
22853e4a KZ |
547 | struct pte *pe; |
548 | int i; | |
549 | ||
e53ced85 | 550 | i = read_int(cxt, 1, dflt, max, 0, _("Partition number")) - 1; |
22853e4a | 551 | pe = &ptes[i]; |
6dbe3af9 | 552 | |
ff5775bd DB |
553 | if (warn && !fdisk_is_disklabel(cxt, GPT)) { |
554 | if ((!fdisk_is_disklabel(cxt, SUN) && | |
555 | !fdisk_is_disklabel(cxt, SGI) && !pe->part_table->sys_ind) | |
556 | || (fdisk_is_disklabel(cxt, SUN) && | |
d6ab93f1 | 557 | sun_is_empty_type(cxt, i)) |
ff5775bd DB |
558 | || (fdisk_is_disklabel(cxt, SGI) && |
559 | (!sgi_get_num_sectors(cxt, i)))) | |
24f4bbff KZ |
560 | fprintf(stderr, |
561 | _("Warning: partition %d has empty type\n"), | |
562 | i+1); | |
563 | } | |
6dbe3af9 KZ |
564 | return i; |
565 | } | |
566 | ||
147e1e73 | 567 | int |
e53ced85 DB |
568 | get_partition(struct fdisk_context *cxt, int warn, int max) { |
569 | return get_partition_dflt(cxt, warn, max, 0); | |
147e1e73 KZ |
570 | } |
571 | ||
b152082d FC |
572 | /* User partition selection unless one partition only is available */ |
573 | ||
24f4bbff | 574 | static int |
e53ced85 | 575 | get_existing_partition(struct fdisk_context *cxt, int warn, int max) { |
24f4bbff KZ |
576 | int pno = -1; |
577 | int i; | |
578 | ||
ff5775bd | 579 | if (!fdisk_is_disklabel(cxt, DOS)) |
b152082d FC |
580 | goto not_implemented; |
581 | ||
24f4bbff KZ |
582 | for (i = 0; i < max; i++) { |
583 | struct pte *pe = &ptes[i]; | |
584 | struct partition *p = pe->part_table; | |
585 | ||
586 | if (p && !is_cleared_partition(p)) { | |
587 | if (pno >= 0) | |
588 | goto not_unique; | |
589 | pno = i; | |
590 | } | |
591 | } | |
365acc97 | 592 | |
24f4bbff KZ |
593 | if (pno >= 0) { |
594 | printf(_("Selected partition %d\n"), pno+1); | |
595 | return pno; | |
596 | } | |
597 | printf(_("No partition is defined yet!\n")); | |
598 | return -1; | |
599 | ||
b152082d FC |
600 | not_implemented: |
601 | not_unique: | |
e53ced85 | 602 | return get_partition(cxt, warn, max); |
24f4bbff KZ |
603 | } |
604 | ||
852ce62b KZ |
605 | static void toggle_dos_compatibility_flag(struct fdisk_context *cxt) |
606 | { | |
607 | struct fdisk_label *lb = fdisk_context_get_label(cxt, "dos"); | |
608 | int flag; | |
609 | ||
610 | if (!lb) | |
611 | return; | |
612 | ||
613 | flag = !fdisk_dos_is_compatible(lb); | |
614 | ||
615 | if (flag) | |
278f63c0 | 616 | printf(_("DOS Compatibility flag is set (DEPRECATED!)\n")); |
edd7b958 | 617 | else |
7eda085c | 618 | printf(_("DOS Compatibility flag is not set\n")); |
edd7b958 | 619 | |
852ce62b KZ |
620 | fdisk_dos_enable_compatible(lb, flag); |
621 | ||
622 | if (fdisk_is_disklabel(cxt, DOS)) | |
623 | fdisk_reset_alignment(cxt); | |
6dbe3af9 KZ |
624 | } |
625 | ||
61c4cb85 | 626 | static void delete_partition(struct fdisk_context *cxt, int partnum) |
47104bae | 627 | { |
61c4cb85 | 628 | if (partnum < 0 || warn_geometry(cxt)) |
4a96a62a FC |
629 | return; |
630 | ||
61c4cb85 | 631 | ptes[partnum].changed = 1; |
1f5eb51b DB |
632 | if (fdisk_delete_partition(cxt, partnum) != 0) |
633 | printf(_("Could not delete partition %d\n"), partnum + 1); | |
634 | else | |
635 | printf(_("Partition %d is deleted\n"), partnum + 1); | |
6dbe3af9 KZ |
636 | } |
637 | ||
02460b8a | 638 | static void change_partition_type(struct fdisk_context *cxt) |
e53ced85 | 639 | { |
559d921e KZ |
640 | int i; |
641 | struct fdisk_parttype *t, *org_t; | |
6dbe3af9 | 642 | |
e3661531 KZ |
643 | assert(cxt); |
644 | assert(cxt->label); | |
645 | ||
646 | i = get_existing_partition(cxt, 0, cxt->label->nparts_max); | |
24f4bbff KZ |
647 | if (i == -1) |
648 | return; | |
2b6fc908 | 649 | |
010186f2 KZ |
650 | org_t = t = fdisk_get_partition_type(cxt, i); |
651 | if (!t) | |
7eda085c | 652 | printf(_("Partition %d does not exist yet!\n"), i + 1); |
010186f2 | 653 | |
02460b8a | 654 | else do { |
559d921e | 655 | t = read_partition_type(cxt); |
559d921e KZ |
656 | if (!t) |
657 | continue; | |
658 | ||
02460b8a KZ |
659 | if (fdisk_set_partition_type(cxt, i, t) == 0) { |
660 | ptes[i].changed = 1; | |
661 | printf (_("Changed type of partition '%s' to '%s'\n"), | |
662 | org_t ? org_t->name : _("Unknown"), | |
663 | t ? t->name : _("Unknown")); | |
664 | } else { | |
665 | printf (_("Type of partition %d is unchanged: %s\n"), | |
666 | i + 1, | |
667 | org_t ? org_t->name : _("Unknown")); | |
6dbe3af9 | 668 | } |
02460b8a KZ |
669 | break; |
670 | } while (1); | |
559d921e KZ |
671 | |
672 | fdisk_free_parttype(t); | |
673 | fdisk_free_parttype(org_t); | |
6dbe3af9 KZ |
674 | } |
675 | ||
22853e4a | 676 | static void |
7737f698 | 677 | list_disk_geometry(struct fdisk_context *cxt) { |
618882d6 | 678 | unsigned long long bytes = cxt->total_sectors * cxt->sector_size; |
24f4bbff KZ |
679 | long megabytes = bytes/1000000; |
680 | ||
681 | if (megabytes < 10000) | |
f8527f4b | 682 | printf(_("\nDisk %s: %ld MB, %lld bytes"), |
823f0fd1 | 683 | cxt->dev_path, megabytes, bytes); |
32b40fec KZ |
684 | else { |
685 | long hectomega = (megabytes + 50) / 100; | |
f8527f4b | 686 | printf(_("\nDisk %s: %ld.%ld GB, %llu bytes"), |
823f0fd1 | 687 | cxt->dev_path, hectomega / 10, hectomega % 10, bytes); |
32b40fec | 688 | } |
f8527f4b | 689 | printf(_(", %llu sectors\n"), cxt->total_sectors); |
852ce62b | 690 | if (is_dos_compatible(cxt)) |
a7a6f7d2 PU |
691 | printf(_("%d heads, %llu sectors/track, %llu cylinders\n"), |
692 | cxt->geom.heads, cxt->geom.sectors, cxt->geom.cylinders); | |
e53ced85 | 693 | printf(_("Units = %s of %d * %ld = %ld bytes\n"), |
ec10aa67 KZ |
694 | fdisk_context_get_unit(cxt, PLURAL), |
695 | fdisk_context_get_units_per_sector(cxt), | |
696 | cxt->sector_size, | |
697 | fdisk_context_get_units_per_sector(cxt) * cxt->sector_size); | |
05dc9645 | 698 | |
e53ced85 DB |
699 | printf(_("Sector size (logical/physical): %lu bytes / %lu bytes\n"), |
700 | cxt->sector_size, cxt->phy_sector_size); | |
a8a86a1c | 701 | printf(_("I/O size (minimum/optimal): %lu bytes / %lu bytes\n"), |
e53ced85 DB |
702 | cxt->min_io_size, cxt->io_size); |
703 | if (cxt->alignment_offset) | |
704 | printf(_("Alignment offset: %lu bytes\n"), cxt->alignment_offset); | |
b546d442 KZ |
705 | if (fdisk_dev_has_disklabel(cxt)) |
706 | printf(_("Disk label type: %s\n"), cxt->label->name); | |
ff5775bd | 707 | if (fdisk_is_disklabel(cxt, DOS)) |
38b36353 | 708 | dos_print_mbr_id(cxt); |
bb6aacfe | 709 | printf("\n"); |
5c36a0eb KZ |
710 | } |
711 | ||
766d5156 DB |
712 | static void list_table(struct fdisk_context *cxt, int xtra) |
713 | { | |
ff5775bd | 714 | if (fdisk_is_disklabel(cxt, SUN)) { |
7737f698 | 715 | sun_list_table(cxt, xtra); |
5c36a0eb KZ |
716 | return; |
717 | } | |
718 | ||
ff5775bd | 719 | if (fdisk_is_disklabel(cxt, SGI)) { |
7737f698 | 720 | sgi_list_table(cxt, xtra); |
5c36a0eb KZ |
721 | return; |
722 | } | |
2b6fc908 | 723 | |
7737f698 | 724 | list_disk_geometry(cxt); |
22853e4a | 725 | |
ff5775bd | 726 | if (fdisk_is_disklabel(cxt, GPT)) { |
766d5156 DB |
727 | gpt_list_table(cxt, xtra); |
728 | return; | |
729 | } | |
730 | ||
ff5775bd | 731 | if (fdisk_is_disklabel(cxt, OSF)) { |
7737f698 | 732 | xbsd_print_disklabel(cxt, xtra); |
22853e4a KZ |
733 | return; |
734 | } | |
735 | ||
6d864a49 KZ |
736 | if (fdisk_is_disklabel(cxt, DOS)) |
737 | dos_list_table(cxt, xtra); | |
6dbe3af9 KZ |
738 | } |
739 | ||
2ca61a61 DB |
740 | static void verify(struct fdisk_context *cxt) |
741 | { | |
24cd580b | 742 | if (warn_geometry(cxt)) |
6dbe3af9 KZ |
743 | return; |
744 | ||
2ca61a61 | 745 | fdisk_verify_disklabel(cxt); |
6dbe3af9 KZ |
746 | } |
747 | ||
e53ced85 DB |
748 | void print_partition_size(struct fdisk_context *cxt, |
749 | int num, sector_t start, sector_t stop, int sysid) | |
20aa2570 FC |
750 | { |
751 | char *str = size_to_human_string(SIZE_SUFFIX_3LETTER | SIZE_SUFFIX_SPACE, | |
7e6e9c70 | 752 | (uint64_t)(stop - start + 1) * cxt->sector_size); |
559d921e KZ |
753 | struct fdisk_parttype *t = fdisk_get_parttype_from_code(cxt, sysid); |
754 | ||
755 | printf(_("Partition %d of type %s and of size %s is set\n"), | |
756 | num, t ? t->name : _("Unknown"), str); | |
20aa2570 FC |
757 | free(str); |
758 | } | |
759 | ||
e53ced85 | 760 | static void new_partition(struct fdisk_context *cxt) |
9dea2923 | 761 | { |
9fcd49d5 KZ |
762 | assert(cxt); |
763 | assert(cxt->label); | |
764 | ||
0f639e54 | 765 | if (warn_geometry(cxt)) |
e8f26419 | 766 | return; |
e8f26419 | 767 | |
416c43a9 | 768 | fdisk_add_partition(cxt, NULL); |
6dbe3af9 KZ |
769 | } |
770 | ||
fae7b1bc DB |
771 | static void write_table(struct fdisk_context *cxt) |
772 | { | |
773 | int rc; | |
6dbe3af9 | 774 | |
fae7b1bc DB |
775 | rc = fdisk_write_disklabel(cxt); |
776 | if (rc) | |
777 | err(EXIT_FAILURE, _("cannot write disk label")); | |
6dbe3af9 | 778 | |
7eda085c | 779 | printf(_("The partition table has been altered!\n\n")); |
7737f698 | 780 | reread_partition_table(cxt, 1); |
eb63b9b8 KZ |
781 | } |
782 | ||
783 | void | |
7737f698 | 784 | reread_partition_table(struct fdisk_context *cxt, int leave) { |
eb63b9b8 | 785 | int i; |
edd867fa | 786 | struct stat statbuf; |
6dbe3af9 | 787 | |
823f0fd1 | 788 | i = fstat(cxt->dev_fd, &statbuf); |
edd867fa | 789 | if (i == 0 && S_ISBLK(statbuf.st_mode)) { |
edd867fa | 790 | sync(); |
6b0054a2 ST |
791 | #ifdef BLKRRPART |
792 | printf(_("Calling ioctl() to re-read partition table.\n")); | |
823f0fd1 | 793 | i = ioctl(cxt->dev_fd, BLKRRPART); |
6b0054a2 ST |
794 | #else |
795 | errno = ENOSYS; | |
796 | i = 1; | |
797 | #endif | |
726f69e2 KZ |
798 | } |
799 | ||
e8f26419 | 800 | if (i) { |
960cf573 | 801 | printf(_("\nWARNING: Re-reading the partition table failed with error %d: %m.\n" |
c64061c9 VD |
802 | "The kernel still uses the old table. The new table will be used at\n" |
803 | "the next reboot or after you run partprobe(8) or kpartx(8)\n"), | |
960cf573 | 804 | errno); |
e8f26419 | 805 | } |
6dbe3af9 | 806 | |
eb63b9b8 | 807 | if (leave) { |
823f0fd1 | 808 | if (fsync(cxt->dev_fd) || close(cxt->dev_fd)) { |
a47f2e66 KZ |
809 | fprintf(stderr, _("\nError closing file\n")); |
810 | exit(1); | |
811 | } | |
eb63b9b8 KZ |
812 | |
813 | printf(_("Syncing disks.\n")); | |
814 | sync(); | |
eb63b9b8 KZ |
815 | exit(!!i); |
816 | } | |
6dbe3af9 KZ |
817 | } |
818 | ||
819 | #define MAX_PER_LINE 16 | |
22853e4a | 820 | static void |
e53ced85 | 821 | print_buffer(struct fdisk_context *cxt, unsigned char pbuffer[]) { |
e99da659 | 822 | unsigned int i, l; |
6dbe3af9 | 823 | |
e53ced85 | 824 | for (i = 0, l = 0; i < cxt->sector_size; i++, l++) { |
6dbe3af9 KZ |
825 | if (l == 0) |
826 | printf("0x%03X:", i); | |
be97c5f3 | 827 | printf(" %02X", pbuffer[i]); |
6dbe3af9 KZ |
828 | if (l == MAX_PER_LINE - 1) { |
829 | printf("\n"); | |
830 | l = -1; | |
831 | } | |
832 | } | |
833 | if (l > 0) | |
834 | printf("\n"); | |
835 | printf("\n"); | |
836 | } | |
837 | ||
e53ced85 DB |
838 | static void print_raw(struct fdisk_context *cxt) |
839 | { | |
e3661531 KZ |
840 | size_t i; |
841 | ||
842 | assert(cxt); | |
843 | assert(cxt->label); | |
6dbe3af9 | 844 | |
e53ced85 | 845 | printf(_("Device: %s\n"), cxt->dev_path); |
ff5775bd DB |
846 | if (fdisk_is_disklabel(cxt, SUN) || |
847 | fdisk_is_disklabel(cxt, SGI) || | |
848 | fdisk_is_disklabel(cxt, GPT)) | |
67987b47 | 849 | print_buffer(cxt, cxt->firstsector); |
e3661531 KZ |
850 | |
851 | else for (i = 3; i < cxt->label->nparts_max; i++) | |
e53ced85 | 852 | print_buffer(cxt, ptes[i].sectorbuffer); |
6dbe3af9 KZ |
853 | } |
854 | ||
823f0fd1 | 855 | static void __attribute__ ((__noreturn__)) handle_quit(struct fdisk_context *cxt) |
365f01fc | 856 | { |
823f0fd1 | 857 | fdisk_free_context(cxt); |
365f01fc DB |
858 | printf("\n"); |
859 | exit(EXIT_SUCCESS); | |
860 | } | |
861 | ||
22853e4a | 862 | static void |
7737f698 | 863 | expert_command_prompt(struct fdisk_context *cxt) |
e97a991a | 864 | { |
22853e4a KZ |
865 | char c; |
866 | ||
e3661531 KZ |
867 | assert(cxt); |
868 | ||
6dbe3af9 | 869 | while(1) { |
e3661531 KZ |
870 | assert(cxt->label); |
871 | ||
6dbe3af9 | 872 | putchar('\n'); |
bddd84e7 | 873 | c = tolower(read_char(cxt, _("Expert command (m for help): "))); |
22853e4a | 874 | switch (c) { |
2b6fc908 | 875 | case 'a': |
ff5775bd | 876 | if (fdisk_is_disklabel(cxt, SUN)) |
e53ced85 | 877 | sun_set_alt_cyl(cxt); |
2b6fc908 | 878 | break; |
2b6fc908 | 879 | case 'b': |
ff5775bd | 880 | if (fdisk_is_disklabel(cxt, DOS)) |
e3661531 KZ |
881 | dos_move_begin(cxt, get_partition(cxt, 0, |
882 | cxt->label->nparts_max)); | |
2b6fc908 KZ |
883 | break; |
884 | case 'c': | |
cf3808e4 | 885 | user_cylinders = read_int(cxt, 1, cxt->geom.cylinders, 1048576, 0, |
22853e4a | 886 | _("Number of cylinders")); |
aa42788d | 887 | fdisk_override_geometry(cxt, user_cylinders, user_heads, user_sectors); |
ff5775bd | 888 | if (fdisk_is_disklabel(cxt, SUN)) |
24cd580b | 889 | sun_set_ncyl(cxt, cxt->geom.cylinders); |
2b6fc908 KZ |
890 | break; |
891 | case 'd': | |
e53ced85 | 892 | print_raw(cxt); |
2b6fc908 KZ |
893 | break; |
894 | case 'e': | |
ff5775bd | 895 | if (fdisk_is_disklabel(cxt, SGI)) |
5c36a0eb | 896 | sgi_set_xcyl(); |
ff5775bd | 897 | else if (fdisk_is_disklabel(cxt, SUN)) |
e53ced85 | 898 | sun_set_xcyl(cxt); |
a2c5f3ca | 899 | else |
ff5775bd | 900 | if (fdisk_is_disklabel(cxt, DOS)) |
5dfca634 | 901 | dos_list_table_expert(cxt, 1); |
5c36a0eb | 902 | break; |
22853e4a | 903 | case 'f': |
ff5775bd | 904 | if (fdisk_is_disklabel(cxt, DOS)) |
e3661531 | 905 | dos_fix_partition_table_order(cxt); |
22853e4a | 906 | break; |
5c36a0eb | 907 | case 'g': |
de3d6c93 | 908 | fdisk_create_disklabel(cxt, "sgi"); |
2b6fc908 KZ |
909 | break; |
910 | case 'h': | |
cf3808e4 | 911 | user_heads = read_int(cxt, 1, cxt->geom.heads, 256, 0, |
7eda085c | 912 | _("Number of heads")); |
aa42788d | 913 | fdisk_override_geometry(cxt, user_cylinders, user_heads, user_sectors); |
2b6fc908 | 914 | break; |
2b6fc908 | 915 | case 'i': |
ff5775bd | 916 | if (fdisk_is_disklabel(cxt, SUN)) |
e53ced85 | 917 | sun_set_ilfact(cxt); |
ff5775bd | 918 | else if (fdisk_is_disklabel(cxt, DOS)) |
38b36353 | 919 | dos_set_mbr_id(cxt); |
2b6fc908 KZ |
920 | break; |
921 | case 'o': | |
ff5775bd | 922 | if (fdisk_is_disklabel(cxt, SUN)) |
e53ced85 | 923 | sun_set_rspeed(cxt); |
2b6fc908 | 924 | break; |
2b6fc908 | 925 | case 'p': |
ff5775bd | 926 | if (fdisk_is_disklabel(cxt, SUN)) |
7737f698 | 927 | list_table(cxt, 1); |
2b6fc908 | 928 | else |
5dfca634 | 929 | dos_list_table_expert(cxt, 0); |
2b6fc908 KZ |
930 | break; |
931 | case 'q': | |
823f0fd1 | 932 | handle_quit(cxt); |
2b6fc908 KZ |
933 | case 'r': |
934 | return; | |
935 | case 's': | |
cf3808e4 | 936 | user_sectors = read_int(cxt, 1, cxt->geom.sectors, 63, 0, |
7eda085c | 937 | _("Number of sectors")); |
852ce62b | 938 | if (is_dos_compatible(cxt)) |
7eda085c | 939 | fprintf(stderr, _("Warning: setting " |
2b6fc908 | 940 | "sector offset for DOS " |
6a95c736 | 941 | "compatibility\n")); |
aa42788d | 942 | fdisk_override_geometry(cxt, user_cylinders, user_heads, user_sectors); |
2b6fc908 KZ |
943 | break; |
944 | case 'v': | |
e53ced85 | 945 | verify(cxt); |
2b6fc908 KZ |
946 | break; |
947 | case 'w': | |
d8de0955 | 948 | write_table(cxt); |
2b6fc908 | 949 | break; |
2b6fc908 | 950 | case 'y': |
ff5775bd | 951 | if (fdisk_is_disklabel(cxt, SUN)) |
e53ced85 | 952 | sun_set_pcylcount(cxt); |
2b6fc908 | 953 | break; |
2b6fc908 | 954 | default: |
ff5775bd | 955 | print_menu(cxt, EXPERT_MENU); |
6dbe3af9 KZ |
956 | } |
957 | } | |
958 | } | |
959 | ||
3b622ddd DB |
960 | static int is_ide_cdrom_or_tape(char *device) |
961 | { | |
962 | int fd, ret; | |
2b6fc908 | 963 | |
1c6b3378 | 964 | if ((fd = open(device, O_RDONLY)) < 0) |
e8f26419 | 965 | return 0; |
3b622ddd | 966 | ret = blkdev_is_cdrom(fd); |
2b6fc908 | 967 | |
3b622ddd DB |
968 | close(fd); |
969 | return ret; | |
2b6fc908 KZ |
970 | } |
971 | ||
ea4824f1 | 972 | /* Print disk geometry and partition table of a specified device (-l option) */ |
4e0e8253 KZ |
973 | static void print_partition_table_from_option(struct fdisk_context *cxt, |
974 | char *device, unsigned long sector_size) | |
e27b42d5 | 975 | { |
4e0e8253 | 976 | if (fdisk_context_assign_device(cxt, device, 1) != 0) /* read-only */ |
289dcc90 | 977 | err(EXIT_FAILURE, _("cannot open %s"), device); |
823f0fd1 | 978 | |
759d093f | 979 | if (sector_size) /* passed -b option, override autodiscovery */ |
aa42788d | 980 | fdisk_override_sector_size(cxt, sector_size); |
759d093f | 981 | |
9a5e29e9 | 982 | if (user_cylinders || user_heads || user_sectors) |
aa42788d | 983 | fdisk_override_geometry(cxt, user_cylinders, |
759d093f | 984 | user_heads, user_sectors); |
84e18f76 KZ |
985 | |
986 | if (!fdisk_dev_has_disklabel(cxt)) { | |
987 | /* | |
988 | * Try BSD -- TODO: move to list_table() too | |
989 | */ | |
7737f698 | 990 | list_disk_geometry(cxt); |
ff5775bd DB |
991 | if (!fdisk_is_disklabel(cxt, AIX) && |
992 | !fdisk_is_disklabel(cxt, MAC)) | |
7737f698 | 993 | btrydev(cxt); |
ff5775bd | 994 | } else |
7737f698 | 995 | list_table(cxt, 0); |
6dbe3af9 KZ |
996 | } |
997 | ||
c129767e KZ |
998 | /* |
999 | * for fdisk -l: | |
1000 | * try all things in /proc/partitions that look like a full disk | |
1001 | */ | |
22853e4a | 1002 | static void |
4e0e8253 KZ |
1003 | print_all_partition_table_from_option(struct fdisk_context *cxt, |
1004 | unsigned long sector_size) | |
ea4824f1 | 1005 | { |
eb63b9b8 | 1006 | FILE *procpt; |
657d9adb | 1007 | char line[128 + 1], ptname[128 + 1], devname[256]; |
981b80b7 KZ |
1008 | int ma, mi; |
1009 | unsigned long long sz; | |
eb63b9b8 | 1010 | |
6bec8710 | 1011 | procpt = fopen(_PATH_PROC_PARTITIONS, "r"); |
eb63b9b8 | 1012 | if (procpt == NULL) { |
6bec8710 | 1013 | fprintf(stderr, _("cannot open %s\n"), _PATH_PROC_PARTITIONS); |
eb63b9b8 KZ |
1014 | return; |
1015 | } | |
1016 | ||
1017 | while (fgets(line, sizeof(line), procpt)) { | |
bb662090 | 1018 | if (sscanf (line, " %d %d %llu %128[^\n ]", |
eb63b9b8 KZ |
1019 | &ma, &mi, &sz, ptname) != 4) |
1020 | continue; | |
c07ebfa1 | 1021 | snprintf(devname, sizeof(devname), "/dev/%s", ptname); |
6bec8710 KZ |
1022 | if (is_whole_disk(devname)) { |
1023 | char *cn = canonicalize_path(devname); | |
1024 | if (cn) { | |
0c48d371 | 1025 | if (!is_ide_cdrom_or_tape(cn)) |
4e0e8253 | 1026 | print_partition_table_from_option(cxt, cn, sector_size); |
6bec8710 KZ |
1027 | free(cn); |
1028 | } | |
1029 | } | |
eb63b9b8 | 1030 | } |
e8f26419 | 1031 | fclose(procpt); |
eb63b9b8 KZ |
1032 | } |
1033 | ||
22853e4a KZ |
1034 | static void |
1035 | unknown_command(int c) { | |
1036 | printf(_("%c: unknown command\n"), c); | |
7eda085c KZ |
1037 | } |
1038 | ||
89fd812f DB |
1039 | static void print_welcome(void) |
1040 | { | |
1041 | printf(_("Welcome to fdisk (%s).\n\n" | |
1042 | "Changes will remain in memory only, until you decide to write them.\n" | |
1043 | "Be careful before using the write command.\n\n"), PACKAGE_STRING); | |
1044 | ||
1045 | fflush(stdout); | |
1046 | } | |
1047 | ||
7737f698 | 1048 | static void command_prompt(struct fdisk_context *cxt) |
56c07b96 | 1049 | { |
4a96a62a | 1050 | int c; |
5dbff4c0 | 1051 | |
e3661531 KZ |
1052 | assert(cxt); |
1053 | ||
ff5775bd | 1054 | if (fdisk_is_disklabel(cxt, OSF)) { |
56c07b96 FC |
1055 | putchar('\n'); |
1056 | /* OSF label, and no DOS label */ | |
1057 | printf(_("Detected an OSF/1 disklabel on %s, entering " | |
1058 | "disklabel mode.\n"), | |
823f0fd1 | 1059 | cxt->dev_path); |
7737f698 | 1060 | bsd_command_prompt(cxt); |
53b422ab | 1061 | |
56c07b96 | 1062 | /* If we return we may want to make an empty DOS label? */ |
53b422ab | 1063 | fdisk_context_switch_label(cxt, "dos"); |
56c07b96 FC |
1064 | } |
1065 | ||
1066 | while (1) { | |
e3661531 KZ |
1067 | |
1068 | assert(cxt->label); | |
1069 | ||
56c07b96 | 1070 | putchar('\n'); |
bddd84e7 | 1071 | c = tolower(read_char(cxt, _("Command (m for help): "))); |
56c07b96 FC |
1072 | switch (c) { |
1073 | case 'a': | |
ff5775bd | 1074 | if (fdisk_is_disklabel(cxt, DOS)) |
e3661531 KZ |
1075 | dos_toggle_active(cxt, |
1076 | get_partition(cxt, 1, cxt->label->nparts_max)); | |
ff5775bd | 1077 | else if (fdisk_is_disklabel(cxt, SUN)) |
e3661531 KZ |
1078 | toggle_sunflags(cxt, |
1079 | get_partition(cxt, 1, cxt->label->nparts_max), | |
1080 | SUN_FLAG_UNMNT); | |
ff5775bd | 1081 | else if (fdisk_is_disklabel(cxt, SGI)) |
38b36353 | 1082 | sgi_set_bootpartition(cxt, |
e3661531 | 1083 | get_partition(cxt, 1, cxt->label->nparts_max)); |
56c07b96 FC |
1084 | else |
1085 | unknown_command(c); | |
1086 | break; | |
1087 | case 'b': | |
53b422ab KZ |
1088 | /* |
1089 | * TODO: create child context for nexted partition tables | |
1090 | */ | |
ff5775bd | 1091 | if (fdisk_is_disklabel(cxt, SGI)) |
38b36353 | 1092 | sgi_set_bootfile(cxt); |
ff5775bd | 1093 | else if (fdisk_is_disklabel(cxt, DOS)) { |
53b422ab | 1094 | fdisk_context_switch_label(cxt, "bsd"); |
7737f698 | 1095 | bsd_command_prompt(cxt); |
53b422ab | 1096 | fdisk_context_switch_label(cxt, "dos"); |
c482303e FC |
1097 | } else |
1098 | unknown_command(c); | |
56c07b96 FC |
1099 | break; |
1100 | case 'c': | |
ff5775bd | 1101 | if (fdisk_is_disklabel(cxt, DOS)) |
e53ced85 | 1102 | toggle_dos_compatibility_flag(cxt); |
ff5775bd | 1103 | else if (fdisk_is_disklabel(cxt, SUN)) |
e3661531 KZ |
1104 | toggle_sunflags(cxt, |
1105 | get_partition(cxt, 1, cxt->label->nparts_max), | |
1106 | SUN_FLAG_RONLY); | |
ff5775bd | 1107 | else if (fdisk_is_disklabel(cxt, SGI)) |
38b36353 | 1108 | sgi_set_swappartition(cxt, |
e3661531 | 1109 | get_partition(cxt, 1, cxt->label->nparts_max)); |
56c07b96 FC |
1110 | else |
1111 | unknown_command(c); | |
1112 | break; | |
1113 | case 'd': | |
e3661531 KZ |
1114 | delete_partition(cxt, |
1115 | get_existing_partition(cxt, 1, cxt->label->nparts_max)); | |
56c07b96 | 1116 | break; |
3f731001 DB |
1117 | case 'g': |
1118 | fdisk_create_disklabel(cxt, "gpt"); | |
1119 | break; | |
7375423c KZ |
1120 | case 'G': |
1121 | fdisk_create_disklabel(cxt, "sgi"); | |
1122 | break; | |
56c07b96 | 1123 | case 'i': |
ff5775bd | 1124 | if (fdisk_is_disklabel(cxt, SGI)) |
38b36353 | 1125 | create_sgiinfo(cxt); |
56c07b96 FC |
1126 | else |
1127 | unknown_command(c); | |
099c7a94 | 1128 | break; |
56c07b96 | 1129 | case 'l': |
7b575fcc | 1130 | list_partition_types(cxt); |
56c07b96 FC |
1131 | break; |
1132 | case 'm': | |
ff5775bd | 1133 | print_menu(cxt, MAIN_MENU); |
56c07b96 FC |
1134 | break; |
1135 | case 'n': | |
e53ced85 | 1136 | new_partition(cxt); |
56c07b96 FC |
1137 | break; |
1138 | case 'o': | |
de3d6c93 | 1139 | fdisk_create_disklabel(cxt, "dos"); |
56c07b96 FC |
1140 | break; |
1141 | case 'p': | |
7737f698 | 1142 | list_table(cxt, 0); |
56c07b96 FC |
1143 | break; |
1144 | case 'q': | |
823f0fd1 | 1145 | handle_quit(cxt); |
56c07b96 | 1146 | case 's': |
de3d6c93 | 1147 | fdisk_create_disklabel(cxt, "sun"); |
56c07b96 FC |
1148 | break; |
1149 | case 't': | |
02460b8a | 1150 | change_partition_type(cxt); |
56c07b96 FC |
1151 | break; |
1152 | case 'u': | |
ec10aa67 | 1153 | toggle_units(cxt); |
56c07b96 FC |
1154 | break; |
1155 | case 'v': | |
e53ced85 | 1156 | verify(cxt); |
56c07b96 FC |
1157 | break; |
1158 | case 'w': | |
d8de0955 | 1159 | write_table(cxt); |
56c07b96 FC |
1160 | break; |
1161 | case 'x': | |
7737f698 | 1162 | expert_command_prompt(cxt); |
56c07b96 FC |
1163 | break; |
1164 | default: | |
1165 | unknown_command(c); | |
ff5775bd | 1166 | print_menu(cxt, MAIN_MENU); |
56c07b96 FC |
1167 | } |
1168 | } | |
1169 | } | |
5dbff4c0 | 1170 | |
50dec1eb | 1171 | static sector_t get_dev_blocks(char *dev) |
6da365de DB |
1172 | { |
1173 | int fd; | |
50dec1eb | 1174 | sector_t size; |
6da365de DB |
1175 | |
1176 | if ((fd = open(dev, O_RDONLY)) < 0) | |
289dcc90 | 1177 | err(EXIT_FAILURE, _("cannot open %s"), dev); |
7737f698 DB |
1178 | if (blkdev_get_sectors(fd, &size) == -1) { |
1179 | close(fd); | |
1180 | err(EXIT_FAILURE, _("BLKGETSIZE ioctl failed on %s"), dev); | |
1181 | } | |
6da365de DB |
1182 | close(fd); |
1183 | return size/2; | |
1184 | } | |
1185 | ||
e1144767 DB |
1186 | int main(int argc, char **argv) |
1187 | { | |
6da365de | 1188 | int c, optl = 0, opts = 0; |
e53ced85 | 1189 | unsigned long sector_size = 0; |
4e0e8253 | 1190 | struct fdisk_context *cxt; |
852ce62b | 1191 | struct fdisk_label *lb; |
2b6fc908 | 1192 | |
7eda085c KZ |
1193 | setlocale(LC_ALL, ""); |
1194 | bindtextdomain(PACKAGE, LOCALEDIR); | |
1195 | textdomain(PACKAGE); | |
b2d28533 | 1196 | atexit(close_stdout); |
2b6fc908 | 1197 | |
4e0e8253 KZ |
1198 | fdisk_init_debug(0); |
1199 | cxt = fdisk_new_context(); | |
1200 | if (!cxt) | |
1201 | err(EXIT_FAILURE, _("failed to allocate libfdisk context")); | |
1202 | ||
416c43a9 KZ |
1203 | fdisk_context_set_ask(cxt, ask_callback, NULL); |
1204 | ||
278f63c0 | 1205 | while ((c = getopt(argc, argv, "b:c::C:hH:lsS:u::vV")) != -1) { |
2b6fc908 KZ |
1206 | switch (c) { |
1207 | case 'b': | |
0e6f4a20 KZ |
1208 | /* Ugly: this sector size is really per device, |
1209 | so cannot be combined with multiple disks, | |
1210 | and te same goes for the C/H/S options. | |
1211 | */ | |
00695059 | 1212 | sector_size = strtou32_or_err(optarg, _("invalid sector size argument")); |
5c36a0eb | 1213 | if (sector_size != 512 && sector_size != 1024 && |
8905beda | 1214 | sector_size != 2048 && sector_size != 4096) |
7c1db6b4 | 1215 | usage(stderr); |
2b6fc908 | 1216 | break; |
0e6f4a20 | 1217 | case 'C': |
00695059 | 1218 | user_cylinders = strtou32_or_err(optarg, _("invalid cylinders argument")); |
0e6f4a20 | 1219 | break; |
78498b7b | 1220 | case 'c': |
852ce62b KZ |
1221 | if (optarg) { |
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 | } |