*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <config.h>
#include <libxml/xmlIO.h>
#include <libxml/xmlwriter.h>
+#include <libxml/xpath.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlsave.h>
#include "progname.h"
#include "c-ctype.h"
int echo_keys = 0;
const char *libvirt_uri = NULL;
int inspector = 1;
+static const char *xpath = NULL;
static void output (char **roots);
static void output_roots (xmlTextWriterPtr xo, char **roots);
static void canonicalize (char *dev);
static void free_strings (char **argv);
static int count_strings (char *const*argv);
+static void do_xpath (const char *query);
static inline char *
bad_cast (char const *s)
" -v|--verbose Verbose messages\n"
" -V|--version Display version and exit\n"
" -x Trace libguestfs API calls\n"
+ " --xpath query Perform an XPath query\n"
"For more information, see the manpage %s(1).\n"),
program_name, program_name, program_name,
program_name);
{ "keys-from-stdin", 0, 0, 0 },
{ "verbose", 0, 0, 'v' },
{ "version", 0, 0, 'V' },
+ { "xpath", 1, 0, 0 },
{ 0, 0, 0, 0 }
};
struct drv *drvs = NULL;
format = NULL;
else
format = optarg;
+ } else if (STREQ (long_options[option_index].name, "xpath")) {
+ xpath = optarg;
} else {
fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
program_name, long_options[option_index].name, option_index);
if (optind != argc)
usage (EXIT_FAILURE);
+ /* XPath is modal: no drives should be specified. There must be
+ * one extra parameter on the command line.
+ */
+ if (xpath) {
+ if (drvs != NULL) {
+ fprintf (stderr, _("%s: cannot use --xpath together with other options.\n"),
+ program_name);
+ exit (EXIT_FAILURE);
+ }
+
+ do_xpath (xpath);
+
+ exit (EXIT_SUCCESS);
+ }
+
/* User must have specified some drives. */
if (drvs == NULL)
usage (EXIT_FAILURE);
int i, r;
char buf[32];
char canonical_root[strlen (root) + 1];
+ size_t size;
XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "operatingsystem"));
output_drive_mappings (xo, root);
+ /* We need to mount everything up in order to read out the list of
+ * applications and the icon, ie. everything below this point.
+ */
+ inspect_mount_root (root);
+
output_applications (xo, root);
+ /* Don't return favicon. XXX Should we? */
+ str = guestfs_inspect_get_icon (g, root, &size,
+ GUESTFS_INSPECT_GET_ICON_FAVICON, 0,
+ -1);
+ if (!str) exit (EXIT_FAILURE);
+ if (size > 0) {
+ XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "icon"));
+ XMLERROR (-1, xmlTextWriterWriteBase64 (xo, str, 0, size));
+ XMLERROR (-1, xmlTextWriterEndElement (xo));
+ }
+ /* Note we must free (str) even if size == 0, because that indicates
+ * there was no icon.
+ */
+ free (str);
+
+ /* Unmount (see inspect_mount_root above). */
+ if (guestfs_umount_all (g) == -1)
+ exit (EXIT_FAILURE);
+
XMLERROR (-1, xmlTextWriterEndElement (xo));
}
struct guestfs_application_list *apps;
size_t i;
- /* We need to mount everything up in order to read out the list of
- * applications.
- */
- inspect_mount_root (root);
-
/* This returns an empty list if we simply couldn't determine the
* applications, so if it returns NULL then it's a real error.
*/
apps = guestfs_inspect_list_applications (g, root);
if (apps == NULL)
exit (EXIT_FAILURE);
- if (guestfs_umount_all (g) == -1)
- exit (EXIT_FAILURE);
XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "applications"));
;
return c;
}
+
+/* Run an XPath query on XML on stdin, print results to stdout. */
+static void
+do_xpath (const char *query)
+{
+ xmlDocPtr doc;
+ xmlXPathContextPtr xpathCtx;
+ xmlXPathObjectPtr xpathObj;
+ xmlNodeSetPtr nodes;
+ char *r;
+ size_t i;
+ xmlSaveCtxtPtr saveCtx;
+ xmlDocPtr wrdoc;
+ xmlNodePtr wrnode;
+
+ doc = xmlReadFd (STDIN_FILENO, NULL, "utf8", 0);
+ if (doc == NULL) {
+ fprintf (stderr, _("%s: unable to parse XML from stdin\n"), program_name);
+ exit (EXIT_FAILURE);
+ }
+
+ xpathCtx = xmlXPathNewContext (doc);
+ if (xpathCtx == NULL) {
+ fprintf (stderr, _("%s: unable to create new XPath context\n"),
+ program_name);
+ exit (EXIT_FAILURE);
+ }
+
+ xpathObj = xmlXPathEvalExpression (BAD_CAST query, xpathCtx);
+ if (xpathObj == NULL) {
+ fprintf (stderr, _("%s: unable to evaluate XPath expression\n"),
+ program_name);
+ exit (EXIT_FAILURE);
+ }
+
+ switch (xpathObj->type) {
+ case XPATH_NODESET:
+ nodes = xpathObj->nodesetval;
+
+ saveCtx = xmlSaveToFd (STDOUT_FILENO, NULL, XML_SAVE_NO_DECL);
+ if (saveCtx == NULL) {
+ fprintf (stderr, _("%s: xmlSaveToFd failed\n"), program_name);
+ exit (EXIT_FAILURE);
+ }
+
+ for (i = 0; i < (size_t) nodes->nodeNr; ++i) {
+ wrdoc = xmlNewDoc (BAD_CAST "1.0");
+ if (wrdoc == NULL) {
+ fprintf (stderr, _("%s: xmlNewDoc failed\n"), program_name);
+ exit (EXIT_FAILURE);
+ }
+ wrnode = xmlCopyNode (nodes->nodeTab[i], 1);
+ if (wrnode == NULL) {
+ fprintf (stderr, _("%s: xmlCopyNode failed\n"), program_name);
+ exit (EXIT_FAILURE);
+ }
+
+ xmlDocSetRootElement (wrdoc, wrnode);
+
+ if (xmlSaveDoc (saveCtx, wrdoc) == -1) {
+ fprintf (stderr, _("%s: xmlSaveDoc failed\n"), program_name);
+ exit (EXIT_FAILURE);
+ }
+
+ xmlFreeDoc (wrdoc);
+ }
+
+ xmlSaveClose (saveCtx);
+
+ break;
+
+ case XPATH_STRING:
+ r = (char *) xpathObj->stringval;
+ printf ("%s", r);
+ i = strlen (r);
+ if (i > 0 && r[i-1] != '\n')
+ printf ("\n");
+ break;
+
+ case XPATH_UNDEFINED: /* grrrrr ... switch-enum is a useless warning */
+ case XPATH_BOOLEAN:
+ case XPATH_NUMBER:
+ case XPATH_POINT:
+ case XPATH_RANGE:
+ case XPATH_LOCATIONSET:
+ case XPATH_USERS:
+ case XPATH_XSLT_TREE:
+ default:
+ r = (char *) xmlXPathCastToString (xpathObj);
+ printf ("%s\n", r);
+ free (r);
+ }
+
+ xmlXPathFreeObject (xpathObj);
+ xmlXPathFreeContext (xpathCtx);
+ xmlFreeDoc (doc);
+
+ exit (EXIT_SUCCESS);
+}