]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libfdisk: basic fdisk_dump_* functions
authorKarel Zak <kzak@redhat.com>
Fri, 22 Aug 2014 12:43:52 +0000 (14:43 +0200)
committerKarel Zak <kzak@redhat.com>
Fri, 22 Aug 2014 12:43:52 +0000 (14:43 +0200)
Signed-off-by: Karel Zak <kzak@redhat.com>
libfdisk/src/Makemodule.am
libfdisk/src/dos.c
libfdisk/src/dump.c [new file with mode: 0644]
libfdisk/src/fdiskP.h
libfdisk/src/init.c
libfdisk/src/partition.c

index d8cbffbe37df3798f89c99c0d6d6c953e5a182fc..2077e36714ce74fb4483357bb704b6ccc0a4e08d 100644 (file)
@@ -20,6 +20,7 @@ libfdisk_la_SOURCES = \
        libfdisk/src/partition.c \
        libfdisk/src/table.c \
        libfdisk/src/iter.c \
+       libfdisk/src/dump.c \
        \
        libfdisk/src/sun.c \
        libfdisk/src/sgi.c \
@@ -51,6 +52,7 @@ endif
 
 check_PROGRAMS += \
        test_fdisk_ask \
+       test_fdisk_dump \
        test_fdisk_utils
 
 libfdisk_tests_cflags  = -DTEST_PROGRAM $(libfdisk_la_CFLAGS)
@@ -74,3 +76,8 @@ test_fdisk_utils_SOURCES = libfdisk/src/utils.c
 test_fdisk_utils_CFLAGS = $(libfdisk_tests_cflags)
 test_fdisk_utils_LDFLAGS = $(libfdisk_tests_ldflags)
 test_fdisk_utils_LDADD = $(libfdisk_tests_ldadd)
