2 * Copyright (C) 1995 Andries E. Brouwer (aeb@cwi.nl)
3 * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
5 * This program is free software. You can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation: either Version 1
8 * or (at your option) any later version.
10 * A.V. Le Blanc (LeBlanc@mcc.ac.uk) wrote Linux fdisk 1992-1994,
11 * patched by various people (faith@cs.unc.edu, martin@cs.unc.edu,
12 * leisner@sdsp.mc.xerox.com, esr@snark.thyrsus.com, aeb@cwi.nl)
13 * 1993-1995, with version numbers (as far as I have seen) 0.93 - 2.0e.
14 * This program had (head,sector,cylinder) as basic unit, and was
15 * (therefore) broken in several ways for the use on larger disks -
16 * for example, my last patch (from 2.0d to 2.0e) was required
17 * to allow a partition to cross cylinder 8064, and to write an
18 * extended partition past the 4GB mark.
20 * Karel Zak wrote new sfdisk based on libfdisk from util-linux
34 #include <libsmartcols.h>
35 #ifdef HAVE_LIBREADLINE
36 # include <readline/readline.h>
45 #include "closestream.h"
54 #include "fdisk-list.h"
57 * sfdisk debug stuff (see fdisk.h and include/debug.h)
59 UL_DEBUG_DEFINE_MASK(sfdisk
);
60 UL_DEBUG_DEFINE_MASKNAMES(sfdisk
) = UL_DEBUG_EMPTY_MASKNAMES
;
62 #define SFDISKPROG_DEBUG_INIT (1 << 1)
63 #define SFDISKPROG_DEBUG_PARSE (1 << 2)
64 #define SFDISKPROG_DEBUG_MISC (1 << 3)
65 #define SFDISKPROG_DEBUG_ASK (1 << 4)
66 #define SFDISKPROG_DEBUG_ALL 0xFFFF
68 #define DBG(m, x) __UL_DBG(sfdisk, SFDISKPROG_DEBUG_, m, x)
69 #define ON_DBG(m, x) __UL_DBG_CALL(sfdisk, SFDISKPROG_DEBUG_, m, x)
92 int partno
; /* -N <partno>, default -1 */
93 int wipemode
; /* remove foreign signatures */
94 const char *label
; /* --label <label> */
95 const char *label_nested
; /* --label-nested <label> */
96 const char *backup_file
; /* -O <path> */
97 const char *move_typescript
; /* --movedata <typescript> */
100 struct fdisk_context
*cxt
; /* libfdisk context */
101 struct fdisk_partition
*orig_pa
; /* -N <partno> before the change */
103 unsigned int verify
: 1, /* call fdisk_verify_disklabel() */
104 quiet
: 1, /* suppres extra messages */
105 interactive
: 1, /* running on tty */
106 noreread
: 1, /* don't check device is in use */
107 force
: 1, /* do also stupid things */
108 backup
: 1, /* backup sectors before write PT */
109 container
: 1, /* PT contains container (MBR extended) partitions */
110 append
: 1, /* don't create new PT, append partitions only */
111 json
: 1, /* JSON dump */
112 movedata
: 1, /* move data after resize */
113 noact
: 1; /* do not write to device */
116 #define SFDISK_PROMPT ">>> "
118 static void sfdiskprog_init_debug(void)
120 __UL_INIT_DEBUG(sfdisk
, SFDISKPROG_DEBUG_
, 0, SFDISK_DEBUG
);
124 static int get_user_reply(const char *prompt
, char *buf
, size_t bufsz
)
129 #ifdef HAVE_LIBREADLINE
130 if (isatty(STDIN_FILENO
)) {
131 p
= readline(prompt
);
134 memcpy(buf
, p
, bufsz
);
139 fputs(prompt
, stdout
);
142 if (!fgets(buf
, bufsz
, stdin
))
146 for (p
= buf
; *p
&& !isgraph(*p
); p
++); /* get first non-blank */
149 memmove(buf
, p
, p
- buf
); /* remove blank space */
151 if (sz
&& *(buf
+ sz
- 1) == '\n')
152 *(buf
+ sz
- 1) = '\0';
154 DBG(ASK
, ul_debug("user's reply: >>>%s<<<", buf
));
158 static int ask_callback(struct fdisk_context
*cxt
__attribute__((__unused__
)),
159 struct fdisk_ask
*ask
,
162 struct sfdisk
*sf
= (struct sfdisk
*) data
;
167 switch(fdisk_ask_get_type(ask
)) {
168 case FDISK_ASKTYPE_INFO
:
171 fputs(fdisk_ask_print_get_mesg(ask
), stdout
);
174 case FDISK_ASKTYPE_WARNX
:
175 color_scheme_fenable("warn", UL_COLOR_RED
, stderr
);
176 fputs(fdisk_ask_print_get_mesg(ask
), stderr
);
177 color_fdisable(stderr
);
180 case FDISK_ASKTYPE_WARN
:
181 color_scheme_fenable("warn", UL_COLOR_RED
, stderr
);
182 fputs(fdisk_ask_print_get_mesg(ask
), stderr
);
183 errno
= fdisk_ask_print_get_errno(ask
);
184 fprintf(stderr
, ": %m\n");
185 color_fdisable(stderr
);
187 case FDISK_ASKTYPE_YESNO
:
193 fputs(fdisk_ask_get_query(ask
), stdout
);
194 rc
= get_user_reply(_(" [Y]es/[N]o: "), buf
, sizeof(buf
));
198 if (x
== RPMATCH_YES
|| x
== RPMATCH_NO
) {
199 fdisk_ask_yesno_set_result(ask
, x
);
203 DBG(ASK
, ul_debug("yes-no ask: reply '%s' [rc=%d]", buf
, rc
));
212 static void sfdisk_init(struct sfdisk
*sf
)
216 sfdiskprog_init_debug();
218 sf
->cxt
= fdisk_new_context();
220 err(EXIT_FAILURE
, _("failed to allocate libfdisk context"));
221 fdisk_set_ask(sf
->cxt
, ask_callback
, (void *) sf
);
222 fdisk_enable_bootbits_protection(sf
->cxt
, 1);
224 if (sf
->label_nested
) {
225 struct fdisk_context
*x
= fdisk_new_nested_context(sf
->cxt
,
228 err(EXIT_FAILURE
, _("failed to allocate nested libfdisk context"));
229 /* the original context is available by fdisk_get_parent() */
234 static int sfdisk_deinit(struct sfdisk
*sf
)
236 struct fdisk_context
*parent
;
241 parent
= fdisk_get_parent(sf
->cxt
);
243 fdisk_unref_context(sf
->cxt
);
247 fdisk_unref_context(sf
->cxt
);
250 memset(sf
, 0, sizeof(*sf
));
254 static struct fdisk_partition
*get_partition(struct fdisk_context
*cxt
, size_t partno
)
256 struct fdisk_table
*tb
= NULL
;
257 struct fdisk_partition
*pa
;
259 if (fdisk_get_partitions(cxt
, &tb
) != 0)
262 pa
= fdisk_table_get_partition_by_partno(tb
, partno
);
264 fdisk_ref_partition(pa
);
265 fdisk_unref_table(tb
);
269 static void backup_sectors(struct sfdisk
*sf
,
273 uint64_t offset
, size_t size
)
278 devfd
= fdisk_get_devfd(sf
->cxt
);
281 xasprintf(&fname
, "%s0x%08jx.bak", tpl
, offset
);
283 fd
= open(fname
, O_CREAT
| O_WRONLY
, S_IRUSR
| S_IWUSR
);
287 if (lseek(devfd
, (off_t
) offset
, SEEK_SET
) == (off_t
) -1) {
288 fdisk_warn(sf
->cxt
, _("cannot seek %s"), devname
);
291 unsigned char *buf
= xmalloc(size
);
293 if (read_all(devfd
, (char *) buf
, size
) != (ssize_t
) size
) {
294 fdisk_warn(sf
->cxt
, _("cannot read %s"), devname
);
297 if (write_all(fd
, buf
, size
) != 0) {
298 fdisk_warn(sf
->cxt
, _("cannot write %s"), fname
);
304 fdisk_info(sf
->cxt
, _("%12s (offset %5ju, size %5ju): %s"),
305 name
, (uintmax_t) offset
, (uintmax_t) size
, fname
);
310 errx(EXIT_FAILURE
, _("%s: failed to create a backup"), devname
);
313 static char *mk_backup_filename_tpl(const char *filename
, const char *devname
, const char *suffix
)
316 char *name
, *buf
= xstrdup(devname
);
318 name
= basename(buf
);
321 const char *home
= getenv ("HOME");
323 errx(EXIT_FAILURE
, _("failed to create a backup file, $HOME undefined"));
324 xasprintf(&tpl
, "%s/sfdisk-%s%s", home
, name
, suffix
);
326 xasprintf(&tpl
, "%s-%s%s", filename
, name
, suffix
);
333 static void backup_partition_table(struct sfdisk
*sf
, const char *devname
)
343 if (!fdisk_has_label(sf
->cxt
))
346 tpl
= mk_backup_filename_tpl(sf
->backup_file
, devname
, "-");
348 color_scheme_enable("header", UL_COLOR_BOLD
);
349 fdisk_info(sf
->cxt
, _("Backup files:"));
352 while (fdisk_locate_disklabel(sf
->cxt
, i
++, &name
, &offset
, &size
) == 0 && size
)
353 backup_sectors(sf
, tpl
, name
, devname
, offset
, size
);
360 static int move_partition_data(struct sfdisk
*sf
, size_t partno
, struct fdisk_partition
*orig_pa
)
362 struct fdisk_partition
*pa
= get_partition(sf
->cxt
, partno
);
363 char *devname
, *typescript
;
365 int ok
= 0, fd
, backward
= 0;
366 fdisk_sector_t nsectors
, from
, to
, step
, i
;
367 size_t ss
, step_bytes
, cc
;
371 assert(sf
->movedata
);
374 warnx(_("failed to read new partition from device (ignore --move-data)"));
375 else if (!fdisk_partition_has_size(pa
))
376 warnx(_("failed to get size of the new partition (ignore --move-data)"));
377 else if (!fdisk_partition_has_start(pa
))
378 warnx(_("failed to get start of the new partition (ignore --move-data)"));
379 else if (!fdisk_partition_has_size(orig_pa
))
380 warnx(_("failed to get size of the old partition (ignore --move-data)"));
381 else if (!fdisk_partition_has_start(orig_pa
))
382 warnx(_("failed to get start of the old partition (ignore --move-data)"));
383 else if (fdisk_partition_get_start(pa
) == fdisk_partition_get_start(orig_pa
))
384 warnx(_("begin of the partition has not been moved (ignore --move-data)"));
385 else if (fdisk_partition_get_size(orig_pa
) < fdisk_partition_get_size(pa
))
386 warnx(_("new partition is smaller than original (ignore --move-data)"));
392 DBG(MISC
, ul_debug("moving data"));
394 fd
= fdisk_get_devfd(sf
->cxt
);
396 ss
= fdisk_get_sector_size(sf
->cxt
);
397 nsectors
= fdisk_partition_get_size(orig_pa
);
398 from
= fdisk_partition_get_start(orig_pa
);
399 to
= fdisk_partition_get_start(pa
);
401 if ((to
>= from
&& from
+ nsectors
>= to
) ||
402 (from
>= to
&& to
+ nsectors
>= from
)) {
403 /* source and target overlay, check if we need to copy
404 * backwardly from end of the source */
405 DBG(MISC
, ul_debug("overlay between source and target"));
406 backward
= from
< to
;
407 DBG(MISC
, ul_debug(" copy order: %s", backward
? "backward" : "forward"));
409 step
= from
> to
? from
- to
: to
- from
;
415 /* make step usable for malloc() */
416 if (step
* ss
> (getpagesize() * 256U))
417 step
= (getpagesize() * 256) / ss
;
419 /* align the step (note that nsectors does not have to be power of 2) */
420 while (nsectors
% step
)
423 step_bytes
= step
* ss
;
424 DBG(MISC
, ul_debug(" step: %ju (%ju bytes)", step
, step_bytes
));
426 #if defined(POSIX_FADV_SEQUENTIAL) && defined(HAVE_POSIX_FADVISE)
428 posix_fadvise(fd
, from
* ss
, nsectors
* ss
, POSIX_FADV_SEQUENTIAL
);
430 devname
= fdisk_partname(fdisk_get_devname(sf
->cxt
), partno
+1);
431 typescript
= mk_backup_filename_tpl(sf
->move_typescript
, devname
, ".move");
434 fdisk_info(sf
->cxt
,"");
435 color_scheme_enable("header", UL_COLOR_BOLD
);
436 fdisk_info(sf
->cxt
, _("Data move:"));
438 fdisk_info(sf
->cxt
, _(" typescript file: %s"), typescript
);
439 printf(_(" old start: %ju, new start: %ju (move %ju sectors)\n"),
440 (uintmax_t) from
, (uintmax_t) to
, nsectors
);
444 if (sf
->interactive
) {
446 fdisk_ask_yesno(sf
->cxt
, _("Do you want to move partition data?"), &yes
);
448 fdisk_info(sf
->cxt
, _("Leaving."));
453 f
= fopen(typescript
, "w");
457 /* don't translate */
458 fprintf(f
, "# sfdisk: " PACKAGE_STRING
"\n");
459 fprintf(f
, "# Disk: %s\n", devname
);
460 fprintf(f
, "# Partition: %zu\n", partno
+ 1);
461 fprintf(f
, "# Operation: move data\n");
462 fprintf(f
, "# Original start offset (sectors/bytes): %ju/%ju\n", from
, from
* ss
);
463 fprintf(f
, "# New start offset (sectors/bytes): %ju/%ju\n", to
, to
* ss
);
464 fprintf(f
, "# Area size (sectors/bytes): %ju/%ju\n", nsectors
, nsectors
* ss
);
465 fprintf(f
, "# Sector size: %zu\n", ss
);
466 fprintf(f
, "# Step size (in bytes): %zu\n", step_bytes
);
467 fprintf(f
, "# Steps: %zu\n", nsectors
/ step
);
469 fprintf(f
, "# <step>: <from> <to> (step offsets in bytes)\n");
471 src
= (backward
? from
+ nsectors
: from
) * ss
;
472 dst
= (backward
? to
+ nsectors
: to
) * ss
;
473 buf
= xmalloc(step_bytes
);
475 DBG(MISC
, ul_debug(" initial: src=%ju dst=%ju", src
, dst
));
477 for (cc
= 1, i
= 0; i
< nsectors
; i
+= step
, cc
++) {
481 src
-= step_bytes
, dst
-= step_bytes
;
483 DBG(MISC
, ul_debug("#%05zu: src=%ju dst=%ju", cc
, src
, dst
));
486 if (lseek(fd
, src
, SEEK_SET
) == (off_t
) -1)
488 rc
= read(fd
, buf
, step_bytes
);
489 if (rc
< 0 || rc
!= (ssize_t
) step_bytes
)
493 if (lseek(fd
, dst
, SEEK_SET
) == (off_t
) -1)
495 rc
= write(fd
, buf
, step_bytes
);
496 if (rc
< 0 || rc
!= (ssize_t
) step_bytes
)
501 fprintf(f
, "%05zu: %12ju %12ju\n", cc
, src
, dst
);
503 #if defined(POSIX_FADV_DONTNEED) && defined(HAVE_POSIX_FADVISE)
504 posix_fadvise(fd
, src
, step_bytes
, POSIX_FADV_DONTNEED
);
507 src
+= step_bytes
, dst
+= step_bytes
;
516 warn(_("%s: failed to move data"), devname
);
521 static int write_changes(struct sfdisk
*sf
)
526 fdisk_info(sf
->cxt
, _("The partition table is unchanged (--no-act)."));
528 rc
= fdisk_write_disklabel(sf
->cxt
);
529 if (rc
== 0 && sf
->movedata
&& sf
->orig_pa
)
530 rc
= move_partition_data(sf
, sf
->partno
, sf
->orig_pa
);
532 fdisk_info(sf
->cxt
, _("\nThe partition table has been altered."));
533 fdisk_reread_partition_table(sf
->cxt
);
537 rc
= fdisk_deassign_device(sf
->cxt
, sf
->noact
); /* no-sync when no-act */
542 * sfdisk --list [<device ..]
544 static int command_list_partitions(struct sfdisk
*sf
, int argc
, char **argv
)
546 fdisk_enable_listonly(sf
->cxt
, 1);
551 for (i
= 0; i
< argc
; i
++) {
553 fputs("\n\n", stdout
);
554 if (print_device_pt(sf
->cxt
, argv
[i
], 0, sf
->verify
) == 0)
558 print_all_devices_pt(sf
->cxt
, sf
->verify
);
564 * sfdisk --list-free [<device ..]
566 static int command_list_freespace(struct sfdisk
*sf
, int argc
, char **argv
)
568 fdisk_enable_listonly(sf
->cxt
, 1);
573 for (i
= 0; i
< argc
; i
++) {
575 fputs("\n\n", stdout
);
576 if (print_device_freespace(sf
->cxt
, argv
[i
], 0) == 0)
580 print_all_devices_freespace(sf
->cxt
);
586 * sfdisk --list-types
588 static int command_list_types(struct sfdisk
*sf
)
590 const struct fdisk_parttype
*t
;
591 struct fdisk_label
*lb
;
599 name
= sf
->label
? sf
->label
: "dos";
600 lb
= fdisk_get_label(sf
->cxt
, name
);
602 errx(EXIT_FAILURE
, _("unsupported label '%s'"), name
);
604 codes
= fdisk_label_has_code_parttypes(lb
);
605 fputs(_("Id Name\n\n"), stdout
);
607 while ((t
= fdisk_label_get_parttype(lb
, i
++))) {
609 printf("%2x %s\n", fdisk_parttype_get_code(t
),
610 fdisk_parttype_get_name(t
));
612 printf("%s %s\n", fdisk_parttype_get_string(t
),
613 fdisk_parttype_get_name(t
));
619 static int verify_device(struct sfdisk
*sf
, const char *devname
)
623 fdisk_enable_listonly(sf
->cxt
, 1);
625 if (fdisk_assign_device(sf
->cxt
, devname
, 1)) {
626 warn(_("cannot open %s"), devname
);
630 color_scheme_enable("header", UL_COLOR_BOLD
);
631 fdisk_info(sf
->cxt
, "%s:", devname
);
634 if (!fdisk_has_label(sf
->cxt
))
635 fdisk_info(sf
->cxt
, _("unrecognized partition table type"));
637 rc
= fdisk_verify_disklabel(sf
->cxt
);
639 fdisk_deassign_device(sf
->cxt
, 1);
644 * sfdisk --verify [<device ..]
646 static int command_verify(struct sfdisk
*sf
, int argc
, char **argv
)
648 int nfails
= 0, ct
= 0;
652 for (i
= 0; i
< argc
; i
++) {
654 fdisk_info(sf
->cxt
, " ");
655 if (verify_device(sf
, argv
[i
]) < 0)
662 while ((dev
= next_proc_partition(&f
))) {
664 fdisk_info(sf
->cxt
, " ");
665 if (verify_device(sf
, dev
) < 0)
675 static int get_size(const char *dev
, int silent
, uintmax_t *sz
)
679 fd
= open(dev
, O_RDONLY
);
682 warn(_("cannot open %s"), dev
);
686 if (blkdev_get_sectors(fd
, (unsigned long long *) sz
) == -1) {
688 warn(_("Cannot get size of %s"), dev
);
697 * sfdisk --show-size [<device ..]
699 * (silly, but just for backward compatibility)
701 static int command_show_size(struct sfdisk
*sf
__attribute__((__unused__
)),
702 int argc
, char **argv
)
708 for (i
= 0; i
< argc
; i
++) {
709 if (get_size(argv
[i
], 0, &sz
) == 0)
710 printf("%ju\n", sz
/ 2);
717 while ((dev
= next_proc_partition(&f
))) {
718 if (get_size(dev
, 1, &sz
) == 0) {
719 printf("%s: %9ju\n", dev
, sz
/ 2);
725 printf(_("total: %ju blocks\n"), total
);
731 static int print_geom(struct sfdisk
*sf
, const char *devname
)
733 fdisk_enable_listonly(sf
->cxt
, 1);
735 if (fdisk_assign_device(sf
->cxt
, devname
, 1)) {
736 warn(_("cannot open %s"), devname
);
740 fdisk_info(sf
->cxt
, "%s: %ju cylinders, %ju heads, %ju sectors/track",
742 (uintmax_t) fdisk_get_geom_cylinders(sf
->cxt
),
743 (uintmax_t) fdisk_get_geom_heads(sf
->cxt
),
744 (uintmax_t) fdisk_get_geom_sectors(sf
->cxt
));
746 fdisk_deassign_device(sf
->cxt
, 1);
751 * sfdisk --show-geometry [<device ..]
753 static int command_show_geometry(struct sfdisk
*sf
, int argc
, char **argv
)
759 for (i
= 0; i
< argc
; i
++) {
760 if (print_geom(sf
, argv
[i
]) < 0)
767 while ((dev
= next_proc_partition(&f
))) {
768 if (print_geom(sf
, dev
) < 0)
778 * sfdisk --activate <device> [<partno> ...]
780 static int command_activate(struct sfdisk
*sf
, int argc
, char **argv
)
782 int rc
, nparts
, i
, listonly
;
783 struct fdisk_partition
*pa
= NULL
;
784 const char *devname
= NULL
;
787 errx(EXIT_FAILURE
, _("no disk device specified"));
790 /* --activate <device> */
791 listonly
= argc
== 1;
793 rc
= fdisk_assign_device(sf
->cxt
, devname
, listonly
);
795 err(EXIT_FAILURE
, _("cannot open %s"), devname
);
797 if (!fdisk_is_label(sf
->cxt
, DOS
))
798 errx(EXIT_FAILURE
, _("toggle boot flags is supported for MBR only"));
800 if (!listonly
&& sf
->backup
)
801 backup_partition_table(sf
, devname
);
803 nparts
= fdisk_get_npartitions(sf
->cxt
);
804 for (i
= 0; i
< nparts
; i
++) {
807 /* note that fdisk_get_partition() reuses the @pa pointer, you
808 * don't have to (re)allocate it */
809 if (fdisk_get_partition(sf
->cxt
, i
, &pa
) != 0)
812 /* sfdisk --activate list bootable partitions */
814 if (!fdisk_partition_is_bootable(pa
))
816 if (fdisk_partition_to_string(pa
, sf
->cxt
,
817 FDISK_FIELD_DEVICE
, &data
) == 0) {
818 printf("%s\n", data
);
822 /* deactivate all active partitions */
823 } else if (fdisk_partition_is_bootable(pa
))
824 fdisk_toggle_partition_flag(sf
->cxt
, i
, DOS_FLAG_ACTIVE
);
827 /* sfdisk --activate <partno> [..] */
828 for (i
= 1; i
< argc
; i
++) {
829 int n
= strtou32_or_err(argv
[i
], _("failed to parse partition number"));
831 rc
= fdisk_toggle_partition_flag(sf
->cxt
, n
- 1, DOS_FLAG_ACTIVE
);
834 _("%s: partition %d: failed to toggle bootable flag"),
838 fdisk_unref_partition(pa
);
840 rc
= fdisk_deassign_device(sf
->cxt
, 1);
842 rc
= write_changes(sf
);
847 * sfdisk --delete <device> [<partno> ...]
849 static int command_delete(struct sfdisk
*sf
, int argc
, char **argv
)
852 const char *devname
= NULL
;
855 errx(EXIT_FAILURE
, _("no disk device specified"));
858 if (fdisk_assign_device(sf
->cxt
, devname
, 0) != 0)
859 err(EXIT_FAILURE
, _("cannot open %s"), devname
);
862 backup_partition_table(sf
, devname
);
866 size_t nparts
= fdisk_get_npartitions(sf
->cxt
);
867 for (i
= 0; i
< nparts
; i
++) {
868 if (fdisk_is_partition_used(sf
->cxt
, i
) &&
869 fdisk_delete_partition(sf
->cxt
, i
) != 0)
870 errx(EXIT_FAILURE
, _("%s: partition %zu: failed to delete"), devname
, i
+ 1);
872 /* delete specified */
874 for (i
= 1; i
< (size_t) argc
; i
++) {
875 size_t n
= strtou32_or_err(argv
[i
], _("failed to parse partition number"));
877 if (fdisk_delete_partition(sf
->cxt
, n
- 1) != 0)
878 errx(EXIT_FAILURE
, _("%s: partition %zu: failed to delete"), devname
, n
);
882 return write_changes(sf
);
886 * sfdisk --reorder <device>
888 static int command_reorder(struct sfdisk
*sf
, int argc
, char **argv
)
890 const char *devname
= NULL
;
896 errx(EXIT_FAILURE
, _("no disk device specified"));
898 rc
= fdisk_assign_device(sf
->cxt
, devname
, 0); /* read-write */
900 err(EXIT_FAILURE
, _("cannot open %s"), devname
);
903 backup_partition_table(sf
, devname
);
905 if (fdisk_reorder_partitions(sf
->cxt
) == 1) /* unchnaged */
906 rc
= fdisk_deassign_device(sf
->cxt
, 1);
908 rc
= write_changes(sf
);
915 * sfdisk --dump <device>
917 static int command_dump(struct sfdisk
*sf
, int argc
, char **argv
)
919 const char *devname
= NULL
;
920 struct fdisk_script
*dp
;
926 errx(EXIT_FAILURE
, _("no disk device specified"));
928 rc
= fdisk_assign_device(sf
->cxt
, devname
, 1); /* read-only */
930 err(EXIT_FAILURE
, _("cannot open %s"), devname
);
932 dp
= fdisk_new_script(sf
->cxt
);
934 err(EXIT_FAILURE
, _("failed to allocate dump struct"));
936 rc
= fdisk_script_read_context(dp
, NULL
);
938 err(EXIT_FAILURE
, _("failed to dump partition table"));
941 fdisk_script_enable_json(dp
, 1);
942 fdisk_script_write_file(dp
, stdout
);
944 fdisk_unref_script(dp
);
945 fdisk_deassign_device(sf
->cxt
, 1); /* no-sync() */
949 static void assign_device_partition(struct sfdisk
*sf
,
956 struct fdisk_label
*lb
= NULL
;
961 /* read-only when a new <type> undefined */
962 rc
= fdisk_assign_device(sf
->cxt
, devname
, rdonly
);
964 err(EXIT_FAILURE
, _("cannot open %s"), devname
);
966 lb
= fdisk_get_label(sf
->cxt
, NULL
);
968 errx(EXIT_FAILURE
, _("%s: no partition table found"), devname
);
970 n
= fdisk_get_npartitions(sf
->cxt
);
972 errx(EXIT_FAILURE
, _("%s: partition %zu: partition table contains "
973 "only %zu partitions"), devname
, partno
, n
);
974 if (!fdisk_is_partition_used(sf
->cxt
, partno
- 1))
975 errx(EXIT_FAILURE
, _("%s: partition %zu: partition is unused"),
980 * sfdisk --part-type <device> <partno> [<type>]
982 static int command_parttype(struct sfdisk
*sf
, int argc
, char **argv
)
985 struct fdisk_parttype
*type
= NULL
;
986 struct fdisk_label
*lb
;
987 const char *devname
= NULL
, *typestr
= NULL
;
990 errx(EXIT_FAILURE
, _("no disk device specified"));
994 errx(EXIT_FAILURE
, _("no partition number specified"));
995 partno
= strtou32_or_err(argv
[1], _("failed to parse partition number"));
1000 errx(EXIT_FAILURE
, _("unexpected arguments"));
1002 /* read-only when a new <type> undefined */
1003 assign_device_partition(sf
, devname
, partno
, !typestr
);
1005 lb
= fdisk_get_label(sf
->cxt
, NULL
);
1007 /* print partition type */
1009 const struct fdisk_parttype
*t
= NULL
;
1010 struct fdisk_partition
*pa
= NULL
;
1012 if (fdisk_get_partition(sf
->cxt
, partno
- 1, &pa
) == 0)
1013 t
= fdisk_partition_get_type(pa
);
1015 errx(EXIT_FAILURE
, _("%s: partition %zu: failed to get partition type"),
1018 if (fdisk_label_has_code_parttypes(lb
))
1019 printf("%2x\n", fdisk_parttype_get_code(t
));
1021 printf("%s\n", fdisk_parttype_get_string(t
));
1023 fdisk_unref_partition(pa
);
1024 fdisk_deassign_device(sf
->cxt
, 1);
1029 backup_partition_table(sf
, devname
);
1031 /* parse <type> and apply to PT */
1032 type
= fdisk_label_parse_parttype(lb
, typestr
);
1034 errx(EXIT_FAILURE
, _("failed to parse %s partition type '%s'"),
1035 fdisk_label_get_name(lb
), typestr
);
1037 else if (fdisk_set_partition_type(sf
->cxt
, partno
- 1, type
) != 0)
1038 errx(EXIT_FAILURE
, _("%s: partition %zu: failed to set partition type"),
1040 fdisk_unref_parttype(type
);
1041 return write_changes(sf
);
1045 * sfdisk --part-uuid <device> <partno> [<uuid>]
1047 static int command_partuuid(struct sfdisk
*sf
, int argc
, char **argv
)
1050 struct fdisk_partition
*pa
= NULL
;
1051 const char *devname
= NULL
, *uuid
= NULL
;
1054 errx(EXIT_FAILURE
, _("no disk device specified"));
1058 errx(EXIT_FAILURE
, _("no partition number specified"));
1059 partno
= strtou32_or_err(argv
[1], _("failed to parse partition number"));
1064 errx(EXIT_FAILURE
, _("unexpected arguments"));
1066 /* read-only if uuid not given */
1067 assign_device_partition(sf
, devname
, partno
, !uuid
);
1069 /* print partition uuid */
1071 const char *str
= NULL
;
1073 if (fdisk_get_partition(sf
->cxt
, partno
- 1, &pa
) == 0)
1074 str
= fdisk_partition_get_uuid(pa
);
1076 errx(EXIT_FAILURE
, _("%s: partition %zu: failed to get partition UUID"),
1078 printf("%s\n", str
);
1079 fdisk_unref_partition(pa
);
1080 fdisk_deassign_device(sf
->cxt
, 1);
1085 backup_partition_table(sf
, devname
);
1087 pa
= fdisk_new_partition();
1089 err(EXIT_FAILURE
, _("failed to allocate partition object"));
1091 if (fdisk_partition_set_uuid(pa
, uuid
) != 0 ||
1092 fdisk_set_partition(sf
->cxt
, partno
- 1, pa
) != 0)
1093 errx(EXIT_FAILURE
, _("%s: partition %zu: failed to set partition UUID"),
1095 fdisk_unref_partition(pa
);
1096 return write_changes(sf
);
1100 * sfdisk --part-label <device> <partno> [<label>]
1102 static int command_partlabel(struct sfdisk
*sf
, int argc
, char **argv
)
1105 struct fdisk_partition
*pa
= NULL
;
1106 const char *devname
= NULL
, *name
= NULL
;
1109 errx(EXIT_FAILURE
, _("no disk device specified"));
1113 errx(EXIT_FAILURE
, _("no partition number specified"));
1114 partno
= strtou32_or_err(argv
[1], _("failed to parse partition number"));
1119 errx(EXIT_FAILURE
, _("unexpected arguments"));
1121 /* read-only if name not given */
1122 assign_device_partition(sf
, devname
, partno
, !name
);
1124 /* print partition name */
1126 const char *str
= NULL
;
1128 if (fdisk_get_partition(sf
->cxt
, partno
- 1, &pa
) == 0)
1129 str
= fdisk_partition_get_name(pa
);
1131 errx(EXIT_FAILURE
, _("%s: partition %zu: failed to get partition name"),
1133 printf("%s\n", str
);
1134 fdisk_unref_partition(pa
);
1135 fdisk_deassign_device(sf
->cxt
, 1);
1140 backup_partition_table(sf
, devname
);
1142 pa
= fdisk_new_partition();
1144 err(EXIT_FAILURE
, _("failed to allocate partition object"));
1146 if (fdisk_partition_set_name(pa
, name
) != 0 ||
1147 fdisk_set_partition(sf
->cxt
, partno
- 1, pa
) != 0)
1148 errx(EXIT_FAILURE
, _("%s: partition %zu: failed to set partition name"),
1151 fdisk_unref_partition(pa
);
1152 return write_changes(sf
);
1156 * sfdisk --part-attrs <device> <partno> [<attrs>]
1158 static int command_partattrs(struct sfdisk
*sf
, int argc
, char **argv
)
1161 struct fdisk_partition
*pa
= NULL
;
1162 const char *devname
= NULL
, *attrs
= NULL
;
1165 errx(EXIT_FAILURE
, _("no disk device specified"));
1169 errx(EXIT_FAILURE
, _("no partition number specified"));
1170 partno
= strtou32_or_err(argv
[1], _("failed to parse partition number"));
1175 errx(EXIT_FAILURE
, _("unexpected arguments"));
1177 /* read-only if name not given */
1178 assign_device_partition(sf
, devname
, partno
, !attrs
);
1180 /* print partition name */
1182 const char *str
= NULL
;
1184 if (fdisk_get_partition(sf
->cxt
, partno
- 1, &pa
) == 0)
1185 str
= fdisk_partition_get_attrs(pa
);
1187 printf("%s\n", str
);
1188 fdisk_unref_partition(pa
);
1189 fdisk_deassign_device(sf
->cxt
, 1);
1194 backup_partition_table(sf
, devname
);
1196 pa
= fdisk_new_partition();
1198 err(EXIT_FAILURE
, _("failed to allocate partition object"));
1200 if (fdisk_partition_set_attrs(pa
, attrs
) != 0 ||
1201 fdisk_set_partition(sf
->cxt
, partno
- 1, pa
) != 0)
1202 errx(EXIT_FAILURE
, _("%s: partition %zu: failed to set partition attributes"),
1205 fdisk_unref_partition(pa
);
1206 return write_changes(sf
);
1209 static void sfdisk_print_partition(struct sfdisk
*sf
, size_t n
)
1211 struct fdisk_partition
*pa
= NULL
;
1218 if (fdisk_get_partition(sf
->cxt
, n
, &pa
) != 0)
1221 fdisk_partition_to_string(pa
, sf
->cxt
, FDISK_FIELD_DEVICE
, &data
);
1222 printf("%12s : ", data
);
1224 fdisk_partition_to_string(pa
, sf
->cxt
, FDISK_FIELD_START
, &data
);
1225 printf("%12s ", data
);
1227 fdisk_partition_to_string(pa
, sf
->cxt
, FDISK_FIELD_END
, &data
);
1228 printf("%12s ", data
);
1230 fdisk_partition_to_string(pa
, sf
->cxt
, FDISK_FIELD_SIZE
, &data
);
1231 printf("(%s) ", data
);
1233 fdisk_partition_to_string(pa
, sf
->cxt
, FDISK_FIELD_TYPE
, &data
);
1234 printf("%s\n", data
);
1236 fdisk_unref_partition(pa
);
1239 static void command_fdisk_help(void)
1241 fputs(_("\nHelp:\n"), stdout
);
1243 fputc('\n', stdout
);
1244 color_scheme_enable("help-title", UL_COLOR_BOLD
);
1245 fputs(_(" Commands:\n"), stdout
);
1247 fputs(_(" write write table to disk and exit\n"), stdout
);
1248 fputs(_(" quit show new situation and wait for user's feedback before write\n"), stdout
);
1249 fputs(_(" abort exit sfdisk shell\n"), stdout
);
1250 fputs(_(" print display the partition table\n"), stdout
);
1251 fputs(_(" help show this help text\n"), stdout
);
1252 fputc('\n', stdout
);
1253 fputs(_(" Ctrl-D the same as 'quit'\n"), stdout
);
1255 fputc('\n', stdout
);
1256 color_scheme_enable("help-title", UL_COLOR_BOLD
);
1257 fputs(_(" Input format:\n"), stdout
);
1259 fputs(_(" <start>, <size>, <type>, <bootable>\n"), stdout
);
1261 fputc('\n', stdout
);
1262 fputs(_(" <start> Beginning of the partition in sectors, or bytes if\n"
1263 " specified in the format <number>{K,M,G,T,P,E,Z,Y}.\n"
1264 " The default is the first free space.\n"), stdout
);
1266 fputc('\n', stdout
);
1267 fputs(_(" <size> Size of the partition in sectors, or bytes if\n"
1268 " specified in the format <number>{K,M,G,T,P,E,Z,Y}.\n"
1269 " The default is all available space.\n"), stdout
);
1271 fputc('\n', stdout
);
1272 fputs(_(" <type> The partition type. Default is a Linux data partition.\n"), stdout
);
1273 fputs(_(" MBR: hex or L,S,E,X shortcuts.\n"), stdout
);
1274 fputs(_(" GPT: UUID or L,S,H shortcuts.\n"), stdout
);
1276 fputc('\n', stdout
);
1277 fputs(_(" <bootable> Use '*' to mark an MBR partition as bootable.\n"), stdout
);
1279 fputc('\n', stdout
);
1280 color_scheme_enable("help-title", UL_COLOR_BOLD
);
1281 fputs(_(" Example:\n"), stdout
);
1283 fputs(_(" , 4G Creates a 4GiB partition at default start offset.\n"), stdout
);
1284 fputc('\n', stdout
);
1288 SFDISK_DONE_NONE
= 0,
1295 /* returns: 0 on success, <0 on error, 1 successfully stop sfdisk */
1296 static int loop_control_commands(struct sfdisk
*sf
,
1297 struct fdisk_script
*dp
,
1300 const char *p
= skip_blank(buf
);
1301 int rc
= SFDISK_DONE_NONE
;
1303 if (strcmp(p
, "print") == 0)
1304 list_disklabel(sf
->cxt
);
1305 else if (strcmp(p
, "help") == 0)
1306 command_fdisk_help();
1307 else if (strcmp(p
, "quit") == 0)
1308 rc
= SFDISK_DONE_ASK
;
1309 else if (strcmp(p
, "write") == 0)
1310 rc
= SFDISK_DONE_WRITE
;
1311 else if (strcmp(p
, "abort") == 0)
1312 rc
= SFDISK_DONE_ABORT
;
1314 if (sf
->interactive
)
1315 fdisk_warnx(sf
->cxt
, _("unsupported command"));
1317 fdisk_warnx(sf
->cxt
, _("line %d: unsupported command"),
1318 fdisk_script_get_nlines(dp
));
1325 static int has_container(struct sfdisk
*sf
)
1328 struct fdisk_partition
*pa
= NULL
;
1331 return sf
->container
;
1333 nparts
= fdisk_get_npartitions(sf
->cxt
);
1334 for (i
= 0; i
< nparts
; i
++) {
1335 if (fdisk_get_partition(sf
->cxt
, i
, &pa
) != 0)
1337 if (fdisk_partition_is_container(pa
)) {
1343 fdisk_unref_partition(pa
);
1344 return sf
->container
;
1347 static size_t last_pt_partno(struct sfdisk
*sf
)
1349 size_t i
, nparts
, partno
= 0;
1350 struct fdisk_partition
*pa
= NULL
;
1353 nparts
= fdisk_get_npartitions(sf
->cxt
);
1354 for (i
= 0; i
< nparts
; i
++) {
1357 if (fdisk_get_partition(sf
->cxt
, i
, &pa
) != 0 ||
1358 !fdisk_partition_is_used(pa
))
1360 x
= fdisk_partition_get_partno(pa
);
1365 fdisk_unref_partition(pa
);
1369 static int is_device_used(struct sfdisk
*sf
)
1378 fd
= fdisk_get_devfd(sf
->cxt
);
1382 if (fstat(fd
, &st
) == 0 && S_ISBLK(st
.st_mode
)
1383 && major(st
.st_rdev
) != LOOPDEV_MAJOR
)
1384 return ioctl(fd
, BLKRRPART
) != 0;
1389 #ifdef HAVE_LIBREADLINE
1390 static char *sfdisk_fgets(struct fdisk_script
*dp
,
1391 char *buf
, size_t bufsz
, FILE *f
)
1393 struct sfdisk
*sf
= (struct sfdisk
*) fdisk_script_get_userdata(dp
);
1399 if (sf
->interactive
) {
1400 char *p
= readline(sf
->prompt
);
1406 if (len
> bufsz
- 2)
1409 memcpy(buf
, p
, len
);
1410 buf
[len
] = '\n'; /* append \n to be compatible with libc fgetc() */
1411 buf
[len
+ 1] = '\0';
1416 return fgets(buf
, bufsz
, f
);
1420 static int ignore_partition(struct fdisk_partition
*pa
)
1422 /* incomplete partition setting */
1423 if (!fdisk_partition_has_start(pa
) && !fdisk_partition_start_is_default(pa
))
1425 if (!fdisk_partition_has_size(pa
) && !fdisk_partition_end_is_default(pa
))
1428 /* probably dump from old sfdisk with start=0 size=0 */
1429 if (fdisk_partition_has_start(pa
) && fdisk_partition_get_start(pa
) == 0 &&
1430 fdisk_partition_has_size(pa
) && fdisk_partition_get_size(pa
) == 0)
1439 * sfdisk <device> [[-N] <partno>]
1441 * Note that the option -N is there for backward compatibility only.
1443 static int command_fdisk(struct sfdisk
*sf
, int argc
, char **argv
)
1445 int rc
= 0, partno
= sf
->partno
, created
= 0;
1446 struct fdisk_script
*dp
;
1447 struct fdisk_table
*tb
= NULL
;
1448 const char *devname
= NULL
, *label
;
1450 size_t next_partno
= (size_t) -1;
1454 if (partno
< 0 && argc
> 1)
1455 partno
= strtou32_or_err(argv
[1],
1456 _("failed to parse partition number"));
1458 errx(EXIT_FAILURE
, _("no disk device specified"));
1460 rc
= fdisk_assign_device(sf
->cxt
, devname
, 0);
1462 err(EXIT_FAILURE
, _("cannot open %s"), devname
);
1464 dp
= fdisk_new_script(sf
->cxt
);
1466 err(EXIT_FAILURE
, _("failed to allocate script handler"));
1467 fdisk_set_script(sf
->cxt
, dp
);
1468 #ifdef HAVE_LIBREADLINE
1469 fdisk_script_set_fgets(dp
, sfdisk_fgets
);
1471 fdisk_script_set_userdata(dp
, (void *) sf
);
1474 * Don't create a new disklabel when [-N] <partno> specified. In this
1475 * case reuse already specified disklabel. Let's check that the disk
1476 * really contains the partition.
1481 if (!fdisk_has_label(sf
->cxt
))
1482 errx(EXIT_FAILURE
, _("%s: cannot modify partition %d: "
1483 "no partition table was found"),
1484 devname
, partno
+ 1);
1485 n
= fdisk_get_npartitions(sf
->cxt
);
1486 if ((size_t) partno
> n
)
1487 errx(EXIT_FAILURE
, _("%s: cannot modify partition %d: "
1488 "partition table contains only %zu "
1490 devname
, partno
+ 1, n
);
1492 if (!fdisk_is_partition_used(sf
->cxt
, partno
))
1493 fdisk_warnx(sf
->cxt
, _("warning: %s: partition %d is not defined yet"),
1494 devname
, partno
+ 1);
1496 next_partno
= partno
;
1499 sf
->orig_pa
= get_partition(sf
->cxt
, partno
);
1504 next_partno
= last_pt_partno(sf
) + 1;
1507 if (!sf
->quiet
&& sf
->interactive
) {
1508 color_scheme_enable("welcome", UL_COLOR_GREEN
);
1509 fdisk_info(sf
->cxt
, _("\nWelcome to sfdisk (%s)."), PACKAGE_STRING
);
1511 fdisk_info(sf
->cxt
, _("Changes will remain in memory only, until you decide to write them.\n"
1512 "Be careful before using the write command.\n"));
1515 if (!sf
->noact
&& !sf
->noreread
) {
1517 fputs(_("Checking that no-one is using this disk right now ..."), stdout
);
1518 if (is_device_used(sf
)) {
1520 fputs(_(" FAILED\n\n"), stdout
);
1522 fdisk_warnx(sf
->cxt
, _(
1523 "This disk is currently in use - repartitioning is probably a bad idea.\n"
1524 "Umount all file systems, and swapoff all swap partitions on this disk.\n"
1525 "Use the --no-reread flag to suppress this check.\n"));
1528 errx(EXIT_FAILURE
, _("Use the --force flag to overrule all checks."));
1529 } else if (!sf
->quiet
)
1530 fputs(_(" OK\n\n"), stdout
);
1533 if (fdisk_get_collision(sf
->cxt
)) {
1534 int dowipe
= sf
->wipemode
== WIPEMODE_ALWAYS
? 1 : 0;
1536 fdisk_warnx(sf
->cxt
, _("%s: device already contains %s signature."),
1537 devname
, fdisk_get_collision(sf
->cxt
));
1539 if (sf
->interactive
&& sf
->wipemode
== WIPEMODE_AUTO
)
1540 dowipe
= 1; /* do it in interactive mode */
1542 fdisk_enable_wipe(sf
->cxt
, dowipe
);
1544 fdisk_warnx(sf
->cxt
, _(
1545 "The signature will be removed by write command."));
1547 fdisk_warnx(sf
->cxt
, _(
1548 "It is strongly recommended to wipe the device with "
1549 "wipefs(8), in order to avoid possible collisions."));
1550 fputc('\n', stderr
);
1554 backup_partition_table(sf
, devname
);
1557 list_disk_geometry(sf
->cxt
);
1558 if (fdisk_has_label(sf
->cxt
)) {
1559 fdisk_info(sf
->cxt
, _("\nOld situation:"));
1560 list_disklabel(sf
->cxt
);
1566 else if (fdisk_has_label(sf
->cxt
))
1567 label
= fdisk_label_get_name(fdisk_get_label(sf
->cxt
, NULL
));
1569 label
= "dos"; /* just for backward compatibility */
1571 fdisk_script_set_header(dp
, "label", label
);
1574 if (!sf
->quiet
&& sf
->interactive
) {
1575 if (!fdisk_has_label(sf
->cxt
) && !sf
->label
)
1577 _("\nsfdisk is going to create a new '%s' disk label.\n"
1578 "Use 'label: <name>' before you define a first partition\n"
1579 "to override the default."), label
);
1580 fdisk_info(sf
->cxt
, _("\nType 'help' to get more information.\n"));
1581 } else if (!sf
->quiet
)
1582 fputc('\n', stdout
);
1584 tb
= fdisk_script_get_table(dp
);
1590 DBG(PARSE
, ul_debug("<---next-line--->"));
1591 if (next_partno
== (size_t) -1)
1592 next_partno
= fdisk_table_get_nents(tb
);
1596 && next_partno
== fdisk_get_npartitions(sf
->cxt
)
1597 && !has_container(sf
)) {
1598 fdisk_info(sf
->cxt
, _("All partitions used."));
1599 rc
= SFDISK_DONE_ASK
;
1604 char *partname
= fdisk_partname(devname
, next_partno
+ 1);
1606 err(EXIT_FAILURE
, _("failed to allocate partition name"));
1607 if (!sf
->prompt
|| !startswith(sf
->prompt
, partname
)) {
1609 xasprintf(&sf
->prompt
,"%s: ", partname
);
1612 } else if (!sf
->prompt
|| !startswith(sf
->prompt
, SFDISK_PROMPT
)) {
1614 sf
->prompt
= xstrdup(SFDISK_PROMPT
);
1617 if (sf
->prompt
&& (sf
->interactive
|| !sf
->quiet
)) {
1618 #ifndef HAVE_LIBREADLINE
1619 fputs(sf
->prompt
, stdout
);
1621 if (!sf
->interactive
)
1622 fputs(sf
->prompt
, stdout
);
1626 rc
= fdisk_script_read_line(dp
, stdin
, buf
, sizeof(buf
));
1628 DBG(PARSE
, ul_debug("script parsing failed, trying sfdisk specific commands"));
1629 buf
[sizeof(buf
) - 1] = '\0';
1630 rc
= loop_control_commands(sf
, dp
, buf
);
1634 } else if (rc
== 1) {
1635 rc
= SFDISK_DONE_EOF
;
1639 nparts
= fdisk_table_get_nents(tb
);
1642 struct fdisk_partition
*pa
= fdisk_table_get_partition(tb
, nparts
- 1);
1646 if (ignore_partition(pa
)) {
1647 fdisk_info(sf
->cxt
, _("Ignoring partition."));
1651 if (!created
) { /* create a new disklabel */
1652 rc
= fdisk_apply_script_headers(sf
->cxt
, dp
);
1655 fdisk_warnx(sf
->cxt
, _(
1656 "Failed to apply script headers, "
1657 "disk label not created."));
1659 if (!rc
&& partno
>= 0) { /* -N <partno>, modify partition */
1660 rc
= fdisk_set_partition(sf
->cxt
, partno
, pa
);
1661 rc
= rc
== 0 ? SFDISK_DONE_ASK
: SFDISK_DONE_ABORT
;
1663 } else if (!rc
) { /* add partition */
1664 rc
= fdisk_add_partition(sf
->cxt
, pa
, &cur_partno
);
1667 fdisk_warn(sf
->cxt
, _("Failed to add partition"));
1671 if (!rc
) { /* success, print reult */
1672 if (sf
->interactive
)
1673 sfdisk_print_partition(sf
, cur_partno
);
1674 next_partno
= cur_partno
+ 1;
1675 } else if (pa
) /* error, drop partition from script */
1676 fdisk_table_remove_partition(tb
, pa
);
1678 fdisk_info(sf
->cxt
, _("Script header accepted."));
1680 if (rc
&& !sf
->interactive
) {
1681 rc
= SFDISK_DONE_ABORT
;
1686 if (!sf
->quiet
&& rc
!= SFDISK_DONE_ABORT
) {
1687 fdisk_info(sf
->cxt
, _("\nNew situation:"));
1688 list_disklabel(sf
->cxt
);
1692 case SFDISK_DONE_ASK
:
1693 case SFDISK_DONE_EOF
:
1694 if (sf
->interactive
) {
1696 fdisk_ask_yesno(sf
->cxt
, _("Do you want to write this to disk?"), &yes
);
1698 fdisk_info(sf
->cxt
, _("Leaving."));
1703 case SFDISK_DONE_WRITE
:
1704 rc
= write_changes(sf
);
1706 case SFDISK_DONE_ABORT
:
1707 default: /* rc < 0 on error */
1708 fdisk_info(sf
->cxt
, _("Leaving.\n"));
1712 fdisk_unref_script(dp
);
1716 static void __attribute__ ((__noreturn__
)) usage(FILE *out
)
1718 fputs(USAGE_HEADER
, out
);
1721 _(" %1$s [options] <dev> [[-N] <part>]\n"
1722 " %1$s [options] <command>\n"), program_invocation_short_name
);
1724 fputs(USAGE_SEPARATOR
, out
);
1725 fputs(_("Display or manipulate a disk partition table.\n"), out
);
1727 fputs(_("\nCommands:\n"), out
);
1728 fputs(_(" -A, --activate <dev> [<part> ...] list or set bootable MBR partitions\n"), out
);
1729 fputs(_(" -d, --dump <dev> dump partition table (usable for later input)\n"), out
);
1730 fputs(_(" -J, --json <dev> dump partition table in JSON format\n"), out
);
1731 fputs(_(" -g, --show-geometry [<dev> ...] list geometry of all or specified devices\n"), out
);
1732 fputs(_(" -l, --list [<dev> ...] list partitions of each device\n"), out
);
1733 fputs(_(" -F, --list-free [<dev> ...] list unpartitions free areas of each device\n"), out
);
1734 fputs(_(" -r, --reorder <dev> fix partitions order (by start offset)\n"), out
);
1735 fputs(_(" -s, --show-size [<dev> ...] list sizes of all or specified devices\n"), out
);
1736 fputs(_(" -T, --list-types print the recognized types (see -X)\n"), out
);
1737 fputs(_(" -V, --verify [<dev> ...] test whether partitions seem correct\n"), out
);
1738 fputs(_(" --delete <dev> [<part> ...] delete all or specified partitions\n"), out
);
1740 fputs(USAGE_SEPARATOR
, out
);
1741 fputs(_(" --part-label <dev> <part> [<str>] print or change partition label\n"), out
);
1742 fputs(_(" --part-type <dev> <part> [<type>] print or change partition type\n"), out
);
1743 fputs(_(" --part-uuid <dev> <part> [<uuid>] print or change partition uuid\n"), out
);
1744 fputs(_(" --part-attrs <dev> <part> [<str>] print or change partition attributes\n"), out
);
1746 fputs(USAGE_SEPARATOR
, out
);
1747 fputs(_(" <dev> device (usually disk) path\n"), out
);
1748 fputs(_(" <part> partition number\n"), out
);
1749 fputs(_(" <type> partition type, GUID for GPT, hex for MBR\n"), out
);
1751 fputs(USAGE_OPTIONS
, out
);
1752 fputs(_(" -a, --append append partitions to existing partition table\n"), out
);
1753 fputs(_(" -b, --backup backup partition table sectors (see -O)\n"), out
);
1754 fputs(_(" --bytes print SIZE in bytes rather than in human readable format\n"), out
);
1755 fputs(_(" --move-data[=<typescript>] move partition data after relocation (requires -N)\n"), out
);
1756 fputs(_(" -f, --force disable all consistency checking\n"), out
);
1757 fputs(_(" --color[=<when>] colorize output (auto, always or never)\n"), out
);
1759 " %s\n", USAGE_COLORS_DEFAULT
);
1760 fputs(_(" -N, --partno <num> specify partition number\n"), out
);
1761 fputs(_(" -n, --no-act do everything except write to device\n"), out
);
1762 fputs(_(" --no-reread do not check whether the device is in use\n"), out
);
1763 fputs(_(" -O, --backup-file <path> override default backup file name\n"), out
);
1764 fputs(_(" -o, --output <list> output columns\n"), out
);
1765 fputs(_(" -q, --quiet suppress extra info messages\n"), out
);
1766 fputs(_(" -w, --wipe <mode> wipe signatures (auto, always or never)\n"), out
);
1767 fputs(_(" -X, --label <name> specify label type (dos, gpt, ...)\n"), out
);
1768 fputs(_(" -Y, --label-nested <name> specify nested label type (dos, bsd)\n"), out
);
1769 fputs(USAGE_SEPARATOR
, out
);
1770 fputs(_(" -L, --Linux deprecated, only for backward compatibility\n"), out
);
1771 fputs(_(" -u, --unit S deprecated, only sector unit is supported\n"), out
);
1773 fputs(USAGE_SEPARATOR
, out
);
1774 fputs(USAGE_HELP
, out
);
1775 fputs(_(" -v, --version output version information and exit\n"), out
);
1777 list_available_columns(out
);
1779 fprintf(out
, USAGE_MAN_TAIL("sfdisk(8)"));
1780 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
1784 int main(int argc
, char *argv
[])
1786 const char *outarg
= NULL
;
1787 int rc
= -EINVAL
, c
, longidx
= -1, bytes
= 0;
1788 int colormode
= UL_COLORMODE_UNDEF
;
1789 struct sfdisk _sf
= {
1791 .wipemode
= WIPEMODE_AUTO
,
1792 .interactive
= isatty(STDIN_FILENO
) ? 1 : 0,
1796 OPT_CHANGE_ID
= CHAR_MAX
+ 1,
1810 static const struct option longopts
[] = {
1811 { "activate",no_argument
, NULL
, 'A' },
1812 { "append", no_argument
, NULL
, 'a' },
1813 { "backup", no_argument
, NULL
, 'b' },
1814 { "backup-file", required_argument
, NULL
, 'O' },
1815 { "bytes", no_argument
, NULL
, OPT_BYTES
},
1816 { "color", optional_argument
, NULL
, OPT_COLOR
},
1817 { "delete", no_argument
, NULL
, OPT_DELETE
},
1818 { "dump", no_argument
, NULL
, 'd' },
1819 { "help", no_argument
, NULL
, 'h' },
1820 { "force", no_argument
, NULL
, 'f' },
1821 { "json", no_argument
, NULL
, 'J' },
1822 { "label", required_argument
, NULL
, 'X' },
1823 { "label-nested", required_argument
, NULL
, 'Y' },
1824 { "list", no_argument
, NULL
, 'l' },
1825 { "list-free", no_argument
, NULL
, 'F' },
1826 { "list-types", no_argument
, NULL
, 'T' },
1827 { "no-act", no_argument
, NULL
, 'n' },
1828 { "no-reread", no_argument
, NULL
, OPT_NOREREAD
},
1829 { "move-data", optional_argument
, NULL
, OPT_MOVEDATA
},
1830 { "output", required_argument
, NULL
, 'o' },
1831 { "partno", required_argument
, NULL
, 'N' },
1832 { "reorder", no_argument
, NULL
, 'r' },
1833 { "show-size", no_argument
, NULL
, 's' },
1834 { "show-geometry", no_argument
, NULL
, 'g' },
1835 { "quiet", no_argument
, NULL
, 'q' },
1836 { "verify", no_argument
, NULL
, 'V' },
1837 { "version", no_argument
, NULL
, 'v' },
1838 { "wipe", required_argument
, NULL
, 'w' },
1840 { "part-uuid", no_argument
, NULL
, OPT_PARTUUID
},
1841 { "part-label", no_argument
, NULL
, OPT_PARTLABEL
},
1842 { "part-type", no_argument
, NULL
, OPT_PARTTYPE
},
1843 { "part-attrs", no_argument
, NULL
, OPT_PARTATTRS
},
1845 { "unit", required_argument
, NULL
, 'u' },
1846 { "Linux", no_argument
, NULL
, 'L' }, /* deprecated */
1848 { "change-id",no_argument
, NULL
, OPT_CHANGE_ID
}, /* deprecated */
1849 { "id", no_argument
, NULL
, 'c' }, /* deprecated */
1850 { "print-id",no_argument
, NULL
, OPT_PRINT_ID
}, /* deprecated */
1855 setlocale(LC_ALL
, "");
1856 bindtextdomain(PACKAGE
, LOCALEDIR
);
1857 textdomain(PACKAGE
);
1858 atexit(close_stdout
);
1860 while ((c
= getopt_long(argc
, argv
, "aAbcdfFghJlLo:O:nN:qrsTu:vVX:Y:w:",
1861 longopts
, &longidx
)) != -1) {
1864 sf
->act
= ACT_ACTIVATE
;
1875 warnx(_("%s is deprecated in favour of --part-type"),
1876 longopts
[longidx
].name
);
1877 sf
->act
= ACT_PARTTYPE
;
1880 warnx(_("--id is deprecated in favour of --part-type"));
1881 sf
->act
= ACT_PARTTYPE
;
1890 sf
->act
= ACT_LIST_FREE
;
1896 sf
->act
= ACT_SHOW_GEOM
;
1905 warnx(_("--Linux option is unnecessary and deprecated"));
1912 sf
->backup_file
= optarg
;
1918 sf
->partno
= strtou32_or_err(optarg
, _("failed to parse partition number")) - 1;
1924 sf
->act
= ACT_REORDER
;
1927 sf
->act
= ACT_SHOW_SIZE
;
1930 sf
->act
= ACT_LIST_TYPES
;
1934 errx(EXIT_FAILURE
, _("unsupported unit '%c'"), *optarg
);
1937 printf(_("%s from %s\n"), program_invocation_short_name
,
1939 return EXIT_SUCCESS
;
1944 sf
->wipemode
= wipemode_from_string(optarg
);
1945 if (sf
->wipemode
< 0)
1946 errx(EXIT_FAILURE
, _("unsupported wipe mode"));
1952 sf
->label_nested
= optarg
;
1956 sf
->act
= ACT_PARTUUID
;
1959 sf
->act
= ACT_PARTTYPE
;
1962 sf
->act
= ACT_PARTLABEL
;
1965 sf
->act
= ACT_PARTATTRS
;
1974 colormode
= UL_COLORMODE_AUTO
;
1976 colormode
= colormode_or_err(optarg
,
1977 _("unsupported color mode"));
1981 sf
->move_typescript
= optarg
;
1984 sf
->act
= ACT_DELETE
;
1991 colors_init(colormode
, "sfdisk");
1995 fdisk_set_size_unit(sf
->cxt
, FDISK_SIZEUNIT_BYTES
);
1998 init_fields(NULL
, outarg
, NULL
);
2000 if (sf
->verify
&& !sf
->act
)
2001 sf
->act
= ACT_VERIFY
; /* --verify make be used with --list too */
2003 sf
->act
= ACT_FDISK
; /* default */
2005 if (sf
->movedata
&& !(sf
->act
== ACT_FDISK
&& sf
->partno
>= 0))
2006 errx(EXIT_FAILURE
, _("--movedata requires -N"));
2010 rc
= command_activate(sf
, argc
- optind
, argv
+ optind
);
2014 rc
= command_delete(sf
, argc
- optind
, argv
+ optind
);
2018 rc
= command_list_partitions(sf
, argc
- optind
, argv
+ optind
);
2021 case ACT_LIST_TYPES
:
2022 rc
= command_list_types(sf
);
2026 rc
= command_list_freespace(sf
, argc
- optind
, argv
+ optind
);
2030 rc
= command_fdisk(sf
, argc
- optind
, argv
+ optind
);
2034 rc
= command_dump(sf
, argc
- optind
, argv
+ optind
);
2038 rc
= command_show_size(sf
, argc
- optind
, argv
+ optind
);
2042 rc
= command_show_geometry(sf
, argc
- optind
, argv
+ optind
);
2046 rc
= command_verify(sf
, argc
- optind
, argv
+ optind
);
2050 rc
= command_parttype(sf
, argc
- optind
, argv
+ optind
);
2054 rc
= command_partuuid(sf
, argc
- optind
, argv
+ optind
);
2058 rc
= command_partlabel(sf
, argc
- optind
, argv
+ optind
);
2062 rc
= command_partattrs(sf
, argc
- optind
, argv
+ optind
);
2066 rc
= command_reorder(sf
, argc
- optind
, argv
+ optind
);
2072 DBG(MISC
, ul_debug("bye! [rc=%d]", rc
));
2073 return rc
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;