summaryrefslogtreecommitdiffstats
path: root/libfdisk/src/script.c
diff options
context:
space:
mode:
authorKarel Zak2014-09-02 13:51:32 +0200
committerKarel Zak2014-09-02 13:51:32 +0200
commit7b83dcc8a8c16c97f68e7903d265b70721a593d7 (patch)
tree74178e4c9866658fb8324a99174b3096d25b7925 /libfdisk/src/script.c
parentlibfdisk: (gpt) follow label-id from script (diff)
downloadkernel-qcow2-util-linux-7b83dcc8a8c16c97f68e7903d265b70721a593d7.tar.gz
kernel-qcow2-util-linux-7b83dcc8a8c16c97f68e7903d265b70721a593d7.tar.xz
kernel-qcow2-util-linux-7b83dcc8a8c16c97f68e7903d265b70721a593d7.zip
libfdisk: add support for sfdisk-like script format
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libfdisk/src/script.c')
-rw-r--r--libfdisk/src/script.c216
1 files changed, 204 insertions, 12 deletions
diff --git a/libfdisk/src/script.c b/libfdisk/src/script.c
index 5b0548f7a..bc92c82a7 100644
--- a/libfdisk/src/script.c
+++ b/libfdisk/src/script.c
@@ -448,6 +448,18 @@ done:
}
+static char *next_separator(char *s)
+{
+ char *end;
+
+ if ((end = strchr(s, ',')) ||
+ (end = strchr(s, ';')) ||
+ (end = strchr(s, ' ')))
+ return end;
+
+ return NULL;
+}
+
static int next_number(char **s, uint64_t *num)
{
char *end = NULL;
@@ -460,15 +472,14 @@ static int next_number(char **s, uint64_t *num)
if (!**s)
return -1;
- end = strchr(*s, ',');
+ end = next_separator(*s);
if (end)
*end = '\0';
rc = strtosize(*s, (uintmax_t *) num);
- if (end) {
- *end = ',';
- *s = end;
- } else
+ if (end)
+ *s = ++end;
+ else
while (**s) (*s)++;
return rc;
@@ -490,13 +501,13 @@ static int next_string(char **s, char **str)
xend = strchr(*s, '"');
if (!xend)
return -EINVAL;
- end = strchr(xend, ',');
+ end = next_separator(xend);
} else
- xend = end = strchr(*s, ',');
+ xend = end = next_separator(*s);
if (xend) {
*str = strndup(*s, xend - *s);
- *s = end ? end : xend + 1;
+ *s = end ? end + 1 : xend + 1;
} else {
*str = strdup(*s);
while (**s) (*s)++;
@@ -533,6 +544,9 @@ static int partno_from_devname(char *s)
return pno - 1;
}
+/* dump format
+ * <device>: start=<num>, size=<num>, type=<string>, ...
+ */
static int parse_script_line(struct fdisk_script *dp, char *s)
{
char *p;
@@ -634,7 +648,7 @@ static int parse_script_line(struct fdisk_script *dp, char *s)
}
while (isblank(*p)) p++;
- if (*p == ',')
+ if (*p == ',' || *p == ';')
p++;
}
@@ -648,10 +662,155 @@ done:
return rc;
}
-static int parse_commas_line(struct fdisk_script *dp, const char *s)
+/* original sfdisk supports partition types shortcuts like 'L' = Linux native
+ */
+static struct fdisk_parttype *translate_type_shortcuts(struct fdisk_script *dp, char *str)
{
- DBG(SCRIPT, ul_debugobj(dp, " commas line parse error"));
- return -EINVAL;
+ struct fdisk_label *lb;
+ const char *type = NULL;
+
+ if (strlen(str) != 1)
+ return NULL;
+
+ lb = script_get_label(dp);
+ if (!lb)
+ return NULL;
+
+ if (lb->id == FDISK_DISKLABEL_DOS) {
+ switch (*str) {
+ case 'L': /* Linux */
+ type = "83";
+ break;
+ case 'S': /* Swap */
+ type = "82";
+ break;
+ case 'E': /* Dos extended */
+ type = "05";
+ break;
+ case 'X': /* Linux extended */
+ type = "85";
+ break;
+ }
+ } else if (lb->id == FDISK_DISKLABEL_GPT) {
+ switch (*str) {
+ case 'L': /* Linux */
+ type = "0FC63DAF-8483-4772-8E79-3D69D8477DE4";
+ break;
+ case 'S': /* Swap */
+ type = "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F";
+ break;
+ case 'H': /* Home */
+ type = "933AC7E1-2EB4-4F13-B844-0E14E2AEF915";
+ break;
+ }
+ }
+
+ return type ? fdisk_label_parse_parttype(lb, type) : NULL;
+}
+
+/* simple format:
+ * <start>, <size>, <type>, <bootable>, ...
+ */
+static int parse_commas_line(struct fdisk_script *dp, char *s)
+{
+ int rc = 0;
+ char *p = s, *str;
+ struct fdisk_partition *pa;
+ enum { ITEM_START, ITEM_SIZE, ITEM_TYPE, ITEM_BOOTABLE };
+ int item = -1;
+
+ assert(dp);
+ assert(s);
+
+ pa = fdisk_new_partition();
+ if (!pa)
+ return -ENOMEM;
+
+ fdisk_partition_start_follow_default(pa, 1);
+ fdisk_partition_end_follow_default(pa, 1);
+
+ while (rc == 0 && p && *p) {
+ uint64_t num;
+
+ while (isblank(*p)) p++;
+ if (!*p)
+ break;
+ item++;
+
+ DBG(SCRIPT, ul_debugobj(dp, " parsing item %d ('%s')", item, p));
+
+ switch (item) {
+ case ITEM_START:
+ if (*p == ',' || *p == ';')
+ fdisk_partition_start_follow_default(pa, 1);
+ else {
+ rc = next_number(&p, &num);
+ if (!rc)
+ fdisk_partition_set_start(pa, num);
+ fdisk_partition_start_follow_default(pa, 0);
+ }
+ break;
+ case ITEM_SIZE:
+ if (*p == ',' || *p == ';')
+ fdisk_partition_end_follow_default(pa, 1);
+ else {
+ rc = next_number(&p, &num);
+ if (!rc)
+ fdisk_partition_set_size(pa, num);
+ fdisk_partition_end_follow_default(pa, 0);
+ }
+ break;
+ case ITEM_TYPE:
+ if (*p == ',' || *p == ';')
+ break; /* use default type */
+
+ rc = next_string(&p, &str);
+ if (rc)
+ break;
+
+ pa->type = translate_type_shortcuts(dp, str);
+ if (!pa->type)
+ pa->type = fdisk_label_parse_parttype(
+ script_get_label(dp), str);
+ free(str);
+
+ if (!pa->type || fdisk_parttype_is_unknown(pa->type)) {
+ rc = -EINVAL;
+ fdisk_free_parttype(pa->type);
+ pa->type = NULL;
+ break;
+ }
+ break;
+ case ITEM_BOOTABLE:
+ if (*p == ',')
+ break;
+ if (*p == '*' &&
+ (!*(p + 1) || *(p + 1) == ' ' || *(p + 1) == ',' || *(p + 1) == ';')) {
+ pa->boot = 1;
+ p++;
+ } else if (*p == '-' &&
+ (!*(p + 1) || *(p + 1) == ' ' || *(p + 1) == ',' || *(p + 1) == ';')) {
+ pa->boot = 0;
+ p++;
+ } else
+ rc = -EINVAL;
+ break;
+ default:
+ break;
+ }
+
+ while (isblank(*p)) p++;
+ if (*p == ',' || *p == ';')
+ p++;
+ }
+
+ if (!rc)
+ rc = fdisk_table_add_partition(dp->table, pa);
+ if (rc)
+ DBG(SCRIPT, ul_debugobj(dp, "script parse error: [rc=%d]", rc));
+
+ fdisk_unref_partition(pa);
+ return rc;
}
/* modifies @s ! */
@@ -889,6 +1048,38 @@ int test_read(struct fdisk_test *ts, int argc, char *argv[])
return 0;
}
+int test_stdin(struct fdisk_test *ts, int argc, char *argv[])
+{
+ struct fdisk_script *dp;
+ struct fdisk_context *cxt;
+ int rc = 0;
+
+ cxt = fdisk_new_context();
+ dp = fdisk_new_script(cxt);
+ fdisk_script_set_header(dp, "label", "dos");
+
+ printf("<start>, <size>, <type>, <bootable: *|->\n");
+ do {
+ struct fdisk_partition *pa;
+ size_t n = fdisk_table_get_nents(dp->table);
+
+ printf(" #%zu :\n", n + 1);
+ rc = fdisk_script_read_line(dp, stdin);
+
+ pa = fdisk_table_get_partition(dp->table, n);
+ printf(" #%zu %12ju %12ju\n", n + 1,
+ fdisk_partition_get_start(pa),
+ fdisk_partition_get_size(pa));
+ } while (rc == 0);
+
+ if (!rc)
+ fdisk_script_write_file(dp, stdout);
+ fdisk_unref_script(dp);
+ fdisk_unref_context(cxt);
+
+ return rc;
+}
+
int test_apply(struct fdisk_test *ts, int argc, char *argv[])
{
char *devname = argv[1], *scriptname = argv[2];
@@ -937,6 +1128,7 @@ int main(int argc, char *argv[])
{ "--dump", test_dump, "<device> dump PT as script" },
{ "--read", test_read, "<file> read PT script from file" },
{ "--apply", test_apply, "<device> <file> try apply script from file to device" },
+ { "--stdin", test_stdin, " read input like sfdisk" },
{ NULL }
};