src: Include <libxml/parser.h>
[virt-top.git] / src / xml-c.c
1 /* 'top'-like tool for libvirt domains.
2    (C) Copyright 2007-2021 Richard W.M. Jones, Red Hat Inc.
3    http://libvirt.org/
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <caml/alloc.h>
27 #include <caml/fail.h>
28 #include <caml/memory.h>
29 #include <caml/mlvalues.h>
30
31 #include <libxml/parser.h>
32 #include <libxml/xpath.h>
33 #include <libxml/xpathInternals.h>
34
35 /* xpathobj contains a list of dev attributes, return the list
36  * as an OCaml array of strings.
37  */
38 static value
39 get_devs (xmlDocPtr doc, xmlXPathObjectPtr xpathobj)
40 {
41   CAMLparam0 ();
42   CAMLlocal2 (rv, nodev);
43   const xmlNodeSetPtr nodes = xpathobj->nodesetval;
44   size_t i, nr_nodes;
45   xmlNodePtr node;
46   char *str;
47   xmlAttrPtr attr;
48
49   if (nodes == NULL || nodes->nodeNr == 0)
50     rv = caml_alloc (0, 0);
51   else {
52     /* Count the nodes that contain data. */
53     nr_nodes = 0;
54     for (i = 0; i < nodes->nodeNr; ++i) {
55       node = nodes->nodeTab[i];
56       if (node->type != XML_ATTRIBUTE_NODE)
57         continue;
58       nr_nodes++;
59     }
60
61     rv = caml_alloc (nr_nodes, 0);
62     nr_nodes = 0;
63     for (i = 0; i < nodes->nodeNr; ++i) {
64       node = nodes->nodeTab[i];
65       if (node->type != XML_ATTRIBUTE_NODE)
66         continue;
67       attr = (xmlAttrPtr) node;
68       str = (char *) xmlNodeListGetString (doc, attr->children, 1);
69       nodev = caml_copy_string (str);
70       free (str);
71       Store_field (rv, nr_nodes, nodev);
72       nr_nodes++;
73     }
74   }
75
76   CAMLreturn (rv);
77 }
78
79 /* external get_blk_net_devs : string -> string array * string array */
80 value
81 get_blk_net_devs (value xmlv)
82 {
83   CAMLparam1 (xmlv);
84   CAMLlocal3 (rv, blkdevs, netifs);
85   xmlDocPtr doc;
86   xmlXPathContextPtr xpathctx;
87   xmlXPathObjectPtr xpathobj;
88   const char *expr;
89
90   /* For security reasons, call xmlReadMemory (not xmlParseMemory) and
91    * pass XML_PARSE_NONET.
92    */
93   doc = xmlReadMemory (String_val (xmlv), caml_string_length (xmlv),
94                        NULL, NULL, XML_PARSE_NONET);
95   if (doc == NULL)
96     caml_invalid_argument ("xmlReadMemory: unable to parse XML");
97
98   xpathctx = xmlXPathNewContext (doc);
99   if (xpathctx == NULL)
100     caml_invalid_argument ("xmlXPathNewContext: unable to create new context");
101
102   expr = "//devices/disk/target/@dev";
103   xpathobj = xmlXPathEvalExpression (BAD_CAST expr, xpathctx);
104   if (xpathobj == NULL)
105     caml_invalid_argument (expr);
106
107   blkdevs = get_devs (doc, xpathobj);
108   xmlXPathFreeObject (xpathobj);
109
110   expr = "//devices/interface/target/@dev";
111   xpathobj = xmlXPathEvalExpression (BAD_CAST expr, xpathctx);
112   if (xpathobj == NULL)
113     caml_invalid_argument (expr);
114
115   netifs = get_devs (doc, xpathobj);
116   xmlXPathFreeObject (xpathobj);
117
118   xmlXPathFreeContext (xpathctx);
119   xmlFreeDoc (doc);
120
121   rv = caml_alloc (2, 0);
122   Store_field (rv, 0, blkdevs);
123   Store_field (rv, 1, netifs);
124   CAMLreturn (rv);
125 }