+
+test_fdisk_dump_SOURCES = libfdisk/src/dump.c
+test_fdisk_dump_CFLAGS = $(libfdisk_tests_cflags)
+test_fdisk_dump_LDFLAGS = $(libfdisk_tests_ldflags)
+test_fdisk_dump_LDADD = $(libfdisk_tests_ldadd)
index c0360893a27612886edaee5116861a2b2c59038c..a427ceb4c64d66500e2c0ec8f16b8ca88882fe12 100644 (file)
@@ -1679,7 +1679,7 @@ static int dos_get_partition(struct fdisk_context *cxt, size_t n,
                return 0;
 
        pa->type = dos_partition_parttype(cxt, p);
-       pa->boot = p->boot_ind ? p->boot_ind == ACTIVE_FLAG ? '*' : '?' : ' ';
+       pa->boot = p->boot_ind == ACTIVE_FLAG ? 1 : 0;
        pa->start = get_abs_partition_start(pe);
        pa->end = get_abs_partition_end(pe);
        pa->size = dos_partition_get_size(p);
@@ -1688,7 +1688,7 @@ static int dos_get_partition(struct fdisk_context *cxt, size_t n,
        if (n >= 4)
                pa->parent_partno = lb->ext_index;
 
-       if (asprintf(&pa->attrs, "%02x", p->boot_ind) < 0)
+       if (p->boot_ind && asprintf(&pa->attrs, "%02x", p->boot_ind) < 0)
                return -ENOMEM;
 
        /* start C/H/S */
diff --git a/libfdisk/src/dump.c b/libfdisk/src/dump.c
new file mode 100644 (file)
index 0000000..2c9e753
--- /dev/null
@@ -0,0 +1,343 @@
+
+#include "fdiskP.h"
+
+/* dump header (e.g. unit: sectors) */
+struct fdisk_dumpheader {
+       struct list_head        headers;
+       char                    *name;
+       char                    *data;
+};
+
+/* dump control struct */
+struct fdisk_dump {
+       struct fdisk_table      *table;
+       struct list_head        headers;
+
+       int                     refcount;
+
+       /* parser's state */
+       FILE                    *file;
+       size_t                  line;
+};
+
+
+static void fdisk_dump_free_header(struct fdisk_dump *dp, struct fdisk_dumpheader *fi)
+{
+       if (!fi)
+               return;
+
+       DBG(DUMP, ul_debugobj(fi, "free"));
+       free(fi->name);
+       free(fi->data);
+       list_del(&fi->headers);
+       free(fi);
+}
+
+/**
+ * fdisk_new_dump:
+ *
+ * The dump hold fdisk_table and additional information to read/write
+ * dump to the file.
+ *
+ * Returns: newly allocated dump struct.
+ */
+struct fdisk_dump *fdisk_new_dump(void)
+{
+       struct fdisk_dump *dp = NULL;
+
+       dp = calloc(1, sizeof(*dp));
+       if (!dp)
+               return NULL;
+
+       DBG(DUMP, ul_debugobj(dp, "alloc"));
+       dp->refcount = 1;
+       INIT_LIST_HEAD(&dp->headers);
+       return dp;
+}
+
+/**
+ * fdisk_ref_dump:
+ * @dp: dump pointer
+ *
+ * Incremparts reference counter.
+ */
+void fdisk_ref_dump(struct fdisk_dump *dp)
+{
+       if (dp)
+               dp->refcount++;
+}
+
+static void fdisk_reset_dump(struct fdisk_dump *dp)
+{
+       assert(dp);
+
+       fdisk_unref_table(dp->table);
+       dp->table = NULL;
+
+       while (!list_empty(&dp->headers)) {
+               struct fdisk_dumpheader *fi = list_entry(dp->headers.next,
+                                                 struct fdisk_dumpheader, headers);
+               fdisk_dump_free_header(dp, fi);
+       }
+       INIT_LIST_HEAD(&dp->headers);
+}
+
+/**
+ * fdisk_unref_dump:
+ * @dp: dump pointer
+ *
+ * De-incremparts reference counter, on zero the @dp is automatically
+ * deallocated.
+ */
+void fdisk_unref_dump(struct fdisk_dump *dp)
+{
+       if (!dp)
+               return;
+
+       dp->refcount--;
+       if (dp->refcount <= 0) {
+               fdisk_reset_dump(dp);
+               DBG(DUMP, ul_debugobj(dp, "free"));
+               free(dp);
+       }
+}
+
+static struct fdisk_dumpheader *fdisk_dump_get_header(struct fdisk_dump *dp,
+                                                    const char *name)
+{
+       struct list_head *p;
+
+       list_for_each(p, &dp->headers) {
+               struct fdisk_dumpheader *fi = list_entry(p, struct fdisk_dumpheader, headers);
+
+               if (strcasecmp(fi->name, name) == 0)
+                       return fi;
+       }
+
+       return NULL;
+}
+
+/**
+ * fdisk_dump_set_header:
+ * @dp: dump instance
+ * @name: header name
+ * @data: header data (or NULL)
+ *
+ * The headers are used as global options (in dump) for whole partition table, always one
+ * header per line.
+ *
+ * If no @data specified then the header is removed. If header does not exist
+ * and @data speified then a new header added.
+ *
+ * Note that libfdisk allows to specify arbitrary custom header, the default
+ * build-in headers are "unit" and "label", and some label specific headers
+ * (for example "uuid" and "name" for GPT).
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_dump_set_header(struct fdisk_dump *dp,
+                           const char *name,
+                           const char *data)
+{
+       struct fdisk_dumpheader *fi;
+
+       assert(dp);
+       assert(name);
+
+       if (!dp || !name)
+               return -EINVAL;
+
+       fi = fdisk_dump_get_header(dp, name);
+       if (!fi && !data)
+               return 0;       /* want to remove header that does not exist, success */
+
+       if (!data) {
+               /* no data, remove the header */
+               fdisk_dump_free_header(dp, fi);
+               return 0;
+       }
+
+       if (!fi) {
+               /* new header */
+               fi = calloc(1, sizeof(*fi));
+               if (!fi)
+                       return -ENOMEM;
+               INIT_LIST_HEAD(&fi->headers);
+               fi->name = strdup(name);
+               fi->data = strdup(data);
+               if (!fi->data || !fi->name) {
+                       fdisk_dump_free_header(dp, fi);
+                       return -ENOMEM;
+               }
+               list_add_tail(&fi->headers, &dp->headers);
+       } else {
+               /* update existing */
+               char *x = strdup(data);
+
+               if (!x)
+                       return -ENOMEM;
+               free(fi->data);
+               fi->data = x;
+       }
+
+       return 0;
+}
+
+/**
+ * fdisk_dump_get_table:
+ * @dp: dump
+ *
+ * The table (container with partitions) is possible to create by
+ * fdisk_dump_read_context() or fdisk_dump_read_file(), otherwise
+ * this function returns NULL.
+ *
+ * Returns: NULL or dump.
+ */
+struct fdisk_table *fdisk_dump_get_table(struct fdisk_dump *dp)
+{
+       assert(dp);
+       return dp ? dp->table : NULL;
+}
+
+/**
+ * fdisk_dump_read_context:
+ * @dp: dump
+ * @cxt: context
+ *
+ * Reads data from the current context (on disk partition table).
+ *
+ * Return: 0 on success, <0 on error.
+ */
+int fdisk_dump_read_context(struct fdisk_dump *dp, struct fdisk_context *cxt)
+{
+       struct fdisk_label *lb;
+       int rc;
+       char *p = NULL;
+
+       assert(dp);
+       assert(cxt);
+
+       if (!dp || !cxt)
+               return -EINVAL;
+
+       fdisk_reset_dump(dp);
+
+       lb = fdisk_get_label(cxt, NULL);
+       if (!lb)
+               return -EINVAL;
+
+       /* allocate and fill new table */
+       rc = fdisk_get_partitions(cxt, &dp->table);
+       if (rc)
+               return rc;
+
+       /* generate headers */
+       rc = fdisk_dump_set_header(dp, "label", fdisk_label_get_name(lb));
+
+       if (!rc && fdisk_get_disklabel_id(cxt, &p) == 0 && p) {
+               rc = fdisk_dump_set_header(dp, "label-id", p);
+               free(p);
+       }
+       if (!rc && cxt->dev_path)
+               rc = fdisk_dump_set_header(dp, "device", cxt->dev_path);
+       if (!rc)
+               rc = fdisk_dump_set_header(dp, "unit", "sectors");
+
+       /* TODO: label specific headers (e.g. uuid for GPT) */
+
+       return rc;
+}
+
+int fdisk_dump_write_file(struct fdisk_dump *dp, FILE *f)
+{
+       struct list_head *h;
+       struct fdisk_partition *pa;
+       struct fdisk_iter itr;
+       const char *devname = NULL;
+
+       assert(dp);
+       assert(f);
+
+       /* dump headers */
+       list_for_each(h, &dp->headers) {
+               struct fdisk_dumpheader *fi = list_entry(h, struct fdisk_dumpheader, headers);
+               fprintf(f, "%s: %s\n", fi->name, fi->data);
+               if (strcmp(fi->name, "device") == 0)
+                       devname = fi->data;
+       }
+
+       if (!dp->table)
+               return 0;
+
+       fputc('\n', f);
+
+       fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
+       while (fdisk_table_next_partition(dp->table, &itr, &pa) == 0) {
+               char *p = NULL;
+
+               if (devname)
+                       p = fdisk_partname(devname, pa->partno + 1);
+               if (p)
+                       fprintf(f, "%s: ", p);
+               else
+                       fprintf(f, "%zu :", pa->partno + 1);
+
+               if (pa->start)
+                       fprintf(f, " start=%12ju", pa->start);
+               if (pa->size)
+                       fprintf(f, ", size=%12ju", pa->size);
+               else if (pa->end)
+                       fprintf(f, ", end=%12ju", pa->end);
+
+               if (pa->type && fdisk_parttype_get_string(pa->type))
+                       fprintf(f, ", type=%s", fdisk_parttype_get_string(pa->type));
+               else if (pa->type)
+                       fprintf(f, ", type=%x", fdisk_parttype_get_code(pa->type));
+
+               if (pa->uuid)
+                       fprintf(f, ", uuid=%s", pa->uuid);
+               if (pa->name && *pa->name)
+                       fprintf(f, ", name=\"%s\"", pa->name);
+               if (pa->attrs)
+                       fprintf(f, ", attrs=%s", pa->attrs);
+               if (pa->boot)
+                       fprintf(f, ", bootable");
+               fputc('\n', f);
+       }
+
+       return 0;
+}
+
+#ifdef TEST_PROGRAM
+int test_dump(struct fdisk_test *ts, int argc, char *argv[])
+{
+       char *devname = argv[1];
+       struct fdisk_context *cxt;
+       struct fdisk_dump *dp;
+
+       cxt = fdisk_new_context();
+       fdisk_assign_device(cxt, devname, 1);
+
+       dp = fdisk_new_dump();
+       fdisk_dump_read_context(dp, cxt);
+       fdisk_dump_set_header(dp, "custom-header-foo", "bar");
+
+       fdisk_free_context(cxt);
+
+       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" },
+       { NULL }
+       };
+
+       return fdisk_run_test(tss, argc, argv);
+}
+
+#endif
index 5a4249e0958ed2fca924e30facb4a335f71bea95..a65bb9e96fb469be70d04b44a91baa6362cf83a0 100644 (file)
@@ -45,6 +45,7 @@
 #define FDISK_DEBUG_PART       (1 << 6)
 #define FDISK_DEBUG_PARTTYPE   (1 << 7)
 #define FDISK_DEBUG_TAB                (1 << 8)
