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