libfdisk: add JSON dump output

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2015-06-15 13:18:09 +02:00
parent 0baeca2aef
commit 3c7fde5f92
4 changed files with 182 additions and 10 deletions

View File

@ -132,6 +132,7 @@ fdisk_script
fdisk_new_script
fdisk_new_script_from_file
fdisk_ref_script
fdisk_script_enable_json
fdisk_script_get_header
fdisk_script_get_nlines
fdisk_script_get_table

View File

@ -624,6 +624,7 @@ void *fdisk_script_get_userdata(struct fdisk_script *dp);
int fdisk_script_set_fgets(struct fdisk_script *dp,
char *(*fn_fgets)(struct fdisk_script *, char *, size_t, FILE *));
int fdisk_script_read_context(struct fdisk_script *dp, struct fdisk_context *cxt);
int fdisk_script_enable_json(struct fdisk_script *dp, int json);
int fdisk_script_write_file(struct fdisk_script *dp, FILE *f);
int fdisk_script_read_file(struct fdisk_script *dp, FILE *f);
int fdisk_script_read_line(struct fdisk_script *dp, FILE *f, char *buf, size_t bufsz);

View File

@ -251,4 +251,5 @@ FDISK_2.27 {
fdisk_script_set_userdata;
fdisk_table_get_partition_by_partno;
fdisk_get_disklabel_item;
fdisk_script_enable_json;
} FDISK_2.26;

View File

