Remove dependency on xml-light, replace with libxml2
[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/xpath.h>
32 #include <libxml/xpathInternals.h>
33
34 /* xpathobj contains a list of dev attributes, return the list
35  * as an OCaml array of strings.
36  */
37 static value
38 get_devs (xmlDocPtr doc, xmlXPathObjectPtr xpathobj)
39 {
40   CAMLparam0 ();
41   CAMLlocal2 (rv, nodev);
42   const xmlNodeSetPtr nodes = xpathobj->nodesetval;
43   size_t i, nr_nodes;
44   xmlNodePtr node;
45   char *str;
46   xmlAttrPtr attr;
47
48   if (nodes == NULL || nodes->nodeNr == 0)
49     rv = caml_alloc (0, 0);
50   else {
51     /* Count the nodes that contain data. */
52     nr_nodes = 0;
53     for (i = 0; i < nodes->nodeNr; ++i) {
54       node = nodes->nodeTab[i];
55       if (node->type != XML_ATTRIBUTE_NODE)
56         continue;
57       nr_nodes++;
58     }
59
60     rv = caml_alloc (nr_nodes, 0);
61     nr_nodes = 0;
62     for (i = 0; i < nodes->nodeNr; ++i) {
63       node = nodes->nodeTab[i];
64       if (node->type != XML_ATTRIBUTE_NODE)
65         continue;
66       attr = (xmlAttrPtr) node;
67       str = (char *) xmlNodeListGetString (doc, attr->children, 1);
68       nodev = caml_copy_string (str);
69       free (str);
70       Store_field (rv, nr_nodes, nodev);
71       nr_nodes++;
72     }
73   }
74
75   CAMLreturn (rv);
76 }
77
78 /* external get_blk_net_devs : string -> string array * string array */
79 value
80 get_blk_net_devs (value xmlv)
81 {
82   CAMLparam1 (xmlv);
83   CAMLlocal3 (rv, blkdevs, netifs);
84   xmlDocPtr doc;
85   xmlXPathContextPtr xpathctx;
86   xmlXPathObjectPtr xpathobj;
87   const char *expr;
88
89   /* For security reasons, call xmlReadMemory (not xmlParseMemory) and
90    * pass XML_PARSE_NONET.
91    */
92   doc = xmlReadMemory (String_val (xmlv), caml_string_length (xmlv),
93                        NULL, NULL, XML_PARSE_NONET);
94   if (doc == NULL)
95     caml_invalid_argument ("xmlReadMemory: unable to parse XML");
96
97   xpathctx = xmlXPathNewContext (doc);
98   if (xpathctx == NULL)
99     caml_invalid_argument ("xmlXPathNewContext: unable to create new context");
100
101   expr = "//devices/disk/target/@dev";
102   xpathobj = xmlXPathEvalExpression (BAD_CAST expr, xpathctx);
103   if (xpathobj == NULL)
104     caml_invalid_argument (expr);
105
106   blkdevs = get_devs (doc, xpathobj);
107   xmlXPathFreeObject (xpathobj);
108
109   expr = "//devices/interface/target/@dev";
110   xpathobj = xmlXPathEvalExpression (BAD_CAST expr, xpathctx);
111   if (xpathobj == NULL)
112     caml_invalid_argument (expr);
113
114   netifs = get_devs (doc, xpathobj);
115   xmlXPathFreeObject (xpathobj);
116
117   xmlXPathFreeContext (xpathctx);
118   xmlFreeDoc (doc);
119
120   rv = caml_alloc (2, 0);
121   Store_field (rv, 0, blkdevs);
122   Store_field (rv, 1, netifs);
123   CAMLreturn (rv);
124 }