diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-10-18 21:51:20 +0100 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-10-18 22:11:53 +0100 |
commit | a3598aa257f6f08e8067621ccdbc68c0270e02f9 (patch) | |
tree | 5ba8e7937852964ec9a5fa615c1827c8f0e45cbb /src/dbdump.c | |
parent | 019b840e4758ccd254925181f6fbaf3192c7bde1 (diff) | |
download | libguestfs-a3598aa257f6f08e8067621ccdbc68c0270e02f9.tar.gz libguestfs-a3598aa257f6f08e8067621ccdbc68c0270e02f9.tar.xz libguestfs-a3598aa257f6f08e8067621ccdbc68c0270e02f9.zip |
inspect: Use command mini-library to parse the output of db_dump command.
Diffstat (limited to 'src/dbdump.c')
-rw-r--r-- | src/dbdump.c | 181 |
1 files changed, 103 insertions, 78 deletions
diff --git a/src/dbdump.c b/src/dbdump.c index 201fa6e4..6c9d7a70 100644 --- a/src/dbdump.c +++ b/src/dbdump.c @@ -39,111 +39,136 @@ #if defined(DB_DUMP) +static void read_db_dump_line (guestfs_h *g, void *datav, const char *line, size_t len); static unsigned char *convert_hex_to_binary (guestfs_h *g, const char *hex, size_t hexlen, size_t *binlen_rtn); +struct cb_data { + guestfs___db_dump_callback callback; + void *opaque; + enum { reading_header, + reading_key, reading_value, + reading_finished, + reading_failed } state; + unsigned char *key; + size_t keylen; +}; + /* This helper function is specialized to just reading the hash-format * output from db_dump/db4_dump. It's just enough to support the RPM - * database format. Note that the filename must not contain any shell - * characters (this is guaranteed by the caller). + * database format. */ int guestfs___read_db_dump (guestfs_h *g, const char *dumpfile, void *opaque, guestfs___db_dump_callback callback) { -#define cmd_len (strlen (dumpfile) + 64) - char cmd[cmd_len]; - FILE *pp = NULL; - char *line = NULL; - size_t len = 0; - ssize_t linelen; - unsigned char *key = NULL, *value = NULL; - size_t keylen, valuelen; - int ret = -1; - - snprintf (cmd, cmd_len, DB_DUMP " -k '%s'", dumpfile); - - debug (g, "read_db_dump command: %s", cmd); - - pp = popen (cmd, "r"); - if (pp == NULL) { - perrorf (g, "popen: %s", cmd); - goto out; - } + struct cb_data data; + struct command *cmd; + int r; - /* Ignore everything to end-of-header marker. */ - while ((linelen = getline (&line, &len, pp)) != -1) { - if (STRPREFIX (line, "HEADER=END")) - break; - } + data.callback = callback; + data.opaque = opaque; + data.state = reading_header; + data.key = NULL; + + cmd = guestfs___new_command (g); + guestfs___cmd_add_arg (cmd, DB_DUMP); + guestfs___cmd_add_arg (cmd, "-k"); + guestfs___cmd_add_arg (cmd, dumpfile); + guestfs___cmd_set_stdout_callback (cmd, read_db_dump_line, &data, 0); + + r = guestfs___cmd_run (cmd); + guestfs___cmd_close (cmd); + free (data.key); - if (linelen == -1) { - error (g, _("unexpected end of output from db_dump command before end of header")); - goto out; + if (r == -1) + return -1; + if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) { + error (g, _("%s: command failed"), DB_DUMP); + return -1; + } + if (data.state != reading_finished) { + error (g, _("%s: unexpected error or end of output"), DB_DUMP); + return -1; } - /* Now read the key, value pairs. They are prefixed with a space and - * printed as hex strings, so convert those strings to binary. Pass - * the strings up to the callback function. - */ - while ((linelen = getline (&line, &len, pp)) != -1) { - if (STRPREFIX (line, "DATA=END")) - break; - - if (linelen < 1 || line[0] != ' ') { - error (g, _("unexpected line from db_dump command, no space prefix")); - goto out; - } + return 0; +} - if ((key = convert_hex_to_binary (g, &line[1], linelen-1, - &keylen)) == NULL) - goto out; +static void +read_db_dump_line (guestfs_h *g, void *datav, const char *line, size_t len) +{ + struct cb_data *data = datav; + unsigned char *value; + size_t valuelen; - if ((linelen = getline (&line, &len, pp)) == -1) - break; + switch (data->state) { + case reading_finished: + case reading_failed: + return; - if (linelen < 1 || line[0] != ' ') { - error (g, _("unexpected line from db_dump command, no space prefix")); - goto out; + case reading_header: + /* Ignore everything to end-of-header marker. */ + if (STRPREFIX (line, "HEADER=END")) + data->state = reading_key; + return; + + /* Read the key, value pairs using a state machine. They are + * prefixed with a space and printed as hex strings, so convert + * those strings to binary. Pass the strings up to the callback + * function. + */ + case reading_key: + if (STRPREFIX (line, "DATA=END")) { + data->state = reading_finished; + return; } - if ((value = convert_hex_to_binary (g, &line[1], linelen-1, - &valuelen)) == NULL) - goto out; + if (len < 1 || line[0] != ' ') { + debug (g, _("unexpected line from db_dump command, no space prefix")); + data->state = reading_failed; + return; + } - if (callback (g, key, keylen, value, valuelen, opaque) == -1) - goto out; + data->key = convert_hex_to_binary (g, &line[1], len-1, &data->keylen); + if (data->key == NULL) { + data->state = reading_failed; + return; + } - free (key); - free (value); - key = value = NULL; - } + data->state = reading_value; + return; - if (linelen == -1) { - error (g, _("unexpected end of output from db_dump command before end of data")); - goto out; - } + case reading_value: + if (len < 1 || line[0] != ' ') { + debug (g, _("unexpected line from db_dump command, no space prefix")); + data->state = reading_failed; + return; + } - /* Catch errors from the db_dump command. */ - if (pclose (pp) != 0) { - perrorf (g, "pclose: %s", cmd); - pp = NULL; - goto out; - } - pp = NULL; + value = convert_hex_to_binary (g, &line[1], len-1, &valuelen); + if (value == NULL) { + data->state = reading_failed; + return; + } - ret = 0; + if (data->callback (g, data->key, data->keylen, + value, valuelen, data->opaque) == -1) { + data->state = reading_failed; + return; + } - out: - if (pp) - pclose (pp); + free (data->key); + data->key = NULL; + free (value); + value = NULL; - free (line); - free (key); - free (value); + data->state = reading_key; + return; - return ret; -#undef cmd_len + default: + abort (); + } } static int |