]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/fdisk.c
(s)fdisk: avoid unneeded empty lines with '--list'
[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>
6c8c429d 24#include <signal.h>
c1154128 25#include <poll.h>
d44115f3 26#include <libsmartcols.h>
740c36f6 27#ifdef HAVE_LIBREADLINE
57ebfde2 28# define _FUNCTION_DEF
740c36f6
KZ
29# include <readline/readline.h>
30#endif
6dbe3af9 31
3f0ac587 32#include "c.h"
52b38677 33#include "xalloc.h"
e916600f 34#include "all-io.h"
22853e4a 35#include "nls.h"
e66ac5d3 36#include "rpmatch.h"
810f986b 37#include "blkdev.h"
b8d22034 38#include "mbsalign.h"
6bec8710
KZ
39#include "pathnames.h"
40#include "canonicalize.h"
20aa2570 41#include "strutils.h"
b2d28533 42#include "closestream.h"
8d2f4498 43#include "pager.h"
5c36a0eb 44
fdb006e8
KZ
45#include "fdisk.h"
46
b4bfbadd 47#include "pt-sun.h" /* to toggle flags */
5c36a0eb 48
48d7b13a 49#ifdef HAVE_LINUX_COMPILER_H
3f0ac587 50# include <linux/compiler.h>
48d7b13a
KZ
51#endif
52#ifdef HAVE_LINUX_BLKPG_H
3f0ac587 53# include <linux/blkpg.h>
7eda085c 54#endif
6dbe3af9 55
ba465623 56int pwipemode = WIPEMODE_AUTO;
fadd8e08 57int device_is_used;
c1154128 58int is_interactive;
fadd8e08
KZ
59struct fdisk_table *original_layout;
60
5635d195 61static int wipemode = WIPEMODE_AUTO;
ba465623 62
e6d0c4c1
KZ
63/*
64 * fdisk debug stuff (see fdisk.h and include/debug.h)
65 */
66UL_DEBUG_DEFINE_MASK(fdisk);
819d9a29 67UL_DEBUG_DEFINE_MASKNAMES(fdisk) = UL_DEBUG_EMPTY_MASKNAMES;
d6b3ba41 68
e6d0c4c1
KZ
69static void fdiskprog_init_debug(void)
70{
a15dca2f 71 __UL_INIT_DEBUG_FROM_ENV(fdisk, FDISKPROG_DEBUG_, 0, FDISK_DEBUG);
e6d0c4c1 72}
d6b3ba41 73
c1154128 74static void reply_sighandler(int sig __attribute__((unused)))
6c8c429d 75{
c1154128 76 DBG(ASK, ul_debug("got signal"));
6c8c429d
VD
77}
78
c1154128 79static int reply_running;
740c36f6 80
c1154128
KZ
81#ifdef HAVE_LIBREADLINE
82static char *reply_line;
740c36f6 83
c1154128 84static void reply_linehandler(char *line)
55cf3716 85{
c1154128
KZ
86 reply_line = line;
87 reply_running = 0;
88 rl_callback_handler_remove(); /* avoid duplicate prompt */
55cf3716 89}
c1154128 90#endif
55cf3716 91
c1154128 92int get_user_reply(const char *prompt, char *buf, size_t bufsz)
d6b3ba41 93{
c1154128
KZ
94 struct sigaction oldact, act = {
95 .sa_handler = reply_sighandler
96 };
97 struct pollfd fds[] = {
98 { .fd = fileno(stdin), .events = POLLIN }
99 };
d6b3ba41 100 size_t sz;
6c8c429d 101 int ret = 0;
6c8c429d 102
36787f7a 103 DBG(ASK, ul_debug("asking for user reply %s", is_interactive ? "[interactive]" : ""));
6c8c429d 104
c1154128 105 sigemptyset(&act.sa_mask);
6c8c429d 106 sigaction(SIGINT, &act, &oldact);
d6b3ba41 107
c1154128
KZ
108#ifdef HAVE_LIBREADLINE
109 if (is_interactive)
110 rl_callback_handler_install(prompt, reply_linehandler);
111#endif
40af0db4 112 errno = 0;
c1154128 113 reply_running = 1;
d6b3ba41 114 do {
c1154128 115 int rc;
6c8c429d 116
c1154128
KZ
117 *buf = '\0';
118#ifdef HAVE_LIBREADLINE
119 if (!is_interactive)
120#endif
121 {
122 fputs(prompt, stdout);
123 fflush(stdout);
6c8c429d
VD
124 }
125
c1154128
KZ
126 rc = poll(fds, 1, -1);
127 if (rc == -1 && errno == EINTR) { /* interrupted by signal */
128 DBG(ASK, ul_debug("cancel by CTRL+C"));
129 ret = -ECANCELED;
130 goto done;
131 }
132 if (rc == -1 && errno != EAGAIN) { /* error */
133 ret = -errno;
134 goto done;
135 }
136#ifdef HAVE_LIBREADLINE
137 if (is_interactive) {
138 /* read input and copy to buf[] */
139 rl_callback_read_char();
140 if (!reply_running && reply_line) {
141 sz = strlen(reply_line);
30636704 142 if (sz == 0)
1d775aa2 143 buf[sz++] = '\n';
30636704
VD
144 else
145 memcpy(buf, reply_line, min(sz, bufsz));
1d775aa2 146 buf[min(sz, bufsz - 1)] = '\0';
c1154128
KZ
147 free(reply_line);
148 reply_line = NULL;
55cf3716 149 }
55cf3716 150 } else
c1154128
KZ
151#endif
152 {
153 if (!fgets(buf, bufsz, stdin))
154 *buf = '\0';
55cf3716 155 break;
c1154128
KZ
156 }
157 } while (reply_running);
158
159 if (!*buf) {
160 DBG(ASK, ul_debug("cancel by CTRL+D"));
161 ret = -ECANCELED;
40af0db4 162 clearerr(stdin);
c1154128
KZ
163 goto done;
164 }
d6b3ba41 165
c1154128
KZ
166 /*
167 * cleanup the reply
168 */
6c183c28 169 sz = ltrim_whitespace((unsigned char *) buf);
d6b3ba41
KZ
170 if (sz && *(buf + sz - 1) == '\n')
171 *(buf + sz - 1) = '\0';
172
c1154128
KZ
173done:
174#ifdef HAVE_LIBREADLINE
175 if (is_interactive)
176 rl_callback_handler_remove();
177#endif
6c8c429d 178 sigaction(SIGINT, &oldact, NULL);
40af0db4 179 DBG(ASK, ul_debug("user's reply: >>>%s<<< [rc=%d]", buf, ret));
6c8c429d 180 return ret;
d6b3ba41
KZ
181}
182
183static int ask_menu(struct fdisk_context *cxt, struct fdisk_ask *ask,
184 char *buf, size_t bufsz)
185
186{
187 const char *q = fdisk_ask_get_query(ask);
188 int dft = fdisk_ask_menu_get_default(ask);
189
190 if (q) {
191 fputs(q, stdout); /* print header */
192 fputc('\n', stdout);
193 }
194
195 do {
196 char prompt[128];
68ddb136 197 int key, c, rc;
d6b3ba41
KZ
198 const char *name, *desc;
199 size_t i = 0;
200
201 /* print menu items */
202 while (fdisk_ask_menu_get_item(ask, i++, &key, &name, &desc) == 0)
203 fprintf(stdout, " %c %s (%s)\n", key, name, desc);
204
205 /* ask for key */
206 snprintf(prompt, sizeof(prompt), _("Select (default %c): "), dft);
c1154128 207 rc = get_user_reply(prompt, buf, bufsz);
68ddb136
KZ
208 if (rc)
209 return rc;
d6b3ba41
KZ
210 if (!*buf) {
211 fdisk_info(cxt, _("Using default response %c."), dft);
212 c = dft;
213 } else
214 c = tolower(buf[0]);
215
216 /* check result */
217 i = 0;
218 while (fdisk_ask_menu_get_item(ask, i++, &key, NULL, NULL) == 0) {
219 if (c == key) {
220 fdisk_ask_menu_set_result(ask, c);
221 return 0; /* success */
222 }
223 }
224 fdisk_warnx(cxt, _("Value out of range."));
225 } while (1);
226
227 return -EINVAL;
228}
229
230
231#define tochar(num) ((int) ('a' + num - 1))
232static int ask_number(struct fdisk_context *cxt,
233 struct fdisk_ask *ask,
234 char *buf, size_t bufsz)
235{
236 char prompt[128] = { '\0' };
237 const char *q = fdisk_ask_get_query(ask);
238 const char *range = fdisk_ask_number_get_range(ask);
239
240 uint64_t dflt = fdisk_ask_number_get_default(ask),
241 low = fdisk_ask_number_get_low(ask),
242 high = fdisk_ask_number_get_high(ask);
243 int inchar = fdisk_ask_number_inchars(ask);
244
245 assert(q);
246
88141067 247 DBG(ASK, ul_debug("asking for number "
fdbd7bb9 248 "['%s', <%"PRIu64",%"PRIu64">, default=%"PRIu64", range: %s]",
d6b3ba41
KZ
249 q, low, high, dflt, range));
250
251 if (range && dflt >= low && dflt <= high) {
252 if (inchar)
253 snprintf(prompt, sizeof(prompt), _("%s (%s, default %c): "),
254 q, range, tochar(dflt));
255 else
fdbd7bb9 256 snprintf(prompt, sizeof(prompt), _("%s (%s, default %"PRIu64"): "),
d6b3ba41
KZ
257 q, range, dflt);
258
259 } else if (dflt >= low && dflt <= high) {
260 if (inchar)
261 snprintf(prompt, sizeof(prompt), _("%s (%c-%c, default %c): "),
262 q, tochar(low), tochar(high), tochar(dflt));
263 else
fdbd7bb9
RM
264 snprintf(prompt, sizeof(prompt),
265 _("%s (%"PRIu64"-%"PRIu64", default %"PRIu64"): "),
d6b3ba41
KZ
266 q, low, high, dflt);
267 } else if (inchar)
268 snprintf(prompt, sizeof(prompt), _("%s (%c-%c): "),
269 q, tochar(low), tochar(high));
270 else
fdbd7bb9 271 snprintf(prompt, sizeof(prompt), _("%s (%"PRIu64"-%"PRIu64"): "),
d6b3ba41
KZ
272 q, low, high);
273
274 do {
c1154128 275 int rc = get_user_reply(prompt, buf, bufsz);
5653c982 276 uint64_t num = 0;
d6b3ba41
KZ
277
278 if (rc)
279 return rc;
280 if (!*buf && dflt >= low && dflt <= high)
281 return fdisk_ask_number_set_result(ask, dflt);
282
283 if (isdigit_string(buf)) {
284 char *end;
285
286 errno = 0;
287 num = strtoumax(buf, &end, 10);
288 if (errno || buf == end || (end && *end))
289 continue;
290 } else if (inchar && isalpha(*buf)) {
291 num = tolower(*buf) - 'a' + 1;
292 } else
293 rc = -EINVAL;
294
295 if (rc == 0 && num >= low && num <= high)
296 return fdisk_ask_number_set_result(ask, num);
297
298 fdisk_warnx(cxt, _("Value out of range."));
299 } while (1);
300
301 return -1;
302}
303
304static int ask_offset(struct fdisk_context *cxt,
305 struct fdisk_ask *ask,
306 char *buf, size_t bufsz)
307{
308 char prompt[128] = { '\0' };
309 const char *q = fdisk_ask_get_query(ask);
310 const char *range = fdisk_ask_number_get_range(ask);
311
312 uint64_t dflt = fdisk_ask_number_get_default(ask),
313 low = fdisk_ask_number_get_low(ask),
314 high = fdisk_ask_number_get_high(ask),
315 base = fdisk_ask_number_get_base(ask);
316
317 assert(q);
318
fdbd7bb9 319 DBG(ASK, ul_debug("asking for offset ['%s', <%"PRIu64",%"PRIu64">, base=%"PRIu64", default=%"PRIu64", range: %s]",
d6b3ba41
KZ
320 q, low, high, base, dflt, range));
321
322 if (range && dflt >= low && dflt <= high)
fdbd7bb9
RM
323 snprintf(prompt, sizeof(prompt), _("%s (%s, default %"PRIu64"): "),
324 q, range, dflt);
d6b3ba41 325 else if (dflt >= low && dflt <= high)
fdbd7bb9
RM
326 snprintf(prompt, sizeof(prompt),
327 _("%s (%"PRIu64"-%"PRIu64", default %"PRIu64"): "),
328 q, low, high, dflt);
d6b3ba41 329 else
fdbd7bb9
RM
330 snprintf(prompt, sizeof(prompt), _("%s (%"PRIu64"-%"PRIu64"): "),
331 q, low, high);
d6b3ba41
KZ
332
333 do {
262c94c2 334 uintmax_t num = 0;
d6b3ba41
KZ
335 char sig = 0, *p;
336 int pwr = 0;
337
c1154128 338 int rc = get_user_reply(prompt, buf, bufsz);
d6b3ba41
KZ
339 if (rc)
340 return rc;
341 if (!*buf && dflt >= low && dflt <= high)
342 return fdisk_ask_number_set_result(ask, dflt);
343
344 p = buf;
345 if (*p == '+' || *p == '-') {
346 sig = *buf;
347 p++;
348 }
349
350 rc = parse_size(p, &num, &pwr);
351 if (rc)
352 continue;
88141067 353 DBG(ASK, ul_debug("parsed size: %ju", num));
d6b3ba41
KZ
354 if (sig && pwr) {
355 /* +{size}{K,M,...} specified, the "num" is in bytes */
356 uint64_t unit = fdisk_ask_number_get_unit(ask);
357 num += unit/2; /* round */
358 num /= unit;
359 }
360 if (sig == '+')
361 num += base;
757cefbb
AG
362 else if (sig == '-' && fdisk_ask_number_is_wrap_negative(ask))
363 num = high - num;
d6b3ba41
KZ
364 else if (sig == '-')
365 num = base - num;
366
88141067 367 DBG(ASK, ul_debug("final offset: %ju [sig: %c, power: %d, %s]",
d6b3ba41
KZ
368 num, sig, pwr,
369 sig ? "relative" : "absolute"));
370 if (num >= low && num <= high) {
8c73e509 371 if (sig && pwr)
d6b3ba41 372 fdisk_ask_number_set_relative(ask, 1);
262c94c2 373 return fdisk_ask_number_set_result(ask, (uint64_t)num);
d6b3ba41
KZ
374 }
375 fdisk_warnx(cxt, _("Value out of range."));
376 } while (1);
377
378 return -1;
379}
380
381static unsigned int info_count;
382
412791a9 383static void fputs_info(struct fdisk_ask *ask, FILE *out)
d6b3ba41
KZ
384{
385 const char *msg;
d6b3ba41
KZ
386 assert(ask);
387
388 msg = fdisk_ask_print_get_mesg(ask);
d6b3ba41
KZ
389 if (!msg)
390 return;
391 if (info_count == 1)
392 fputc('\n', out);
412791a9
KZ
393
394 fputs(msg, out);
d6b3ba41
KZ
395 fputc('\n', out);
396}
397
398int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask,
399 void *data __attribute__((__unused__)))
400{
401 int rc = 0;
89770db4 402 char buf[BUFSIZ] = { '\0' };
d6b3ba41
KZ
403
404 assert(cxt);
405 assert(ask);
406
407 if (fdisk_ask_get_type(ask) != FDISK_ASKTYPE_INFO)
408 info_count = 0;
409
410 switch(fdisk_ask_get_type(ask)) {
411 case FDISK_ASKTYPE_MENU:
412 return ask_menu(cxt, ask, buf, sizeof(buf));
413 case FDISK_ASKTYPE_NUMBER:
414 return ask_number(cxt, ask, buf, sizeof(buf));
415 case FDISK_ASKTYPE_OFFSET:
416 return ask_offset(cxt, ask, buf, sizeof(buf));
417 case FDISK_ASKTYPE_INFO:
152788aa
KZ
418 if (!fdisk_is_listonly(cxt))
419 info_count++;
412791a9 420 fputs_info(ask, stdout);
d6b3ba41
KZ
421 break;
422 case FDISK_ASKTYPE_WARNX:
95aae4fc 423 fflush(stdout);
496c979a 424 color_scheme_fenable("warn", UL_COLOR_RED, stderr);
d6b3ba41
KZ
425 fputs(fdisk_ask_print_get_mesg(ask), stderr);
426 color_fdisable(stderr);
427 fputc('\n', stderr);
428 break;
429 case FDISK_ASKTYPE_WARN:
95aae4fc 430 fflush(stdout);
496c979a 431 color_scheme_fenable("warn", UL_COLOR_RED, stderr);
d6b3ba41
KZ
432 fputs(fdisk_ask_print_get_mesg(ask), stderr);
433 errno = fdisk_ask_print_get_errno(ask);
434 fprintf(stderr, ": %m\n");
435 color_fdisable(stderr);
436 break;
437 case FDISK_ASKTYPE_YESNO:
438 fputc('\n', stdout);
2d129032
KZ
439 do {
440 int x;
441 fputs(fdisk_ask_get_query(ask), stdout);
c1154128 442 rc = get_user_reply(_(" [Y]es/[N]o: "), buf, sizeof(buf));
2d129032
KZ
443 if (rc)
444 break;
445 x = rpmatch(buf);
cd2a6f1c 446 if (x == RPMATCH_YES || x == RPMATCH_NO) {
2d129032
KZ
447 fdisk_ask_yesno_set_result(ask, x);
448 break;
449 }
450 } while(1);
88141067 451 DBG(ASK, ul_debug("yes-no ask: reply '%s' [rc=%d]", buf, rc));
d6b3ba41
KZ
452 break;
453 case FDISK_ASKTYPE_STRING:
454 {
455 char prmt[BUFSIZ];
456 snprintf(prmt, sizeof(prmt), "%s: ", fdisk_ask_get_query(ask));
457 fputc('\n', stdout);
c1154128 458 rc = get_user_reply(prmt, buf, sizeof(buf));
d6b3ba41
KZ
459 if (rc == 0)
460 fdisk_ask_string_set_result(ask, xstrdup(buf));
88141067 461 DBG(ASK, ul_debug("string ask: reply '%s' [rc=%d]", buf, rc));
d6b3ba41
KZ
462 break;
463 }
464 default:
465 warnx(_("internal error: unsupported dialog type %d"), fdisk_ask_get_type(ask));
466 return -EINVAL;
467 }
468 return rc;
469}
470
19e4cfef 471static struct fdisk_parttype *ask_partition_type(struct fdisk_context *cxt, int *canceled)
d6b3ba41
KZ
472{
473 const char *q;
a745611d
KZ
474 struct fdisk_label *lb;
475
476 assert(cxt);
477 lb = fdisk_get_label(cxt, NULL);
d6b3ba41 478
a745611d 479 if (!lb)
d6b3ba41
KZ
480 return NULL;
481
19e4cfef 482 *canceled = 0;
006607ab
KZ
483
484 if (fdisk_label_has_parttypes_shortcuts(lb))
485 q = fdisk_label_has_code_parttypes(lb) ?
486 _("Hex code or alias (type L to list all): ") :
487 _("Partition type or alias (type L to list all): ");
488 else
489 q = fdisk_label_has_code_parttypes(lb) ?
490 _("Hex code (type L to list all codes): ") :
491 _("Partition type (type L to list all types): ");
d6b3ba41 492 do {
89770db4 493 char buf[256] = { '\0' };
c1154128 494 int rc = get_user_reply(q, buf, sizeof(buf));
d6b3ba41 495
19e4cfef
KZ
496 if (rc) {
497 if (rc == -ECANCELED)
498 *canceled = 1;
d6b3ba41 499 break;
19e4cfef 500 }
d6b3ba41
KZ
501
502 if (buf[1] == '\0' && toupper(*buf) == 'L')
503 list_partition_types(cxt);
e6effcac 504 else if (*buf) {
006607ab
KZ
505 struct fdisk_parttype *t = fdisk_label_advparse_parttype(lb, buf,
506 FDISK_PARTTYPE_PARSE_DATA
507 | FDISK_PARTTYPE_PARSE_ALIAS
508 | FDISK_PARTTYPE_PARSE_SEQNUM);
e6effcac
KZ
509 if (!t)
510 fdisk_info(cxt, _("Failed to parse '%s' partition type."), buf);
511 return t;
512 }
d6b3ba41
KZ
513 } while (1);
514
515 return NULL;
516}
517
8d2f4498 518
7b575fcc 519void list_partition_types(struct fdisk_context *cxt)
6dbe3af9 520{
006607ab 521 size_t ntypes = 0, next = 0;
f45f5c83 522 struct fdisk_label *lb;
006607ab 523 int pager = 0;
6dbe3af9 524
a745611d
KZ
525 assert(cxt);
526 lb = fdisk_get_label(cxt, NULL);
527 if (!lb)
528 return;
529 ntypes = fdisk_label_get_nparttypes(lb);
530 if (!ntypes)
7b575fcc 531 return;
2b6fc908 532
a745611d 533 if (fdisk_label_has_code_parttypes(lb)) {
7b575fcc
KZ
534 /*
535 * Prints in 4 columns in format <hex> <name>
536 */
006607ab 537 size_t last[4], done = 0, size;
76f17cf2 538 int i;
b8d22034 539
76f17cf2 540 size = ntypes;
7b575fcc
KZ
541
542 for (i = 3; i >= 0; i--)
543 last[3 - i] = done += (size + i - done) / (i + 1);
544 i = done = 0;
545
546 do {
547 #define NAME_WIDTH 15
548 char name[NAME_WIDTH * MB_LEN_MAX];
549 size_t width = NAME_WIDTH;
a745611d 550 const struct fdisk_parttype *t = fdisk_label_get_parttype(lb, next);
7b575fcc
KZ
551 size_t ret;
552
e6d0c4c1 553 if (fdisk_parttype_get_name(t)) {
5d271cef 554 printf("%s%02x ", i ? " " : "\n",
a745611d
KZ
555 fdisk_parttype_get_code(t));
556 ret = mbsalign(_(fdisk_parttype_get_name(t)),
557 name, sizeof(name),
558 &width, MBS_ALIGN_LEFT, 0);
7b575fcc 559
76f17cf2 560 if (ret == (size_t)-1 || ret >= sizeof(name))
a745611d
KZ
561 printf("%-15.15s",
562 _(fdisk_parttype_get_name(t)));
76f17cf2
KZ
563 else
564 fputs(name, stdout);
565 }
7b575fcc
KZ
566
567 next = last[i++] + done;
568 if (i > 3 || next >= last[i]) {
569 i = 0;
570 next = ++done;
571 }
572 } while (done < last[0]);
573
006607ab 574 putchar('\n');
7b575fcc
KZ
575 } else {
576 /*
577 * Prints 1 column in format <idx> <name> <typestr>
578 */
76f17cf2 579 size_t i;
7b575fcc 580
8d2f4498 581 pager_open();
006607ab 582 pager = 1;
8d2f4498 583
a745611d
KZ
584 for (i = 0; i < ntypes; i++) {
585 const struct fdisk_parttype *t = fdisk_label_get_parttype(lb, i);
586 printf("%3zu %-30s %s\n", i + 1,
587 fdisk_parttype_get_name(t),
588 fdisk_parttype_get_string(t));
76f17cf2 589 }
8d2f4498 590
7b575fcc 591 }
006607ab
KZ
592
593
594 /*
595 * Aliases
596 */
597 if (fdisk_label_has_parttypes_shortcuts(lb)) {
598 const char *alias = NULL, *typestr = NULL;
599 int rc = 0;
600
601 fputs(_("\nAliases:\n"), stdout);
602
603 for (next = 0; rc == 0 || rc == 2; next++) {
604 /* rc: <0 error, 0 success, 1 end, 2 deprecated */
605 rc = fdisk_label_get_parttype_shortcut(lb,
606 next, &typestr, NULL, &alias);
607 if (rc == 0)
608 printf(" %-14s - %s\n", alias, typestr);
609 }
610 }
611
612 if (pager)
613 pager_close();
614
6dbe3af9
KZ
615}
616
f02fecd1 617void toggle_dos_compatibility_flag(struct fdisk_context *cxt)
852ce62b 618{
6a632136 619 struct fdisk_label *lb = fdisk_get_label(cxt, "dos");
852ce62b
KZ
620 int flag;
621
622 if (!lb)
623 return;
624
625 flag = !fdisk_dos_is_compatible(lb);
09f0c3d9
KZ
626 fdisk_info(cxt, flag ?
627 _("DOS Compatibility flag is set (DEPRECATED!)") :
628 _("DOS Compatibility flag is not set"));
edd7b958 629
852ce62b
KZ
630 fdisk_dos_enable_compatible(lb, flag);
631
aa36c2cf 632 if (fdisk_is_label(cxt, DOS))
09f0c3d9 633 fdisk_reset_alignment(cxt); /* reset the current label */
6dbe3af9
KZ
634}
635
27ddd4f1 636void change_partition_type(struct fdisk_context *cxt)
e53ced85 637{
641a75ca 638 size_t i;
85151521
KZ
639 struct fdisk_parttype *t = NULL;
640 struct fdisk_partition *pa = NULL;
641 const char *old = NULL;
19e4cfef 642 int canceled = 0;
6dbe3af9 643
e3661531 644 assert(cxt);
e3661531 645
641a75ca 646 if (fdisk_ask_partnum(cxt, &i, FALSE))
24f4bbff 647 return;
2b6fc908 648
85151521
KZ
649 if (fdisk_get_partition(cxt, i, &pa)) {
650 fdisk_warnx(cxt, _("Partition %zu does not exist yet!"), i + 1);
651 return;
652 }
653
654 t = (struct fdisk_parttype *) fdisk_partition_get_type(pa);
e6d0c4c1 655 old = t ? fdisk_parttype_get_name(t) : _("Unknown");
85151521
KZ
656
657 do {
19e4cfef
KZ
658 t = ask_partition_type(cxt, &canceled);
659 if (canceled)
660 break;
85151521
KZ
661 } while (!t);
662
e6effcac 663 if (canceled == 0 && t && fdisk_set_partition_type(cxt, i, t) == 0)
0477369a 664 fdisk_info(cxt,
85151521 665 _("Changed type of partition '%s' to '%s'."),
a745611d 666 old, t ? fdisk_parttype_get_name(t) : _("Unknown"));
85151521
KZ
667 else
668 fdisk_info(cxt,
669 _("Type of partition %zu is unchanged: %s."),
670 i + 1, old);
671
d6cfa8b3 672 fdisk_unref_partition(pa);
4bd02cdf 673 fdisk_unref_parttype(t);
6dbe3af9
KZ
674}
675
3e3b51b3
JLB
676int print_partition_info(struct fdisk_context *cxt)
677{
678 struct fdisk_partition *pa = NULL;
6360bcca 679 int rc = 0;
3e3b51b3
JLB
680 size_t i, nfields;
681 int *fields = NULL;
682 struct fdisk_label *lb = fdisk_get_label(cxt, NULL);
683
684 if ((rc = fdisk_ask_partnum(cxt, &i, FALSE)))
685 return rc;
686
687 if ((rc = fdisk_get_partition(cxt, i, &pa))) {
688 fdisk_warnx(cxt, _("Partition %zu does not exist yet!"), i + 1);
689 return rc;
690 }
691
6360bcca 692 if ((rc = fdisk_label_get_fields_ids_all(lb, cxt, &fields, &nfields)))
3e3b51b3 693 goto clean_data;
3e3b51b3
JLB
694
695 for (i = 0; i < nfields; ++i) {
696 int id = fields[i];
697 char *data = NULL;
698 const struct fdisk_field *fd = fdisk_label_get_field(lb, id);
699
700 if (!fd)
701 continue;
702
703 rc = fdisk_partition_to_string(pa, cxt, id, &data);
704 if (rc < 0)
705 goto clean_data;
6360bcca
KZ
706 if (!data || !*data)
707 continue;
14056588 708 fdisk_info(cxt, "%15s: %s", fdisk_field_get_name(fd), data);
3e3b51b3
JLB
709 free(data);
710 }
711
712clean_data:
713 fdisk_unref_partition(pa);
714 free(fields);
715 return rc;
716}
717
e916600f
KZ
718static size_t skip_empty(const unsigned char *buf, size_t i, size_t sz)
719{
720 size_t next;
721 const unsigned char *p0 = buf + i;
722
723 for (next = i + 16; next < sz; next += 16) {
724 if (memcmp(p0, buf + next, 16) != 0)
725 break;
726 }
727
728 return next == i + 16 ? i : next;
729}
6dbe3af9 730
e916600f 731static void dump_buffer(off_t base, unsigned char *buf, size_t sz, int all)
09f0c3d9 732{
e916600f
KZ
733 size_t i, l, next = 0;
734
735 if (!buf)
736 return;
737 for (i = 0, l = 0; i < sz; i++, l++) {
738 if (l == 0) {
739 if (all == 0 && !next)
740 next = skip_empty(buf, i, sz);
fdbd7bb9 741 printf("%08jx ", (intmax_t)base + i);
e916600f
KZ
742 }
743 printf(" %02x", buf[i]);
744 if (l == 7) /* words separator */
745 fputs(" ", stdout);
746 else if (l == 15) {
747 fputc('\n', stdout); /* next line */
6dbe3af9 748 l = -1;
e916600f
KZ
749 if (next > i) {
750 printf("*\n");
751 i = next - 1;
752 }
753 next = 0;
6dbe3af9
KZ
754 }
755 }
756 if (l > 0)
757 printf("\n");
6dbe3af9
KZ
758}
759
e916600f 760static void dump_blkdev(struct fdisk_context *cxt, const char *name,
9bbcf43f 761 uint64_t offset, size_t size, int all)
e53ced85 762{
8eccde20
KZ
763 int fd = fdisk_get_devfd(cxt);
764
fdbd7bb9 765 fdisk_info(cxt, _("\n%s: offset = %"PRIu64", size = %zu bytes."),
e916600f
KZ
766 name, offset, size);
767
8eccde20
KZ
768 assert(fd >= 0);
769
9bbcf43f 770 if (lseek(fd, (off_t) offset, SEEK_SET) == (off_t) -1)
e916600f 771 fdisk_warn(cxt, _("cannot seek"));
5afed187
KZ
772 else {
773 unsigned char *buf = xmalloc(size);
774
8eccde20 775 if (read_all(fd, (char *) buf, size) != (ssize_t) size)
5afed187
KZ
776 fdisk_warn(cxt, _("cannot read"));
777 else
778 dump_buffer(offset, buf, size, all);
779 free(buf);
780 }
e916600f
KZ
781}
782
783void dump_firstsector(struct fdisk_context *cxt)
784{
785 int all = !isatty(STDOUT_FILENO);
786
e3661531 787 assert(cxt);
6dbe3af9 788
8eccde20 789 dump_blkdev(cxt, _("First sector"), 0, fdisk_get_sector_size(cxt), all);
e916600f
KZ
790}
791
792void dump_disklabel(struct fdisk_context *cxt)
793{
794 int all = !isatty(STDOUT_FILENO);
795 int i = 0;
796 const char *name = NULL;
9bbcf43f 797 uint64_t offset = 0;
e916600f
KZ
798 size_t size = 0;
799
800 assert(cxt);
e3661531 801
e916600f
KZ
802 while (fdisk_locate_disklabel(cxt, i++, &name, &offset, &size) == 0 && size)
803 dump_blkdev(cxt, name, offset, size, all);
6dbe3af9
KZ
804}
805
0073a4cf 806static fdisk_sector_t get_dev_blocks(char *dev)
6da365de 807{
bbe67996 808 int fd, ret;
0073a4cf 809 fdisk_sector_t size;
6da365de
DB
810
811 if ((fd = open(dev, O_RDONLY)) < 0)
289dcc90 812 err(EXIT_FAILURE, _("cannot open %s"), dev);
0073a4cf 813 ret = blkdev_get_sectors(fd, (unsigned long long *) &size);
6da365de 814 close(fd);
bbe67996
SK
815 if (ret < 0)
816 err(EXIT_FAILURE, _("BLKGETSIZE ioctl failed on %s"), dev);
6da365de
DB
817 return size/2;
818}
819
5635d195
KZ
820
821void follow_wipe_mode(struct fdisk_context *cxt)
822{
823 int dowipe = wipemode == WIPEMODE_ALWAYS ? 1 : 0;
824
825 if (isatty(STDIN_FILENO) && wipemode == WIPEMODE_AUTO)
826 dowipe = 1; /* do it in interactive mode */
827
828 if (fdisk_is_ptcollision(cxt) && wipemode != WIPEMODE_NEVER)
829 dowipe = 1; /* always remove old PT */
830
831 fdisk_enable_wipe(cxt, dowipe);
832 if (dowipe)
833 fdisk_warnx(cxt, _(
6cd671d4 834 "The device contains '%s' signature and it will be removed by a write command. "
ce16f04e 835 "See fdisk(8) man page and --wipe option for more details."),
5635d195
KZ
836 fdisk_get_collision(cxt));
837 else
838 fdisk_warnx(cxt, _(
6cd671d4 839 "The device contains '%s' signature and it may remain on the device. "
5635d195
KZ
840 "It is recommended to wipe the device with wipefs(8) or "
841 "fdisk --wipe, in order to avoid possible collisions."),
842 fdisk_get_collision(cxt));
843}
844
6e1eda6f 845static void __attribute__((__noreturn__)) usage(void)
e3a4aaa7 846{
6e1eda6f
RM
847 FILE *out = stdout;
848
e3a4aaa7
KZ
849 fputs(USAGE_HEADER, out);
850
851 fprintf(out,
7eeb2c82
WS
852 _(" %1$s [options] <disk> change partition table\n"
853 " %1$s [options] -l [<disk>...] list partition table(s)\n"),
e3a4aaa7
KZ
854 program_invocation_short_name);
855
451dbcfa
BS
856 fputs(USAGE_SEPARATOR, out);
857 fputs(_("Display or manipulate a disk partition table.\n"), out);
858
e3a4aaa7
KZ
859 fputs(USAGE_OPTIONS, out);
860 fputs(_(" -b, --sector-size <size> physical and logical sector size\n"), out);
718b6f0c 861 fputs(_(" -B, --protect-boot don't erase bootbits when creating a new label\n"), out);
e3a4aaa7 862 fputs(_(" -c, --compatibility[=<mode>] mode is 'dos' or 'nondos' (default)\n"), out);
a7466bdc
SK
863 fprintf(out,
864 _(" -L, --color[=<when>] colorize output (%s, %s or %s)\n"), "auto", "always", "never");
5d51dc2a
KZ
865 fprintf(out,
866 " %s\n", USAGE_COLORS_DEFAULT);
9e930041 867 fputs(_(" -l, --list display partitions and exit\n"), out);
99d78b2f
KZ
868 fputs(_(" -x, --list-details like --list but with more details\n"), out);
869
f2229320 870 fputs(_(" -n, --noauto-pt don't create default partition table on empty devices\n"), out);
2d7dffeb 871 fputs(_(" -o, --output <list> output columns\n"), out);
e3a4aaa7
KZ
872 fputs(_(" -t, --type <type> recognize specified partition table type only\n"), out);
873 fputs(_(" -u, --units[=<unit>] display units: 'cylinders' or 'sectors' (default)\n"), out);
874 fputs(_(" -s, --getsz display device size in 512-byte sectors [DEPRECATED]\n"), out);
354f8cc8 875 fputs(_(" --bytes print SIZE in bytes rather than in human readable format\n"), out);
a7466bdc
SK
876 fprintf(out,
877 _(" -w, --wipe <mode> wipe signatures (%s, %s or %s)\n"), "auto", "always", "never");
878 fprintf(out,
879 _(" -W, --wipe-partitions <mode> wipe signatures from new partitions (%s, %s or %s)\n"), "auto", "always", "never");
e3a4aaa7
KZ
880
881 fputs(USAGE_SEPARATOR, out);
4b4e391a
KZ
882 fputs(_(" -C, --cylinders <number> specify the number of cylinders\n"), out);
883 fputs(_(" -H, --heads <number> specify the number of heads\n"), out);
884 fputs(_(" -S, --sectors <number> specify the number of sectors per track\n"), out);
e3a4aaa7
KZ
885
886 fputs(USAGE_SEPARATOR, out);
f45f3ec3 887 printf(USAGE_HELP_OPTIONS(31));
e3a4aaa7 888
fff8ad58
KZ
889 list_available_columns(out);
890
f45f3ec3 891 printf(USAGE_MAN_TAIL("fdisk(8)"));
6e1eda6f 892 exit(EXIT_SUCCESS);
e3a4aaa7
KZ
893}
894
895
5b72b3dd
KZ
896enum {
897 ACT_FDISK = 0, /* default */
898 ACT_LIST,
99d78b2f 899 ACT_LIST_DETAILS,
5b72b3dd
KZ
900 ACT_SHOWSIZE
901};
902
e1144767
DB
903int main(int argc, char **argv)
904{
f2229320 905 int rc, i, c, act = ACT_FDISK, noauto_pt = 0;
d0c9ddc3 906 int colormode = UL_COLORMODE_UNDEF;
4e0e8253 907 struct fdisk_context *cxt;
fff8ad58 908 char *outarg = NULL;
354f8cc8
KZ
909 enum {
910 OPT_BYTES = CHAR_MAX + 1
911 };
e3a4aaa7 912 static const struct option longopts[] = {
354f8cc8 913 { "bytes", no_argument, NULL, OPT_BYTES },
e3a4aaa7
KZ
914 { "color", optional_argument, NULL, 'L' },
915 { "compatibility", optional_argument, NULL, 'c' },
4b4e391a 916 { "cylinders", required_argument, NULL, 'C' },
f1970cc5 917 { "heads", required_argument, NULL, 'H' },
4b4e391a 918 { "sectors", required_argument, NULL, 'S' },
e3a4aaa7
KZ
919 { "getsz", no_argument, NULL, 's' },
920 { "help", no_argument, NULL, 'h' },
921 { "list", no_argument, NULL, 'l' },
99d78b2f 922 { "list-details", no_argument, NULL, 'x' },
f2229320 923 { "noauto-pt", no_argument, NULL, 'n' },
e3a4aaa7
KZ
924 { "sector-size", required_argument, NULL, 'b' },
925 { "type", required_argument, NULL, 't' },
926 { "units", optional_argument, NULL, 'u' },
927 { "version", no_argument, NULL, 'V' },
2d7dffeb 928 { "output", no_argument, NULL, 'o' },
aeb9a30b 929 { "protect-boot", no_argument, NULL, 'B' },
cb9a4b00 930 { "wipe", required_argument, NULL, 'w' },
ba465623 931 { "wipe-partitions",required_argument, NULL, 'W' },
e3a4aaa7
KZ
932 { NULL, 0, NULL, 0 }
933 };
934
7eda085c
KZ
935 setlocale(LC_ALL, "");
936 bindtextdomain(PACKAGE, LOCALEDIR);
937 textdomain(PACKAGE);
2c308875 938 close_stdout_atexit();
2b6fc908 939
4e0e8253 940 fdisk_init_debug(0);
053939a4 941 scols_init_debug(0);
e6d0c4c1
KZ
942 fdiskprog_init_debug();
943
4e0e8253
KZ
944 cxt = fdisk_new_context();
945 if (!cxt)
946 err(EXIT_FAILURE, _("failed to allocate libfdisk context"));
947
6a632136 948 fdisk_set_ask(cxt, ask_callback, NULL);
416c43a9 949
f2229320 950 while ((c = getopt_long(argc, argv, "b:Bc::C:hH:lL::no:sS:t:u::vVw:W:x",
e3a4aaa7 951 longopts, NULL)) != -1) {
2b6fc908
KZ
952 switch (c) {
953 case 'b':
6bcd192c
KZ
954 {
955 size_t sz = strtou32_or_err(optarg,
956 _("invalid sector size argument"));
957 if (sz != 512 && sz != 1024 && sz != 2048 && sz != 4096)
6e1eda6f 958 errx(EXIT_FAILURE, _("invalid sector size argument"));
6bcd192c 959 fdisk_save_user_sector_size(cxt, sz, sz);
2b6fc908 960 break;
6bcd192c 961 }
9ff89c5d 962 case 'B':
aeb9a30b
KZ
963 fdisk_enable_bootbits_protection(cxt, 1);
964 break;
0e6f4a20 965 case 'C':
1653f0b0
KZ
966 fdisk_save_user_geometry(cxt,
967 strtou32_or_err(optarg,
968 _("invalid cylinders argument")),
969 0, 0);
0e6f4a20 970 break;
78498b7b 971 case 'c':
852ce62b 972 if (optarg) {
2b0bc17b 973 /* this setting is independent on the current
e3a4aaa7
KZ
974 * actively used label
975 */
976 char *p = *optarg == '=' ? optarg + 1 : optarg;
6a632136 977 struct fdisk_label *lb = fdisk_get_label(cxt, "dos");
e3a4aaa7 978
852ce62b
KZ
979 if (!lb)
980 err(EXIT_FAILURE, _("not found DOS label driver"));
e3a4aaa7 981 if (strcmp(p, "dos") == 0)
852ce62b 982 fdisk_dos_enable_compatible(lb, TRUE);
e3a4aaa7 983 else if (strcmp(p, "nondos") == 0)
852ce62b 984 fdisk_dos_enable_compatible(lb, FALSE);
6e1eda6f
RM
985 else
986 errx(EXIT_FAILURE, _("unknown compatibility mode '%s'"), p);
852ce62b
KZ
987 }
988 /* use default if no optarg specified */
78498b7b 989 break;
0e6f4a20 990 case 'H':
1653f0b0
KZ
991 fdisk_save_user_geometry(cxt, 0,
992 strtou32_or_err(optarg,
993 _("invalid heads argument")),
994 0);
0e6f4a20
KZ
995 break;
996 case 'S':
1653f0b0
KZ
997 fdisk_save_user_geometry(cxt, 0, 0,
998 strtou32_or_err(optarg,
999 _("invalid sectors argument")));
0e6f4a20 1000 break;
2b6fc908 1001 case 'l':
5b72b3dd 1002 act = ACT_LIST;
2b6fc908 1003 break;
99d78b2f
KZ
1004 case 'x':
1005 act = ACT_LIST_DETAILS;
1006 break;
80a1712f 1007 case 'L':
5d51dc2a 1008 colormode = UL_COLORMODE_AUTO;
80a1712f
KZ
1009 if (optarg)
1010 colormode = colormode_or_err(optarg,
1011 _("unsupported color mode"));
1012 break;
f2229320
KZ
1013 case 'n':
1014 noauto_pt = 1;
1015 break;
fff8ad58
KZ
1016 case 'o':
1017 outarg = optarg;
1018 break;
2b6fc908 1019 case 's':
5b72b3dd 1020 act = ACT_SHOWSIZE;
2b6fc908 1021 break;
565b7da6
KZ
1022 case 't':
1023 {
1024 struct fdisk_label *lb = NULL;
1025
6a632136 1026 while (fdisk_next_label(cxt, &lb) == 0)
565b7da6
KZ
1027 fdisk_label_set_disabled(lb, 1);
1028
6a632136 1029 lb = fdisk_get_label(cxt, optarg);
565b7da6
KZ
1030 if (!lb)
1031 errx(EXIT_FAILURE, _("unsupported disklabel: %s"), optarg);
1032 fdisk_label_set_disabled(lb, 0);
1ce1a112 1033 break;
565b7da6 1034 }
2b6fc908 1035 case 'u':
ec10aa67
KZ
1036 if (optarg && *optarg == '=')
1037 optarg++;
6a632136 1038 if (fdisk_set_unit(cxt, optarg) != 0)
6e1eda6f 1039 errx(EXIT_FAILURE, _("unsupported unit"));
2b6fc908 1040 break;
e3a4aaa7
KZ
1041 case 'V': /* preferred for util-linux */
1042 case 'v': /* for backward compatibility only */
2c308875 1043 print_version(EXIT_SUCCESS);
cb9a4b00
KZ
1044 case 'w':
1045 wipemode = wipemode_from_string(optarg);
1046 if (wipemode < 0)
1047 errx(EXIT_FAILURE, _("unsupported wipe mode"));
1048 break;
ba465623
KZ
1049 case 'W':
1050 pwipemode = wipemode_from_string(optarg);
1051 if (pwipemode < 0)
1052 errx(EXIT_FAILURE, _("unsupported wipe mode"));
1053 break;
e1144767 1054 case 'h':
6e1eda6f 1055 usage();
354f8cc8
KZ
1056 case OPT_BYTES:
1057 fdisk_set_size_unit(cxt, FDISK_SIZEUNIT_BYTES);
1058 break;
2b6fc908 1059 default:
677ec86c 1060 errtryhelp(EXIT_FAILURE);
2b6fc908 1061 }
6dbe3af9 1062 }
2b6fc908 1063
6bcd192c
KZ
1064 if (argc-optind != 1 && fdisk_has_user_device_properties(cxt))
1065 warnx(_("The device properties (sector size and geometry) should"
1066 " be used with one specified device only."));
7eda085c 1067
d0c9ddc3 1068 colors_init(colormode, "fdisk");
c1154128 1069 is_interactive = isatty(STDIN_FILENO);
ffcf0540 1070
5b72b3dd
KZ
1071 switch (act) {
1072 case ACT_LIST:
99d78b2f 1073 case ACT_LIST_DETAILS:
6a632136 1074 fdisk_enable_listonly(cxt, 1);
99d78b2f
KZ
1075
1076 if (act == ACT_LIST_DETAILS)
1077 fdisk_enable_details(cxt, 1);
1078
fff8ad58 1079 init_fields(cxt, outarg, NULL);
ffcf0540 1080
2b6fc908
KZ
1081 if (argc > optind) {
1082 int k;
8fdd483c 1083
4a52959d
WS
1084 for (rc = 0, k = optind; k < argc; k++)
1085 rc += print_device_pt(cxt, argv[k], 1, 0, k != optind);
8fdd483c 1086
8fdd483c
KZ
1087 if (rc)
1088 return EXIT_FAILURE;
ea4824f1 1089 } else
d2c47697 1090 print_all_devices_pt(cxt, 0);
5b72b3dd 1091 break;
2b6fc908 1092
5b72b3dd 1093 case ACT_SHOWSIZE:
9564e46c 1094 /* deprecated */
6e1eda6f
RM
1095 if (argc - optind <= 0) {
1096 warnx(_("bad usage"));
1097 errtryhelp(EXIT_FAILURE);
1098 }
6da365de 1099 for (i = optind; i < argc; i++) {
0073a4cf
KZ
1100 uintmax_t blks = get_dev_blocks(argv[i]);
1101
5b72b3dd 1102 if (argc - optind == 1)
0073a4cf 1103 printf("%ju\n", blks);
2b6fc908 1104 else
0073a4cf 1105 printf("%s: %ju\n", argv[i], blks);
6dbe3af9 1106 }
5b72b3dd 1107 break;
6dbe3af9 1108
5b72b3dd 1109 case ACT_FDISK:
6e1eda6f
RM
1110 if (argc-optind != 1) {
1111 warnx(_("bad usage"));
1112 errtryhelp(EXIT_FAILURE);
1113 }
7eda085c 1114
5b72b3dd 1115 /* Here starts interactive mode, use fdisk_{warn,info,..} functions */
496c979a 1116 color_scheme_enable("welcome", UL_COLOR_GREEN);
09f0c3d9 1117 fdisk_info(cxt, _("Welcome to fdisk (%s)."), PACKAGE_STRING);
80a1712f
KZ
1118 color_disable();
1119 fdisk_info(cxt, _("Changes will remain in memory only, until you decide to write them.\n"
1120 "Be careful before using the write command.\n"));
2d8988bd 1121
6a632136 1122 rc = fdisk_assign_device(cxt, argv[optind], 0);
e146ae4e 1123 if (rc == -EACCES) {
6a632136 1124 rc = fdisk_assign_device(cxt, argv[optind], 1);
e146ae4e 1125 if (rc == 0)
62eea9ce 1126 fdisk_warnx(cxt, _("Device is open in read-only mode."));
e146ae4e
KZ
1127 }
1128 if (rc)
2d8988bd
KZ
1129 err(EXIT_FAILURE, _("cannot open %s"), argv[optind]);
1130
5b72b3dd 1131 fflush(stdout);
56c07b96 1132
5635d195
KZ
1133 if (fdisk_get_collision(cxt))
1134 follow_wipe_mode(cxt);
cb9a4b00 1135
aa36c2cf 1136 if (!fdisk_has_label(cxt)) {
2d8988bd 1137 fdisk_info(cxt, _("Device does not contain a recognized partition table."));
f2229320
KZ
1138 if (!noauto_pt)
1139 fdisk_create_disklabel(cxt, NULL);
433d05ff 1140
aa36c2cf 1141 } else if (fdisk_is_label(cxt, GPT) && fdisk_gpt_is_hybrid(cxt))
433d05ff 1142 fdisk_warnx(cxt, _(
09af3db4 1143 "A hybrid GPT was detected. You have to sync "
433d05ff 1144 "the hybrid MBR manually (expert command 'M')."));
6dbe3af9 1145
fff8ad58
KZ
1146 init_fields(cxt, outarg, NULL); /* -o <columns> */
1147
fadd8e08
KZ
1148 if (!fdisk_is_readonly(cxt)) {
1149 fdisk_get_partitions(cxt, &original_layout);
1150 device_is_used = fdisk_device_is_used(cxt);
1151 }
1152
5b72b3dd
KZ
1153 while (1)
1154 process_fdisk_menu(&cxt);
1155 }
9777759a 1156
c7119037 1157 fdisk_unref_context(cxt);
5b72b3dd 1158 return EXIT_SUCCESS;
6dbe3af9 1159}