2 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
3 * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org>
5 * Copyright (C) 2007-2013 Karel Zak <kzak@redhat.com>
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.
26 #include <libsmartcols.h>
27 #ifdef HAVE_LIBREADLINE
28 # define _FUNCTION_DEF
29 # include <readline/readline.h>
39 #include "pathnames.h"
40 #include "canonicalize.h"
42 #include "closestream.h"
47 #include "pt-sun.h" /* to toggle flags */
49 #ifdef HAVE_LINUX_COMPILER_H
50 # include <linux/compiler.h>
52 #ifdef HAVE_LINUX_BLKPG_H
53 # include <linux/blkpg.h>
56 int pwipemode
= WIPEMODE_AUTO
;
59 struct fdisk_table
*original_layout
;
61 static int wipemode
= WIPEMODE_AUTO
;
64 * fdisk debug stuff (see fdisk.h and include/debug.h)
66 UL_DEBUG_DEFINE_MASK(fdisk
);
67 UL_DEBUG_DEFINE_MASKNAMES(fdisk
) = UL_DEBUG_EMPTY_MASKNAMES
;
69 static void fdiskprog_init_debug(void)
71 __UL_INIT_DEBUG_FROM_ENV(fdisk
, FDISKPROG_DEBUG_
, 0, FDISK_DEBUG
);
74 static void reply_sighandler(int sig
__attribute__((unused
)))
76 DBG(ASK
, ul_debug("got signal"));
79 static int reply_running
;
81 #ifdef HAVE_LIBREADLINE
82 static char *reply_line
;
84 static void reply_linehandler(char *line
)
88 rl_callback_handler_remove(); /* avoid duplicate prompt */
92 int get_user_reply(const char *prompt
, char *buf
, size_t bufsz
)
94 struct sigaction oldact
, act
= {
95 .sa_handler
= reply_sighandler
97 struct pollfd fds
[] = {
98 { .fd
= fileno(stdin
), .events
= POLLIN
}
103 DBG(ASK
, ul_debug("asking for user reply %s", is_interactive
? "[interactive]" : ""));
105 sigemptyset(&act
.sa_mask
);
106 sigaction(SIGINT
, &act
, &oldact
);
108 #ifdef HAVE_LIBREADLINE
110 rl_callback_handler_install(prompt
, reply_linehandler
);
117 #ifdef HAVE_LIBREADLINE
121 fputs(prompt
, stdout
);
125 rc
= poll(fds
, 1, -1);
126 if (rc
== -1 && errno
== EINTR
) { /* interrupted by signal */
127 DBG(ASK
, ul_debug("cancel by CTRL+C"));
131 if (rc
== -1 && errno
!= EAGAIN
) { /* error */
135 #ifdef HAVE_LIBREADLINE
136 if (is_interactive
) {
137 /* read input and copy to buf[] */
138 rl_callback_read_char();
139 if (!reply_running
&& reply_line
) {
140 sz
= strlen(reply_line
);
144 memcpy(buf
, reply_line
, min(sz
, bufsz
));
145 buf
[min(sz
, bufsz
- 1)] = '\0';
152 if (!fgets(buf
, bufsz
, stdin
))
156 } while (reply_running
);
159 DBG(ASK
, ul_debug("cancel by CTRL+D"));
167 sz
= ltrim_whitespace((unsigned char *) buf
);
168 if (sz
&& *(buf
+ sz
- 1) == '\n')
169 *(buf
+ sz
- 1) = '\0';
171 DBG(ASK
, ul_debug("user's reply: >>>%s<<<", buf
));
173 #ifdef HAVE_LIBREADLINE
175 rl_callback_handler_remove();
177 sigaction(SIGINT
, &oldact
, NULL
);
181 static int ask_menu(struct fdisk_context
*cxt
, struct fdisk_ask
*ask
,
182 char *buf
, size_t bufsz
)
185 const char *q
= fdisk_ask_get_query(ask
);
186 int dft
= fdisk_ask_menu_get_default(ask
);
189 fputs(q
, stdout
); /* print header */
196 const char *name
, *desc
;
199 /* print menu items */
200 while (fdisk_ask_menu_get_item(ask
, i
++, &key
, &name
, &desc
) == 0)
201 fprintf(stdout
, " %c %s (%s)\n", key
, name
, desc
);
204 snprintf(prompt
, sizeof(prompt
), _("Select (default %c): "), dft
);
205 rc
= get_user_reply(prompt
, buf
, bufsz
);
209 fdisk_info(cxt
, _("Using default response %c."), dft
);
216 while (fdisk_ask_menu_get_item(ask
, i
++, &key
, NULL
, NULL
) == 0) {
218 fdisk_ask_menu_set_result(ask
, c
);
219 return 0; /* success */
222 fdisk_warnx(cxt
, _("Value out of range."));
229 #define tochar(num) ((int) ('a' + num - 1))
230 static int ask_number(struct fdisk_context
*cxt
,
231 struct fdisk_ask
*ask
,
232 char *buf
, size_t bufsz
)
234 char prompt
[128] = { '\0' };
235 const char *q
= fdisk_ask_get_query(ask
);
236 const char *range
= fdisk_ask_number_get_range(ask
);
238 uint64_t dflt
= fdisk_ask_number_get_default(ask
),
239 low
= fdisk_ask_number_get_low(ask
),
240 high
= fdisk_ask_number_get_high(ask
);
241 int inchar
= fdisk_ask_number_inchars(ask
);
245 DBG(ASK
, ul_debug("asking for number "
246 "['%s', <%"PRIu64
",%"PRIu64
">, default=%"PRIu64
", range: %s]",
247 q
, low
, high
, dflt
, range
));
249 if (range
&& dflt
>= low
&& dflt
<= high
) {
251 snprintf(prompt
, sizeof(prompt
), _("%s (%s, default %c): "),
252 q
, range
, tochar(dflt
));
254 snprintf(prompt
, sizeof(prompt
), _("%s (%s, default %"PRIu64
"): "),
257 } else if (dflt
>= low
&& dflt
<= high
) {
259 snprintf(prompt
, sizeof(prompt
), _("%s (%c-%c, default %c): "),
260 q
, tochar(low
), tochar(high
), tochar(dflt
));
262 snprintf(prompt
, sizeof(prompt
),
263 _("%s (%"PRIu64
"-%"PRIu64
", default %"PRIu64
"): "),
266 snprintf(prompt
, sizeof(prompt
), _("%s (%c-%c): "),
267 q
, tochar(low
), tochar(high
));
269 snprintf(prompt
, sizeof(prompt
), _("%s (%"PRIu64
"-%"PRIu64
"): "),
273 int rc
= get_user_reply(prompt
, buf
, bufsz
);
278 if (!*buf
&& dflt
>= low
&& dflt
<= high
)
279 return fdisk_ask_number_set_result(ask
, dflt
);
281 if (isdigit_string(buf
)) {
285 num
= strtoumax(buf
, &end
, 10);
286 if (errno
|| buf
== end
|| (end
&& *end
))
288 } else if (inchar
&& isalpha(*buf
)) {
289 num
= tolower(*buf
) - 'a' + 1;
293 if (rc
== 0 && num
>= low
&& num
<= high
)
294 return fdisk_ask_number_set_result(ask
, num
);
296 fdisk_warnx(cxt
, _("Value out of range."));
302 static int ask_offset(struct fdisk_context
*cxt
,
303 struct fdisk_ask
*ask
,
304 char *buf
, size_t bufsz
)
306 char prompt
[128] = { '\0' };
307 const char *q
= fdisk_ask_get_query(ask
);
308 const char *range
= fdisk_ask_number_get_range(ask
);
310 uint64_t dflt
= fdisk_ask_number_get_default(ask
),
311 low
= fdisk_ask_number_get_low(ask
),
312 high
= fdisk_ask_number_get_high(ask
),
313 base
= fdisk_ask_number_get_base(ask
);
317 DBG(ASK
, ul_debug("asking for offset ['%s', <%"PRIu64
",%"PRIu64
">, base=%"PRIu64
", default=%"PRIu64
", range: %s]",
318 q
, low
, high
, base
, dflt
, range
));
320 if (range
&& dflt
>= low
&& dflt
<= high
)
321 snprintf(prompt
, sizeof(prompt
), _("%s (%s, default %"PRIu64
"): "),
323 else if (dflt
>= low
&& dflt
<= high
)
324 snprintf(prompt
, sizeof(prompt
),
325 _("%s (%"PRIu64
"-%"PRIu64
", default %"PRIu64
"): "),
328 snprintf(prompt
, sizeof(prompt
), _("%s (%"PRIu64
"-%"PRIu64
"): "),
336 int rc
= get_user_reply(prompt
, buf
, bufsz
);
339 if (!*buf
&& dflt
>= low
&& dflt
<= high
)
340 return fdisk_ask_number_set_result(ask
, dflt
);
343 if (*p
== '+' || *p
== '-') {
348 rc
= parse_size(p
, &num
, &pwr
);
351 DBG(ASK
, ul_debug("parsed size: %ju", num
));
353 /* +{size}{K,M,...} specified, the "num" is in bytes */
354 uint64_t unit
= fdisk_ask_number_get_unit(ask
);
355 num
+= unit
/2; /* round */
360 else if (sig
== '-' && fdisk_ask_number_is_wrap_negative(ask
))
365 DBG(ASK
, ul_debug("final offset: %ju [sig: %c, power: %d, %s]",
367 sig
? "relative" : "absolute"));
368 if (num
>= low
&& num
<= high
) {
370 fdisk_ask_number_set_relative(ask
, 1);
371 return fdisk_ask_number_set_result(ask
, (uint64_t)num
);
373 fdisk_warnx(cxt
, _("Value out of range."));
379 static unsigned int info_count
;
381 static void fputs_info(struct fdisk_ask
*ask
, FILE *out
)
386 msg
= fdisk_ask_print_get_mesg(ask
);
396 int ask_callback(struct fdisk_context
*cxt
, struct fdisk_ask
*ask
,
397 void *data
__attribute__((__unused__
)))
400 char buf
[BUFSIZ
] = { '\0' };
405 if (fdisk_ask_get_type(ask
) != FDISK_ASKTYPE_INFO
)
408 switch(fdisk_ask_get_type(ask
)) {
409 case FDISK_ASKTYPE_MENU
:
410 return ask_menu(cxt
, ask
, buf
, sizeof(buf
));
411 case FDISK_ASKTYPE_NUMBER
:
412 return ask_number(cxt
, ask
, buf
, sizeof(buf
));
413 case FDISK_ASKTYPE_OFFSET
:
414 return ask_offset(cxt
, ask
, buf
, sizeof(buf
));
415 case FDISK_ASKTYPE_INFO
:
416 if (!fdisk_is_listonly(cxt
))
418 fputs_info(ask
, stdout
);
420 case FDISK_ASKTYPE_WARNX
:
422 color_scheme_fenable("warn", UL_COLOR_RED
, stderr
);
423 fputs(fdisk_ask_print_get_mesg(ask
), stderr
);
424 color_fdisable(stderr
);
427 case FDISK_ASKTYPE_WARN
:
429 color_scheme_fenable("warn", UL_COLOR_RED
, stderr
);
430 fputs(fdisk_ask_print_get_mesg(ask
), stderr
);
431 errno
= fdisk_ask_print_get_errno(ask
);
432 fprintf(stderr
, ": %m\n");
433 color_fdisable(stderr
);
435 case FDISK_ASKTYPE_YESNO
:
439 fputs(fdisk_ask_get_query(ask
), stdout
);
440 rc
= get_user_reply(_(" [Y]es/[N]o: "), buf
, sizeof(buf
));
444 if (x
== RPMATCH_YES
|| x
== RPMATCH_NO
) {
445 fdisk_ask_yesno_set_result(ask
, x
);
449 DBG(ASK
, ul_debug("yes-no ask: reply '%s' [rc=%d]", buf
, rc
));
451 case FDISK_ASKTYPE_STRING
:
454 snprintf(prmt
, sizeof(prmt
), "%s: ", fdisk_ask_get_query(ask
));
456 rc
= get_user_reply(prmt
, buf
, sizeof(buf
));
458 fdisk_ask_string_set_result(ask
, xstrdup(buf
));
459 DBG(ASK
, ul_debug("string ask: reply '%s' [rc=%d]", buf
, rc
));
463 warnx(_("internal error: unsupported dialog type %d"), fdisk_ask_get_type(ask
));
469 static struct fdisk_parttype
*ask_partition_type(struct fdisk_context
*cxt
, int *canceled
)
472 struct fdisk_label
*lb
;
475 lb
= fdisk_get_label(cxt
, NULL
);
481 q
= fdisk_label_has_code_parttypes(lb
) ?
482 _("Hex code (type L to list all codes): ") :
483 _("Partition type (type L to list all types): ");
485 char buf
[256] = { '\0' };
486 int rc
= get_user_reply(q
, buf
, sizeof(buf
));
489 if (rc
== -ECANCELED
)
494 if (buf
[1] == '\0' && toupper(*buf
) == 'L')
495 list_partition_types(cxt
);
497 struct fdisk_parttype
*t
= fdisk_label_parse_parttype(lb
, buf
);
500 fdisk_info(cxt
, _("Failed to parse '%s' partition type."), buf
);
509 void list_partition_types(struct fdisk_context
*cxt
)
512 struct fdisk_label
*lb
;
515 lb
= fdisk_get_label(cxt
, NULL
);
518 ntypes
= fdisk_label_get_nparttypes(lb
);
522 if (fdisk_label_has_code_parttypes(lb
)) {
524 * Prints in 4 columns in format <hex> <name>
526 size_t last
[4], done
= 0, next
= 0, size
;
531 for (i
= 3; i
>= 0; i
--)
532 last
[3 - i
] = done
+= (size
+ i
- done
) / (i
+ 1);
536 #define NAME_WIDTH 15
537 char name
[NAME_WIDTH
* MB_LEN_MAX
];
538 size_t width
= NAME_WIDTH
;
539 const struct fdisk_parttype
*t
= fdisk_label_get_parttype(lb
, next
);
542 if (fdisk_parttype_get_name(t
)) {
543 printf("%c%2x ", i
? ' ' : '\n',
544 fdisk_parttype_get_code(t
));
545 ret
= mbsalign(_(fdisk_parttype_get_name(t
)),
547 &width
, MBS_ALIGN_LEFT
, 0);
549 if (ret
== (size_t)-1 || ret
>= sizeof(name
))
551 _(fdisk_parttype_get_name(t
)));
556 next
= last
[i
++] + done
;
557 if (i
> 3 || next
>= last
[i
]) {
561 } while (done
< last
[0]);
565 * Prints 1 column in format <idx> <name> <typestr>
571 for (i
= 0; i
< ntypes
; i
++) {
572 const struct fdisk_parttype
*t
= fdisk_label_get_parttype(lb
, i
);
573 printf("%3zu %-30s %s\n", i
+ 1,
574 fdisk_parttype_get_name(t
),
575 fdisk_parttype_get_string(t
));
583 void toggle_dos_compatibility_flag(struct fdisk_context
*cxt
)
585 struct fdisk_label
*lb
= fdisk_get_label(cxt
, "dos");
591 flag
= !fdisk_dos_is_compatible(lb
);
592 fdisk_info(cxt
, flag
?
593 _("DOS Compatibility flag is set (DEPRECATED!)") :
594 _("DOS Compatibility flag is not set"));
596 fdisk_dos_enable_compatible(lb
, flag
);
598 if (fdisk_is_label(cxt
, DOS
))
599 fdisk_reset_alignment(cxt
); /* reset the current label */
602 void change_partition_type(struct fdisk_context
*cxt
)
605 struct fdisk_parttype
*t
= NULL
;
606 struct fdisk_partition
*pa
= NULL
;
607 const char *old
= NULL
;
612 if (fdisk_ask_partnum(cxt
, &i
, FALSE
))
615 if (fdisk_get_partition(cxt
, i
, &pa
)) {
616 fdisk_warnx(cxt
, _("Partition %zu does not exist yet!"), i
+ 1);
620 t
= (struct fdisk_parttype
*) fdisk_partition_get_type(pa
);
621 old
= t
? fdisk_parttype_get_name(t
) : _("Unknown");
624 t
= ask_partition_type(cxt
, &canceled
);
629 if (canceled
== 0 && t
&& fdisk_set_partition_type(cxt
, i
, t
) == 0)
631 _("Changed type of partition '%s' to '%s'."),
632 old
, t
? fdisk_parttype_get_name(t
) : _("Unknown"));
635 _("Type of partition %zu is unchanged: %s."),
638 fdisk_unref_partition(pa
);
639 fdisk_unref_parttype(t
);
642 int print_partition_info(struct fdisk_context
*cxt
)
644 struct fdisk_partition
*pa
= NULL
;
648 struct fdisk_label
*lb
= fdisk_get_label(cxt
, NULL
);
650 if ((rc
= fdisk_ask_partnum(cxt
, &i
, FALSE
)))
653 if ((rc
= fdisk_get_partition(cxt
, i
, &pa
))) {
654 fdisk_warnx(cxt
, _("Partition %zu does not exist yet!"), i
+ 1);
658 if ((rc
= fdisk_label_get_fields_ids_all(lb
, cxt
, &fields
, &nfields
)))
661 for (i
= 0; i
< nfields
; ++i
) {
664 const struct fdisk_field
*fd
= fdisk_label_get_field(lb
, id
);
669 rc
= fdisk_partition_to_string(pa
, cxt
, id
, &data
);
674 fdisk_info(cxt
, "%15s: %s", fdisk_field_get_name(fd
), data
);
679 fdisk_unref_partition(pa
);
684 static size_t skip_empty(const unsigned char *buf
, size_t i
, size_t sz
)
687 const unsigned char *p0
= buf
+ i
;
689 for (next
= i
+ 16; next
< sz
; next
+= 16) {
690 if (memcmp(p0
, buf
+ next
, 16) != 0)
694 return next
== i
+ 16 ? i
: next
;
697 static void dump_buffer(off_t base
, unsigned char *buf
, size_t sz
, int all
)
699 size_t i
, l
, next
= 0;
703 for (i
= 0, l
= 0; i
< sz
; i
++, l
++) {
705 if (all
== 0 && !next
)
706 next
= skip_empty(buf
, i
, sz
);
707 printf("%08jx ", (intmax_t)base
+ i
);
709 printf(" %02x", buf
[i
]);
710 if (l
== 7) /* words separator */
713 fputc('\n', stdout
); /* next line */
726 static void dump_blkdev(struct fdisk_context
*cxt
, const char *name
,
727 uint64_t offset
, size_t size
, int all
)
729 int fd
= fdisk_get_devfd(cxt
);
731 fdisk_info(cxt
, _("\n%s: offset = %"PRIu64
", size = %zu bytes."),
736 if (lseek(fd
, (off_t
) offset
, SEEK_SET
) == (off_t
) -1)
737 fdisk_warn(cxt
, _("cannot seek"));
739 unsigned char *buf
= xmalloc(size
);
741 if (read_all(fd
, (char *) buf
, size
) != (ssize_t
) size
)
742 fdisk_warn(cxt
, _("cannot read"));
744 dump_buffer(offset
, buf
, size
, all
);
749 void dump_firstsector(struct fdisk_context
*cxt
)
751 int all
= !isatty(STDOUT_FILENO
);
755 dump_blkdev(cxt
, _("First sector"), 0, fdisk_get_sector_size(cxt
), all
);
758 void dump_disklabel(struct fdisk_context
*cxt
)
760 int all
= !isatty(STDOUT_FILENO
);
762 const char *name
= NULL
;
768 while (fdisk_locate_disklabel(cxt
, i
++, &name
, &offset
, &size
) == 0 && size
)
769 dump_blkdev(cxt
, name
, offset
, size
, all
);
772 static fdisk_sector_t
get_dev_blocks(char *dev
)
777 if ((fd
= open(dev
, O_RDONLY
)) < 0)
778 err(EXIT_FAILURE
, _("cannot open %s"), dev
);
779 ret
= blkdev_get_sectors(fd
, (unsigned long long *) &size
);
782 err(EXIT_FAILURE
, _("BLKGETSIZE ioctl failed on %s"), dev
);
787 void follow_wipe_mode(struct fdisk_context
*cxt
)
789 int dowipe
= wipemode
== WIPEMODE_ALWAYS
? 1 : 0;
791 if (isatty(STDIN_FILENO
) && wipemode
== WIPEMODE_AUTO
)
792 dowipe
= 1; /* do it in interactive mode */
794 if (fdisk_is_ptcollision(cxt
) && wipemode
!= WIPEMODE_NEVER
)
795 dowipe
= 1; /* always remove old PT */
797 fdisk_enable_wipe(cxt
, dowipe
);
800 "The old %s signature will be removed by a write command."),
801 fdisk_get_collision(cxt
));
804 "The old %s signature may remain on the device. "
805 "It is recommended to wipe the device with wipefs(8) or "
806 "fdisk --wipe, in order to avoid possible collisions."),
807 fdisk_get_collision(cxt
));
810 static void __attribute__((__noreturn__
)) usage(void)
814 fputs(USAGE_HEADER
, out
);
817 _(" %1$s [options] <disk> change partition table\n"
818 " %1$s [options] -l [<disk>] list partition table(s)\n"),
819 program_invocation_short_name
);
821 fputs(USAGE_SEPARATOR
, out
);
822 fputs(_("Display or manipulate a disk partition table.\n"), out
);
824 fputs(USAGE_OPTIONS
, out
);
825 fputs(_(" -b, --sector-size <size> physical and logical sector size\n"), out
);
826 fputs(_(" -B, --protect-boot don't erase bootbits when creating a new label\n"), out
);
827 fputs(_(" -c, --compatibility[=<mode>] mode is 'dos' or 'nondos' (default)\n"), out
);
828 fputs(_(" -L, --color[=<when>] colorize output (auto, always or never)\n"), out
);
830 " %s\n", USAGE_COLORS_DEFAULT
);
831 fputs(_(" -l, --list display partitions and exit\n"), out
);
832 fputs(_(" -o, --output <list> output columns\n"), out
);
833 fputs(_(" -t, --type <type> recognize specified partition table type only\n"), out
);
834 fputs(_(" -u, --units[=<unit>] display units: 'cylinders' or 'sectors' (default)\n"), out
);
835 fputs(_(" -s, --getsz display device size in 512-byte sectors [DEPRECATED]\n"), out
);
836 fputs(_(" --bytes print SIZE in bytes rather than in human readable format\n"), out
);
837 fputs(_(" -w, --wipe <mode> wipe signatures (auto, always or never)\n"), out
);
838 fputs(_(" -W, --wipe-partitions <mode> wipe signatures from new partitions (auto, always or never)\n"), out
);
840 fputs(USAGE_SEPARATOR
, out
);
841 fputs(_(" -C, --cylinders <number> specify the number of cylinders\n"), out
);
842 fputs(_(" -H, --heads <number> specify the number of heads\n"), out
);
843 fputs(_(" -S, --sectors <number> specify the number of sectors per track\n"), out
);
845 fputs(USAGE_SEPARATOR
, out
);
846 printf(USAGE_HELP_OPTIONS(31));
848 list_available_columns(out
);
850 printf(USAGE_MAN_TAIL("fdisk(8)"));
856 ACT_FDISK
= 0, /* default */
861 int main(int argc
, char **argv
)
863 int rc
, i
, c
, act
= ACT_FDISK
;
864 int colormode
= UL_COLORMODE_UNDEF
;
865 struct fdisk_context
*cxt
;
868 OPT_BYTES
= CHAR_MAX
+ 1
870 static const struct option longopts
[] = {
871 { "bytes", no_argument
, NULL
, OPT_BYTES
},
872 { "color", optional_argument
, NULL
, 'L' },
873 { "compatibility", optional_argument
, NULL
, 'c' },
874 { "cylinders", required_argument
, NULL
, 'C' },
875 { "heads", required_argument
, NULL
, 'H' },
876 { "sectors", required_argument
, NULL
, 'S' },
877 { "getsz", no_argument
, NULL
, 's' },
878 { "help", no_argument
, NULL
, 'h' },
879 { "list", no_argument
, NULL
, 'l' },
880 { "sector-size", required_argument
, NULL
, 'b' },
881 { "type", required_argument
, NULL
, 't' },
882 { "units", optional_argument
, NULL
, 'u' },
883 { "version", no_argument
, NULL
, 'V' },
884 { "output", no_argument
, NULL
, 'o' },
885 { "protect-boot", no_argument
, NULL
, 'B' },
886 { "wipe", required_argument
, NULL
, 'w' },
887 { "wipe-partitions",required_argument
, NULL
, 'W' },
891 setlocale(LC_ALL
, "");
892 bindtextdomain(PACKAGE
, LOCALEDIR
);
894 close_stdout_atexit();
898 fdiskprog_init_debug();
900 cxt
= fdisk_new_context();
902 err(EXIT_FAILURE
, _("failed to allocate libfdisk context"));
904 fdisk_set_ask(cxt
, ask_callback
, NULL
);
906 while ((c
= getopt_long(argc
, argv
, "b:Bc::C:hH:lL::o:sS:t:u::vVw:W:",
907 longopts
, NULL
)) != -1) {
911 size_t sz
= strtou32_or_err(optarg
,
912 _("invalid sector size argument"));
913 if (sz
!= 512 && sz
!= 1024 && sz
!= 2048 && sz
!= 4096)
914 errx(EXIT_FAILURE
, _("invalid sector size argument"));
915 fdisk_save_user_sector_size(cxt
, sz
, sz
);
919 fdisk_enable_bootbits_protection(cxt
, 1);
922 fdisk_save_user_geometry(cxt
,
923 strtou32_or_err(optarg
,
924 _("invalid cylinders argument")),
929 /* this setting is independent on the current
930 * actively used label
932 char *p
= *optarg
== '=' ? optarg
+ 1 : optarg
;
933 struct fdisk_label
*lb
= fdisk_get_label(cxt
, "dos");
936 err(EXIT_FAILURE
, _("not found DOS label driver"));
937 if (strcmp(p
, "dos") == 0)
938 fdisk_dos_enable_compatible(lb
, TRUE
);
939 else if (strcmp(p
, "nondos") == 0)
940 fdisk_dos_enable_compatible(lb
, FALSE
);
942 errx(EXIT_FAILURE
, _("unknown compatibility mode '%s'"), p
);
944 /* use default if no optarg specified */
947 fdisk_save_user_geometry(cxt
, 0,
948 strtou32_or_err(optarg
,
949 _("invalid heads argument")),
953 fdisk_save_user_geometry(cxt
, 0, 0,
954 strtou32_or_err(optarg
,
955 _("invalid sectors argument")));
961 colormode
= UL_COLORMODE_AUTO
;
963 colormode
= colormode_or_err(optarg
,
964 _("unsupported color mode"));
974 struct fdisk_label
*lb
= NULL
;
976 while (fdisk_next_label(cxt
, &lb
) == 0)
977 fdisk_label_set_disabled(lb
, 1);
979 lb
= fdisk_get_label(cxt
, optarg
);
981 errx(EXIT_FAILURE
, _("unsupported disklabel: %s"), optarg
);
982 fdisk_label_set_disabled(lb
, 0);
986 if (optarg
&& *optarg
== '=')
988 if (fdisk_set_unit(cxt
, optarg
) != 0)
989 errx(EXIT_FAILURE
, _("unsupported unit"));
991 case 'V': /* preferred for util-linux */
992 case 'v': /* for backward compatibility only */
993 print_version(EXIT_SUCCESS
);
995 wipemode
= wipemode_from_string(optarg
);
997 errx(EXIT_FAILURE
, _("unsupported wipe mode"));
1000 pwipemode
= wipemode_from_string(optarg
);
1002 errx(EXIT_FAILURE
, _("unsupported wipe mode"));
1007 fdisk_set_size_unit(cxt
, FDISK_SIZEUNIT_BYTES
);
1010 errtryhelp(EXIT_FAILURE
);
1014 if (argc
-optind
!= 1 && fdisk_has_user_device_properties(cxt
))
1015 warnx(_("The device properties (sector size and geometry) should"
1016 " be used with one specified device only."));
1018 colors_init(colormode
, "fdisk");
1019 is_interactive
= isatty(STDIN_FILENO
);
1023 fdisk_enable_listonly(cxt
, 1);
1024 init_fields(cxt
, outarg
, NULL
);
1026 if (argc
> optind
) {
1030 for (rc
= 0, k
= optind
; k
< argc
; k
++) {
1032 fputs("\n\n", stdout
);
1034 rc
+= print_device_pt(cxt
, argv
[k
], 1, 0);
1038 return EXIT_FAILURE
;
1040 print_all_devices_pt(cxt
, 0);
1045 if (argc
- optind
<= 0) {
1046 warnx(_("bad usage"));
1047 errtryhelp(EXIT_FAILURE
);
1049 for (i
= optind
; i
< argc
; i
++) {
1050 uintmax_t blks
= get_dev_blocks(argv
[i
]);
1052 if (argc
- optind
== 1)
1053 printf("%ju\n", blks
);
1055 printf("%s: %ju\n", argv
[i
], blks
);
1060 if (argc
-optind
!= 1) {
1061 warnx(_("bad usage"));
1062 errtryhelp(EXIT_FAILURE
);
1065 /* Here starts interactive mode, use fdisk_{warn,info,..} functions */
1066 color_scheme_enable("welcome", UL_COLOR_GREEN
);
1067 fdisk_info(cxt
, _("Welcome to fdisk (%s)."), PACKAGE_STRING
);
1069 fdisk_info(cxt
, _("Changes will remain in memory only, until you decide to write them.\n"
1070 "Be careful before using the write command.\n"));
1072 rc
= fdisk_assign_device(cxt
, argv
[optind
], 0);
1073 if (rc
== -EACCES
) {
1074 rc
= fdisk_assign_device(cxt
, argv
[optind
], 1);
1076 fdisk_warnx(cxt
, _("Device is open in read-only mode."));
1079 err(EXIT_FAILURE
, _("cannot open %s"), argv
[optind
]);
1083 if (fdisk_get_collision(cxt
))
1084 follow_wipe_mode(cxt
);
1086 if (!fdisk_has_label(cxt
)) {
1087 fdisk_info(cxt
, _("Device does not contain a recognized partition table."));
1088 fdisk_create_disklabel(cxt
, NULL
);
1090 } else if (fdisk_is_label(cxt
, GPT
) && fdisk_gpt_is_hybrid(cxt
))
1092 "A hybrid GPT was detected. You have to sync "
1093 "the hybrid MBR manually (expert command 'M')."));
1095 init_fields(cxt
, outarg
, NULL
); /* -o <columns> */
1097 if (!fdisk_is_readonly(cxt
)) {
1098 fdisk_get_partitions(cxt
, &original_layout
);
1099 device_is_used
= fdisk_device_is_used(cxt
);
1103 process_fdisk_menu(&cxt
);
1106 fdisk_unref_context(cxt
);
1107 return EXIT_SUCCESS
;