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