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.
24 #include <libsmartcols.h>
25 #ifdef HAVE_LIBREADLINE
26 # include <readline/readline.h>
36 #include "pathnames.h"
37 #include "canonicalize.h"
39 #include "closestream.h"
44 #include "pt-sun.h" /* to toggle flags */
46 #ifdef HAVE_LINUX_COMPILER_H
47 # include <linux/compiler.h>
49 #ifdef HAVE_LINUX_BLKPG_H
50 # include <linux/blkpg.h>
54 * fdisk debug stuff (see fdisk.h and include/debug.h)
56 UL_DEBUG_DEFINE_MASK(fdisk
);
57 UL_DEBUG_DEFINE_MASKNAMES(fdisk
) = UL_DEBUG_EMPTY_MASKNAMES
;
59 static void fdiskprog_init_debug(void)
61 __UL_INIT_DEBUG(fdisk
, FDISKPROG_DEBUG_
, 0, FDISK_DEBUG
);
64 #ifdef HAVE_LIBREADLINE
65 static char *rl_fgets(char *s
, int n
, FILE *stream
, const char *prompt
)
69 rl_outstream
= stream
;
81 int get_user_reply(struct fdisk_context
*cxt
, const char *prompt
,
82 char *buf
, size_t bufsz
)
88 #ifdef HAVE_LIBREADLINE
89 if (isatty(STDIN_FILENO
)) {
90 if (!rl_fgets(buf
, bufsz
, stdout
, prompt
)) {
91 if (fdisk_label_is_changed(fdisk_get_label(cxt
, NULL
))) {
92 if (rl_fgets(buf
, bufsz
, stderr
,
93 _("\nDo you really want to quit? "))
97 fdisk_unref_context(cxt
);
105 fputs(prompt
, stdout
);
107 if (!fgets(buf
, bufsz
, stdin
)) {
108 if (fdisk_label_is_changed(fdisk_get_label(cxt
, NULL
))) {
109 fprintf(stderr
, _("\nDo you really want to quit? "));
111 if (fgets(buf
, bufsz
, stdin
) && !rpmatch(buf
))
114 fdisk_unref_context(cxt
);
121 for (p
= buf
; *p
&& !isgraph(*p
); p
++); /* get first non-blank */
124 memmove(buf
, p
, p
- buf
); /* remove blank space */
126 if (sz
&& *(buf
+ sz
- 1) == '\n')
127 *(buf
+ sz
- 1) = '\0';
129 DBG(ASK
, ul_debug("user's reply: >>>%s<<<", buf
));
133 static int ask_menu(struct fdisk_context
*cxt
, struct fdisk_ask
*ask
,
134 char *buf
, size_t bufsz
)
137 const char *q
= fdisk_ask_get_query(ask
);
138 int dft
= fdisk_ask_menu_get_default(ask
);
141 fputs(q
, stdout
); /* print header */
148 const char *name
, *desc
;
151 /* print menu items */
152 while (fdisk_ask_menu_get_item(ask
, i
++, &key
, &name
, &desc
) == 0)
153 fprintf(stdout
, " %c %s (%s)\n", key
, name
, desc
);
156 snprintf(prompt
, sizeof(prompt
), _("Select (default %c): "), dft
);
157 rc
= get_user_reply(cxt
, prompt
, buf
, bufsz
);
161 fdisk_info(cxt
, _("Using default response %c."), dft
);
168 while (fdisk_ask_menu_get_item(ask
, i
++, &key
, NULL
, NULL
) == 0) {
170 fdisk_ask_menu_set_result(ask
, c
);
171 return 0; /* success */
174 fdisk_warnx(cxt
, _("Value out of range."));
181 #define tochar(num) ((int) ('a' + num - 1))
182 static int ask_number(struct fdisk_context
*cxt
,
183 struct fdisk_ask
*ask
,
184 char *buf
, size_t bufsz
)
186 char prompt
[128] = { '\0' };
187 const char *q
= fdisk_ask_get_query(ask
);
188 const char *range
= fdisk_ask_number_get_range(ask
);
190 uint64_t dflt
= fdisk_ask_number_get_default(ask
),
191 low
= fdisk_ask_number_get_low(ask
),
192 high
= fdisk_ask_number_get_high(ask
);
193 int inchar
= fdisk_ask_number_inchars(ask
);
197 DBG(ASK
, ul_debug("asking for number "
198 "['%s', <%ju,%ju>, default=%ju, range: %s]",
199 q
, low
, high
, dflt
, range
));
201 if (range
&& dflt
>= low
&& dflt
<= high
) {
203 snprintf(prompt
, sizeof(prompt
), _("%s (%s, default %c): "),
204 q
, range
, tochar(dflt
));
206 snprintf(prompt
, sizeof(prompt
), _("%s (%s, default %ju): "),
209 } else if (dflt
>= low
&& dflt
<= high
) {
211 snprintf(prompt
, sizeof(prompt
), _("%s (%c-%c, default %c): "),
212 q
, tochar(low
), tochar(high
), tochar(dflt
));
214 snprintf(prompt
, sizeof(prompt
), _("%s (%ju-%ju, default %ju): "),
217 snprintf(prompt
, sizeof(prompt
), _("%s (%c-%c): "),
218 q
, tochar(low
), tochar(high
));
220 snprintf(prompt
, sizeof(prompt
), _("%s (%ju-%ju): "),
224 int rc
= get_user_reply(cxt
, prompt
, buf
, bufsz
);
229 if (!*buf
&& dflt
>= low
&& dflt
<= high
)
230 return fdisk_ask_number_set_result(ask
, dflt
);
232 if (isdigit_string(buf
)) {
236 num
= strtoumax(buf
, &end
, 10);
237 if (errno
|| buf
== end
|| (end
&& *end
))
239 } else if (inchar
&& isalpha(*buf
)) {
240 num
= tolower(*buf
) - 'a' + 1;
244 if (rc
== 0 && num
>= low
&& num
<= high
)
245 return fdisk_ask_number_set_result(ask
, num
);
247 fdisk_warnx(cxt
, _("Value out of range."));
253 static int ask_offset(struct fdisk_context
*cxt
,
254 struct fdisk_ask
*ask
,
255 char *buf
, size_t bufsz
)
257 char prompt
[128] = { '\0' };
258 const char *q
= fdisk_ask_get_query(ask
);
259 const char *range
= fdisk_ask_number_get_range(ask
);
261 uint64_t dflt
= fdisk_ask_number_get_default(ask
),
262 low
= fdisk_ask_number_get_low(ask
),
263 high
= fdisk_ask_number_get_high(ask
),
264 base
= fdisk_ask_number_get_base(ask
);
268 DBG(ASK
, ul_debug("asking for offset ['%s', <%ju,%ju>, base=%ju, default=%ju, range: %s]",
269 q
, low
, high
, base
, dflt
, range
));
271 if (range
&& dflt
>= low
&& dflt
<= high
)
272 snprintf(prompt
, sizeof(prompt
), _("%s (%s, default %ju): "), q
, range
, dflt
);
273 else if (dflt
>= low
&& dflt
<= high
)
274 snprintf(prompt
, sizeof(prompt
), _("%s (%ju-%ju, default %ju): "), q
, low
, high
, dflt
);
276 snprintf(prompt
, sizeof(prompt
), _("%s (%ju-%ju): "), q
, low
, high
);
283 int rc
= get_user_reply(cxt
, prompt
, buf
, bufsz
);
286 if (!*buf
&& dflt
>= low
&& dflt
<= high
)
287 return fdisk_ask_number_set_result(ask
, dflt
);
290 if (*p
== '+' || *p
== '-') {
295 rc
= parse_size(p
, &num
, &pwr
);
298 DBG(ASK
, ul_debug("parsed size: %ju", num
));
300 /* +{size}{K,M,...} specified, the "num" is in bytes */
301 uint64_t unit
= fdisk_ask_number_get_unit(ask
);
302 num
+= unit
/2; /* round */
310 DBG(ASK
, ul_debug("final offset: %ju [sig: %c, power: %d, %s]",
312 sig
? "relative" : "absolute"));
313 if (num
>= low
&& num
<= high
) {
315 fdisk_ask_number_set_relative(ask
, 1);
316 return fdisk_ask_number_set_result(ask
, num
);
318 fdisk_warnx(cxt
, _("Value out of range."));
324 static unsigned int info_count
;
326 static void fputs_info(struct fdisk_ask
*ask
, FILE *out
)
331 msg
= fdisk_ask_print_get_mesg(ask
);
341 int ask_callback(struct fdisk_context
*cxt
, struct fdisk_ask
*ask
,
342 void *data
__attribute__((__unused__
)))
350 if (fdisk_ask_get_type(ask
) != FDISK_ASKTYPE_INFO
)
353 switch(fdisk_ask_get_type(ask
)) {
354 case FDISK_ASKTYPE_MENU
:
355 return ask_menu(cxt
, ask
, buf
, sizeof(buf
));
356 case FDISK_ASKTYPE_NUMBER
:
357 return ask_number(cxt
, ask
, buf
, sizeof(buf
));
358 case FDISK_ASKTYPE_OFFSET
:
359 return ask_offset(cxt
, ask
, buf
, sizeof(buf
));
360 case FDISK_ASKTYPE_INFO
:
361 if (!fdisk_is_listonly(cxt
))
363 fputs_info(ask
, stdout
);
365 case FDISK_ASKTYPE_WARNX
:
366 color_scheme_fenable("warn", UL_COLOR_RED
, stderr
);
367 fputs(fdisk_ask_print_get_mesg(ask
), stderr
);
368 color_fdisable(stderr
);
371 case FDISK_ASKTYPE_WARN
:
372 color_scheme_fenable("warn", UL_COLOR_RED
, stderr
);
373 fputs(fdisk_ask_print_get_mesg(ask
), stderr
);
374 errno
= fdisk_ask_print_get_errno(ask
);
375 fprintf(stderr
, ": %m\n");
376 color_fdisable(stderr
);
378 case FDISK_ASKTYPE_YESNO
:
382 fputs(fdisk_ask_get_query(ask
), stdout
);
383 rc
= get_user_reply(cxt
, _(" [Y]es/[N]o: "), buf
, sizeof(buf
));
387 if (x
== RPMATCH_YES
|| x
== RPMATCH_NO
) {
388 fdisk_ask_yesno_set_result(ask
, x
);
392 DBG(ASK
, ul_debug("yes-no ask: reply '%s' [rc=%d]", buf
, rc
));
394 case FDISK_ASKTYPE_STRING
:
397 snprintf(prmt
, sizeof(prmt
), "%s: ", fdisk_ask_get_query(ask
));
399 rc
= get_user_reply(cxt
, prmt
, buf
, sizeof(buf
));
401 fdisk_ask_string_set_result(ask
, xstrdup(buf
));
402 DBG(ASK
, ul_debug("string ask: reply '%s' [rc=%d]", buf
, rc
));
406 warnx(_("internal error: unsupported dialog type %d"), fdisk_ask_get_type(ask
));
412 struct fdisk_parttype
*ask_partition_type(struct fdisk_context
*cxt
)
415 struct fdisk_label
*lb
;
418 lb
= fdisk_get_label(cxt
, NULL
);
423 q
= fdisk_label_has_code_parttypes(lb
) ?
424 _("Partition type (type L to list all types): ") :
425 _("Hex code (type L to list all codes): ");
428 int rc
= get_user_reply(cxt
, q
, buf
, sizeof(buf
));
433 if (buf
[1] == '\0' && toupper(*buf
) == 'L')
434 list_partition_types(cxt
);
436 return fdisk_label_parse_parttype(lb
, buf
);
442 void list_partition_types(struct fdisk_context
*cxt
)
445 struct fdisk_label
*lb
= fdisk_get_label(cxt
, NULL
);
448 lb
= fdisk_get_label(cxt
, NULL
);
451 ntypes
= fdisk_label_get_nparttypes(lb
);
455 if (fdisk_label_has_code_parttypes(lb
)) {
457 * Prints in 4 columns in format <hex> <name>
459 size_t last
[4], done
= 0, next
= 0, size
;
464 for (i
= 3; i
>= 0; i
--)
465 last
[3 - i
] = done
+= (size
+ i
- done
) / (i
+ 1);
469 #define NAME_WIDTH 15
470 char name
[NAME_WIDTH
* MB_LEN_MAX
];
471 size_t width
= NAME_WIDTH
;
472 const struct fdisk_parttype
*t
= fdisk_label_get_parttype(lb
, next
);
475 if (fdisk_parttype_get_name(t
)) {
476 printf("%c%2x ", i
? ' ' : '\n',
477 fdisk_parttype_get_code(t
));
478 ret
= mbsalign(_(fdisk_parttype_get_name(t
)),
480 &width
, MBS_ALIGN_LEFT
, 0);
482 if (ret
== (size_t)-1 || ret
>= sizeof(name
))
484 _(fdisk_parttype_get_name(t
)));
489 next
= last
[i
++] + done
;
490 if (i
> 3 || next
>= last
[i
]) {
494 } while (done
< last
[0]);
498 * Prints 1 column in format <idx> <name> <typestr>
502 for (i
= 0; i
< ntypes
; i
++) {
503 const struct fdisk_parttype
*t
= fdisk_label_get_parttype(lb
, i
);
504 printf("%3zu %-30s %s\n", i
+ 1,
505 fdisk_parttype_get_name(t
),
506 fdisk_parttype_get_string(t
));
512 void toggle_dos_compatibility_flag(struct fdisk_context
*cxt
)
514 struct fdisk_label
*lb
= fdisk_get_label(cxt
, "dos");
520 flag
= !fdisk_dos_is_compatible(lb
);
521 fdisk_info(cxt
, flag
?
522 _("DOS Compatibility flag is set (DEPRECATED!)") :
523 _("DOS Compatibility flag is not set"));
525 fdisk_dos_enable_compatible(lb
, flag
);
527 if (fdisk_is_label(cxt
, DOS
))
528 fdisk_reset_alignment(cxt
); /* reset the current label */
531 void change_partition_type(struct fdisk_context
*cxt
)
534 struct fdisk_parttype
*t
= NULL
;
535 struct fdisk_partition
*pa
= NULL
;
536 const char *old
= NULL
;
540 if (fdisk_ask_partnum(cxt
, &i
, FALSE
))
543 if (fdisk_get_partition(cxt
, i
, &pa
)) {
544 fdisk_warnx(cxt
, _("Partition %zu does not exist yet!"), i
+ 1);
548 t
= (struct fdisk_parttype
*) fdisk_partition_get_type(pa
);
549 old
= t
? fdisk_parttype_get_name(t
) : _("Unknown");
552 t
= ask_partition_type(cxt
);
555 if (fdisk_set_partition_type(cxt
, i
, t
) == 0)
557 _("Changed type of partition '%s' to '%s'."),
558 old
, t
? fdisk_parttype_get_name(t
) : _("Unknown"));
561 _("Type of partition %zu is unchanged: %s."),
564 fdisk_unref_partition(pa
);
567 static size_t skip_empty(const unsigned char *buf
, size_t i
, size_t sz
)
570 const unsigned char *p0
= buf
+ i
;
572 for (next
= i
+ 16; next
< sz
; next
+= 16) {
573 if (memcmp(p0
, buf
+ next
, 16) != 0)
577 return next
== i
+ 16 ? i
: next
;
580 static void dump_buffer(off_t base
, unsigned char *buf
, size_t sz
, int all
)
582 size_t i
, l
, next
= 0;
586 for (i
= 0, l
= 0; i
< sz
; i
++, l
++) {
588 if (all
== 0 && !next
)
589 next
= skip_empty(buf
, i
, sz
);
590 printf("%08jx ", base
+ i
);
592 printf(" %02x", buf
[i
]);
593 if (l
== 7) /* words separator */
596 fputc('\n', stdout
); /* next line */
609 static void dump_blkdev(struct fdisk_context
*cxt
, const char *name
,
610 uint64_t offset
, size_t size
, int all
)
612 int fd
= fdisk_get_devfd(cxt
);
614 fdisk_info(cxt
, _("\n%s: offset = %ju, size = %zu bytes."),
619 if (lseek(fd
, (off_t
) offset
, SEEK_SET
) == (off_t
) -1)
620 fdisk_warn(cxt
, _("cannot seek"));
622 unsigned char *buf
= xmalloc(size
);
624 if (read_all(fd
, (char *) buf
, size
) != (ssize_t
) size
)
625 fdisk_warn(cxt
, _("cannot read"));
627 dump_buffer(offset
, buf
, size
, all
);
632 void dump_firstsector(struct fdisk_context
*cxt
)
634 int all
= !isatty(STDOUT_FILENO
);
638 dump_blkdev(cxt
, _("First sector"), 0, fdisk_get_sector_size(cxt
), all
);
641 void dump_disklabel(struct fdisk_context
*cxt
)
643 int all
= !isatty(STDOUT_FILENO
);
645 const char *name
= NULL
;
651 while (fdisk_locate_disklabel(cxt
, i
++, &name
, &offset
, &size
) == 0 && size
)
652 dump_blkdev(cxt
, name
, offset
, size
, all
);
655 static fdisk_sector_t
get_dev_blocks(char *dev
)
660 if ((fd
= open(dev
, O_RDONLY
)) < 0)
661 err(EXIT_FAILURE
, _("cannot open %s"), dev
);
662 ret
= blkdev_get_sectors(fd
, (unsigned long long *) &size
);
665 err(EXIT_FAILURE
, _("BLKGETSIZE ioctl failed on %s"), dev
);
669 static void __attribute__ ((__noreturn__
)) usage(FILE *out
)
671 fputs(USAGE_HEADER
, out
);
674 _(" %1$s [options] <disk> change partition table\n"
675 " %1$s [options] -l [<disk>] list partition table(s)\n"),
676 program_invocation_short_name
);
678 fputs(USAGE_SEPARATOR
, out
);
679 fputs(_("Display or manipulate a disk partition table.\n"), out
);
681 fputs(USAGE_OPTIONS
, out
);
682 fputs(_(" -b, --sector-size <size> physical and logical sector size\n"), out
);
683 fputs(_(" -B, --protect-boot don't erase bootbits when creat a new label\n"), out
);
684 fputs(_(" -c, --compatibility[=<mode>] mode is 'dos' or 'nondos' (default)\n"), out
);
685 fputs(_(" -L, --color[=<when>] colorize output (auto, always or never)\n"), out
);
687 " %s\n", USAGE_COLORS_DEFAULT
);
688 fputs(_(" -l, --list display partitions end exit\n"), out
);
689 fputs(_(" -o, --output <list> output columns\n"), out
);
690 fputs(_(" -t, --type <type> recognize specified partition table type only\n"), out
);
691 fputs(_(" -u, --units[=<unit>] display units: 'cylinders' or 'sectors' (default)\n"), out
);
692 fputs(_(" -s, --getsz display device size in 512-byte sectors [DEPRECATED]\n"), out
);
693 fputs(_(" --bytes print SIZE in bytes rather than in human readable format\n"), out
);
695 fputs(USAGE_SEPARATOR
, out
);
696 fputs(_(" -C, --cylinders <number> specify the number of cylinders\n"), out
);
697 fputs(_(" -H, --heads <number> specify the number of heads\n"), out
);
698 fputs(_(" -S, --sectors <number> specify the number of sectors per track\n"), out
);
700 fputs(USAGE_SEPARATOR
, out
);
701 fputs(USAGE_HELP
, out
);
702 fputs(USAGE_VERSION
, out
);
704 list_available_columns(out
);
706 fprintf(out
, USAGE_MAN_TAIL("fdisk(8)"));
707 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
712 ACT_FDISK
= 0, /* default */
717 int main(int argc
, char **argv
)
719 int rc
, i
, c
, act
= ACT_FDISK
;
720 int colormode
= UL_COLORMODE_UNDEF
;
721 struct fdisk_context
*cxt
;
724 OPT_BYTES
= CHAR_MAX
+ 1
726 static const struct option longopts
[] = {
727 { "bytes", no_argument
, NULL
, OPT_BYTES
},
728 { "color", optional_argument
, NULL
, 'L' },
729 { "compatibility", optional_argument
, NULL
, 'c' },
730 { "cylinders", required_argument
, NULL
, 'C' },
731 { "heads", required_argument
, NULL
, 'H' },
732 { "sectors", required_argument
, NULL
, 'S' },
733 { "getsz", no_argument
, NULL
, 's' },
734 { "help", no_argument
, NULL
, 'h' },
735 { "list", no_argument
, NULL
, 'l' },
736 { "sector-size", required_argument
, NULL
, 'b' },
737 { "type", required_argument
, NULL
, 't' },
738 { "units", optional_argument
, NULL
, 'u' },
739 { "version", no_argument
, NULL
, 'V' },
740 { "output", no_argument
, NULL
, 'o' },
741 { "protect-boot", no_argument
, NULL
, 'B' },
745 setlocale(LC_ALL
, "");
746 bindtextdomain(PACKAGE
, LOCALEDIR
);
748 atexit(close_stdout
);
751 fdiskprog_init_debug();
753 cxt
= fdisk_new_context();
755 err(EXIT_FAILURE
, _("failed to allocate libfdisk context"));
757 fdisk_set_ask(cxt
, ask_callback
, NULL
);
759 while ((c
= getopt_long(argc
, argv
, "b:Bc::C:hH:lL::o:sS:t:u::vV",
760 longopts
, NULL
)) != -1) {
764 size_t sz
= strtou32_or_err(optarg
,
765 _("invalid sector size argument"));
766 if (sz
!= 512 && sz
!= 1024 && sz
!= 2048 && sz
!= 4096)
768 fdisk_save_user_sector_size(cxt
, sz
, sz
);
772 fdisk_enable_bootbits_protection(cxt
, 1);
775 fdisk_save_user_geometry(cxt
,
776 strtou32_or_err(optarg
,
777 _("invalid cylinders argument")),
782 /* this setting is independent on the current
783 * actively used label
785 char *p
= *optarg
== '=' ? optarg
+ 1 : optarg
;
786 struct fdisk_label
*lb
= fdisk_get_label(cxt
, "dos");
789 err(EXIT_FAILURE
, _("not found DOS label driver"));
790 if (strcmp(p
, "dos") == 0)
791 fdisk_dos_enable_compatible(lb
, TRUE
);
792 else if (strcmp(p
, "nondos") == 0)
793 fdisk_dos_enable_compatible(lb
, FALSE
);
795 warnx(_("unknown compatibility mode '%s'"), p
);
799 /* use default if no optarg specified */
802 fdisk_save_user_geometry(cxt
, 0,
803 strtou32_or_err(optarg
,
804 _("invalid heads argument")),
808 fdisk_save_user_geometry(cxt
, 0, 0,
809 strtou32_or_err(optarg
,
810 _("invalid sectors argument")));
816 colormode
= UL_COLORMODE_AUTO
;
818 colormode
= colormode_or_err(optarg
,
819 _("unsupported color mode"));
829 struct fdisk_label
*lb
= NULL
;
831 while (fdisk_next_label(cxt
, &lb
) == 0)
832 fdisk_label_set_disabled(lb
, 1);
834 lb
= fdisk_get_label(cxt
, optarg
);
836 errx(EXIT_FAILURE
, _("unsupported disklabel: %s"), optarg
);
837 fdisk_label_set_disabled(lb
, 0);
841 if (optarg
&& *optarg
== '=')
843 if (fdisk_set_unit(cxt
, optarg
) != 0)
846 case 'V': /* preferred for util-linux */
847 case 'v': /* for backward compatibility only */
848 printf(UTIL_LINUX_VERSION
);
853 fdisk_set_size_unit(cxt
, FDISK_SIZEUNIT_BYTES
);
860 if (argc
-optind
!= 1 && fdisk_has_user_device_properties(cxt
))
861 warnx(_("The device properties (sector size and geometry) should"
862 " be used with one specified device only."));
864 colors_init(colormode
, "fdisk");
868 fdisk_enable_listonly(cxt
, 1);
869 init_fields(cxt
, outarg
, NULL
);
873 for (k
= optind
; k
< argc
; k
++)
874 print_device_pt(cxt
, argv
[k
], 1, 0);
876 print_all_devices_pt(cxt
, 0);
881 if (argc
- optind
<= 0)
884 for (i
= optind
; i
< argc
; i
++) {
885 uintmax_t blks
= get_dev_blocks(argv
[i
]);
887 if (argc
- optind
== 1)
888 printf("%ju\n", blks
);
890 printf("%s: %ju\n", argv
[i
], blks
);
895 if (argc
-optind
!= 1)
898 /* Here starts interactive mode, use fdisk_{warn,info,..} functions */
899 color_scheme_enable("welcome", UL_COLOR_GREEN
);
900 fdisk_info(cxt
, _("Welcome to fdisk (%s)."), PACKAGE_STRING
);
902 fdisk_info(cxt
, _("Changes will remain in memory only, until you decide to write them.\n"
903 "Be careful before using the write command.\n"));
905 rc
= fdisk_assign_device(cxt
, argv
[optind
], 0);
907 rc
= fdisk_assign_device(cxt
, argv
[optind
], 1);
909 fdisk_warnx(cxt
, _("Device open in read-only mode."));
912 err(EXIT_FAILURE
, _("cannot open %s"), argv
[optind
]);
916 if (!fdisk_has_label(cxt
)) {
917 fdisk_info(cxt
, _("Device does not contain a recognized partition table."));
918 fdisk_create_disklabel(cxt
, NULL
);
920 } else if (fdisk_is_label(cxt
, GPT
) && fdisk_gpt_is_hybrid(cxt
))
922 "A hybrid GPT was detected. You have to sync "
923 "the hybrid MBR manually (expert command 'M')."));
925 init_fields(cxt
, outarg
, NULL
); /* -o <columns> */
928 process_fdisk_menu(&cxt
);
931 fdisk_unref_context(cxt
);