#include <fcntl.h>
#include <libsmartcols.h>
#ifdef HAVE_LIBREADLINE
+# define _FUNCTION_DEF
# include <readline/readline.h>
#endif
#include <libgen.h>
+#include <sys/time.h>
#include "c.h"
#include "xalloc.h"
#include "blkdev.h"
#include "all-io.h"
#include "rpmatch.h"
-#include "loopdev.h"
+#include "optutils.h"
+#include "ttyutils.h"
#include "libfdisk.h"
#include "fdisk-list.h"
/*
* sfdisk debug stuff (see fdisk.h and include/debug.h)
*/
-UL_DEBUG_DEFINE_MASK(sfdisk);
+static UL_DEBUG_DEFINE_MASK(sfdisk);
UL_DEBUG_DEFINE_MASKNAMES(sfdisk) = UL_DEBUG_EMPTY_MASKNAMES;
#define SFDISKPROG_DEBUG_INIT (1 << 1)
append : 1, /* don't create new PT, append partitions only */
json : 1, /* JSON dump */
movedata: 1, /* move data after resize */
+ movefsync: 1, /* use fsync() afetr each write() */
notell : 1, /* don't tell kernel aout new PT */
noact : 1; /* do not write to device */
};
static void sfdiskprog_init_debug(void)
{
- __UL_INIT_DEBUG(sfdisk, SFDISKPROG_DEBUG_, 0, SFDISK_DEBUG);
+ __UL_INIT_DEBUG_FROM_ENV(sfdisk, SFDISKPROG_DEBUG_, 0, SFDISK_DEBUG);
}
p = readline(prompt);
if (!p)
return 1;
- memcpy(buf, p, bufsz);
+ xstrncpy(buf, p, bufsz);
free(p);
} else
#endif
break;
case FDISK_ASKTYPE_YESNO:
{
- char buf[BUFSIZ];
+ char buf[BUFSIZ] = { '\0' };
fputc('\n', stdout);
do {
int x;
name = basename(buf);
- if (!filename) {
+ if (!filename || strcmp(filename, "@default") == 0) {
const char *home = getenv ("HOME");
if (!home)
errx(EXIT_FAILURE, _("failed to create a backup file, $HOME undefined"));
char *devname = NULL, *typescript = NULL, *buf = NULL;
FILE *f = NULL;
int ok = 0, fd, backward = 0;
- fdisk_sector_t nsectors, from, to, step, i;
- size_t ss, step_bytes, cc;
+ fdisk_sector_t nsectors, from, to, step, i, prev;
+ size_t io, ss, step_bytes, cc;
uintmax_t src, dst;
- int errsv;
+ int errsv, progress = 0;
+ struct timeval prev_time;
+ uint64_t bytes_per_sec = 0;
assert(sf->movedata);
fd = fdisk_get_devfd(sf->cxt);
- ss = fdisk_get_sector_size(sf->cxt);
+ /* set move direction and overlay */
nsectors = fdisk_partition_get_size(orig_pa);
from = fdisk_partition_get_start(orig_pa);
to = fdisk_partition_get_start(pa);
DBG(MISC, ul_debug("overlay between source and target"));
backward = from < to;
DBG(MISC, ul_debug(" copy order: %s", backward ? "backward" : "forward"));
+ }
- step = from > to ? from - to : to - from;
- if (step > nsectors)
- step = nsectors;
- } else
- step = nsectors;
+ /* set optimal step size -- nearest to 1MiB aligned to optimal I/O */
+ io = fdisk_get_optimal_iosize(sf->cxt);
+ ss = fdisk_get_sector_size(sf->cxt);
+ if (!io)
+ io = ss;
+ if (io < 1024 * 1024)
+ step_bytes = ((1024 * 1024) + io/2) / io * io;
+ else
+ step_bytes = io;
- /* make step usable for malloc() */
- if (step * ss > (getpagesize() * 256U))
- step = (getpagesize() * 256) / ss;
+ step = step_bytes / ss;
/* align the step (note that nsectors does not have to be power of 2) */
while (nsectors % step)
step--;
- step_bytes = step * ss;
DBG(MISC, ul_debug(" step: %ju (%zu bytes)", (uintmax_t)step, step_bytes));
#if defined(POSIX_FADV_SEQUENTIAL) && defined(HAVE_POSIX_FADVISE)
posix_fadvise(fd, from * ss, nsectors * ss, POSIX_FADV_SEQUENTIAL);
#endif
devname = fdisk_partname(fdisk_get_devname(sf->cxt), partno+1);
- typescript = mk_backup_filename_tpl(sf->move_typescript, devname, ".move");
+ if (sf->move_typescript)
+ typescript = mk_backup_filename_tpl(sf->move_typescript, devname, ".move");
if (!sf->quiet) {
fdisk_info(sf->cxt,"");
color_scheme_enable("header", UL_COLOR_BOLD);
- fdisk_info(sf->cxt, _("Data move:"));
+ fdisk_info(sf->cxt, sf->noact ? _("Data move: (--no-act)") : _("Data move:"));
color_disable();
- fdisk_info(sf->cxt, _(" typescript file: %s"), typescript);
- printf(_(" old start: %ju, new start: %ju (move %ju sectors)\n"),
- (uintmax_t) from, (uintmax_t) to, (uintmax_t) nsectors);
+ if (typescript)
+ fdisk_info(sf->cxt, _(" typescript file: %s"), typescript);
+ printf(_(" start sector: (from/to) %ju / %ju\n"), (uintmax_t) from, (uintmax_t) to);
+ printf(_(" sectors: %ju\n"), (uintmax_t) nsectors);
+ printf(_(" step size: %zu bytes\n"), step_bytes);
+ putchar('\n');
fflush(stdout);
+
+ if (isatty(fileno(stdout)))
+ progress = 1;
}
if (sf->interactive) {
}
}
- f = fopen(typescript, "w");
- if (!f)
- goto fail;
+ if (typescript) {
+ f = fopen(typescript, "w");
+ if (!f) {
+ fdisk_warn(sf->cxt, _("cannot open %s"), typescript);
+ goto fail;
+ }
- /* don't translate */
- fprintf(f, "# sfdisk: " PACKAGE_STRING "\n");
- fprintf(f, "# Disk: %s\n", devname);
- fprintf(f, "# Partition: %zu\n", partno + 1);
- fprintf(f, "# Operation: move data\n");
- fprintf(f, "# Original start offset (sectors/bytes): %ju/%ju\n",
- (uintmax_t)from, (uintmax_t)from * ss);
- fprintf(f, "# New start offset (sectors/bytes): %ju/%ju\n",
- (uintmax_t)to, (uintmax_t)to * ss);
- fprintf(f, "# Area size (sectors/bytes): %ju/%ju\n",
- (uintmax_t)nsectors, (uintmax_t)nsectors * ss);
- fprintf(f, "# Sector size: %zu\n", ss);
- fprintf(f, "# Step size (in bytes): %zu\n", step_bytes);
- fprintf(f, "# Steps: %ju\n", (uintmax_t)(nsectors / step));
- fprintf(f, "#\n");
- fprintf(f, "# <step>: <from> <to> (step offsets in bytes)\n");
+ /* don't translate */
+ fprintf(f, "# sfdisk: " PACKAGE_STRING "\n");
+ fprintf(f, "# Disk: %s\n", devname);
+ fprintf(f, "# Partition: %zu\n", partno + 1);
+ fprintf(f, "# Operation: move data\n");
+ fprintf(f, "# Original start offset (sectors/bytes): %ju/%ju\n",
+ (uintmax_t)from, (uintmax_t)from * ss);
+ fprintf(f, "# New start offset (sectors/bytes): %ju/%ju\n",
+ (uintmax_t)to, (uintmax_t)to * ss);
+ fprintf(f, "# Area size (sectors/bytes): %ju/%ju\n",
+ (uintmax_t)nsectors, (uintmax_t)nsectors * ss);
+ fprintf(f, "# Sector size: %zu\n", ss);
+ fprintf(f, "# Step size (in bytes): %zu\n", step_bytes);
+ fprintf(f, "# Steps: %ju\n", (uintmax_t)(nsectors / step));
+ fprintf(f, "#\n");
+ fprintf(f, "# <step>: <from> <to> (step offsets in bytes)\n");
+ }
src = (backward ? from + nsectors : from) * ss;
dst = (backward ? to + nsectors : to) * ss;
DBG(MISC, ul_debug(" initial: src=%ju dst=%ju", src, dst));
+ gettimeofday(&prev_time, NULL);
+ prev = 0;
+
for (cc = 1, i = 0; i < nsectors; i += step, cc++) {
ssize_t rc;
DBG(MISC, ul_debug("#%05zu: src=%ju dst=%ju", cc, src, dst));
- /* read source */
- if (lseek(fd, src, SEEK_SET) == (off_t) -1)
- goto fail;
- rc = read(fd, buf, step_bytes);
- if (rc < 0 || rc != (ssize_t) step_bytes)
- goto fail;
-
- /* write target */
- if (lseek(fd, dst, SEEK_SET) == (off_t) -1)
- goto fail;
- rc = write(fd, buf, step_bytes);
- if (rc < 0 || rc != (ssize_t) step_bytes)
- goto fail;
- fsync(fd);
+ if (!sf->noact) {
+ /* read source */
+ if (lseek(fd, src, SEEK_SET) == (off_t) -1)
+ goto fail;
+ rc = read(fd, buf, step_bytes);
+ if (rc < 0 || rc != (ssize_t) step_bytes)
+ goto fail;
+
+ /* write target */
+ if (lseek(fd, dst, SEEK_SET) == (off_t) -1)
+ goto fail;
+ rc = write(fd, buf, step_bytes);
+ if (rc < 0 || rc != (ssize_t) step_bytes)
+ goto fail;
+ if (sf->movefsync)
+ fsync(fd);
+ }
/* write log */
- fprintf(f, "%05zu: %12ju %12ju\n", cc, src, dst);
+ if (f)
+ fprintf(f, "%05zu: %12ju %12ju\n", cc, src, dst);
+
+ if (progress && i % 10 == 0) {
+ unsigned int elapsed = 0; /* usec */
+ struct timeval cur_time;
+
+ gettimeofday(&cur_time, NULL);
+ if (cur_time.tv_sec - prev_time.tv_sec > 1) {
+ elapsed = ((cur_time.tv_sec - prev_time.tv_sec) * 1000000) +
+ (cur_time.tv_usec - prev_time.tv_usec);
+
+ bytes_per_sec = ((i - prev) * ss) / elapsed; /* per usec */
+ bytes_per_sec *= 1000000; /* per sec */
+
+ prev_time = cur_time;
+ prev = i;
+ }
+
+ if (bytes_per_sec)
+ fprintf(stdout, _("Moved %ju from %ju sectors (%.3f%%, %.1f MiB/s)."),
+ i + 1, nsectors,
+ 100.0 / ((double) nsectors/(i+1)),
+ (double) (bytes_per_sec / (1024 * 1024)));
+ else
+ fprintf(stdout, _("Moved %ju from %ju sectors (%.3f%%)."),
+ i + 1, nsectors,
+ 100.0 / ((double) nsectors/(i+1)));
+ fflush(stdout);
+ fputc('\r', stdout);
+
+ }
-#if defined(POSIX_FADV_DONTNEED) && defined(HAVE_POSIX_FADVISE)
- posix_fadvise(fd, src, step_bytes, POSIX_FADV_DONTNEED);
-#endif
if (!backward)
src += step_bytes, dst += step_bytes;
}
- fclose(f);
+ if (progress) {
+ int x = get_terminal_width(80);
+ for (; x > 0; x--)
+ fputc(' ', stdout);
+ fflush(stdout);
+ fputc('\r', stdout);
+ fprintf(stdout, _("Moved %ju from %ju sectors (%.3f%%)."),
+ i, nsectors,
+ 100.0 / ((double) nsectors/(i+1)));
+ fputc('\n', stdout);
+ }
+ if (f)
+ fclose(f);
free(buf);
free(devname);
free(typescript);
+ if (sf->noact)
+ fdisk_info(sf->cxt, _("Your data has not been moved (--no-act)."));
+
return 0;
fail:
errsv = -errno;
if (sf->noact)
fdisk_info(sf->cxt, _("The partition table is unchanged (--no-act)."));
- else {
+ else
rc = fdisk_write_disklabel(sf->cxt);
- if (rc == 0 && sf->movedata && sf->orig_pa)
- rc = move_partition_data(sf, sf->partno, sf->orig_pa);
- if (!rc) {
- fdisk_info(sf->cxt, _("\nThe partition table has been altered."));
- if (!sf->notell)
- fdisk_reread_partition_table(sf->cxt);
+
+ if (rc == 0 && sf->movedata && sf->orig_pa)
+ rc = move_partition_data(sf, sf->partno, sf->orig_pa);
+
+ if (!sf->noact && !rc) {
+ fdisk_info(sf->cxt, _("\nThe partition table has been altered."));
+ if (!sf->notell) {
+ /* Let's wait a little bit. It's possible that our
+ * system is still busy with a previous re-read
+ * ioctl (on sfdisk start) or with another task
+ * related to the write to the device.
+ */
+ xusleep(250000);
+ fdisk_reread_partition_table(sf->cxt);
}
}
+
if (!rc)
rc = fdisk_deassign_device(sf->cxt,
sf->noact || sf->notell); /* no-sync */
if (rc)
err(EXIT_FAILURE, _("cannot open %s"), devname);
- if (!fdisk_is_label(sf->cxt, DOS))
- errx(EXIT_FAILURE, _("toggle boot flags is supported for MBR only"));
+ if (fdisk_is_label(sf->cxt, GPT)) {
+ if (fdisk_gpt_is_hybrid(sf->cxt))
+ errx(EXIT_FAILURE, _("toggle boot flags is unsupported for Hybrid GPT/MBR"));
+
+ /* Switch from GPT to PMBR */
+ sf->cxt = fdisk_new_nested_context(sf->cxt, "dos");
+ if (!sf->cxt)
+ err(EXIT_FAILURE, _("cannot switch to PMBR"));
+ fdisk_info(sf->cxt, _("Activation is unsupported for GPT -- entering nested PMBR."));
+
+ } else if (!fdisk_is_label(sf->cxt, DOS))
+ errx(EXIT_FAILURE, _("toggle boot flags is supported for MBR or PMBR only"));
if (!listonly && sf->backup)
backup_partition_table(sf, devname);
/* sfdisk --activate <partno> [..] */
for (i = 1; i < argc; i++) {
- int n = strtou32_or_err(argv[i], _("failed to parse partition number"));
+ int n;
+
+ if (i == 1 && strcmp(argv[1], "-") == 0)
+ break;
+ n = strtou32_or_err(argv[i], _("failed to parse partition number"));
rc = fdisk_toggle_partition_flag(sf->cxt, n - 1, DOS_FLAG_ACTIVE);
if (rc)
}
fdisk_unref_partition(pa);
+
if (listonly)
rc = fdisk_deassign_device(sf->cxt, 1);
else
fputc('\n', stdout);
fputs(_(" <type> The partition type. Default is a Linux data partition.\n"), stdout);
- fputs(_(" MBR: hex or L,S,E,X shortcuts.\n"), stdout);
- fputs(_(" GPT: UUID or L,S,H shortcuts.\n"), stdout);
+ fputs(_(" MBR: hex or L,S,E,X,U,R,V shortcuts.\n"), stdout);
+ fputs(_(" GPT: UUID or L,S,H,U,R,V shortcuts.\n"), stdout);
fputc('\n', stdout);
fputs(_(" <bootable> Use '*' to mark an MBR partition as bootable.\n"), stdout);
return partno;
}
-static int is_device_used(struct sfdisk *sf)
-{
-#ifdef BLKRRPART
- struct stat st;
- int fd;
-
- assert(sf);
- assert(sf->cxt);
-
- fd = fdisk_get_devfd(sf->cxt);
- if (fd < 0)
- return 0;
-
- if (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode)
- && major(st.st_rdev) != LOOPDEV_MAJOR)
- return ioctl(fd, BLKRRPART) != 0;
-#endif
- return 0;
-}
-
#ifdef HAVE_LIBREADLINE
static char *sfdisk_fgets(struct fdisk_script *dp,
char *buf, size_t bufsz, FILE *f)
return 0;
}
+static void follow_wipe_mode(struct sfdisk *sf)
+{
+ int dowipe = sf->wipemode == WIPEMODE_ALWAYS ? 1 : 0;
+
+ if (sf->interactive && sf->wipemode == WIPEMODE_AUTO)
+ dowipe = 1; /* do it in interactive mode */
+
+ if (fdisk_is_ptcollision(sf->cxt) && sf->wipemode != WIPEMODE_NEVER)
+ dowipe = 1; /* always wipe old PT */
+
+ fdisk_enable_wipe(sf->cxt, dowipe);
+ if (sf->quiet)
+ return;
+
+ if (dowipe) {
+ if (!fdisk_is_ptcollision(sf->cxt)) {
+ fdisk_warnx(sf->cxt, _(
+ "The device contains '%s' signature and it will be removed by a write command. "
+ "See sfdisk(8) man page and --wipe option for more details."),
+ fdisk_get_collision(sf->cxt));
+ fputc('\n', stdout);
+ }
+ } else {
+ fdisk_warnx(sf->cxt, _(
+ "The device contains '%s' signature and it may remain on the device. "
+ "It is recommended to wipe the device with wipefs(8) or "
+ "sfdisk --wipe, in order to avoid possible collisions."),
+ fdisk_get_collision(sf->cxt));
+ fputc('\n', stderr);
+ }
+}
+
static int wipe_partition(struct sfdisk *sf, size_t partno)
{
int rc, yes = 0;
- char *fstype = NULL;;
+ char *fstype = NULL;
struct fdisk_partition *tmp = NULL;
DBG(MISC, ul_debug("checking for signature"));
if (!sf->noact && !sf->noreread) {
if (!sf->quiet)
fputs(_("Checking that no-one is using this disk right now ..."), stdout);
- if (is_device_used(sf)) {
+ if (fdisk_device_is_used(sf->cxt)) {
if (!sf->quiet)
fputs(_(" FAILED\n\n"), stdout);
fputs(_(" OK\n\n"), stdout);
}
- if (fdisk_get_collision(sf->cxt)) {
- int dowipe = sf->wipemode == WIPEMODE_ALWAYS ? 1 : 0;
-
- fdisk_warnx(sf->cxt, _("Device %s already contains a %s signature."),
- devname, fdisk_get_collision(sf->cxt));
-
- if (sf->interactive && sf->wipemode == WIPEMODE_AUTO)
- dowipe = 1; /* do it in interactive mode */
-
- fdisk_enable_wipe(sf->cxt, dowipe);
- if (dowipe)
- fdisk_warnx(sf->cxt, _(
- "The signature will be removed by a write command."));
- else
- fdisk_warnx(sf->cxt, _(
- "It is strongly recommended to wipe the device with "
- "wipefs(8), in order to avoid possible collisions."));
- fputc('\n', stderr);
- }
+ if (fdisk_get_collision(sf->cxt))
+ follow_wipe_mode(sf);
if (sf->backup)
backup_partition_table(sf, devname);
}
refresh_prompt_buffer(sf, devname, next_partno, created);
+
+
if (sf->prompt && (sf->interactive || !sf->quiet)) {
#ifndef HAVE_LIBREADLINE
fputs(sf->prompt, stdout);
continue;
} else if (rc == 1) {
rc = SFDISK_DONE_EOF;
- fputs(_("Done.\n"), stdout);
+ if (!sf->quiet)
+ fputs(_("Done.\n"), stdout);
break;
}
nparts = fdisk_table_get_nents(tb);
if (nparts) {
- size_t cur_partno;
+ size_t cur_partno = (size_t) -1;
struct fdisk_partition *pa = fdisk_table_get_partition(tb, nparts - 1);
assert(pa);
fdisk_warnx(sf->cxt, _(
"Failed to apply script headers, "
"disk label not created."));
+
+ if (rc == 0 && fdisk_get_collision(sf->cxt))
+ follow_wipe_mode(sf);
}
if (!rc && partno >= 0) { /* -N <partno>, modify partition */
rc = fdisk_set_partition(sf->cxt, partno, pa);
rc = rc == 0 ? SFDISK_DONE_ASK : SFDISK_DONE_ABORT;
break;
} else if (!rc) { /* add partition */
- if (!sf->interactive &&
+ if (!sf->interactive && !sf->quiet &&
(!sf->prompt || startswith(sf->prompt, SFDISK_PROMPT))) {
refresh_prompt_buffer(sf, devname, next_partno, created);
fputs(sf->prompt, stdout);
rc = fdisk_add_partition(sf->cxt, pa, &cur_partno);
if (rc) {
errno = -rc;
- fdisk_warn(sf->cxt, _("Failed to add partition"));
-
+ fdisk_warn(sf->cxt, _("Failed to add #%d partition"), next_partno + 1);
}
}
}
} while (1);
+ /* create empty disk label if label, but no partition specified */
+ if ((rc == SFDISK_DONE_EOF || rc == SFDISK_DONE_WRITE) && created == 0
+ && fdisk_script_has_force_label(dp) == 1
+ && fdisk_table_get_nents(tb) == 0
+ && fdisk_script_get_header(dp, "label")) {
+
+ int xrc = fdisk_apply_script_headers(sf->cxt, dp);
+ created = !xrc;
+ if (xrc) {
+ fdisk_warnx(sf->cxt, _(
+ "Failed to apply script headers, "
+ "disk label not created."));
+ rc = SFDISK_DONE_ABORT;
+ }
+ }
+
if (!sf->quiet && rc != SFDISK_DONE_ABORT) {
fdisk_info(sf->cxt, _("\nNew situation:"));
+ list_disk_identifier(sf->cxt);
list_disklabel(sf->cxt);
}
break;
}
}
+ /* fallthrough */
case SFDISK_DONE_WRITE:
rc = write_changes(sf);
break;
return rc;
}
-static void __attribute__ ((__noreturn__)) usage(FILE *out)
+static void __attribute__((__noreturn__)) usage(void)
{
+ FILE *out = stdout;
fputs(USAGE_HEADER, out);
fprintf(out,
fputs(USAGE_SEPARATOR, out);
fputs(_("Display or manipulate a disk partition table.\n"), out);
- fputs(_("\nCommands:\n"), out);
- fputs(_(" -A, --activate <dev> [<part> ...] list or set bootable MBR partitions\n"), out);
+ fputs(USAGE_COMMANDS, out);
+ fputs(_(" -A, --activate <dev> [<part> ...] list or set bootable (P)MBR partitions\n"), out);
fputs(_(" -d, --dump <dev> dump partition table (usable for later input)\n"), out);
fputs(_(" -J, --json <dev> dump partition table in JSON format\n"), out);
fputs(_(" -g, --show-geometry [<dev> ...] list geometry of all or specified devices\n"), out);
fputs(_(" -b, --backup backup partition table sectors (see -O)\n"), out);
fputs(_(" --bytes print SIZE in bytes rather than in human readable format\n"), out);
fputs(_(" --move-data[=<typescript>] move partition data after relocation (requires -N)\n"), out);
+ fputs(_(" --move-use-fsync use fsync after each write when move data\n"), out);
fputs(_(" -f, --force disable all consistency checking\n"), out);
- fputs(_(" --color[=<when>] colorize output (auto, always or never)\n"), out);
+ fprintf(out,
+ _(" --color[=<when>] colorize output (%s, %s or %s)\n"), "auto", "always", "never");
fprintf(out,
" %s\n", USAGE_COLORS_DEFAULT);
fputs(_(" -N, --partno <num> specify partition number\n"), out);
fputs(_(" -O, --backup-file <path> override default backup file name\n"), out);
fputs(_(" -o, --output <list> output columns\n"), out);
fputs(_(" -q, --quiet suppress extra info messages\n"), out);
- fputs(_(" -w, --wipe <mode> wipe signatures (auto, always or never)\n"), out);
- fputs(_(" -W, --wipe-partitions <mode> wipe signatures from new partitions (auto, always or never)\n"), out);
+ fprintf(out,
+ _(" -w, --wipe <mode> wipe signatures (%s, %s or %s)\n"), "auto", "always", "never");
+ fprintf(out,
+ _(" -W, --wipe-partitions <mode> wipe signatures from new partitions (%s, %s or %s)\n"), "auto", "always", "never");
fputs(_(" -X, --label <name> specify label type (dos, gpt, ...)\n"), out);
fputs(_(" -Y, --label-nested <name> specify nested label type (dos, bsd)\n"), out);
fputs(USAGE_SEPARATOR, out);
fputs(_(" -u, --unit S deprecated, only sector unit is supported\n"), out);
fputs(USAGE_SEPARATOR, out);
- fputs(USAGE_HELP, out);
- fputs(_(" -v, --version output version information and exit\n"), out);
+ printf( " -h, --help %s\n", USAGE_OPTSTR_HELP);
+ printf( " -v, --version %s\n", USAGE_OPTSTR_VERSION);
list_available_columns(out);
- fprintf(out, USAGE_MAN_TAIL("sfdisk(8)"));
- exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+ printf(USAGE_MAN_TAIL("sfdisk(8)"));
+ exit(EXIT_SUCCESS);
}
OPT_BYTES,
OPT_COLOR,
OPT_MOVEDATA,
+ OPT_MOVEFSYNC,
OPT_DELETE,
OPT_NOTELL
};
{ "no-reread", no_argument, NULL, OPT_NOREREAD },
{ "no-tell-kernel", no_argument, NULL, OPT_NOTELL },
{ "move-data", optional_argument, NULL, OPT_MOVEDATA },
+ { "move-use-fsync", no_argument, NULL, OPT_MOVEFSYNC },
{ "output", required_argument, NULL, 'o' },
{ "partno", required_argument, NULL, 'N' },
{ "reorder", no_argument, NULL, 'r' },
- { "show-size", no_argument, NULL, 's' },
{ "show-geometry", no_argument, NULL, 'g' },
{ "quiet", no_argument, NULL, 'q' },
{ "verify", no_argument, NULL, 'V' },
{ "part-attrs", no_argument, NULL, OPT_PARTATTRS },
{ "show-pt-geometry", no_argument, NULL, 'G' }, /* deprecated */
- { "unit", required_argument, NULL, 'u' },
+ { "unit", required_argument, NULL, 'u' }, /* deprecated */
{ "Linux", no_argument, NULL, 'L' }, /* deprecated */
+ { "show-size", no_argument, NULL, 's' }, /* deprecated */
{ "change-id",no_argument, NULL, OPT_CHANGE_ID }, /* deprecated */
{ "id", no_argument, NULL, 'c' }, /* deprecated */
{ "print-id",no_argument, NULL, OPT_PRINT_ID }, /* deprecated */
- { NULL, 0, 0, 0 },
+ { NULL, 0, NULL, 0 },
};
+ static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
+ { 'F','J','d'}, /* --list-free --json --dump */
+ { 's','u'}, /* --show-size --unit */
+ { 0 }
+ };
+ int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
+
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
- atexit(close_stdout);
+ close_stdout_atexit();
while ((c = getopt_long(argc, argv, "aAbcdfFgGhJlLo:O:nN:qrsTu:vVX:Y:w:W:",
longopts, &longidx)) != -1) {
+
+ err_exclusive_options(c, longopts, excl, excl_st);
+
switch(c) {
case 'A':
sf->act = ACT_ACTIVATE;
break;
case 'G':
warnx(_("--show-pt-geometry is no more implemented. Using --show-geometry."));
+ /* fallthrough */
case 'g':
sf->act = ACT_SHOW_GEOM;
break;
case 'h':
- usage(stdout);
+ usage();
break;
case 'l':
sf->act = ACT_LIST;
errx(EXIT_FAILURE, _("unsupported unit '%c'"), *optarg);
break;
case 'v':
- printf(_("%s from %s\n"), program_invocation_short_name,
- PACKAGE_STRING);
- return EXIT_SUCCESS;
+ print_version(EXIT_SUCCESS);
case 'V':
sf->verify = 1;
break;
sf->movedata = 1;
sf->move_typescript = optarg;
break;
+ case OPT_MOVEFSYNC:
+ sf->movefsync = 1;
+ break;
case OPT_DELETE:
sf->act = ACT_DELETE;
break;
sf->notell = 1;
break;
default:
- usage(stderr);
+ errtryhelp(EXIT_FAILURE);
}
}