summaryrefslogtreecommitdiffstats
path: root/libfdisk/src/dump.c
diff options
context:
space:
mode:
authorKarel Zak2014-08-25 15:33:02 +0200
committerKarel Zak2014-08-25 15:33:02 +0200
commit1d691b258e34c6d8956209e408211350edefcb93 (patch)
treea77b9c7ef50159ee5d71b2c62243cee03725a018 /libfdisk/src/dump.c
parentlibblkid: move string trim function to strutils.h (diff)
downloadkernel-qcow2-util-linux-1d691b258e34c6d8956209e408211350edefcb93.tar.gz
kernel-qcow2-util-linux-1d691b258e34c6d8956209e408211350edefcb93.tar.xz
kernel-qcow2-util-linux-1d691b258e34c6d8956209e408211350edefcb93.zip
libfdisk: vary basic dump parsing functions
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libfdisk/src/dump.c')
-rw-r--r--libfdisk/src/dump.c307
1 files changed, 303 insertions, 4 deletions
diff --git a/libfdisk/src/dump.c b/libfdisk/src/dump.c
index 2c9e7530e..e1fb0031d 100644
--- a/libfdisk/src/dump.c
+++ b/libfdisk/src/dump.c
@@ -1,5 +1,6 @@
#include "fdiskP.h"
+#include "strutils.h"
/* dump header (e.g. unit: sectors) */
struct fdisk_dumpheader {
@@ -16,8 +17,8 @@ struct fdisk_dump {
int refcount;
/* parser's state */
- FILE *file;
- size_t line;
+ size_t nlines;
+ int fmt; /* input format */
};
@@ -117,6 +118,7 @@ static struct fdisk_dumpheader *fdisk_dump_get_header(struct fdisk_dump *dp,
return NULL;
}
+
/**
* fdisk_dump_set_header:
* @dp: dump instance
@@ -204,7 +206,7 @@ struct fdisk_table *fdisk_dump_get_table(struct fdisk_dump *dp)
* @dp: dump
* @cxt: context
*
- * Reads data from the current context (on disk partition table).
+ * Reads data from the current context (on disk partition table) into the dump.
*
* Return: 0 on success, <0 on error.
*/
@@ -248,6 +250,15 @@ int fdisk_dump_read_context(struct fdisk_dump *dp, struct fdisk_context *cxt)
return rc;
}
+/**
+ * fdisk_dump_write_file:
+ * @dp: dump
+ * @f: output file
+ *
+ * Writes dump @dp to the ile @f.
+ *
+ * Returns: 0 on sucess, <0 on error.
+ */
int fdisk_dump_write_file(struct fdisk_dump *dp, FILE *f)
{
struct list_head *h;
@@ -278,7 +289,7 @@ int fdisk_dump_write_file(struct fdisk_dump *dp, FILE *f)
if (devname)
p = fdisk_partname(devname, pa->partno + 1);
if (p)
- fprintf(f, "%s: ", p);
+ fprintf(f, "%s : ", p);
else
fprintf(f, "%zu :", pa->partno + 1);
@@ -308,6 +319,273 @@ int fdisk_dump_write_file(struct fdisk_dump *dp, FILE *f)
return 0;
}
+static inline int is_header_line(const char *s)
+{
+ const char *p = strchr(s, ':');
+
+ if (!p || p == s || !*(p + 1) || strchr(s, '='))
+ return 0;
+
+ return 1;
+}
+
+/* parses "<name>: value", note modifies @s*/
+static int parse_header_line(struct fdisk_dump *dp, char *s)
+{
+ int rc = -EINVAL;
+ char *name, *value;
+
+ DBG(DUMP, ul_debug(" parse header '%s'", s));
+
+ if (!s || !*s)
+ return -EINVAL;
+
+ name = s;
+ value = strchr(s, ':');
+ if (!value)
+ goto done;
+ *value = '\0';
+ value++;
+
+ ltrim_whitespace((unsigned char *) name);
+ rtrim_whitespace((unsigned char *) name);
+ ltrim_whitespace((unsigned char *) value);
+ rtrim_whitespace((unsigned char *) value);
+
+ if (*name && *value)
+ rc = fdisk_dump_set_header(dp, name, value);
+done:
+ if (rc)
+ DBG(DUMP, ul_debug("header parse error: [rc=%d]", rc));
+ return rc;
+
+}
+
+static int next_number(char **s, uint64_t *num)
+{
+ char *end = NULL;
+ int rc;
+
+ assert(num);
+ assert(s);
+
+ *s = (char *) skip_blank(*s);
+ if (!**s)
+ return -1;
+
+ end = strchr(*s, ',');
+ if (end)
+ *end = '\0';
+
+ rc = strtosize(*s, (uintmax_t *) num);
+ if (end) {
+ *end = ',';
+ *s = end;
+ } else
+ while (**s) (*s)++;
+
+ return rc;
+}
+
+static int partno_from_devname(char *s)
+{
+ int pno;
+ size_t sz;
+ char *end, *p;
+
+ sz = rtrim_whitespace((unsigned char *)s);
+ p = s + sz - 1;
+
+ while (p > s && isdigit(*(p - 1)))
+ p--;
+
+ errno = 0;
+ pno = strtol(p, &end, 10);
+ if (errno || !end || p == end)
+ return -1;
+ return pno - 1;
+}
+
+static int parse_dump_line(struct fdisk_dump *dp, char *s)
+{
+ char *p;
+ struct fdisk_partition *pa;
+ int rc = 0;
+ uint64_t num;
+ int pno;
+
+ assert(dp);
+ assert(s);
+
+ DBG(DUMP, ul_debug(" parse dump line: '%s'", s));
+
+ pa = fdisk_new_partition();
+ if (!pa)
+ return -ENOMEM;
+
+ p = strchr(s, ':');
+ if (!p)
+ return -EINVAL;
+ *p = '\0';
+ p++;
+
+ pno = partno_from_devname(s);
+ if (pno < 0)
+ fdisk_partition_partno_follow_default(pa, 1);
+ else
+ fdisk_partition_set_partno(pa, pno);
+
+
+ while (rc == 0 && p && *p) {
+ while (isblank(*p)) p++;
+ if (!*p)
+ break;
+
+ if (!strncasecmp(p, "start=", 6)) {
+ p += 6;
+ rc = next_number(&p, &num);
+ if (!rc)
+ fdisk_partition_set_start(pa, num);
+
+ } else if (!strncasecmp(p, "size=", 5)) {
+ p += 5;
+ rc = next_number(&p, &num);
+ if (!rc)
+ fdisk_partition_set_size(pa, num);
+
+ } else if (!strncasecmp(p, "end=", 4)) {
+ p += 4;
+ rc = next_number(&p, &num);
+ if (!rc)
+ fdisk_partition_set_end(pa, num);
+ } else {
+ DBG(DUMP, ul_debug("dump parse error: unknown field '%s'", p));
+ rc = -EINVAL;
+ break;
+ }
+
+ while (isblank(*p)) p++;
+ if (*p == ',')
+ p++;
+ }
+
+ if (!rc)
+ rc = fdisk_table_add_partition(dp->table, pa);
+ if (rc)
+ DBG(DUMP, ul_debug("dump parse error: [rc=%d]", rc));
+
+ fdisk_unref_partition(pa);
+ return 0;
+}
+
+static int parse_commas_line(struct fdisk_dump *dp, const char *s)
+{
+ DBG(DUMP, ul_debug(" commas line parse error"));
+ return -EINVAL;
+}
+
+/* modifies @s ! */
+int fdisk_dump_read_buffer(struct fdisk_dump *dp, char *s)
+{
+ int rc = 0;
+
+ assert(dp);
+ assert(s);
+
+ DBG(DUMP, ul_debug(" parsing buffer"));
+
+ s = (char *) skip_blank(s);
+ if (!s || !*s)
+ return 0; /* nothing baby, ignore */
+
+ if (!dp->table) {
+ dp->table = fdisk_new_table();
+ if (!dp->table)
+ return -ENOMEM;
+ }
+
+ /* parse header lines only if no partition specified yet */
+ if (fdisk_table_is_empty(dp->table) && is_header_line(s))
+ rc = parse_header_line(dp, s);
+
+ /* parse dump format */
+ else if (strchr(s, '='))
+ rc = parse_dump_line(dp, s);
+
+ /* parse simple <value>, ... format */
+ else
+ rc = parse_commas_line(dp, s);
+
+ if (rc)
+ DBG(DUMP, ul_debugobj(dp, "%zu: parse error [rc=%d]",
+ dp->nlines, rc));
+ return rc;
+}
+
+char fdisk_dump_read_line(struct fdisk_dump *dp, FILE *f)
+{
+ char buf[BUFSIZ];
+ char *s;
+
+ assert(dp);
+ assert(f);
+
+ DBG(DUMP, ul_debug(" parsing line"));
+
+ /* read the next non-blank non-comment line */
+ do {
+ if (fgets(buf, sizeof(buf), f) == NULL)
+ return -EINVAL;
+ dp->nlines++;
+ s = strchr(buf, '\n');
+ if (!s) {
+ /* Missing final newline? Otherwise an extremely */
+ /* long line - assume file was corrupted */
+ if (feof(f)) {
+ DBG(DUMP, ul_debugobj(dp, "no final newline"));
+ s = strchr(buf, '\0');
+ } else {
+ DBG(DUMP, ul_debugobj(dp,
+ "%zu: missing newline at line", dp->nlines));
+ return -EINVAL;
+ }
+ }
+
+ *s = '\0';
+ if (--s >= buf && *s == '\r')
+ *s = '\0';
+ s = (char *) skip_blank(buf);
+ } while (*s == '\0' || *s == '#');
+
+ return fdisk_dump_read_buffer(dp, s);
+}
+
+
+/**
+ * fdisk_dump_read_file:
+ * @dp: dump
+ * @f input file
+ *
+ * Reads file @f into dump @dp.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_dump_read_file(struct fdisk_dump *dp, FILE *f)
+{
+ int rc = NULL;
+
+ assert(dp);
+ assert(f);
+
+ DBG(DUMP, ul_debug("parsing file"));
+
+ while (rc == 0 && !feof(f))
+ rc = fdisk_dump_read_line(dp, f);
+
+ return rc;
+}
+
+
#ifdef TEST_PROGRAM
int test_dump(struct fdisk_test *ts, int argc, char *argv[])
{
@@ -330,10 +608,31 @@ int test_dump(struct fdisk_test *ts, int argc, char *argv[])
return 0;
}
+int test_read(struct fdisk_test *ts, int argc, char *argv[])
+{
+ char *filename = argv[1];
+ struct fdisk_dump *dp;
+ FILE *f;
+
+ if (!(f = fopen(filename, "r")))
+ err(EXIT_FAILURE, "%s: cannot open", filename);
+
+ dp = fdisk_new_dump();
+
+ fdisk_dump_read_file(dp, f);
+ fclose(f);
+
+ fdisk_dump_write_file(dp, stdout);
+ fdisk_unref_dump(dp);
+
+ return 0;
+}
+
int main(int argc, char *argv[])
{
struct fdisk_test tss[] = {
{ "--dump", test_dump, "<device> print PT" },
+ { "--read", test_read, "<file> read PT scrit from file" },
{ NULL }
};