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