@ -1,6 +1,7 @@
#include "fdiskP.h"
#include "strutils.h"
#include "carefulputc.h"
/**
* SECTION: script
@ -33,8 +34,9 @@ struct fdisk_script {
/* parser's state */
size_t nlines;
int fmt; /* input format */
struct fdisk_label *label;
unsigned int json : 1; /* JSON output */
};
@ -404,31 +406,179 @@ int fdisk_script_read_context(struct fdisk_script *dp, struct fdisk_context *cxt
rc = fdisk_script_set_header(dp, "unit", "sectors");
if (!rc && fdisk_is_label(cxt, GPT)) {
struct fdisk_labelitem item;
char buf[64];
snprintf(buf, sizeof(buf), "%ju", cxt->first_lba);
rc = fdisk_script_set_header(dp, "first-lba", buf);
rc = fdisk_get_disklabel_item(cxt, GPT_LABELITEM_FIRSTLBA, &item);
if (rc == 0) {
snprintf(buf, sizeof(buf), "%ju", item.data.num64);
rc = fdisk_script_set_header(dp, "first-lba", buf);
}
if (rc < 0)
goto done;
if (!rc) {
snprintf(buf, sizeof(buf), "%ju", cxt->last_lba);
rc = fdisk_get_disklabel_item(cxt, GPT_LABELITEM_LASTLBA, &item);
if (rc == 0) {
snprintf(buf, sizeof(buf), "%ju", item.data.num64);
rc = fdisk_script_set_header(dp, "last-lba", buf);
}
if (rc < 0)
goto done;
}
done:
DBG(SCRIPT, ul_debugobj(dp, "read context done [rc=%d]", rc));
return rc;
}
/**
* fdisk_script_write_file:
* fdisk_script_enable_json:
* @dp: script
* @f: output file
* @json: 0 or 1
*
* Writes script @dp to the ile @f.
* Disable/Enable JSON output format.
*
* Returns: 0 on success, <0 on error.
*/
int fdisk_script_write_file(struct fdisk_script *dp, FILE *f)
int fdisk_script_enable_json(struct fdisk_script *dp, int json)
{
assert(dp);
dp->json = json;
return 0;
}
static void fput_indent(int indent, FILE *f)
{
int i;
for (i = 0; i <= indent; i++)
fputs(" ", f);
}
static int write_file_json(struct fdisk_script *dp, FILE *f)
{
struct list_head *h;
struct fdisk_partition *pa;
struct fdisk_iter itr;
const char *devname = NULL;
int ct = 0, indent = 0;
assert(dp);
assert(f);
DBG(SCRIPT, ul_debugobj(dp, "writing json dump to file"));
fputs("{\n", f);
fput_indent(indent, f);
fputs("\"partitiontable\": {\n", f);
indent++;
/* script headers */
list_for_each(h, &dp->headers) {
struct fdisk_scriptheader *fi = list_entry(h, struct fdisk_scriptheader, headers);
const char *name = fi->name;
int num = 0;
if (strcmp(name, "first-lba") == 0) {
name = "firstlba";
num = 1;
} else if (strcmp(name, "last-lba") == 0) {
name = "lastlba";
num = 1;
} else if (strcmp(name, "label-id") == 0)
name = "id";
fput_indent(indent, f);
fputs_quoted_lower(name, f);
fputs(": ", f);
if (!num)
fputs_quoted(fi->data, f);
else
fputs(fi->data, f);
if (!dp->table && fi == list_last_entry(&dp->headers, struct fdisk_scriptheader, headers))
fputc('\n', f);
else
fputs(",\n", f);
if (strcmp(name, "device") == 0)
devname = fi->data;
}
if (!dp->table) {
DBG(SCRIPT, ul_debugobj(dp, "script table empty"));
goto done;
}
DBG(SCRIPT, ul_debugobj(dp, "%zu entries", fdisk_table_get_nents(dp->table)));
fput_indent(indent, f);
fputs("\"partitions\": [\n", f);
indent++;
fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
while (fdisk_table_next_partition(dp->table, &itr, &pa) == 0) {
char *p = NULL;
ct++;
fput_indent(indent, f);
fputc('{', f);
if (devname)
p = fdisk_partname(devname, pa->partno + 1);
if (p) {
DBG(SCRIPT, ul_debugobj(dp, "write %s entry", p));
fputs("\"node\": ", f);
fputs_quoted(p, f);
}
if (fdisk_partition_has_start(pa))
fprintf(f, ", \"start\": %ju", pa->start);
if (fdisk_partition_has_size(pa))
fprintf(f, ", \"size\": %ju", pa->size);
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) {
fputs(", \"name\": ", f),
fputs_quoted(pa->name, f);
}
/* for MBR attr=80 means bootable */
if (pa->attrs) {
struct fdisk_label *lb = script_get_label(dp);
if (!lb || fdisk_label_get_type(lb) != FDISK_DISKLABEL_DOS)
fprintf(f, ", \"attrs\": \"%s\"", pa->attrs);
}
if (fdisk_partition_is_bootable(pa))
fprintf(f, ", \"bootable\": true");
if (ct < fdisk_table_get_nents(dp->table))
fputs("},\n", f);
else
fputs("}\n", f);
}
indent--;
fput_indent(indent, f);
fputs("]\n", f);
done:
indent--;
fput_indent(indent, f);
fputs("}\n}\n", f);
DBG(SCRIPT, ul_debugobj(dp, "write script done"));
return 0;
}
static int write_file_sfdisk(struct fdisk_script *dp, FILE *f)
{
struct list_head *h;
struct fdisk_partition *pa;
@ -438,7 +588,7 @@ int fdisk_script_write_file(struct fdisk_script *dp, FILE *f)
assert(dp);
assert(f);
DBG(SCRIPT, ul_debugobj(dp, "writing script to file"));
DBG(SCRIPT, ul_debugobj(dp, "writing sfdisk-like script to file"));
/* script headers */
list_for_each(h, &dp->headers) {
@ -500,6 +650,25 @@ int fdisk_script_write_file(struct fdisk_script *dp, FILE *f)
return 0;
}
/**
* fdisk_script_write_file:
* @dp: script
* @f: output file
*
* Writes script @dp to the ile @f.
*
* Returns: 0 on success, <0 on error.
*/
int fdisk_script_write_file(struct fdisk_script *dp, FILE *f)
{
assert(dp);
if (dp->json)
return write_file_json(dp, f);
return write_file_sfdisk(dp, f);
}
static inline int is_header_line(const char *s)
{
const char *p = strchr(s, ':');