+#define FDISK_DEBUG_DUMP       (1 << 9)
 #define FDISK_DEBUG_ALL                0xFFFF
 
 UL_DEBUG_DECLARE_MASK(libfdisk);
@@ -136,7 +137,6 @@ struct fdisk_partition {
        uint64_t        bsize;
        uint64_t        cpg;
 
-       char            boot;                   /* is bootable (MBS only) */
        char            *start_addr;            /* start C/H/S in string */
        char            *end_addr;              /* end C/H/S in string */
 
@@ -146,7 +146,8 @@ struct fdisk_partition {
                        freespace : 1,          /* this is free space */
                        container : 1,          /* container partition (e.g. extended partition) */
                        wholedisk : 1,          /* special system partition */
-                       used   : 1;             /* partition already used */
+                       boot : 1,               /* bootable (MBR only) */
+                       used : 1;               /* partition already used */
 };
 
 #define FDISK_EMPTY_PARTNO     ((size_t) -1)
index 13964184afc7ba669e4ff06dd4ac10ddbac8d64f..d9486612c9a0aea52e29dbc39eced27046b8e318 100644 (file)
@@ -13,6 +13,7 @@ UL_DEBUG_DEFINE_MASKANEMS(libfdisk) =
        { "part", FDISK_DEBUG_PART },
        { "parttype", FDISK_DEBUG_PARTTYPE },
        { "tab", FDISK_DEBUG_TAB},
+       { "dump", FDISK_DEBUG_DUMP},
        { NULL, 0 }
 };
 /**
index d3a7b27fa545d1883f9c4492d2211c6af5b1e440..822ca23d417bd82ac05c7025b1366bb678f9b7a2 100644 (file)
@@ -430,7 +430,7 @@ int fdisk_partition_to_string(struct fdisk_partition *pa,
                        p = fdisk_partname(cxt->dev_path, pa->partno + 1);
                break;
        case FDISK_FIELD_BOOT:
-               rc = asprintf(&p, "%c", pa->boot);
+               rc = asprintf(&p, "%c", pa->boot ? '*' : ' ');
                break;
        case FDISK_FIELD_START:
                x = fdisk_cround(cxt, pa->start);