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.
33 #include "wholedisk.h"
34 #include "pathnames.h"
35 #include "canonicalize.h"
37 #include "closestream.h"
39 #include "pt-sun.h" /* to toggle flags */
41 #ifdef HAVE_LINUX_COMPILER_H
42 # include <linux/compiler.h>
44 #ifdef HAVE_LINUX_BLKPG_H
45 # include <linux/blkpg.h>
48 static void __attribute__ ((__noreturn__
)) usage(FILE *out
)
50 fputs(USAGE_HEADER
, out
);
53 _(" %1$s [options] <disk> change partition table\n"
54 " %1$s [options] -l [<disk>] list partition table(s)\n"),
55 program_invocation_short_name
);
57 fputs(USAGE_OPTIONS
, out
);
58 fputs(_(" -b <size> sector size (512, 1024, 2048 or 4096)\n"), out
);
59 fputs(_(" -c[=<mode>] compatible mode: 'dos' or 'nondos' (default)\n"), out
);
60 fputs(_(" -h print this help text\n"), out
);
61 fputs(_(" -c[=<mode>] compatible mode: 'dos' or 'nondos' (default)\n"), out
);
62 fputs(_(" -L[=<when>] colorize output (auto, always or never)\n"), out
);
63 fputs(_(" -t <type> force fdisk to recognize specified partition table type only\n"), out
);
64 fputs(_(" -u[=<unit>] display units: 'cylinders' or 'sectors' (default)\n"), out
);
65 fputs(_(" -v print program version\n"), out
);
66 fputs(_(" -C <number> specify the number of cylinders\n"), out
);
67 fputs(_(" -H <number> specify the number of heads\n"), out
);
68 fputs(_(" -S <number> specify the number of sectors per track\n"), out
);
70 fprintf(out
, USAGE_MAN_TAIL("fdisk(8)"));
71 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
76 int get_user_reply(struct fdisk_context
*cxt
, const char *prompt
,
77 char *buf
, size_t bufsz
)
83 fputs(prompt
, stdout
);
86 if (!fgets(buf
, bufsz
, stdin
)) {
87 if (fdisk_label_is_changed(cxt
->label
)) {
88 fprintf(stderr
, _("\nDo you really want to quit? "));
90 if (fgets(buf
, bufsz
, stdin
) && !rpmatch(buf
))
93 fdisk_free_context(cxt
);
99 for (p
= buf
; *p
&& !isgraph(*p
); p
++); /* get first non-blank */
102 memmove(buf
, p
, p
- buf
); /* remove blank space */
104 if (sz
&& *(buf
+ sz
- 1) == '\n')
105 *(buf
+ sz
- 1) = '\0';
107 DBG(ASK
, ul_debug("user's reply: >>>%s<<<", buf
));
111 static int ask_menu(struct fdisk_context
*cxt
, struct fdisk_ask
*ask
,
112 char *buf
, size_t bufsz
)
115 const char *q
= fdisk_ask_get_query(ask
);
116 int dft
= fdisk_ask_menu_get_default(ask
);
119 fputs(q
, stdout
); /* print header */
126 const char *name
, *desc
;
129 /* print menu items */
130 while (fdisk_ask_menu_get_item(ask
, i
++, &key
, &name
, &desc
) == 0)
131 fprintf(stdout
, " %c %s (%s)\n", key
, name
, desc
);
134 snprintf(prompt
, sizeof(prompt
), _("Select (default %c): "), dft
);
135 get_user_reply(cxt
, prompt
, buf
, bufsz
);
137 fdisk_info(cxt
, _("Using default response %c."), dft
);
144 while (fdisk_ask_menu_get_item(ask
, i
++, &key
, NULL
, NULL
) == 0) {
146 fdisk_ask_menu_set_result(ask
, c
);
147 return 0; /* success */
150 fdisk_warnx(cxt
, _("Value out of range."));
157 #define tochar(num) ((int) ('a' + num - 1))
158 static int ask_number(struct fdisk_context
*cxt
,
159 struct fdisk_ask
*ask
,
160 char *buf
, size_t bufsz
)
162 char prompt
[128] = { '\0' };
163 const char *q
= fdisk_ask_get_query(ask
);
164 const char *range
= fdisk_ask_number_get_range(ask
);
166 uint64_t dflt
= fdisk_ask_number_get_default(ask
),
167 low
= fdisk_ask_number_get_low(ask
),
168 high
= fdisk_ask_number_get_high(ask
);
169 int inchar
= fdisk_ask_number_inchars(ask
);
173 DBG(ASK
, ul_debug("asking for number "
174 "['%s', <%ju,%ju>, default=%ju, range: %s]",
175 q
, low
, high
, dflt
, range
));
177 if (range
&& dflt
>= low
&& dflt
<= high
) {
179 snprintf(prompt
, sizeof(prompt
), _("%s (%s, default %c): "),
180 q
, range
, tochar(dflt
));
182 snprintf(prompt
, sizeof(prompt
), _("%s (%s, default %ju): "),
185 } else if (dflt
>= low
&& dflt
<= high
) {
187 snprintf(prompt
, sizeof(prompt
), _("%s (%c-%c, default %c): "),
188 q
, tochar(low
), tochar(high
), tochar(dflt
));
190 snprintf(prompt
, sizeof(prompt
), _("%s (%ju-%ju, default %ju): "),
193 snprintf(prompt
, sizeof(prompt
), _("%s (%c-%c): "),
194 q
, tochar(low
), tochar(high
));
196 snprintf(prompt
, sizeof(prompt
), _("%s (%ju-%ju): "),
200 int rc
= get_user_reply(cxt
, prompt
, buf
, bufsz
);
205 if (!*buf
&& dflt
>= low
&& dflt
<= high
)
206 return fdisk_ask_number_set_result(ask
, dflt
);
208 if (isdigit_string(buf
)) {
212 num
= strtoumax(buf
, &end
, 10);
213 if (errno
|| buf
== end
|| (end
&& *end
))
215 } else if (inchar
&& isalpha(*buf
)) {
216 num
= tolower(*buf
) - 'a' + 1;
220 if (rc
== 0 && num
>= low
&& num
<= high
)
221 return fdisk_ask_number_set_result(ask
, num
);
223 fdisk_warnx(cxt
, _("Value out of range."));
229 static int ask_offset(struct fdisk_context
*cxt
,
230 struct fdisk_ask
*ask
,
231 char *buf
, size_t bufsz
)
233 char prompt
[128] = { '\0' };
234 const char *q
= fdisk_ask_get_query(ask
);
235 const char *range
= fdisk_ask_number_get_range(ask
);
237 uint64_t dflt
= fdisk_ask_number_get_default(ask
),
238 low
= fdisk_ask_number_get_low(ask
),
239 high
= fdisk_ask_number_get_high(ask
),
240 base
= fdisk_ask_number_get_base(ask
);
244 DBG(ASK
, ul_debug("asking for offset ['%s', <%ju,%ju>, base=%ju, default=%ju, range: %s]",
245 q
, low
, high
, base
, dflt
, range
));
247 if (range
&& dflt
>= low
&& dflt
<= high
)
248 snprintf(prompt
, sizeof(prompt
), _("%s (%s, default %ju): "), q
, range
, dflt
);
249 else if (dflt
>= low
&& dflt
<= high
)
250 snprintf(prompt
, sizeof(prompt
), _("%s (%ju-%ju, default %ju): "), q
, low
, high
, dflt
);
252 snprintf(prompt
, sizeof(prompt
), _("%s (%ju-%ju): "), q
, low
, high
);
259 int rc
= get_user_reply(cxt
, prompt
, buf
, bufsz
);
262 if (!*buf
&& dflt
>= low
&& dflt
<= high
)
263 return fdisk_ask_number_set_result(ask
, dflt
);
266 if (*p
== '+' || *p
== '-') {
271 rc
= parse_size(p
, &num
, &pwr
);
274 DBG(ASK
, ul_debug("parsed size: %ju", num
));
276 /* +{size}{K,M,...} specified, the "num" is in bytes */
277 uint64_t unit
= fdisk_ask_number_get_unit(ask
);
278 num
+= unit
/2; /* round */
286 DBG(ASK
, ul_debug("final offset: %ju [sig: %c, power: %d, %s]",
288 sig
? "relative" : "absolute"));
289 if (num
>= low
&& num
<= high
) {
291 fdisk_ask_number_set_relative(ask
, 1);
292 return fdisk_ask_number_set_result(ask
, num
);
294 fdisk_warnx(cxt
, _("Value out of range."));
300 static unsigned int info_count
;
302 static void fputs_info(struct fdisk_ask
*ask
, FILE *out
, char *buf
, size_t bufsz
)
309 msg
= fdisk_ask_print_get_mesg(ask
);
310 flags
= fdisk_ask_get_flags(ask
);
316 if (flags
== 0 || !colors_wanted())
319 if (flags
& FDISK_INFO_COLON
) {
322 char *p
= strstr(msg
, sep
);
328 strncpy(buf
, msg
, bufsz
);
329 buf
[p
- msg
+ sz
] = '\0';
331 color_enable(UL_COLOR_BROWN
);
336 } else if (flags
& FDISK_INFO_SUCCESS
) {
337 color_enable(UL_COLOR_BOLD
);
347 int ask_callback(struct fdisk_context
*cxt
, struct fdisk_ask
*ask
,
348 void *data
__attribute__((__unused__
)))
356 if (fdisk_ask_get_type(ask
) != FDISK_ASKTYPE_INFO
)
359 switch(fdisk_ask_get_type(ask
)) {
360 case FDISK_ASKTYPE_MENU
:
361 return ask_menu(cxt
, ask
, buf
, sizeof(buf
));
362 case FDISK_ASKTYPE_NUMBER
:
363 return ask_number(cxt
, ask
, buf
, sizeof(buf
));
364 case FDISK_ASKTYPE_OFFSET
:
365 return ask_offset(cxt
, ask
, buf
, sizeof(buf
));
366 case FDISK_ASKTYPE_INFO
:
368 fputs_info(ask
, stdout
, buf
, sizeof(buf
));
370 case FDISK_ASKTYPE_WARNX
:
371 color_fenable(UL_COLOR_RED
, stderr
);
372 fputs(fdisk_ask_print_get_mesg(ask
), stderr
);
373 color_fdisable(stderr
);
376 case FDISK_ASKTYPE_WARN
:
377 color_fenable(UL_COLOR_RED
, stderr
);
378 fputs(fdisk_ask_print_get_mesg(ask
), stderr
);
379 errno
= fdisk_ask_print_get_errno(ask
);
380 fprintf(stderr
, ": %m\n");
381 color_fdisable(stderr
);
383 case FDISK_ASKTYPE_YESNO
:
385 fputs(fdisk_ask_get_query(ask
), stdout
);
386 rc
= get_user_reply(cxt
, _(" [Y]es/[N]o: "), buf
, sizeof(buf
));
388 fdisk_ask_yesno_set_result(ask
, rpmatch(buf
));
389 DBG(ASK
, ul_debug("yes-no ask: reply '%s' [rc=%d]", buf
, rc
));
391 case FDISK_ASKTYPE_STRING
:
394 snprintf(prmt
, sizeof(prmt
), "%s: ", fdisk_ask_get_query(ask
));
396 rc
= get_user_reply(cxt
, prmt
, buf
, sizeof(buf
));
398 fdisk_ask_string_set_result(ask
, xstrdup(buf
));
399 DBG(ASK
, ul_debug("string ask: reply '%s' [rc=%d]", buf
, rc
));
403 warnx(_("internal error: unsupported dialog type %d"), fdisk_ask_get_type(ask
));
409 struct fdisk_parttype
*ask_partition_type(struct fdisk_context
*cxt
)
413 if (!cxt
|| !cxt
->label
|| !cxt
->label
->nparttypes
)
416 q
= fdisk_is_parttype_string(cxt
) ?
417 _("Partition type (type L to list all types): ") :
418 _("Hex code (type L to list all codes): ");
421 int rc
= get_user_reply(cxt
, q
, buf
, sizeof(buf
));
426 if (buf
[1] == '\0' && toupper(*buf
) == 'L')
427 list_partition_types(cxt
);
429 return fdisk_parse_parttype(cxt
, buf
);
435 void list_partition_types(struct fdisk_context
*cxt
)
437 struct fdisk_parttype
*types
;
440 if (!cxt
|| !cxt
->label
|| !cxt
->label
->parttypes
)
443 types
= cxt
->label
->parttypes
;
444 ntypes
= cxt
->label
->nparttypes
;
446 if (types
[0].typestr
== NULL
) {
448 * Prints in 4 columns in format <hex> <name>
450 size_t last
[4], done
= 0, next
= 0, size
;
454 if (types
[ntypes
- 1].name
== NULL
)
457 for (i
= 3; i
>= 0; i
--)
458 last
[3 - i
] = done
+= (size
+ i
- done
) / (i
+ 1);
462 #define NAME_WIDTH 15
463 char name
[NAME_WIDTH
* MB_LEN_MAX
];
464 size_t width
= NAME_WIDTH
;
465 struct fdisk_parttype
*t
= &types
[next
];
469 printf("%c%2x ", i
? ' ' : '\n', t
->type
);
470 ret
= mbsalign(_(t
->name
), name
, sizeof(name
),
471 &width
, MBS_ALIGN_LEFT
, 0);
473 if (ret
== (size_t)-1 || ret
>= sizeof(name
))
474 printf("%-15.15s", _(t
->name
));
479 next
= last
[i
++] + done
;
480 if (i
> 3 || next
>= last
[i
]) {
484 } while (done
< last
[0]);
488 * Prints 1 column in format <idx> <name> <typestr>
490 struct fdisk_parttype
*t
;
493 for (i
= 0, t
= types
; t
&& i
< ntypes
; t
++, i
++) {
495 printf("%3zu %-30s %s\n", i
+ 1,
496 t
->name
, t
->typestr
);
502 void toggle_dos_compatibility_flag(struct fdisk_context
*cxt
)
504 struct fdisk_label
*lb
= fdisk_context_get_label(cxt
, "dos");
510 flag
= !fdisk_dos_is_compatible(lb
);
511 fdisk_info(cxt
, flag
?
512 _("DOS Compatibility flag is set (DEPRECATED!)") :
513 _("DOS Compatibility flag is not set"));
515 fdisk_dos_enable_compatible(lb
, flag
);
517 if (fdisk_is_disklabel(cxt
, DOS
))
518 fdisk_reset_alignment(cxt
); /* reset the current label */
521 void change_partition_type(struct fdisk_context
*cxt
)
524 struct fdisk_parttype
*t
= NULL
;
525 struct fdisk_partition
*pa
= NULL
;
526 const char *old
= NULL
;
531 if (fdisk_ask_partnum(cxt
, &i
, FALSE
))
534 if (fdisk_get_partition(cxt
, i
, &pa
)) {
535 fdisk_warnx(cxt
, _("Partition %zu does not exist yet!"), i
+ 1);
539 t
= (struct fdisk_parttype
*) fdisk_partition_get_type(pa
);
540 old
= t
? t
->name
: _("Unknown");
543 t
= ask_partition_type(cxt
);
546 if (fdisk_set_partition_type(cxt
, i
, t
) == 0)
547 fdisk_sinfo(cxt
, FDISK_INFO_SUCCESS
,
548 _("Changed type of partition '%s' to '%s'."),
549 old
, t
? t
->name
: _("Unknown"));
552 _("Type of partition %zu is unchanged: %s."),
555 fdisk_unref_partition(pa
);
558 void list_disk_geometry(struct fdisk_context
*cxt
)
561 uint64_t bytes
= cxt
->total_sectors
* cxt
->sector_size
;
562 char *strsz
= size_to_human_string(SIZE_SUFFIX_SPACE
563 | SIZE_SUFFIX_3LETTER
, bytes
);
565 fdisk_colon(cxt
, _("Disk %s: %s, %ju bytes, %ju sectors"),
566 cxt
->dev_path
, strsz
,
567 bytes
, (uintmax_t) cxt
->total_sectors
);
570 if (fdisk_require_geometry(cxt
) || fdisk_context_use_cylinders(cxt
))
571 fdisk_colon(cxt
, _("Geometry: %d heads, %llu sectors/track, %llu cylinders"),
572 cxt
->geom
.heads
, cxt
->geom
.sectors
, cxt
->geom
.cylinders
);
574 fdisk_colon(cxt
, _("Units: %s of %d * %ld = %ld bytes"),
575 fdisk_context_get_unit(cxt
, PLURAL
),
576 fdisk_context_get_units_per_sector(cxt
),
578 fdisk_context_get_units_per_sector(cxt
) * cxt
->sector_size
);
580 fdisk_colon(cxt
, _("Sector size (logical/physical): %lu bytes / %lu bytes"),
581 cxt
->sector_size
, cxt
->phy_sector_size
);
582 fdisk_colon(cxt
, _("I/O size (minimum/optimal): %lu bytes / %lu bytes"),
583 cxt
->min_io_size
, cxt
->io_size
);
584 if (cxt
->alignment_offset
)
585 fdisk_colon(cxt
, _("Alignment offset: %lu bytes"),
586 cxt
->alignment_offset
);
587 if (fdisk_dev_has_disklabel(cxt
))
588 fdisk_colon(cxt
, _("Disklabel type: %s"), cxt
->label
->name
);
590 if (fdisk_get_disklabel_id(cxt
, &id
) == 0 && id
)
591 fdisk_colon(cxt
, _("Disk identifier: %s"), id
);
594 void list_disklabel(struct fdisk_context
*cxt
)
596 struct fdisk_table
*tb
= NULL
;
599 /* print label specific stuff by libfdisk FDISK_ASK_INFO API */
600 fdisk_list_disklabel(cxt
);
602 /* print partitions */
603 if (fdisk_get_partitions(cxt
, &tb
))
605 if (fdisk_table_to_string(tb
, cxt
, NULL
, 0, &str
) == 0) {
610 fdisk_unref_table(tb
);
613 static size_t skip_empty(const unsigned char *buf
, size_t i
, size_t sz
)
616 const unsigned char *p0
= buf
+ i
;
618 for (next
= i
+ 16; next
< sz
; next
+= 16) {
619 if (memcmp(p0
, buf
+ next
, 16) != 0)
623 return next
== i
+ 16 ? i
: next
;
626 static void dump_buffer(off_t base
, unsigned char *buf
, size_t sz
, int all
)
628 size_t i
, l
, next
= 0;
632 for (i
= 0, l
= 0; i
< sz
; i
++, l
++) {
634 if (all
== 0 && !next
)
635 next
= skip_empty(buf
, i
, sz
);
636 printf("%08jx ", base
+ i
);
638 printf(" %02x", buf
[i
]);
639 if (l
== 7) /* words separator */
642 fputc('\n', stdout
); /* next line */
655 static void dump_blkdev(struct fdisk_context
*cxt
, const char *name
,
656 off_t offset
, size_t size
, int all
)
658 fdisk_colon(cxt
, _("\n%s: offset = %ju, size = %zu bytes."),
661 if (lseek(cxt
->dev_fd
, offset
, SEEK_SET
) == (off_t
) -1)
662 fdisk_warn(cxt
, _("cannot seek"));
664 unsigned char *buf
= xmalloc(size
);
666 if (read_all(cxt
->dev_fd
, (char *) buf
, size
) != (ssize_t
) size
)
667 fdisk_warn(cxt
, _("cannot read"));
669 dump_buffer(offset
, buf
, size
, all
);
674 void dump_firstsector(struct fdisk_context
*cxt
)
676 int all
= !isatty(STDOUT_FILENO
);
681 dump_blkdev(cxt
, _("First sector"), 0, cxt
->sector_size
, all
);
684 void dump_disklabel(struct fdisk_context
*cxt
)
686 int all
= !isatty(STDOUT_FILENO
);
688 const char *name
= NULL
;
695 while (fdisk_locate_disklabel(cxt
, i
++, &name
, &offset
, &size
) == 0 && size
)
696 dump_blkdev(cxt
, name
, offset
, size
, all
);
699 static int is_ide_cdrom_or_tape(char *device
)
703 if ((fd
= open(device
, O_RDONLY
)) < 0)
705 ret
= blkdev_is_cdrom(fd
);
711 static void print_device_pt(struct fdisk_context
*cxt
, char *device
)
713 if (fdisk_context_assign_device(cxt
, device
, 1) != 0) /* read-only */
714 err(EXIT_FAILURE
, _("cannot open %s"), device
);
716 list_disk_geometry(cxt
);
718 if (fdisk_dev_has_disklabel(cxt
))
723 static void print_all_devices_pt(struct fdisk_context
*cxt
)
728 f
= fopen(_PATH_PROC_PARTITIONS
, "r");
730 warn(_("cannot open %s"), _PATH_PROC_PARTITIONS
);
734 DBG(FRONTEND
, ul_debug("reading "_PATH_PROC_PARTITIONS
));
736 while (fgets(line
, sizeof(line
), f
)) {
737 char ptname
[128 + 1], devname
[256];
739 if (sscanf(line
, " %*d %*d %*d %128[^\n ]", ptname
) != 1)
742 snprintf(devname
, sizeof(devname
), "/dev/%s", ptname
);
744 DBG(FRONTEND
, ul_debug("listing %s", devname
));
746 if (is_whole_disk(devname
)) {
747 char *cn
= canonicalize_path(devname
);
749 if (!is_ide_cdrom_or_tape(cn
))
750 print_device_pt(cxt
, cn
);
758 static sector_t
get_dev_blocks(char *dev
)
763 if ((fd
= open(dev
, O_RDONLY
)) < 0)
764 err(EXIT_FAILURE
, _("cannot open %s"), dev
);
765 if (blkdev_get_sectors(fd
, &size
) == -1) {
767 err(EXIT_FAILURE
, _("BLKGETSIZE ioctl failed on %s"), dev
);
774 ACT_FDISK
= 0, /* default */
779 int main(int argc
, char **argv
)
781 int i
, c
, act
= ACT_FDISK
;
782 int colormode
= UL_COLORMODE_UNDEF
;
783 struct fdisk_context
*cxt
;
785 setlocale(LC_ALL
, "");
786 bindtextdomain(PACKAGE
, LOCALEDIR
);
788 atexit(close_stdout
);
791 cxt
= fdisk_new_context();
793 err(EXIT_FAILURE
, _("failed to allocate libfdisk context"));
795 fdisk_context_set_ask(cxt
, ask_callback
, NULL
);
797 while ((c
= getopt(argc
, argv
, "b:c::C:hH:lL::sS:t:u::vV")) != -1) {
801 size_t sz
= strtou32_or_err(optarg
,
802 _("invalid sector size argument"));
803 if (sz
!= 512 && sz
!= 1024 && sz
!= 2048 && sz
!= 4096)
805 fdisk_save_user_sector_size(cxt
, sz
, sz
);
809 fdisk_save_user_geometry(cxt
,
810 strtou32_or_err(optarg
,
811 _("invalid cylinders argument")),
816 /* this setting is independent on the current
817 * actively used label */
818 struct fdisk_label
*lb
= fdisk_context_get_label(cxt
, "dos");
820 err(EXIT_FAILURE
, _("not found DOS label driver"));
821 if (strcmp(optarg
, "=dos") == 0)
822 fdisk_dos_enable_compatible(lb
, TRUE
);
823 else if (strcmp(optarg
, "=nondos") == 0)
824 fdisk_dos_enable_compatible(lb
, FALSE
);
828 /* use default if no optarg specified */
831 fdisk_save_user_geometry(cxt
, 0,
832 strtou32_or_err(optarg
,
833 _("invalid heads argument")),
837 fdisk_save_user_geometry(cxt
, 0, 0,
838 strtou32_or_err(optarg
,
839 _("invalid sectors argument")));
846 colormode
= colormode_or_err(optarg
,
847 _("unsupported color mode"));
854 struct fdisk_label
*lb
= NULL
;
856 while (fdisk_context_next_label(cxt
, &lb
) == 0)
857 fdisk_label_set_disabled(lb
, 1);
859 lb
= fdisk_context_get_label(cxt
, optarg
);
861 errx(EXIT_FAILURE
, _("unsupported disklabel: %s"), optarg
);
862 fdisk_label_set_disabled(lb
, 0);
865 if (optarg
&& *optarg
== '=')
867 if (fdisk_context_set_unit(cxt
, optarg
) != 0)
872 printf(UTIL_LINUX_VERSION
);
881 if (argc
-optind
!= 1 && fdisk_has_user_device_properties(cxt
))
882 warnx(_("The device properties (sector size and geometry) should"
883 " be used with one specified device only."));
885 colors_init(colormode
, "fdisk");
889 fdisk_context_enable_listonly(cxt
, 1);
893 for (k
= optind
; k
< argc
; k
++)
894 print_device_pt(cxt
, argv
[k
]);
896 print_all_devices_pt(cxt
);
901 if (argc
- optind
<= 0)
904 for (i
= optind
; i
< argc
; i
++) {
905 if (argc
- optind
== 1)
906 printf("%llu\n", get_dev_blocks(argv
[i
]));
908 printf("%s: %llu\n", argv
[i
], get_dev_blocks(argv
[i
]));
913 if (argc
-optind
!= 1)
916 /* Here starts interactive mode, use fdisk_{warn,info,..} functions */
917 color_enable(UL_COLOR_GREEN
);
918 fdisk_info(cxt
, _("Welcome to fdisk (%s)."), PACKAGE_STRING
);
920 fdisk_info(cxt
, _("Changes will remain in memory only, until you decide to write them.\n"
921 "Be careful before using the write command.\n"));
923 if (fdisk_context_assign_device(cxt
, argv
[optind
], 0) != 0)
924 err(EXIT_FAILURE
, _("cannot open %s"), argv
[optind
]);
928 if (!fdisk_dev_has_disklabel(cxt
)) {
929 fdisk_info(cxt
, _("Device does not contain a recognized partition table."));
930 fdisk_create_disklabel(cxt
, NULL
);
932 } else if (fdisk_is_disklabel(cxt
, GPT
) && fdisk_gpt_is_hybrid(cxt
))
934 "The hybrid GPT detected. You have to sync "
935 "the hybrid MBR manually (expert command 'M')."));
938 process_fdisk_menu(&cxt
);
941 fdisk_free_context(cxt
);