From: Karel Zak Date: Fri, 22 Aug 2014 12:43:52 +0000 (+0200) Subject: libfdisk: basic fdisk_dump_* functions X-Git-Tag: v2.26-rc1~491 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cb4d6804677518bd701a8055d76e32eb4bc48b54;p=thirdparty%2Futil-linux.git libfdisk: basic fdisk_dump_* functions Signed-off-by: Karel Zak --- diff --git a/libfdisk/src/Makemodule.am b/libfdisk/src/Makemodule.am index d8cbffbe37..2077e36714 100644 --- a/libfdisk/src/Makemodule.am +++ b/libfdisk/src/Makemodule.am @@ -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) diff --git a/libfdisk/src/dos.c b/libfdisk/src/dos.c index c0360893a2..a427ceb4c6 100644 --- a/libfdisk/src/dos.c +++ b/libfdisk/src/dos.c @@ -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 index 0000000000..2c9e7530e4 --- /dev/null +++ b/libfdisk/src/dump.c @@ -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, " print PT" }, + { NULL } + }; + + return fdisk_run_test(tss, argc, argv); +} + +#endif diff --git a/libfdisk/src/fdiskP.h b/libfdisk/src/fdiskP.h index 5a4249e095..a65bb9e96f 100644 --- a/libfdisk/src/fdiskP.h +++ b/libfdisk/src/fdiskP.h @@ -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) diff --git a/libfdisk/src/init.c b/libfdisk/src/init.c index 13964184af..d9486612c9 100644 --- a/libfdisk/src/init.c +++ b/libfdisk/src/init.c @@ -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 } }; /** diff --git a/libfdisk/src/partition.c b/libfdisk/src/partition.c index d3a7b27fa5..822ca23d41 100644 --- a/libfdisk/src/partition.c +++ b/libfdisk/src/partition.c @@ -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);