]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libfdisk: add {first,last}-lba header to sfdisk scritps
authorKarel Zak <kzak@redhat.com>
Mon, 2 Mar 2015 12:58:23 +0000 (13:58 +0100)
committerKarel Zak <kzak@redhat.com>
Mon, 2 Mar 2015 12:58:23 +0000 (13:58 +0100)
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>
libfdisk/src/gpt.c
libfdisk/src/script.c

index 7a2997cccc74ac7f396ae9d74aef226095dfdf77..61b0a32e1ea17d4fa3096f38e1c6435a04397244 100644 (file)
@@ -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);
 
index 5a89790d702ae5a871bd18533d0bebdcb90a3d9b..eb4e31d20ead92d2f550bbce1662d657efc55fa4 100644 (file)
@@ -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 */