summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarel Zak <kzak@redhat.com>2015-03-02 13:58:23 +0100
committerKarel Zak <kzak@redhat.com>2015-03-12 10:14:35 +0100
commitef70ccd914c51babf61685d0ea17d0cb7ce58c1c (patch)
treec39f63110f253ca913fc1f1348b48fb406d24288
parentbf2a40ba26aa65df0873ce1d259e87927d1ff6e9 (diff)
downloadutil-linux-ef70ccd914c51babf61685d0ea17d0cb7ce58c1c.tar.gz
libfdisk: add {first,last}-lba header to sfdisk scritps
The current sfdisk does not allow to create partition that starts before the default libfdisk First LBA (~1MiB). It means that # sfdisk --dump /dev/sda > foo # sfdisk /dev/sdb < foo does not work on systems where 1st partition does not start at offset 2048. This patch add new headers to scripts to inform libfdisk about different First/Last LBA ranges. For example: label: gpt first-lba: 34 allows to override the library default. Signed-off-by: Karel Zak <kzak@redhat.com>
-rw-r--r--libfdisk/src/gpt.c81
-rw-r--r--libfdisk/src/script.c23
2 files changed, 94 insertions, 10 deletions
diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c
index 7a2997ccc..61b0a32e1 100644
--- a/libfdisk/src/gpt.c
+++ b/libfdisk/src/gpt.c
@@ -520,20 +520,82 @@ static struct gpt_header *gpt_copy_header(struct fdisk_context *cxt,
return res;
}
-static void count_first_last_lba(struct fdisk_context *cxt,
+static int get_script_u64(struct fdisk_context *cxt, uint64_t *num, const char *name)
+{
+ const char *str;
+ int pwr = 0, rc = 0;
+
+ assert(cxt);
+
+ *num = 0;
+
+ if (!cxt->script)
+ return 1;
+
+ str = fdisk_script_get_header(cxt->script, name);
+ if (!str)
+ return 1;
+
+ rc = parse_size(str, (uintmax_t *) num, &pwr);
+ if (rc < 0)
+ return rc;
+ if (pwr)
+ *num /= cxt->sector_size;
+ return 0;
+}
+
+static int count_first_last_lba(struct fdisk_context *cxt,
uint64_t *first, uint64_t *last)
{
+ int rc = 0;
+ uint64_t flba, llba;
+
uint64_t esz = 0;
assert(cxt);
+ assert(first);
+ assert(last);
+ *first = *last = 0;
+
+ /* UEFI default */
esz = sizeof(struct gpt_entry) * GPT_NPARTITIONS / cxt->sector_size;
- *last = cxt->total_sectors - 2 - esz;
- *first = esz + 2;
+ llba = cxt->total_sectors - 2 - esz;
+ flba = esz + 2;
+
+ /* script default */
+ if (cxt->script) {
+ rc = get_script_u64(cxt, first, "first-lba");
+ if (rc < 0)
+ return rc;
+
+ DBG(LABEL, ul_debug("FirstLBA: script=%ju, uefi=%ju, topology=%ju.", *first, flba, cxt->first_lba));
+
+ if (rc == 0 && (*first < flba || *first > llba)) {
+ fdisk_warnx(cxt, _("First LBA specified by script is out of range."));
+ return -ERANGE;
+ }
+
+ rc = get_script_u64(cxt, last, "last-lba");
+ if (rc < 0)
+ return rc;
+
+ DBG(LABEL, ul_debug("LastLBA: script=%ju, uefi=%ju, topology=%ju.", *last, llba, cxt->last_lba));
- if (*first < cxt->first_lba && cxt->first_lba < *last)
- /* Align according to topology */
- *first = cxt->first_lba;
+ if (rc == 0 && (*last > llba || *last < flba)) {
+ fdisk_warnx(cxt, _("Last LBA specified by script is out of range."));
+ return -ERANGE;
+ }
+ }
+
+ if (!*last)
+ *last = llba;
+
+ /* default by topology */
+ if (!*first)
+ *first = flba < cxt->first_lba &&
+ cxt->first_lba < *last ? cxt->first_lba : flba;
+ return 0;
}
/*
@@ -548,7 +610,7 @@ static int gpt_mknew_header(struct fdisk_context *cxt,
struct gpt_header *header, uint64_t lba)
{
uint64_t first, last;
- int has_id = 0;
+ int has_id = 0, rc;
if (!cxt || !header)
return -ENOSYS;
@@ -571,7 +633,10 @@ static int gpt_mknew_header(struct fdisk_context *cxt,
header->npartition_entries = cpu_to_le32(GPT_NPARTITIONS);
header->sizeof_partition_entry = cpu_to_le32(sizeof(struct gpt_entry));
- count_first_last_lba(cxt, &first, &last);
+ rc = count_first_last_lba(cxt, &first, &last);
+ if (rc)
+ return rc;
+
header->first_usable_lba = cpu_to_le64(first);
header->last_usable_lba = cpu_to_le64(last);
diff --git a/libfdisk/src/script.c b/libfdisk/src/script.c
index 5a89790d7..eb4e31d20 100644
--- a/libfdisk/src/script.c
+++ b/libfdisk/src/script.c
@@ -238,17 +238,22 @@ int fdisk_script_set_header(struct fdisk_script *dp,
if (!dp || !name)
return -EINVAL;
+
fi = script_get_header(dp, name);
if (!fi && !data)
return 0; /* want to remove header that does not exist, success */
if (!data) {
+ DBG(SCRIPT, ul_debugobj(dp, "freeing header %s", name));
+
/* no data, remove the header */
fdisk_script_free_header(dp, fi);
return 0;
}
if (!fi) {
+ DBG(SCRIPT, ul_debugobj(dp, "setting new header %s='%s'", name, data));
+
/* new header */
fi = calloc(1, sizeof(*fi));
if (!fi)
@@ -265,6 +270,8 @@ int fdisk_script_set_header(struct fdisk_script *dp,
/* update existing */
char *x = strdup(data);
+ DBG(SCRIPT, ul_debugobj(dp, "update '%s' header '%s' -> '%s'", name, fi->data, data));
+
if (!x)
return -ENOMEM;
free(fi->data);
@@ -366,7 +373,17 @@ int fdisk_script_read_context(struct fdisk_script *dp, struct fdisk_context *cxt
if (!rc)
rc = fdisk_script_set_header(dp, "unit", "sectors");
- /* TODO: label specific headers (e.g. uuid for GPT) */
+ if (!rc && fdisk_is_label(cxt, GPT)) {
+ char buf[64];
+
+ snprintf(buf, sizeof(buf), "%ju", cxt->first_lba);
+ rc = fdisk_script_set_header(dp, "first-lba", buf);
+
+ if (!rc) {
+ snprintf(buf, sizeof(buf), "%ju", cxt->last_lba);
+ rc = fdisk_script_set_header(dp, "last-lba", buf);
+ }
+ }
DBG(SCRIPT, ul_debugobj(dp, "read context done [rc=%d]", rc));
return rc;
@@ -493,7 +510,9 @@ static int parse_header_line(struct fdisk_script *dp, char *s)
if (strcmp(value, "sectors") != 0)
goto done; /* only "sectors" supported */
} else if (strcmp(name, "label-id") == 0
- || strcmp(name, "device") == 0) {
+ || strcmp(name, "device") == 0
+ || strcmp(name, "first-lba") == 0
+ || strcmp(name, "last-lba") == 0) {
; /* whatever is posssible */
} else
goto done; /* unknown header */