summaryrefslogtreecommitdiffstats
path: root/disk-utils/sfdisk.c
diff options
context:
space:
mode:
authorKarel Zak2014-09-19 11:31:07 +0200
committerKarel Zak2014-10-07 14:55:32 +0200
commitab02d87e4f9acdc1cb35805e93bf24c819ad035a (patch)
tree32b5e472240c55d63f29bfb7946239dc7e456cd6 /disk-utils/sfdisk.c
parentsfdisk: add --no-reread and --force (diff)
downloadkernel-qcow2-util-linux-ab02d87e4f9acdc1cb35805e93bf24c819ad035a.tar.gz
kernel-qcow2-util-linux-ab02d87e4f9acdc1cb35805e93bf24c819ad035a.tar.xz
kernel-qcow2-util-linux-ab02d87e4f9acdc1cb35805e93bf24c819ad035a.zip
sfdisk: add --backup and --backup-file
The option --backup force sfdisk to store *all* fragments of the partition table (including MBR partition tables store in the extended partitions) to $HOME/sfdisk-<devname>-<offset>.bak The options -O, -backup-file <path> allows to override the default path, but sfdisk still appends <devname>-<offset>.bak to the <path>. The backup files always contain only raw data from the device, so it's possible to use dd(1) to restore original data on the device. The original sfdisk also supported -O <file>, but semantic was little bit different: - all was based on 512-byte sectors - all sectors was stored to the one file in format <offset>|<sector>|<offset>|... this original concept makes the backup files specific to sfdisk and with dependence on sector size. The new concept is the same we already use for wipefs(8) backup files. Example (disk with GPT): # sfdisk /dev/sda --backup Welcome to sfdisk (util-linux 2.25.202-f4deb-dirty). Changes will remain in memory only, until you decide to write them. Be careful before using the write command. Backup files: PMBR (offset 0, size 512): /root/sfdisk-sda-0x00000000.bak GPT Header (offset 512, size 512): /root/sfdisk-sda-0x00000200.bak GPT Entries (offset 1024, size 16384): /root/sfdisk-sda-0x00000400.bak Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'disk-utils/sfdisk.c')
-rw-r--r--disk-utils/sfdisk.c126
1 files changed, 113 insertions, 13 deletions
diff --git a/disk-utils/sfdisk.c b/disk-utils/sfdisk.c
index 45121f5e6..1a6db9877 100644
--- a/disk-utils/sfdisk.c
+++ b/disk-utils/sfdisk.c
@@ -39,6 +39,7 @@
#include "closestream.h"
#include "colors.h"
#include "blkdev.h"
+#include "all-io.h"
#include "libfdisk.h"
#include "fdisk-list.h"
@@ -75,6 +76,7 @@ struct sfdisk {
int act; /* action */
int partno; /* -N <partno>, default -1 */
const char *label; /* --label <label> */
+ const char *backup_file; /* -O <path> */
struct fdisk_context *cxt; /* libfdisk context */
@@ -82,6 +84,7 @@ struct sfdisk {
quiet : 1, /* suppres extra messages */
noreread : 1, /* don't check device is in use */
force : 1, /* do also stupid things */
+ backup : 1, /* backup sectors before write PT */
noact : 1; /* do not write to device */
};
@@ -196,6 +199,85 @@ static int sfdisk_deinit(struct sfdisk *sf)
return rc;
}
+static void backup_sectors(struct sfdisk *sf,
+ const char *tpl,
+ const char *name,
+ const char *devname,
+ off_t offset, size_t size)
+{
+ char *fname;
+ int fd, devfd;
+
+ devfd = fdisk_get_devfd(sf->cxt);
+ assert(devfd >= 0);
+
+ xasprintf(&fname, "%s0x%08jx.bak", tpl, offset);
+
+ fd = open(fname, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
+ if (fd < 0)
+ goto fail;
+
+ if (lseek(devfd, offset, SEEK_SET) == (off_t) -1) {
+ fdisk_warn(sf->cxt, _("cannot seek %s"), devname);
+ goto fail;
+ } else {
+ unsigned char *buf = xmalloc(size);
+
+ if (read_all(devfd, (char *) buf, size) != (ssize_t) size) {
+ fdisk_warn(sf->cxt, _("cannot read %s"), devname);
+ goto fail;
+ }
+ if (write_all(fd, buf, size) != 0) {
+ fdisk_warn(sf->cxt, _("cannot write %s"), fname);
+ goto fail;
+ }
+ free(buf);
+ }
+
+ fdisk_info(sf->cxt, _("%12s (offset %5ju, size %5ju): %s"),
+ name, (uintmax_t) offset, (uintmax_t) size, fname);
+ close(fd);
+ free(fname);
+ return;
+fail:
+ errx(EXIT_FAILURE, _("%s: failed to create a backup"), devname);
+}
+
+static void backup_partition_table(struct sfdisk *sf, const char *devname)
+{
+ const char *name;
+ char *tpl;
+ off_t offset = 0;
+ size_t size = 0;
+ int i = 0;
+
+ assert(sf);
+
+ if (!fdisk_has_label(sf->cxt))
+ return;
+
+ if (!sf->backup_file) {
+ /* initialize default backup filename */
+ const char *home = getenv ("HOME");
+ if (!home)
+ errx(EXIT_FAILURE, _("failed to create a signature backup, $HOME undefined"));
+ xasprintf(&tpl, "%s/sfdisk-%s-", home, basename(devname));
+ } else
+ xasprintf(&tpl, "%s-%s-", sf->backup_file, basename(devname));
+
+ color_scheme_enable("header", UL_COLOR_BOLD);
+ fdisk_info(sf->cxt, _("Backup files:"));
+ color_disable();
+
+ while (fdisk_locate_disklabel(sf->cxt, i++, &name, &offset, &size) == 0 && size)
+ backup_sectors(sf, tpl, name, devname, offset, size);
+
+ if (!sf->quiet)
+ fputc('\n', stdout);
+ free(tpl);
+}
+
+
/*
* sfdisk --list [<device ..]
*/
@@ -433,6 +515,8 @@ static int command_activate(struct sfdisk *sf, int argc, char **argv)
if (!fdisk_is_label(sf->cxt, DOS))
errx(EXIT_FAILURE, _("toggle boot flags is supported for MBR only"));
+ if (!listonly && sf->backup)
+ backup_partition_table(sf, devname);
nparts = fdisk_get_npartitions(sf->cxt);
for (i = 0; i < nparts; i++) {
@@ -573,6 +657,9 @@ static int command_parttype(struct sfdisk *sf, int argc, char **argv)
return 0;
}
+ if (sf->backup)
+ backup_partition_table(sf, devname);
+
/* parse <type> and apply yo PT */
type = fdisk_label_parse_parttype(lb, typestr);
if (!type || fdisk_parttype_is_unknown(type))
@@ -800,6 +887,9 @@ static int command_fdisk(struct sfdisk *sf, int argc, char **argv)
fputs(_(" OK\n\n"), stdout);
}
+ if (sf->backup)
+ backup_partition_table(sf, devname);
+
if (!sf->quiet) {
list_disk_geometry(sf->cxt);
if (fdisk_has_label(sf->cxt)) {
@@ -953,20 +1043,22 @@ static void __attribute__ ((__noreturn__)) usage(FILE *out)
fputs(USAGE_SEPARATOR, out);
- fputs(_(" <dev> device (usually disk) path\n"), out);
- fputs(_(" <part> partition number\n"), out);
- fputs(_(" <type> partition type, GUID for GPT, hex for MBR\n"), out);
+ fputs(_(" <dev> device (usually disk) path\n"), out);
+ fputs(_(" <part> partition number\n"), out);
+ fputs(_(" <type> partition type, GUID for GPT, hex for MBR\n"), out);
fputs(USAGE_OPTIONS, out);
- fputs(_(" -f, --force disable all consistency checking\n"), out);
- fputs(_(" -N, --partno <num> specify partition number\n"), out);
- fputs(_(" -X, --label <name> specify label type (dos, gpt, ...)\n"), out);
- fputs(_(" -q, --quiet suppress extra info messages\n"), out);
- fputs(_(" -n, --no-act do everything except write to device\n"), out);
- fputs(_(" --no-reread do not check whether the device is in use\n"), out);
+ fputs(_(" -b, --backup backup partition table sectors (see -O)\n"), out);
+ fputs(_(" -f, --force disable all consistency checking\n"), out);
+ fputs(_(" -O, --backup-file <path> override default backout file name\n"), out);
+ fputs(_(" -N, --partno <num> specify partition number\n"), out);
+ fputs(_(" -X, --label <name> specify label type (dos, gpt, ...)\n"), out);
+ fputs(_(" -q, --quiet suppress extra info messages\n"), out);
+ fputs(_(" -n, --no-act do everything except write to device\n"), out);
+ fputs(_(" --no-reread do not check whether the device is in use\n"), out);
fputs(USAGE_SEPARATOR, out);
- fputs(_(" -u, --unit S deprecated, only sector unit is supported\n"), out);
- fputs(_(" -L, --Linux deprecated and ignored, only for backward copatibility\n"), out);
+ fputs(_(" -u, --unit S deprecated, only sector unit is supported\n"), out);
+ fputs(_(" -L, --Linux deprecated, only for backward copatibility\n"), out);
fputs(USAGE_SEPARATOR, out);
fputs(USAGE_HELP, out);
@@ -977,7 +1069,6 @@ static void __attribute__ ((__noreturn__)) usage(FILE *out)
}
-
int main(int argc, char *argv[])
{
int rc = -EINVAL, c, longidx = -1;
@@ -994,6 +1085,8 @@ int main(int argc, char *argv[])
static const struct option longopts[] = {
{ "activate",no_argument, NULL, 'a' },
+ { "backup", no_argument, NULL, 'b' },
+ { "backup-file", required_argument, NULL, 'O' },
{ "dump", no_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
{ "force", no_argument, NULL, 'f' },
@@ -1025,12 +1118,15 @@ int main(int argc, char *argv[])
textdomain(PACKAGE);
atexit(close_stdout);
- while ((c = getopt_long(argc, argv, "adfhglLnN:qsTu:vVX:",
+ while ((c = getopt_long(argc, argv, "adfhglLO:nN:qsTu:vVX:",
longopts, &longidx)) != -1) {
switch(c) {
case 'a':
sf->act = ACT_ACTIVATE;
break;
+ case 'b':
+ sf->backup = 1;
+ break;
case OPT_CHANGE_ID:
case OPT_PRINT_ID:
case OPT_ID:
@@ -1052,6 +1148,10 @@ int main(int argc, char *argv[])
case 'L':
warnx(_("--Linux option is deprecated and unnecessary"));
break;
+ case 'O':
+ sf->backup = 1;
+ sf->backup_file = optarg;
+ break;
case 'd':
sf->act = ACT_DUMP;
break;