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
);
118 #ifdef HAVE_LIBREADLINE
122 fputs(prompt
, stdout
);
126 rc
= poll(fds
, 1, -1);
127 if (rc
== -1 && errno
== EINTR
) { /* interrupted by signal */
128 DBG(ASK
, ul_debug("cancel by CTRL+C"));
132 if (rc
== -1 && errno
!= EAGAIN
) { /* error */
136 #ifdef HAVE_LIBREADLINE
137 if (is_interactive
) {
138 /* read input and copy to buf[] */
139 rl_callback_read_char();
140 if (!reply_running
&& reply_line
) {
141 sz
= strlen(reply_line
);
145 memcpy(buf
, reply_line
, min(sz
, bufsz
));
146 buf
[min(sz
, bufsz
- 1)] = '\0';
153 if (!fgets(buf
, bufsz
, stdin
))
157 } while (reply_running
);
160 DBG(ASK
, ul_debug("cancel by CTRL+D"));
169 sz
= ltrim_whitespace((unsigned char *) buf
);
170 if (sz
&& *(buf
+ sz
- 1) == '\n')
171 *(buf
+ sz
- 1) = '\0';
174 #ifdef HAVE_LIBREADLINE
176 rl_callback_handler_remove();
178 sigaction(SIGINT
, &oldact
, NULL
);
179 DBG(ASK
, ul_debug("user's reply: >>>%s<<< [rc=%d]", buf
, ret
));
183 static int ask_menu(struct fdisk_context
*cxt
, struct fdisk_ask
*ask
,
184 char *buf
, size_t bufsz
)
187 const char *q
= fdisk_ask_get_query(ask
);
188 int dft
= fdisk_ask_menu_get_default(ask
);
191 fputs(q
, stdout
); /* print header */
198 const char *name
, *desc
;
201 /* print menu items */
202 while (fdisk_ask_menu_get_item(ask
, i
++, &key
, &name
, &desc
) == 0)
203 fprintf(stdout
, " %c %s (%s)\n", key
, name
, desc
);
206 snprintf(prompt
, sizeof(prompt
), _("Select (default %c): "), dft
);
207 rc
= get_user_reply(prompt
, buf
, bufsz
);
211 fdisk_info(cxt
, _("Using default response %c."), dft
);
218 while (fdisk_ask_menu_get_item(ask
, i
++, &key
, NULL
, NULL
) == 0) {
220 fdisk_ask_menu_set_result(ask
, c
);
221 return 0; /* success */
224 fdisk_warnx(cxt
, _("Value out of range."));
231 #define tochar(num) ((int) ('a' + num - 1))
232 static int ask_number(struct fdisk_context
*cxt
,
233 struct fdisk_ask
*ask
,
234 char *buf
, size_t bufsz
)
236 char prompt
[128] = { '\0' };
237 const char *q
= fdisk_ask_get_query(ask
);
238 const char *range
= fdisk_ask_number_get_range(ask
);
240 uint64_t dflt
= fdisk_ask_number_get_default(ask
),
241 low
= fdisk_ask_number_get_low(ask
),
242 high
= fdisk_ask_number_get_high(ask
);
243 int inchar
= fdisk_ask_number_inchars(ask
);
247 DBG(ASK
, ul_debug("asking for number "
248 "['%s', <%"PRIu64
",%"PRIu64
">, default=%"PRIu64
", range: %s]",
249 q
, low
, high
, dflt
, range
));
251 if (range
&& dflt
>= low
&& dflt
<= high
) {
253 snprintf(prompt
, sizeof(prompt
), _("%s (%s, default %c): "),
254 q
, range
, tochar(dflt
));
256 snprintf(prompt
, sizeof(prompt
), _("%s (%s, default %"PRIu64
"): "),
259 } else if (dflt
>= low
&& dflt
<= high
) {
261 snprintf(prompt
, sizeof(prompt
), _("%s (%c-%c, default %c): "),
262 q
, tochar(low
), tochar(high
), tochar(dflt
));
264 snprintf(prompt
, sizeof(prompt
),
265 _("%s (%"PRIu64
"-%"PRIu64
", default %"PRIu64
"): "),
268 snprintf(prompt
, sizeof(prompt
), _("%s (%c-%c): "),
269 q
, tochar(low
), tochar(high
));
271 snprintf(prompt
, sizeof(prompt
), _("%s (%"PRIu64
"-%"PRIu64
"): "),
275 int rc
= get_user_reply(prompt
, buf
, bufsz
);
280 if (!*buf
&& dflt
>= low
&& dflt
<= high
)
281 return fdisk_ask_number_set_result(ask
, dflt
);
283 if (isdigit_string(buf
)) {
287 num
= strtoumax(buf
, &end
, 10);
288 if (errno
|| buf
== end
|| (end
&& *end
))
290 } else if (inchar
&& isalpha(*buf
)) {
291 num
= tolower(*buf
) - 'a' + 1;
295 if (rc
== 0 && num
>= low
&& num
<= high
)
296 return fdisk_ask_number_set_result(ask
, num
);
298 fdisk_warnx(cxt
, _("Value out of range."));
304 static int ask_offset(struct fdisk_context
*cxt
,
305 struct fdisk_ask
*ask
,
306 char *buf
, size_t bufsz
)
308 char prompt
[128] = { '\0' };
309 const char *q
= fdisk_ask_get_query(ask
);
310 const char *range
= fdisk_ask_number_get_range(ask
);
312 uint64_t dflt
= fdisk_ask_number_get_default(ask
),
313 low
= fdisk_ask_number_get_low(ask
),
314 high
= fdisk_ask_number_get_high(ask
),
315 base
= fdisk_ask_number_get_base(ask
);
319 DBG(ASK
, ul_debug("asking for offset ['%s', <%"PRIu64
",%"PRIu64
">, base=%"PRIu64
", default=%"PRIu64
", range: %s]",
320 q
, low
, high
, base
, dflt
, range
));
322 if (range
&& dflt
>= low
&& dflt
<= high
)
323 snprintf(prompt
, sizeof(prompt
), _("%s (%s, default %"PRIu64
"): "),
325 else if (dflt
>= low
&& dflt
<= high
)
326 snprintf(prompt
, sizeof(prompt
),
327 _("%s (%"PRIu64
"-%"PRIu64
", default %"PRIu64
"): "),
330 snprintf(prompt
, sizeof(prompt
), _("%s (%"PRIu64
"-%"PRIu64
"): "),
338 int rc
= get_user_reply(prompt
, buf
, bufsz
);
341 if (!*buf
&& dflt
>= low
&& dflt
<= high
)
342 return fdisk_ask_number_set_result(ask
, dflt
);
345 if (*p
== '+' || *p
== '-') {
350 rc
= parse_size(p
, &num
, &pwr
);
353 DBG(ASK
, ul_debug("parsed size: %ju", num
));
355 /* +{size}{K,M,...} specified, the "num" is in bytes */
356 uint64_t unit
= fdisk_ask_number_get_unit(ask
);
357 num
+= unit
/2; /* round */
362 else if (sig
== '-' && fdisk_ask_number_is_wrap_negative(ask
))
367 DBG(ASK
, ul_debug("final offset: %ju [sig: %c, power: %d, %s]",
369 sig
? "relative" : "absolute"));
370 if (num
>= low
&& num
<= high
) {
372 fdisk_ask_number_set_relative(ask
, 1);
373 return fdisk_ask_number_set_result(ask
, (uint64_t)num
);
375 fdisk_warnx(cxt
, _("Value out of range."));
381 static unsigned int info_count
;
383 static void fputs_info(struct fdisk_ask
*ask
, FILE *out
)
388 msg
= fdisk_ask_print_get_mesg(ask
);
398 int ask_callback(struct fdisk_context
*cxt
, struct fdisk_ask
*ask
,
399 void *data
__attribute__((__unused__
)))
402 char buf
[BUFSIZ
] = { '\0' };
407 if (fdisk_ask_get_type(ask
) != FDISK_ASKTYPE_INFO
)
410 switch(fdisk_ask_get_type(ask
)) {
411 case FDISK_ASKTYPE_MENU
:
412 return ask_menu(cxt
, ask
, buf
, sizeof(buf
));
413 case FDISK_ASKTYPE_NUMBER
:
414 return ask_number(cxt
, ask
, buf
, sizeof(buf
));
415 case FDISK_ASKTYPE_OFFSET
:
416 return ask_offset(cxt
, ask
, buf
, sizeof(buf
));
417 case FDISK_ASKTYPE_INFO
:
418 if (!fdisk_is_listonly(cxt
))
420 fputs_info(ask
, stdout
);
422 case FDISK_ASKTYPE_WARNX
:
424 color_scheme_fenable("warn", UL_COLOR_RED
, stderr
);
425 fputs(fdisk_ask_print_get_mesg(ask
), stderr
);
426 color_fdisable(stderr
);
429 case FDISK_ASKTYPE_WARN
:
431 color_scheme_fenable("warn", UL_COLOR_RED
, stderr
);
432 fputs(fdisk_ask_print_get_mesg(ask
), stderr
);
433 errno
= fdisk_ask_print_get_errno(ask
);
434 fprintf(stderr
, ": %m\n");
435 color_fdisable(stderr
);
437 case FDISK_ASKTYPE_YESNO
:
441 fputs(fdisk_ask_get_query(ask
), stdout
);
442 rc
= get_user_reply(_(" [Y]es/[N]o: "), buf
, sizeof(buf
));
446 if (x
== RPMATCH_YES
|| x
== RPMATCH_NO
) {
447 fdisk_ask_yesno_set_result(ask
, x
);
451 DBG(ASK
, ul_debug("yes-no ask: reply '%s' [rc=%d]", buf
, rc
));
453 case FDISK_ASKTYPE_STRING
:
456 snprintf(prmt
, sizeof(prmt
), "%s: ", fdisk_ask_get_query(ask
));
458 rc
= get_user_reply(prmt
, buf
, sizeof(buf
));
460 fdisk_ask_string_set_result(ask
, xstrdup(buf
));
461 DBG(ASK
, ul_debug("string ask: reply '%s' [rc=%d]", buf
, rc
));
465 warnx(_("internal error: unsupported dialog type %d"), fdisk_ask_get_type(ask
));
471 static struct fdisk_parttype
*ask_partition_type(struct fdisk_context
*cxt
, int *canceled
)
474 struct fdisk_label
*lb
;
477 lb
= fdisk_get_label(cxt
, NULL
);
484 if (fdisk_label_has_parttypes_shortcuts(lb
))
485 q
= fdisk_label_has_code_parttypes(lb
) ?
486 _("Hex code or alias (type L to list all): ") :
487 _("Partition type or alias (type L to list all): ");
489 q
= fdisk_label_has_code_parttypes(lb
) ?
490 _("Hex code (type L to list all codes): ") :
491 _("Partition type (type L to list all types): ");
493 char buf
[256] = { '\0' };
494 int rc
= get_user_reply(q
, buf
, sizeof(buf
));
497 if (rc
== -ECANCELED
)
502 if (buf
[1] == '\0' && toupper(*buf
) == 'L')
503 list_partition_types(cxt
);
505 struct fdisk_parttype
*t
= fdisk_label_advparse_parttype(lb
, buf
,
506 FDISK_PARTTYPE_PARSE_DATA
507 | FDISK_PARTTYPE_PARSE_ALIAS
508 | FDISK_PARTTYPE_PARSE_NAME
509 | FDISK_PARTTYPE_PARSE_SEQNUM
);
511 fdisk_info(cxt
, _("Failed to parse '%s' partition type."), buf
);
520 void list_partition_types(struct fdisk_context
*cxt
)
522 size_t ntypes
= 0, next
= 0;
523 struct fdisk_label
*lb
;
527 lb
= fdisk_get_label(cxt
, NULL
);
530 ntypes
= fdisk_label_get_nparttypes(lb
);
534 if (fdisk_label_has_code_parttypes(lb
)) {
536 * Prints in 4 columns in format <hex> <name>
538 size_t last
[4], done
= 0, size
;
543 for (i
= 3; i
>= 0; i
--)
544 last
[3 - i
] = done
+= (size
+ i
- done
) / (i
+ 1);
548 #define NAME_WIDTH 15
549 char name
[NAME_WIDTH
* MB_LEN_MAX
];
550 size_t width
= NAME_WIDTH
;
551 const struct fdisk_parttype
*t
= fdisk_label_get_parttype(lb
, next
);
554 if (fdisk_parttype_get_name(t
)) {
555 printf("%s%02x ", i
? " " : "\n",
556 fdisk_parttype_get_code(t
));
557 ret
= mbsalign(_(fdisk_parttype_get_name(t
)),
559 &width
, MBS_ALIGN_LEFT
, 0);
561 if (ret
== (size_t)-1 || ret
>= sizeof(name
))
563 _(fdisk_parttype_get_name(t
)));
568 next
= last
[i
++] + done
;
569 if (i
> 3 || next
>= last
[i
]) {
573 } while (done
< last
[0]);
578 * Prints 1 column in format <idx> <name> <typestr>
585 for (i
= 0; i
< ntypes
; i
++) {
586 const struct fdisk_parttype
*t
= fdisk_label_get_parttype(lb
, i
);
587 printf("%3zu %-30s %s\n", i
+ 1,
588 fdisk_parttype_get_name(t
),
589 fdisk_parttype_get_string(t
));
598 if (fdisk_label_has_parttypes_shortcuts(lb
)) {
599 const char *alias
= NULL
, *typestr
= NULL
;
602 fputs(_("\nAliases:\n"), stdout
);
604 for (next
= 0; rc
== 0 || rc
== 2; next
++) {
605 /* rc: <0 error, 0 success, 1 end, 2 deprecated */
606 rc
= fdisk_label_get_parttype_shortcut(lb
,
607 next
, &typestr
, NULL
, &alias
);
609 printf(" %-14s - %s\n", alias
, typestr
);
618 void toggle_dos_compatibility_flag(struct fdisk_context
*cxt
)
620 struct fdisk_label
*lb
= fdisk_get_label(cxt
, "dos");
626 flag
= !fdisk_dos_is_compatible(lb
);
627 fdisk_info(cxt
, flag
?
628 _("DOS Compatibility flag is set (DEPRECATED!)") :
629 _("DOS Compatibility flag is not set"));
631 fdisk_dos_enable_compatible(lb
, flag
);
633 if (fdisk_is_label(cxt
, DOS
))
634 fdisk_reset_alignment(cxt
); /* reset the current label */
637 void change_partition_type(struct fdisk_context
*cxt
)
640 struct fdisk_parttype
*t
= NULL
;
641 struct fdisk_partition
*pa
= NULL
;
642 const char *old
= NULL
;
647 if (fdisk_ask_partnum(cxt
, &i
, FALSE
))
650 if (fdisk_get_partition(cxt
, i
, &pa
)) {
651 fdisk_warnx(cxt
, _("Partition %zu does not exist yet!"), i
+ 1);
655 t
= (struct fdisk_parttype
*) fdisk_partition_get_type(pa
);
656 old
= t
? fdisk_parttype_get_name(t
) : _("Unknown");
659 t
= ask_partition_type(cxt
, &canceled
);
664 if (canceled
== 0 && t
&& fdisk_set_partition_type(cxt
, i
, t
) == 0)
666 _("Changed type of partition '%s' to '%s'."),
667 old
, t
? fdisk_parttype_get_name(t
) : _("Unknown"));
670 _("Type of partition %zu is unchanged: %s."),
673 fdisk_unref_partition(pa
);
674 fdisk_unref_parttype(t
);
677 int print_partition_info(struct fdisk_context
*cxt
)
679 struct fdisk_partition
*pa
= NULL
;
683 struct fdisk_label
*lb
= fdisk_get_label(cxt
, NULL
);
685 if ((rc
= fdisk_ask_partnum(cxt
, &i
, FALSE
)))
688 if ((rc
= fdisk_get_partition(cxt
, i
, &pa
))) {
689 fdisk_warnx(cxt
, _("Partition %zu does not exist yet!"), i
+ 1);
693 if ((rc
= fdisk_label_get_fields_ids_all(lb
, cxt
, &fields
, &nfields
)))
696 for (i
= 0; i
< nfields
; ++i
) {
699 const struct fdisk_field
*fd
= fdisk_label_get_field(lb
, id
);
704 rc
= fdisk_partition_to_string(pa
, cxt
, id
, &data
);
709 fdisk_info(cxt
, "%15s: %s", fdisk_field_get_name(fd
), data
);
714 fdisk_unref_partition(pa
);
719 static size_t skip_empty(const unsigned char *buf
, size_t i
, size_t sz
)
722 const unsigned char *p0
= buf
+ i
;
724 for (next
= i
+ 16; next
< sz
; next
+= 16) {
725 if (memcmp(p0
, buf
+ next
, 16) != 0)
729 return next
== i
+ 16 ? i
: next
;
732 static void dump_buffer(off_t base
, unsigned char *buf
, size_t sz
)
734 size_t i
, l
, next
= 0;
738 for (i
= 0, l
= 0; i
< sz
; i
++, l
++) {
741 next
= skip_empty(buf
, i
, sz
);
742 printf("%08jx ", (intmax_t)base
+ i
);
744 printf(" %02x", buf
[i
]);
745 if (l
== 7) /* words separator */
748 fputc('\n', stdout
); /* next line */
761 static void dump_blkdev(struct fdisk_context
*cxt
, const char *name
,
762 uint64_t offset
, size_t size
)
764 int fd
= fdisk_get_devfd(cxt
);
766 fdisk_info(cxt
, _("\n%s: offset = %"PRIu64
", size = %zu bytes."),
771 if (lseek(fd
, (off_t
) offset
, SEEK_SET
) == (off_t
) -1)
772 fdisk_warn(cxt
, _("cannot seek"));
774 unsigned char *buf
= xmalloc(size
);
776 if (read_all(fd
, (char *) buf
, size
) != (ssize_t
) size
)
777 fdisk_warn(cxt
, _("cannot read"));
779 dump_buffer(offset
, buf
, size
);
784 void dump_firstsector(struct fdisk_context
*cxt
)
788 dump_blkdev(cxt
, _("First sector"), 0, fdisk_get_sector_size(cxt
));
791 void dump_disklabel(struct fdisk_context
*cxt
)
794 const char *name
= NULL
;
800 while (fdisk_locate_disklabel(cxt
, i
++, &name
, &offset
, &size
) == 0 && size
)
801 dump_blkdev(cxt
, name
, offset
, size
);
804 static fdisk_sector_t
get_dev_blocks(char *dev
)
809 if ((fd
= open(dev
, O_RDONLY
|O_NONBLOCK
)) < 0)
810 err(EXIT_FAILURE
, _("cannot open %s"), dev
);
811 ret
= blkdev_get_sectors(fd
, (unsigned long long *) &size
);
814 err(EXIT_FAILURE
, _("BLKGETSIZE ioctl failed on %s"), dev
);
819 void follow_wipe_mode(struct fdisk_context
*cxt
)
821 int dowipe
= wipemode
== WIPEMODE_ALWAYS
? 1 : 0;
823 if (isatty(STDIN_FILENO
) && wipemode
== WIPEMODE_AUTO
)
824 dowipe
= 1; /* do it in interactive mode */
826 if (fdisk_is_ptcollision(cxt
) && wipemode
!= WIPEMODE_NEVER
)
827 dowipe
= 1; /* always remove old PT */
829 fdisk_enable_wipe(cxt
, dowipe
);
832 "The device contains '%s' signature and it will be removed by a write command. "
833 "See fdisk(8) man page and --wipe option for more details."),
834 fdisk_get_collision(cxt
));
837 "The device contains '%s' signature and it may remain on the device. "
838 "It is recommended to wipe the device with wipefs(8) or "
839 "fdisk --wipe, in order to avoid possible collisions."),
840 fdisk_get_collision(cxt
));
843 static void __attribute__((__noreturn__
)) usage(void)
847 fputs(USAGE_HEADER
, out
);
850 _(" %1$s [options] <disk> change partition table\n"
851 " %1$s [options] -l [<disk>...] list partition table(s)\n"),
852 program_invocation_short_name
);
854 fputs(USAGE_SEPARATOR
, out
);
855 fputs(_("Display or manipulate a disk partition table.\n"), out
);
857 fputs(USAGE_OPTIONS
, out
);
858 fputs(_(" -b, --sector-size <size> physical and logical sector size\n"), out
);
859 fputs(_(" -B, --protect-boot don't erase bootbits when creating a new label\n"), out
);
860 fputs(_(" -c, --compatibility[=<mode>] mode is 'dos' or 'nondos' (default)\n"), out
);
862 _(" -L, --color[=<when>] colorize output (%s, %s or %s)\n"), "auto", "always", "never");
864 " %s\n", USAGE_COLORS_DEFAULT
);
865 fputs(_(" -l, --list display partitions and exit\n"), out
);
866 fputs(_(" -x, --list-details like --list but with more details\n"), out
);
868 fputs(_(" -n, --noauto-pt don't create default partition table on empty devices\n"), out
);
869 fputs(_(" -o, --output <list> output columns\n"), out
);
870 fputs(_(" -t, --type <type> recognize specified partition table type only\n"), out
);
871 fputs(_(" -u, --units[=<unit>] display units: 'cylinders' or 'sectors' (default)\n"), out
);
872 fputs(_(" -s, --getsz display device size in 512-byte sectors [DEPRECATED]\n"), out
);
873 fputs(_(" --bytes print SIZE in bytes rather than in human readable format\n"), out
);
875 _(" --lock[=<mode>] use exclusive device lock (%s, %s or %s)\n"), "yes", "no", "nonblock");
877 _(" -w, --wipe <mode> wipe signatures (%s, %s or %s)\n"), "auto", "always", "never");
879 _(" -W, --wipe-partitions <mode> wipe signatures from new partitions (%s, %s or %s)\n"), "auto", "always", "never");
881 fputs(USAGE_SEPARATOR
, out
);
882 fputs(_(" -C, --cylinders <number> specify the number of cylinders\n"), out
);
883 fputs(_(" -H, --heads <number> specify the number of heads\n"), out
);
884 fputs(_(" -S, --sectors <number> specify the number of sectors per track\n"), out
);
886 fputs(USAGE_SEPARATOR
, out
);
887 printf(USAGE_HELP_OPTIONS(31));
889 list_available_columns(out
);
891 printf(USAGE_MAN_TAIL("fdisk(8)"));
897 ACT_FDISK
= 0, /* default */
903 int main(int argc
, char **argv
)
905 int rc
, i
, c
, act
= ACT_FDISK
, noauto_pt
= 0;
906 int colormode
= UL_COLORMODE_UNDEF
;
907 struct fdisk_context
*cxt
;
909 const char *devname
, *lockmode
= NULL
;
911 OPT_BYTES
= CHAR_MAX
+ 1,
914 static const struct option longopts
[] = {
915 { "bytes", no_argument
, NULL
, OPT_BYTES
},
916 { "color", optional_argument
, NULL
, 'L' },
917 { "compatibility", optional_argument
, NULL
, 'c' },
918 { "cylinders", required_argument
, NULL
, 'C' },
919 { "heads", required_argument
, NULL
, 'H' },
920 { "sectors", required_argument
, NULL
, 'S' },
921 { "getsz", no_argument
, NULL
, 's' },
922 { "help", no_argument
, NULL
, 'h' },
923 { "list", no_argument
, NULL
, 'l' },
924 { "list-details", no_argument
, NULL
, 'x' },
925 { "lock", optional_argument
, NULL
, OPT_LOCK
},
926 { "noauto-pt", no_argument
, NULL
, 'n' },
927 { "sector-size", required_argument
, NULL
, 'b' },
928 { "type", required_argument
, NULL
, 't' },
929 { "units", optional_argument
, NULL
, 'u' },
930 { "version", no_argument
, NULL
, 'V' },
931 { "output", required_argument
, NULL
, 'o' },
932 { "protect-boot", no_argument
, NULL
, 'B' },
933 { "wipe", required_argument
, NULL
, 'w' },
934 { "wipe-partitions",required_argument
, NULL
, 'W' },
938 setlocale(LC_ALL
, "");
939 bindtextdomain(PACKAGE
, LOCALEDIR
);
941 close_stdout_atexit();
945 fdiskprog_init_debug();
947 cxt
= fdisk_new_context();
949 err(EXIT_FAILURE
, _("failed to allocate libfdisk context"));
951 fdisk_set_ask(cxt
, ask_callback
, NULL
);
953 while ((c
= getopt_long(argc
, argv
, "b:Bc::C:hH:lL::no:sS:t:u::vVw:W:x",
954 longopts
, NULL
)) != -1) {
958 size_t sz
= strtou32_or_err(optarg
,
959 _("invalid sector size argument"));
960 if (sz
!= 512 && sz
!= 1024 && sz
!= 2048 && sz
!= 4096)
961 errx(EXIT_FAILURE
, _("invalid sector size argument"));
962 fdisk_save_user_sector_size(cxt
, sz
, sz
);
966 fdisk_enable_bootbits_protection(cxt
, 1);
969 fdisk_save_user_geometry(cxt
,
970 strtou32_or_err(optarg
,
971 _("invalid cylinders argument")),
976 /* this setting is independent on the current
977 * actively used label
979 char *p
= *optarg
== '=' ? optarg
+ 1 : optarg
;
980 struct fdisk_label
*lb
= fdisk_get_label(cxt
, "dos");
983 err(EXIT_FAILURE
, _("not found DOS label driver"));
984 if (strcmp(p
, "dos") == 0)
985 fdisk_dos_enable_compatible(lb
, TRUE
);
986 else if (strcmp(p
, "nondos") == 0)
987 fdisk_dos_enable_compatible(lb
, FALSE
);
989 errx(EXIT_FAILURE
, _("unknown compatibility mode '%s'"), p
);
991 /* use default if no optarg specified */
994 fdisk_save_user_geometry(cxt
, 0,
995 strtou32_or_err(optarg
,
996 _("invalid heads argument")),
1000 fdisk_save_user_geometry(cxt
, 0, 0,
1001 strtou32_or_err(optarg
,
1002 _("invalid sectors argument")));
1008 act
= ACT_LIST_DETAILS
;
1011 colormode
= UL_COLORMODE_AUTO
;
1013 colormode
= colormode_or_err(optarg
,
1014 _("unsupported color mode"));
1027 struct fdisk_label
*lb
= NULL
;
1029 while (fdisk_next_label(cxt
, &lb
) == 0)
1030 fdisk_label_set_disabled(lb
, 1);
1032 lb
= fdisk_get_label(cxt
, optarg
);
1034 errx(EXIT_FAILURE
, _("unsupported disklabel: %s"), optarg
);
1035 fdisk_label_set_disabled(lb
, 0);
1039 if (optarg
&& *optarg
== '=')
1041 if (fdisk_set_unit(cxt
, optarg
) != 0)
1042 errx(EXIT_FAILURE
, _("unsupported unit"));
1044 case 'V': /* preferred for util-linux */
1045 case 'v': /* for backward compatibility only */
1046 print_version(EXIT_SUCCESS
);
1048 wipemode
= wipemode_from_string(optarg
);
1050 errx(EXIT_FAILURE
, _("unsupported wipe mode"));
1053 pwipemode
= wipemode_from_string(optarg
);
1055 errx(EXIT_FAILURE
, _("unsupported wipe mode"));
1060 fdisk_set_size_unit(cxt
, FDISK_SIZEUNIT_BYTES
);
1071 errtryhelp(EXIT_FAILURE
);
1075 if (argc
-optind
!= 1 && fdisk_has_user_device_properties(cxt
))
1076 warnx(_("The device properties (sector size and geometry) should"
1077 " be used with one specified device only."));
1079 colors_init(colormode
, "fdisk");
1080 is_interactive
= isatty(STDIN_FILENO
);
1084 case ACT_LIST_DETAILS
:
1085 fdisk_enable_listonly(cxt
, 1);
1087 if (act
== ACT_LIST_DETAILS
)
1088 fdisk_enable_details(cxt
, 1);
1090 init_fields(cxt
, outarg
, NULL
);
1092 if (argc
> optind
) {
1095 for (rc
= 0, k
= optind
; k
< argc
; k
++)
1096 rc
+= print_device_pt(cxt
, argv
[k
], 1, 0, k
!= optind
);
1099 return EXIT_FAILURE
;
1101 print_all_devices_pt(cxt
, 0);
1106 if (argc
- optind
<= 0) {
1107 warnx(_("bad usage"));
1108 errtryhelp(EXIT_FAILURE
);
1110 for (i
= optind
; i
< argc
; i
++) {
1111 uintmax_t blks
= get_dev_blocks(argv
[i
]);
1113 if (argc
- optind
== 1)
1114 printf("%ju\n", blks
);
1116 printf("%s: %ju\n", argv
[i
], blks
);
1121 if (argc
-optind
!= 1) {
1122 warnx(_("bad usage"));
1123 errtryhelp(EXIT_FAILURE
);
1126 /* Here starts interactive mode, use fdisk_{warn,info,..} functions */
1127 color_scheme_enable("welcome", UL_COLOR_GREEN
);
1128 fdisk_info(cxt
, _("Welcome to fdisk (%s)."), PACKAGE_STRING
);
1130 fdisk_info(cxt
, _("Changes will remain in memory only, until you decide to write them.\n"
1131 "Be careful before using the write command.\n"));
1133 devname
= argv
[optind
];
1134 rc
= fdisk_assign_device(cxt
, devname
, 0);
1135 if (rc
== -EACCES
) {
1136 rc
= fdisk_assign_device(cxt
, devname
, 1);
1138 fdisk_warnx(cxt
, _("Device is open in read-only mode."));
1141 err(EXIT_FAILURE
, _("cannot open %s"), devname
);
1143 if (fdisk_device_is_used(cxt
))
1145 "This disk is currently in use - repartitioning is probably a bad idea.\n"
1146 "It's recommended to umount all file systems, and swapoff all swap\n"
1147 "partitions on this disk.\n"));
1151 if (!fdisk_is_readonly(cxt
)
1152 && blkdev_lock(fdisk_get_devfd(cxt
), devname
, lockmode
) != 0) {
1153 fdisk_deassign_device(cxt
, 1);
1154 fdisk_unref_context(cxt
);
1155 return EXIT_FAILURE
;
1158 if (fdisk_get_collision(cxt
))
1159 follow_wipe_mode(cxt
);
1161 if (!fdisk_has_label(cxt
)) {
1162 fdisk_info(cxt
, _("Device does not contain a recognized partition table."));
1164 fdisk_create_disklabel(cxt
, NULL
);
1166 } else if (fdisk_is_label(cxt
, GPT
) && fdisk_gpt_is_hybrid(cxt
))
1168 "A hybrid GPT was detected. You have to sync "
1169 "the hybrid MBR manually (expert command 'M')."));
1171 init_fields(cxt
, outarg
, NULL
); /* -o <columns> */
1173 if (!fdisk_is_readonly(cxt
)) {
1174 fdisk_get_partitions(cxt
, &original_layout
);
1175 device_is_used
= fdisk_device_is_used(cxt
);
1179 process_fdisk_menu(&cxt
);
1182 fdisk_unref_context(cxt
);
1183 return EXIT_SUCCESS
;