]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/fdisk.c
tests: add hexdump from GPT
[thirdparty/util-linux.git] / disk-utils / fdisk.c
CommitLineData
3f0ac587 1/*
6dbe3af9 2 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
38b36353 3 * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org>
6dbe3af9 4 *
3f0ac587
KZ
5 * Copyright (C) 2007-2013 Karel Zak <kzak@redhat.com>
6 *
6dbe3af9
KZ
7 * This program is free software. You can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation: either version 1 or
10 * (at your option) any later version.
6dbe3af9 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>
d44115f3 24#include <libsmartcols.h>
740c36f6
KZ
25#ifdef HAVE_LIBREADLINE
26# include <readline/readline.h>
27#endif
6dbe3af9 28
3f0ac587 29#include "c.h"
52b38677 30#include "xalloc.h"
e916600f 31#include "all-io.h"
22853e4a 32#include "nls.h"
e66ac5d3 33#include "rpmatch.h"
810f986b 34#include "blkdev.h"
b8d22034 35#include "mbsalign.h"
6bec8710
KZ
36#include "pathnames.h"
37#include "canonicalize.h"
20aa2570 38#include "strutils.h"
b2d28533 39#include "closestream.h"
a22c6eb2 40#include "sysfs.h"
5c36a0eb 41
fdb006e8
KZ
42#include "fdisk.h"
43
b4bfbadd 44#include "pt-sun.h" /* to toggle flags */
5c36a0eb 45
48d7b13a 46#ifdef HAVE_LINUX_COMPILER_H
3f0ac587 47# include <linux/compiler.h>
48d7b13a
KZ
48#endif
49#ifdef HAVE_LINUX_BLKPG_H
3f0ac587 50# include <linux/blkpg.h>
7eda085c 51#endif
6dbe3af9 52
e6d0c4c1
KZ
53/*
54 * fdisk debug stuff (see fdisk.h and include/debug.h)
55 */
56UL_DEBUG_DEFINE_MASK(fdisk);
819d9a29 57UL_DEBUG_DEFINE_MASKNAMES(fdisk) = UL_DEBUG_EMPTY_MASKNAMES;
d6b3ba41 58
e6d0c4c1
KZ
59static void fdiskprog_init_debug(void)
60{
61 __UL_INIT_DEBUG(fdisk, FDISKPROG_DEBUG_, 0, FDISK_DEBUG);
62}
d6b3ba41 63
740c36f6
KZ
64#ifdef HAVE_LIBREADLINE
65static char *rl_fgets(char *s, int n, FILE *stream, const char *prompt)
66{
67 char *p;
68
69 rl_outstream = stream;
70 p = readline(prompt);
71 if (!p)
72 return NULL;
73
84ab260a
KZ
74 strncpy(s, p, n);
75 s[n - 1] = '\0';
740c36f6
KZ
76 free(p);
77 return s;
78}
79#endif
80
d6b3ba41
KZ
81int get_user_reply(struct fdisk_context *cxt, const char *prompt,
82 char *buf, size_t bufsz)
83{
84 char *p;
85 size_t sz;
86
87 do {
740c36f6
KZ
88#ifdef HAVE_LIBREADLINE
89 if (isatty(STDIN_FILENO)) {
90 if (!rl_fgets(buf, bufsz, stdout, prompt)) {
91 if (fdisk_label_is_changed(fdisk_get_label(cxt, NULL))) {
92 if (rl_fgets(buf, bufsz, stderr,
93 _("\nDo you really want to quit? "))
94 && !rpmatch(buf))
95 continue;
96 }
97 fdisk_unref_context(cxt);
98 exit(EXIT_FAILURE);
99 } else
100 break;
101 }
102 else
103#endif
104 {
105 fputs(prompt, stdout);
106 fflush(stdout);
107 if (!fgets(buf, bufsz, stdin)) {
108 if (fdisk_label_is_changed(fdisk_get_label(cxt, NULL))) {
109 fprintf(stderr, _("\nDo you really want to quit? "));
d6b3ba41 110
740c36f6
KZ
111 if (fgets(buf, bufsz, stdin) && !rpmatch(buf))
112 continue;
113 }
114 fdisk_unref_context(cxt);
115 exit(EXIT_FAILURE);
116 } else
117 break;
118 }
d6b3ba41
KZ
119 } while (1);
120
121 for (p = buf; *p && !isgraph(*p); p++); /* get first non-blank */
122
123 if (p > buf)
124 memmove(buf, p, p - buf); /* remove blank space */
125 sz = strlen(buf);
126 if (sz && *(buf + sz - 1) == '\n')
127 *(buf + sz - 1) = '\0';
128
88141067 129 DBG(ASK, ul_debug("user's reply: >>>%s<<<", buf));
d6b3ba41
KZ
130 return 0;
131}
132
133static int ask_menu(struct fdisk_context *cxt, struct fdisk_ask *ask,
134 char *buf, size_t bufsz)
135
136{
137 const char *q = fdisk_ask_get_query(ask);
138 int dft = fdisk_ask_menu_get_default(ask);
139
140 if (q) {
141 fputs(q, stdout); /* print header */
142 fputc('\n', stdout);
143 }
144
145 do {
146 char prompt[128];
68ddb136 147 int key, c, rc;
d6b3ba41
KZ
148 const char *name, *desc;
149 size_t i = 0;
150
151 /* print menu items */
152 while (fdisk_ask_menu_get_item(ask, i++, &key, &name, &desc) == 0)
153 fprintf(stdout, " %c %s (%s)\n", key, name, desc);
154
155 /* ask for key */
156 snprintf(prompt, sizeof(prompt), _("Select (default %c): "), dft);
68ddb136
KZ
157 rc = get_user_reply(cxt, prompt, buf, bufsz);
158 if (rc)
159 return rc;
d6b3ba41
KZ
160 if (!*buf) {
161 fdisk_info(cxt, _("Using default response %c."), dft);
162 c = dft;
163 } else
164 c = tolower(buf[0]);
165
166 /* check result */
167 i = 0;
168 while (fdisk_ask_menu_get_item(ask, i++, &key, NULL, NULL) == 0) {
169 if (c == key) {
170 fdisk_ask_menu_set_result(ask, c);
171 return 0; /* success */
172 }
173 }
174 fdisk_warnx(cxt, _("Value out of range."));
175 } while (1);
176
177 return -EINVAL;
178}
179
180
181#define tochar(num) ((int) ('a' + num - 1))
182static int ask_number(struct fdisk_context *cxt,
183 struct fdisk_ask *ask,
184 char *buf, size_t bufsz)
185{
186 char prompt[128] = { '\0' };
187 const char *q = fdisk_ask_get_query(ask);
188 const char *range = fdisk_ask_number_get_range(ask);
189
190 uint64_t dflt = fdisk_ask_number_get_default(ask),
191 low = fdisk_ask_number_get_low(ask),
192 high = fdisk_ask_number_get_high(ask);
193 int inchar = fdisk_ask_number_inchars(ask);
194
195 assert(q);
196
88141067 197 DBG(ASK, ul_debug("asking for number "
d6b3ba41
KZ
198 "['%s', <%ju,%ju>, default=%ju, range: %s]",
199 q, low, high, dflt, range));
200
201 if (range && dflt >= low && dflt <= high) {
202 if (inchar)
203 snprintf(prompt, sizeof(prompt), _("%s (%s, default %c): "),
204 q, range, tochar(dflt));
205 else
206 snprintf(prompt, sizeof(prompt), _("%s (%s, default %ju): "),
207 q, range, dflt);
208
209 } else if (dflt >= low && dflt <= high) {
210 if (inchar)
211 snprintf(prompt, sizeof(prompt), _("%s (%c-%c, default %c): "),
212 q, tochar(low), tochar(high), tochar(dflt));
213 else
214 snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju, default %ju): "),
215 q, low, high, dflt);
216 } else if (inchar)
217 snprintf(prompt, sizeof(prompt), _("%s (%c-%c): "),
218 q, tochar(low), tochar(high));
219 else
220 snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju): "),
221 q, low, high);
222
223 do {
224 int rc = get_user_reply(cxt, prompt, buf, bufsz);
225 uint64_t num;
226
227 if (rc)
228 return rc;
229 if (!*buf && dflt >= low && dflt <= high)
230 return fdisk_ask_number_set_result(ask, dflt);
231
232 if (isdigit_string(buf)) {
233 char *end;
234
235 errno = 0;
236 num = strtoumax(buf, &end, 10);
237 if (errno || buf == end || (end && *end))
238 continue;
239 } else if (inchar && isalpha(*buf)) {
240 num = tolower(*buf) - 'a' + 1;
241 } else
242 rc = -EINVAL;
243
244 if (rc == 0 && num >= low && num <= high)
245 return fdisk_ask_number_set_result(ask, num);
246
247 fdisk_warnx(cxt, _("Value out of range."));
248 } while (1);
249
250 return -1;
251}
252
253static int ask_offset(struct fdisk_context *cxt,
254 struct fdisk_ask *ask,
255 char *buf, size_t bufsz)
256{
257 char prompt[128] = { '\0' };
258 const char *q = fdisk_ask_get_query(ask);
259 const char *range = fdisk_ask_number_get_range(ask);
260
261 uint64_t dflt = fdisk_ask_number_get_default(ask),
262 low = fdisk_ask_number_get_low(ask),
263 high = fdisk_ask_number_get_high(ask),
264 base = fdisk_ask_number_get_base(ask);
265
266 assert(q);
267
88141067 268 DBG(ASK, ul_debug("asking for offset ['%s', <%ju,%ju>, base=%ju, default=%ju, range: %s]",
d6b3ba41
KZ
269 q, low, high, base, dflt, range));
270
271 if (range && dflt >= low && dflt <= high)
272 snprintf(prompt, sizeof(prompt), _("%s (%s, default %ju): "), q, range, dflt);
273 else if (dflt >= low && dflt <= high)
274 snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju, default %ju): "), q, low, high, dflt);
275 else
276 snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju): "), q, low, high);
277
278 do {
279 uint64_t num = 0;
280 char sig = 0, *p;
281 int pwr = 0;
282
283 int rc = get_user_reply(cxt, prompt, buf, bufsz);
284 if (rc)
285 return rc;
286 if (!*buf && dflt >= low && dflt <= high)
287 return fdisk_ask_number_set_result(ask, dflt);
288
289 p = buf;
290 if (*p == '+' || *p == '-') {
291 sig = *buf;
292 p++;
293 }
294
295 rc = parse_size(p, &num, &pwr);
296 if (rc)
297 continue;
88141067 298 DBG(ASK, ul_debug("parsed size: %ju", num));
d6b3ba41
KZ
299 if (sig && pwr) {
300 /* +{size}{K,M,...} specified, the "num" is in bytes */
301 uint64_t unit = fdisk_ask_number_get_unit(ask);
302 num += unit/2; /* round */
303 num /= unit;
304 }
305 if (sig == '+')
306 num += base;
307 else if (sig == '-')
308 num = base - num;
309
88141067 310 DBG(ASK, ul_debug("final offset: %ju [sig: %c, power: %d, %s]",
d6b3ba41
KZ
311 num, sig, pwr,
312 sig ? "relative" : "absolute"));
313 if (num >= low && num <= high) {
9b0b9fb1 314 if (sig && pwr)
d6b3ba41
KZ
315 fdisk_ask_number_set_relative(ask, 1);
316 return fdisk_ask_number_set_result(ask, num);
317 }
318 fdisk_warnx(cxt, _("Value out of range."));
319 } while (1);
320
321 return -1;
322}
323
324static unsigned int info_count;
325
412791a9 326static void fputs_info(struct fdisk_ask *ask, FILE *out)
d6b3ba41
KZ
327{
328 const char *msg;
d6b3ba41
KZ
329 assert(ask);
330
331 msg = fdisk_ask_print_get_mesg(ask);
d6b3ba41
KZ
332 if (!msg)
333 return;
334 if (info_count == 1)
335 fputc('\n', out);
412791a9
KZ
336
337 fputs(msg, out);
d6b3ba41
KZ
338 fputc('\n', out);
339}
340
341int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask,
342 void *data __attribute__((__unused__)))
343{
344 int rc = 0;
345 char buf[BUFSIZ];
346
347 assert(cxt);
348 assert(ask);
349
350 if (fdisk_ask_get_type(ask) != FDISK_ASKTYPE_INFO)
351 info_count = 0;
352
353 switch(fdisk_ask_get_type(ask)) {
354 case FDISK_ASKTYPE_MENU:
355 return ask_menu(cxt, ask, buf, sizeof(buf));
356 case FDISK_ASKTYPE_NUMBER:
357 return ask_number(cxt, ask, buf, sizeof(buf));
358 case FDISK_ASKTYPE_OFFSET:
359 return ask_offset(cxt, ask, buf, sizeof(buf));
360 case FDISK_ASKTYPE_INFO:
152788aa
KZ
361 if (!fdisk_is_listonly(cxt))
362 info_count++;
412791a9 363 fputs_info(ask, stdout);
d6b3ba41
KZ
364 break;
365 case FDISK_ASKTYPE_WARNX:
496c979a 366 color_scheme_fenable("warn", UL_COLOR_RED, stderr);
d6b3ba41
KZ
367 fputs(fdisk_ask_print_get_mesg(ask), stderr);
368 color_fdisable(stderr);
369 fputc('\n', stderr);
370 break;
371 case FDISK_ASKTYPE_WARN:
496c979a 372 color_scheme_fenable("warn", UL_COLOR_RED, stderr);
d6b3ba41
KZ
373 fputs(fdisk_ask_print_get_mesg(ask), stderr);
374 errno = fdisk_ask_print_get_errno(ask);
375 fprintf(stderr, ": %m\n");
376 color_fdisable(stderr);
377 break;
378 case FDISK_ASKTYPE_YESNO:
379 fputc('\n', stdout);
2d129032
KZ
380 do {
381 int x;
382 fputs(fdisk_ask_get_query(ask), stdout);
383 rc = get_user_reply(cxt, _(" [Y]es/[N]o: "), buf, sizeof(buf));
384 if (rc)
385 break;
386 x = rpmatch(buf);
cd2a6f1c 387 if (x == RPMATCH_YES || x == RPMATCH_NO) {
2d129032
KZ
388 fdisk_ask_yesno_set_result(ask, x);
389 break;
390 }
391 } while(1);
88141067 392 DBG(ASK, ul_debug("yes-no ask: reply '%s' [rc=%d]", buf, rc));
d6b3ba41
KZ
393 break;
394 case FDISK_ASKTYPE_STRING:
395 {
396 char prmt[BUFSIZ];
397 snprintf(prmt, sizeof(prmt), "%s: ", fdisk_ask_get_query(ask));
398 fputc('\n', stdout);
399 rc = get_user_reply(cxt, prmt, buf, sizeof(buf));
400 if (rc == 0)
401 fdisk_ask_string_set_result(ask, xstrdup(buf));
88141067 402 DBG(ASK, ul_debug("string ask: reply '%s' [rc=%d]", buf, rc));
d6b3ba41
KZ
403 break;
404 }
405 default:
406 warnx(_("internal error: unsupported dialog type %d"), fdisk_ask_get_type(ask));
407 return -EINVAL;
408 }
409 return rc;
410}
411
412struct fdisk_parttype *ask_partition_type(struct fdisk_context *cxt)
413{
414 const char *q;
a745611d
KZ
415 struct fdisk_label *lb;
416
417 assert(cxt);
418 lb = fdisk_get_label(cxt, NULL);
d6b3ba41 419
a745611d 420 if (!lb)
d6b3ba41
KZ
421 return NULL;
422
a745611d 423 q = fdisk_label_has_code_parttypes(lb) ?
d6b3ba41
KZ
424 _("Partition type (type L to list all types): ") :
425 _("Hex code (type L to list all codes): ");
426 do {
427 char buf[256];
428 int rc = get_user_reply(cxt, q, buf, sizeof(buf));
429
430 if (rc)
431 break;
432
433 if (buf[1] == '\0' && toupper(*buf) == 'L')
434 list_partition_types(cxt);
435 else if (*buf)
a745611d 436 return fdisk_label_parse_parttype(lb, buf);
d6b3ba41
KZ
437 } while (1);
438
439 return NULL;
440}
441
7b575fcc 442void list_partition_types(struct fdisk_context *cxt)
6dbe3af9 443{
76f17cf2 444 size_t ntypes = 0;
a745611d 445 struct fdisk_label *lb = fdisk_get_label(cxt, NULL);
6dbe3af9 446
a745611d
KZ
447 assert(cxt);
448 lb = fdisk_get_label(cxt, NULL);
449 if (!lb)
450 return;
451 ntypes = fdisk_label_get_nparttypes(lb);
452 if (!ntypes)
7b575fcc 453 return;
2b6fc908 454
a745611d 455 if (fdisk_label_has_code_parttypes(lb)) {
7b575fcc
KZ
456 /*
457 * Prints in 4 columns in format <hex> <name>
458 */
76f17cf2
KZ
459 size_t last[4], done = 0, next = 0, size;
460 int i;
b8d22034 461
76f17cf2 462 size = ntypes;
7b575fcc
KZ
463
464 for (i = 3; i >= 0; i--)
465 last[3 - i] = done += (size + i - done) / (i + 1);
466 i = done = 0;
467
468 do {
469 #define NAME_WIDTH 15
470 char name[NAME_WIDTH * MB_LEN_MAX];
471 size_t width = NAME_WIDTH;
a745611d 472 const struct fdisk_parttype *t = fdisk_label_get_parttype(lb, next);
7b575fcc
KZ
473 size_t ret;
474
e6d0c4c1 475 if (fdisk_parttype_get_name(t)) {
a745611d
KZ
476 printf("%c%2x ", i ? ' ' : '\n',
477 fdisk_parttype_get_code(t));
478 ret = mbsalign(_(fdisk_parttype_get_name(t)),
479 name, sizeof(name),
480 &width, MBS_ALIGN_LEFT, 0);
7b575fcc 481
76f17cf2 482 if (ret == (size_t)-1 || ret >= sizeof(name))
a745611d
KZ
483 printf("%-15.15s",
484 _(fdisk_parttype_get_name(t)));
76f17cf2
KZ
485 else
486 fputs(name, stdout);
487 }
7b575fcc
KZ
488
489 next = last[i++] + done;
490 if (i > 3 || next >= last[i]) {
491 i = 0;
492 next = ++done;
493 }
494 } while (done < last[0]);
495
496 } else {
497 /*
498 * Prints 1 column in format <idx> <name> <typestr>
499 */
76f17cf2 500 size_t i;
7b575fcc 501
a745611d
KZ
502 for (i = 0; i < ntypes; i++) {
503 const struct fdisk_parttype *t = fdisk_label_get_parttype(lb, i);
504 printf("%3zu %-30s %s\n", i + 1,
505 fdisk_parttype_get_name(t),
506 fdisk_parttype_get_string(t));
76f17cf2 507 }
7b575fcc 508 }
6dbe3af9
KZ
509 putchar('\n');
510}
511
f02fecd1 512void toggle_dos_compatibility_flag(struct fdisk_context *cxt)
852ce62b 513{
6a632136 514 struct fdisk_label *lb = fdisk_get_label(cxt, "dos");
852ce62b
KZ
515 int flag;
516
517 if (!lb)
518 return;
519
520 flag = !fdisk_dos_is_compatible(lb);
09f0c3d9
KZ
521 fdisk_info(cxt, flag ?
522 _("DOS Compatibility flag is set (DEPRECATED!)") :
523 _("DOS Compatibility flag is not set"));
edd7b958 524
852ce62b
KZ
525 fdisk_dos_enable_compatible(lb, flag);
526
aa36c2cf 527 if (fdisk_is_label(cxt, DOS))
09f0c3d9 528 fdisk_reset_alignment(cxt); /* reset the current label */
6dbe3af9
KZ
529}
530
27ddd4f1 531void change_partition_type(struct fdisk_context *cxt)
e53ced85 532{
641a75ca 533 size_t i;
85151521
KZ
534 struct fdisk_parttype *t = NULL;
535 struct fdisk_partition *pa = NULL;
536 const char *old = NULL;
6dbe3af9 537
e3661531 538 assert(cxt);
e3661531 539
641a75ca 540 if (fdisk_ask_partnum(cxt, &i, FALSE))
24f4bbff 541 return;
2b6fc908 542
85151521
KZ
543 if (fdisk_get_partition(cxt, i, &pa)) {
544 fdisk_warnx(cxt, _("Partition %zu does not exist yet!"), i + 1);
545 return;
546 }
547
548 t = (struct fdisk_parttype *) fdisk_partition_get_type(pa);
e6d0c4c1 549 old = t ? fdisk_parttype_get_name(t) : _("Unknown");
85151521
KZ
550
551 do {
552 t = ask_partition_type(cxt);
553 } while (!t);
554
85151521 555 if (fdisk_set_partition_type(cxt, i, t) == 0)
0477369a 556 fdisk_info(cxt,
85151521 557 _("Changed type of partition '%s' to '%s'."),
a745611d 558 old, t ? fdisk_parttype_get_name(t) : _("Unknown"));
85151521
KZ
559 else
560 fdisk_info(cxt,
561 _("Type of partition %zu is unchanged: %s."),
562 i + 1, old);
563
d6cfa8b3 564 fdisk_unref_partition(pa);
6dbe3af9
KZ
565}
566
e916600f
KZ
567static size_t skip_empty(const unsigned char *buf, size_t i, size_t sz)
568{
569 size_t next;
570 const unsigned char *p0 = buf + i;
571
572 for (next = i + 16; next < sz; next += 16) {
573 if (memcmp(p0, buf + next, 16) != 0)
574 break;
575 }
576
577 return next == i + 16 ? i : next;
578}
6dbe3af9 579
e916600f 580static void dump_buffer(off_t base, unsigned char *buf, size_t sz, int all)
09f0c3d9 581{
e916600f
KZ
582 size_t i, l, next = 0;
583
584 if (!buf)
585 return;
586 for (i = 0, l = 0; i < sz; i++, l++) {
587 if (l == 0) {
588 if (all == 0 && !next)
589 next = skip_empty(buf, i, sz);
590 printf("%08jx ", base + i);
591 }
592 printf(" %02x", buf[i]);
593 if (l == 7) /* words separator */
594 fputs(" ", stdout);
595 else if (l == 15) {
596 fputc('\n', stdout); /* next line */
6dbe3af9 597 l = -1;
e916600f
KZ
598 if (next > i) {
599 printf("*\n");
600 i = next - 1;
601 }
602 next = 0;
6dbe3af9
KZ
603 }
604 }
605 if (l > 0)
606 printf("\n");
6dbe3af9
KZ
607}
608
e916600f 609static void dump_blkdev(struct fdisk_context *cxt, const char *name,
9bbcf43f 610 uint64_t offset, size_t size, int all)
e53ced85 611{
8eccde20
KZ
612 int fd = fdisk_get_devfd(cxt);
613
412791a9 614 fdisk_info(cxt, _("\n%s: offset = %ju, size = %zu bytes."),
e916600f
KZ
615 name, offset, size);
616
8eccde20
KZ
617 assert(fd >= 0);
618
9bbcf43f 619 if (lseek(fd, (off_t) offset, SEEK_SET) == (off_t) -1)
e916600f 620 fdisk_warn(cxt, _("cannot seek"));
5afed187
KZ
621 else {
622 unsigned char *buf = xmalloc(size);
623
8eccde20 624 if (read_all(fd, (char *) buf, size) != (ssize_t) size)
5afed187
KZ
625 fdisk_warn(cxt, _("cannot read"));
626 else
627 dump_buffer(offset, buf, size, all);
628 free(buf);
629 }
e916600f
KZ
630}
631
632void dump_firstsector(struct fdisk_context *cxt)
633{
634 int all = !isatty(STDOUT_FILENO);
635
e3661531 636 assert(cxt);
6dbe3af9 637
8eccde20 638 dump_blkdev(cxt, _("First sector"), 0, fdisk_get_sector_size(cxt), all);
e916600f
KZ
639}
640
641void dump_disklabel(struct fdisk_context *cxt)
642{
643 int all = !isatty(STDOUT_FILENO);
644 int i = 0;
645 const char *name = NULL;
9bbcf43f 646 uint64_t offset = 0;
e916600f
KZ
647 size_t size = 0;
648
649 assert(cxt);
e3661531 650
e916600f
KZ
651 while (fdisk_locate_disklabel(cxt, i++, &name, &offset, &size) == 0 && size)
652 dump_blkdev(cxt, name, offset, size, all);
6dbe3af9
KZ
653}
654
0073a4cf 655static fdisk_sector_t get_dev_blocks(char *dev)
6da365de 656{
bbe67996 657 int fd, ret;
0073a4cf 658 fdisk_sector_t size;
6da365de
DB
659
660 if ((fd = open(dev, O_RDONLY)) < 0)
289dcc90 661 err(EXIT_FAILURE, _("cannot open %s"), dev);
0073a4cf 662 ret = blkdev_get_sectors(fd, (unsigned long long *) &size);
6da365de 663 close(fd);
bbe67996
SK
664 if (ret < 0)
665 err(EXIT_FAILURE, _("BLKGETSIZE ioctl failed on %s"), dev);
6da365de
DB
666 return size/2;
667}
668
e3a4aaa7
KZ
669static void __attribute__ ((__noreturn__)) usage(FILE *out)
670{
671 fputs(USAGE_HEADER, out);
672
673 fprintf(out,
674 _(" %1$s [options] <disk> change partition table\n"
675 " %1$s [options] -l [<disk>] list partition table(s)\n"),
676 program_invocation_short_name);
677
451dbcfa
BS
678 fputs(USAGE_SEPARATOR, out);
679 fputs(_("Display or manipulate a disk partition table.\n"), out);
680
e3a4aaa7
KZ
681 fputs(USAGE_OPTIONS, out);
682 fputs(_(" -b, --sector-size <size> physical and logical sector size\n"), out);
aeb9a30b 683 fputs(_(" -B, --protect-boot don't erase bootbits when creat a new label\n"), out);
e3a4aaa7
KZ
684 fputs(_(" -c, --compatibility[=<mode>] mode is 'dos' or 'nondos' (default)\n"), out);
685 fputs(_(" -L, --color[=<when>] colorize output (auto, always or never)\n"), out);
5d51dc2a
KZ
686 fprintf(out,
687 " %s\n", USAGE_COLORS_DEFAULT);
e3a4aaa7 688 fputs(_(" -l, --list display partitions end exit\n"), out);
2d7dffeb 689 fputs(_(" -o, --output <list> output columns\n"), out);
e3a4aaa7
KZ
690 fputs(_(" -t, --type <type> recognize specified partition table type only\n"), out);
691 fputs(_(" -u, --units[=<unit>] display units: 'cylinders' or 'sectors' (default)\n"), out);
692 fputs(_(" -s, --getsz display device size in 512-byte sectors [DEPRECATED]\n"), out);
354f8cc8 693 fputs(_(" --bytes print SIZE in bytes rather than in human readable format\n"), out);
e3a4aaa7
KZ
694
695 fputs(USAGE_SEPARATOR, out);
4b4e391a
KZ
696 fputs(_(" -C, --cylinders <number> specify the number of cylinders\n"), out);
697 fputs(_(" -H, --heads <number> specify the number of heads\n"), out);
698 fputs(_(" -S, --sectors <number> specify the number of sectors per track\n"), out);
e3a4aaa7
KZ
699
700 fputs(USAGE_SEPARATOR, out);
701 fputs(USAGE_HELP, out);
702 fputs(USAGE_VERSION, out);
703
fff8ad58
KZ
704 list_available_columns(out);
705
e3a4aaa7
KZ
706 fprintf(out, USAGE_MAN_TAIL("fdisk(8)"));
707 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
708}
709
710
5b72b3dd
KZ
711enum {
712 ACT_FDISK = 0, /* default */
713 ACT_LIST,
714 ACT_SHOWSIZE
715};
716
e1144767
DB
717int main(int argc, char **argv)
718{
e146ae4e 719 int rc, i, c, act = ACT_FDISK;
d0c9ddc3 720 int colormode = UL_COLORMODE_UNDEF;
4e0e8253 721 struct fdisk_context *cxt;
fff8ad58 722 char *outarg = NULL;
354f8cc8
KZ
723 enum {
724 OPT_BYTES = CHAR_MAX + 1
725 };
e3a4aaa7 726 static const struct option longopts[] = {
354f8cc8 727 { "bytes", no_argument, NULL, OPT_BYTES },
e3a4aaa7
KZ
728 { "color", optional_argument, NULL, 'L' },
729 { "compatibility", optional_argument, NULL, 'c' },
4b4e391a
KZ
730 { "cylinders", required_argument, NULL, 'C' },
731 { "heads", required_argument, NULL, 'H' },
732 { "sectors", required_argument, NULL, 'S' },
e3a4aaa7
KZ
733 { "getsz", no_argument, NULL, 's' },
734 { "help", no_argument, NULL, 'h' },
735 { "list", no_argument, NULL, 'l' },
736 { "sector-size", required_argument, NULL, 'b' },
737 { "type", required_argument, NULL, 't' },
738 { "units", optional_argument, NULL, 'u' },
739 { "version", no_argument, NULL, 'V' },
2d7dffeb 740 { "output", no_argument, NULL, 'o' },
aeb9a30b 741 { "protect-boot", no_argument, NULL, 'B' },
e3a4aaa7
KZ
742 { NULL, 0, NULL, 0 }
743 };
744
7eda085c
KZ
745 setlocale(LC_ALL, "");
746 bindtextdomain(PACKAGE, LOCALEDIR);
747 textdomain(PACKAGE);
b2d28533 748 atexit(close_stdout);
2b6fc908 749
4e0e8253 750 fdisk_init_debug(0);
e6d0c4c1
KZ
751 fdiskprog_init_debug();
752
4e0e8253
KZ
753 cxt = fdisk_new_context();
754 if (!cxt)
755 err(EXIT_FAILURE, _("failed to allocate libfdisk context"));
756
6a632136 757 fdisk_set_ask(cxt, ask_callback, NULL);
416c43a9 758
aeb9a30b 759 while ((c = getopt_long(argc, argv, "b:Bc::C:hH:lL::o:sS:t:u::vV",
e3a4aaa7 760 longopts, NULL)) != -1) {
2b6fc908
KZ
761 switch (c) {
762 case 'b':
6bcd192c
KZ
763 {
764 size_t sz = strtou32_or_err(optarg,
765 _("invalid sector size argument"));
766 if (sz != 512 && sz != 1024 && sz != 2048 && sz != 4096)
7c1db6b4 767 usage(stderr);
6bcd192c 768 fdisk_save_user_sector_size(cxt, sz, sz);
2b6fc908 769 break;
6bcd192c 770 }
9ff89c5d 771 case 'B':
aeb9a30b
KZ
772 fdisk_enable_bootbits_protection(cxt, 1);
773 break;
0e6f4a20 774 case 'C':
1653f0b0
KZ
775 fdisk_save_user_geometry(cxt,
776 strtou32_or_err(optarg,
777 _("invalid cylinders argument")),
778 0, 0);
0e6f4a20 779 break;
78498b7b 780 case 'c':
852ce62b 781 if (optarg) {
2b0bc17b 782 /* this setting is independent on the current
e3a4aaa7
KZ
783 * actively used label
784 */
785 char *p = *optarg == '=' ? optarg + 1 : optarg;
6a632136 786 struct fdisk_label *lb = fdisk_get_label(cxt, "dos");
e3a4aaa7 787
852ce62b
KZ
788 if (!lb)
789 err(EXIT_FAILURE, _("not found DOS label driver"));
e3a4aaa7 790 if (strcmp(p, "dos") == 0)
852ce62b 791 fdisk_dos_enable_compatible(lb, TRUE);
e3a4aaa7 792 else if (strcmp(p, "nondos") == 0)
852ce62b 793 fdisk_dos_enable_compatible(lb, FALSE);
e3a4aaa7
KZ
794 else {
795 warnx(_("unknown compatibility mode '%s'"), p);
852ce62b 796 usage(stderr);
e3a4aaa7 797 }
852ce62b
KZ
798 }
799 /* use default if no optarg specified */
78498b7b 800 break;
0e6f4a20 801 case 'H':
1653f0b0
KZ
802 fdisk_save_user_geometry(cxt, 0,
803 strtou32_or_err(optarg,
804 _("invalid heads argument")),
805 0);
0e6f4a20
KZ
806 break;
807 case 'S':
1653f0b0
KZ
808 fdisk_save_user_geometry(cxt, 0, 0,
809 strtou32_or_err(optarg,
810 _("invalid sectors argument")));
0e6f4a20 811 break;
2b6fc908 812 case 'l':
5b72b3dd 813 act = ACT_LIST;
2b6fc908 814 break;
80a1712f 815 case 'L':
5d51dc2a 816 colormode = UL_COLORMODE_AUTO;
80a1712f
KZ
817 if (optarg)
818 colormode = colormode_or_err(optarg,
819 _("unsupported color mode"));
820 break;
fff8ad58
KZ
821 case 'o':
822 outarg = optarg;
823 break;
2b6fc908 824 case 's':
5b72b3dd 825 act = ACT_SHOWSIZE;
2b6fc908 826 break;
565b7da6
KZ
827 case 't':
828 {
829 struct fdisk_label *lb = NULL;
830
6a632136 831 while (fdisk_next_label(cxt, &lb) == 0)
565b7da6
KZ
832 fdisk_label_set_disabled(lb, 1);
833
6a632136 834 lb = fdisk_get_label(cxt, optarg);
565b7da6
KZ
835 if (!lb)
836 errx(EXIT_FAILURE, _("unsupported disklabel: %s"), optarg);
837 fdisk_label_set_disabled(lb, 0);
1ce1a112 838 break;
565b7da6 839 }
2b6fc908 840 case 'u':
ec10aa67
KZ
841 if (optarg && *optarg == '=')
842 optarg++;
6a632136 843 if (fdisk_set_unit(cxt, optarg) != 0)
7c1db6b4 844 usage(stderr);
2b6fc908 845 break;
e3a4aaa7
KZ
846 case 'V': /* preferred for util-linux */
847 case 'v': /* for backward compatibility only */
a2482eb3
DB
848 printf(UTIL_LINUX_VERSION);
849 return EXIT_SUCCESS;
e1144767
DB
850 case 'h':
851 usage(stdout);
354f8cc8
KZ
852 case OPT_BYTES:
853 fdisk_set_size_unit(cxt, FDISK_SIZEUNIT_BYTES);
854 break;
2b6fc908 855 default:
7c1db6b4 856 usage(stderr);
2b6fc908 857 }
6dbe3af9 858 }
2b6fc908 859
6bcd192c
KZ
860 if (argc-optind != 1 && fdisk_has_user_device_properties(cxt))
861 warnx(_("The device properties (sector size and geometry) should"
862 " be used with one specified device only."));
7eda085c 863
d0c9ddc3 864 colors_init(colormode, "fdisk");
ffcf0540 865
5b72b3dd
KZ
866 switch (act) {
867 case ACT_LIST:
6a632136 868 fdisk_enable_listonly(cxt, 1);
fff8ad58 869 init_fields(cxt, outarg, NULL);
ffcf0540 870
2b6fc908
KZ
871 if (argc > optind) {
872 int k;
c129767e 873 for (k = optind; k < argc; k++)
d2c47697 874 print_device_pt(cxt, argv[k], 1, 0);
ea4824f1 875 } else
d2c47697 876 print_all_devices_pt(cxt, 0);
5b72b3dd 877 break;
2b6fc908 878
5b72b3dd 879 case ACT_SHOWSIZE:
9564e46c 880 /* deprecated */
5b72b3dd 881 if (argc - optind <= 0)
7c1db6b4 882 usage(stderr);
2b6fc908 883
6da365de 884 for (i = optind; i < argc; i++) {
0073a4cf
KZ
885 uintmax_t blks = get_dev_blocks(argv[i]);
886
5b72b3dd 887 if (argc - optind == 1)
0073a4cf 888 printf("%ju\n", blks);
2b6fc908 889 else
0073a4cf 890 printf("%s: %ju\n", argv[i], blks);
6dbe3af9 891 }
5b72b3dd 892 break;
6dbe3af9 893
5b72b3dd
KZ
894 case ACT_FDISK:
895 if (argc-optind != 1)
896 usage(stderr);
7eda085c 897
5b72b3dd 898 /* Here starts interactive mode, use fdisk_{warn,info,..} functions */
496c979a 899 color_scheme_enable("welcome", UL_COLOR_GREEN);
09f0c3d9 900 fdisk_info(cxt, _("Welcome to fdisk (%s)."), PACKAGE_STRING);
80a1712f
KZ
901 color_disable();
902 fdisk_info(cxt, _("Changes will remain in memory only, until you decide to write them.\n"
903 "Be careful before using the write command.\n"));
2d8988bd 904
6a632136 905 rc = fdisk_assign_device(cxt, argv[optind], 0);
e146ae4e 906 if (rc == -EACCES) {
6a632136 907 rc = fdisk_assign_device(cxt, argv[optind], 1);
e146ae4e
KZ
908 if (rc == 0)
909 fdisk_warnx(cxt, _("Device open in read-only mode."));
910 }
911 if (rc)
2d8988bd
KZ
912 err(EXIT_FAILURE, _("cannot open %s"), argv[optind]);
913
5b72b3dd 914 fflush(stdout);
56c07b96 915
aa36c2cf 916 if (!fdisk_has_label(cxt)) {
2d8988bd 917 fdisk_info(cxt, _("Device does not contain a recognized partition table."));
5b72b3dd 918 fdisk_create_disklabel(cxt, NULL);
433d05ff 919
aa36c2cf 920 } else if (fdisk_is_label(cxt, GPT) && fdisk_gpt_is_hybrid(cxt))
433d05ff 921 fdisk_warnx(cxt, _(
09af3db4 922 "A hybrid GPT was detected. You have to sync "
433d05ff 923 "the hybrid MBR manually (expert command 'M')."));
6dbe3af9 924
fff8ad58
KZ
925 init_fields(cxt, outarg, NULL); /* -o <columns> */
926
5b72b3dd
KZ
927 while (1)
928 process_fdisk_menu(&cxt);
929 }
9777759a 930
c7119037 931 fdisk_unref_context(cxt);
5b72b3dd 932 return EXIT_SUCCESS;
6dbe3af9 933}