Skip to content

Commit b25b2ca

Browse files
author
David Sommerseth
committed
Implemented native libxml2 XML API for dmidecode
To use this API, you need to import dmidecodeXML. This is a wrapper class for the internal XML API which has been implemented. In addition, you might also want to import libxml2 as well. dmidecodeXML::QuerySection(<string>) Valid section strings can be found in the pymap.xml file, in the <GroupMapping> tag section. dmidecodeXML::TypeId(<integer between 0-255>) Valid values should match the DMI/SMBIOS specification. dmidecodeXML::SetResultType(resultType) Result type can be either dmidecodeXML.DMIXML_NODE or dmidecodeXML.DMIXML_DOC ---------------------------------------------------------- import libxml2 import dmidecodeXML dmixml = dmidecodeXML.dmidecodeXML() section_nodes = dmixml.QuerySection('processor') dmixml.SetResultType(dmidecodeXML.DMIXML_DOC) typeid_doc = dmixml.QueryTypeId(0x10) dmixml.SetResultType(dmidecodeXML.DMIXML_NODE) typeid_doc.saveFormatFileEnc("-", "UTF-8", 1) ----------------------------------------------------------
1 parent b6d42c7 commit b25b2ca

3 files changed

Lines changed: 180 additions & 16 deletions

File tree

src/dmidecodeXML.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import libxml2
2+
import dmidecode
3+
4+
DMIXML_NODE='n'
5+
DMIXML_DOC='d'
6+
7+
class dmidecodeXML:
8+
"Native Python API for retrieving dmidecode information as XML"
9+
10+
def __init__(self):
11+
self.restype = DMIXML_NODE;
12+
13+
def SetResultType(self, type):
14+
"""
15+
Sets the result type of queries. The value can be DMIXML_NODE or DMIXML_DOC,
16+
which will return an libxml2::xmlNode or libxml2::xmlDoc object, respectively
17+
"""
18+
19+
if type == DMIXML_NODE:
20+
self.restype = DMIXML_NODE
21+
elif type == DMIXML_DOC:
22+
self.restype = DMIXML_DOC
23+
else:
24+
raise TypeError, "Invalid result type value"
25+
return True
26+
27+
def QuerySection(self, sectname):
28+
"""
29+
Queries the DMI data structure for a given section name. A section
30+
can often contain several DMI type elements
31+
"""
32+
if self.restype == DMIXML_NODE:
33+
ret = libxml2.xmlNode( _obj = dmidecode.xmlapi(query_type='s',
34+
result_type=self.restype,
35+
section=sectname) )
36+
elif self.restype == DMIXML_DOC:
37+
ret = libxml2.xmlDoc( _obj = dmidecode.xmlapi(query_type='s',
38+
result_type=self.restype,
39+
section=sectname) )
40+
else:
41+
raise TypeError, "Invalid result type value"
42+
43+
return ret
44+
45+
46+
def QueryTypeId(self, tpid):
47+
"""
48+
Queries the DMI data structure for a specific DMI type.
49+
"""
50+
if self.restype == DMIXML_NODE:
51+
ret = libxml2.xmlNode( _obj = dmidecode.xmlapi(query_type='t',
52+
result_type=self.restype,
53+
typeid=tpid))
54+
elif self.restype == DMIXML_DOC:
55+
ret = libxml2.xmlDoc( _obj = dmidecode.xmlapi(query_type='t',
56+
result_type=self.restype,
57+
typeid=tpid))
58+
else:
59+
raise TypeError, "Invalid result type value"
60+
61+
return ret
62+

src/dmidecodemodule.c

Lines changed: 116 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include <Python.h>
4343

4444
#include <libxml/tree.h>
45+
#include "libxml_wrap.h"
4546

4647
#include "xmlpythonizer.h"
4748
#include "dmidecodemodule.h"
@@ -245,18 +246,9 @@ xmlNode* load_mappingxml(options *opt) {
245246
return dmiMAP_GetRootElement(opt->mappingxml);
246247
}
247248

248-
static PyObject *dmidecode_get_group(options *opt, const char *section)
249-
{
250-
PyObject *pydata = NULL;
249+
xmlNode *__dmidecode_xml_getsection(options *opt, const char *section) {
251250
xmlNode *dmixml_n = NULL;
252251
xmlNode *group_n = NULL;
253-
ptzMAP *mapping = NULL;
254-
255-
/* Set default option values */
256-
if( opt->devmem == NULL ) {
257-
opt->devmem = DEFAULT_MEM_DEV;
258-
}
259-
opt->flags = 0;
260252

261253
dmixml_n = xmlNewNode(NULL, (xmlChar *) "dmidecode");
262254
assert( dmixml_n != NULL );
@@ -319,6 +311,27 @@ static PyObject *dmidecode_get_group(options *opt, const char *section)
319311
xmlSaveFormatFileEnc("-", doc, "UTF-8", 1);
320312
xmlFreeDoc(doc);
321313
#endif
314+
return dmixml_n;
315+
}
316+
317+
static PyObject *dmidecode_get_group(options *opt, const char *section)
318+
{
319+
PyObject *pydata = NULL;
320+
xmlNode *dmixml_n = NULL;
321+
ptzMAP *mapping = NULL;
322+
323+
/* Set default option values */
324+
if( opt->devmem == NULL ) {
325+
opt->devmem = DEFAULT_MEM_DEV;
326+
}
327+
opt->flags = 0;
328+
329+
// Decode the dmidata into an XML node
330+
dmixml_n = __dmidecode_xml_getsection(opt, section);
331+
if( dmixml_n == NULL ) {
332+
// Exception already set
333+
return NULL;
334+
}
322335

323336
// Convert the retrieved XML nodes to a Python dictionary
324337
mapping = dmiMAP_ParseMappingXML_GroupName(opt->mappingxml, section);
@@ -339,11 +352,9 @@ static PyObject *dmidecode_get_group(options *opt, const char *section)
339352
}
340353

341354

342-
static PyObject *dmidecode_get_typeid(options *opt, int typeid)
355+
xmlNode *__dmidecode_xml_gettypeid(options *opt, int typeid)
343356
{
344-
PyObject *pydata = NULL;
345357
xmlNode *dmixml_n = NULL;
346-
ptzMAP *mapping = NULL;
347358

348359
/* Set default option values */
349360
if( opt->devmem == NULL ) {
@@ -369,6 +380,22 @@ static PyObject *dmidecode_get_typeid(options *opt, int typeid)
369380
PyReturnError(PyExc_RuntimeError, "Error decoding DMI data");
370381
}
371382

383+
return dmixml_n;
384+
}
385+
386+
387+
static PyObject *dmidecode_get_typeid(options *opt, int typeid)
388+
{
389+
PyObject *pydata = NULL;
390+
xmlNode *dmixml_n = NULL;
391+
ptzMAP *mapping = NULL;
392+
393+
dmixml_n = __dmidecode_xml_gettypeid(opt, typeid);
394+
if( dmixml_n == NULL ) {
395+
// Exception already set
396+
return NULL;
397+
}
398+
372399
// Convert the retrieved XML nodes to a Python dictionary
373400
mapping = dmiMAP_ParseMappingXML_TypeID(opt->mappingxml, opt->type);
374401
if( mapping == NULL ) {
@@ -448,6 +475,77 @@ static PyObject *dmidecode_get_type(PyObject * self, PyObject * args)
448475
return pydata;
449476
}
450477

478+
static PyObject *dmidecode_xmlapi(PyObject *self, PyObject *args, PyObject *keywds)
479+
{
480+
static char *keywordlist[] = {"query_type", "result_type", "section", "typeid"};
481+
PyObject *pydata = NULL;
482+
xmlDoc *dmixml_doc = NULL;
483+
xmlNode *dmixml_n = NULL;
484+
char *sect_query = NULL, *qtype = NULL, *rtype = NULL;
485+
int type_query = -1;
486+
487+
// Parse the keywords - we only support keywords, as this is an internal API
488+
if( !PyArg_ParseTupleAndKeywords(args, keywds, "ss|si", keywordlist,
489+
&qtype, &rtype, &sect_query, &type_query) ) {
490+
return NULL;
491+
}
492+
493+
// Check for sensible arguments and retrieve the xmlNode with DMI data
494+
switch( *qtype ) {
495+
case 's': // Section / GroupName
496+
if( sect_query == NULL ) {
497+
PyReturnError(PyExc_TypeError, "section keyword cannot be NULL")
498+
}
499+
dmixml_n = __dmidecode_xml_getsection(global_options, sect_query);
500+
break;
501+
502+
case 't': // TypeID / direct TypeMap
503+
if( type_query < 0 ) {
504+
PyReturnError(PyExc_TypeError,
505+
"typeid keyword must be set and must be a positive integer");
506+
} else if( type_query > 255 ) {
507+
PyReturnError(PyExc_ValueError,
508+
"typeid keyword must be an integer between 0 and 255");
509+
}
510+
dmixml_n = __dmidecode_xml_gettypeid(global_options, type_query);
511+
break;
512+
513+
default:
514+
PyReturnError(PyExc_TypeError, "Internal error - invalid query type '%c'", *qtype);
515+
}
516+
517+
// Check if we got any data
518+
if( dmixml_n == NULL ) {
519+
// Exception already set
520+
return NULL;
521+
}
522+
523+
// Check for sensible return type and wrap the correct type into a Python Object
524+
switch( *rtype ) {
525+
case 'n':
526+
pydata = libxml_xmlNodePtrWrap((xmlNode *) dmixml_n);
527+
break;
528+
529+
case 'd':
530+
dmixml_doc = xmlNewDoc((xmlChar *) "1.0");
531+
if( dmixml_doc == NULL ) {
532+
PyReturnError(PyExc_MemoryError, "Could not create new XML document");
533+
}
534+
xmlDocSetRootElement(dmixml_doc, dmixml_n);
535+
pydata = libxml_xmlDocPtrWrap((xmlDoc *) dmixml_doc);
536+
break;
537+
538+
default:
539+
PyReturnError(PyExc_TypeError, "Internal error - invalid result type '%c'", *rtype);
540+
}
541+
542+
// Return XML data
543+
Py_INCREF(pydata);
544+
return pydata;
545+
}
546+
547+
548+
451549
static PyObject *dmidecode_dump(PyObject * self, PyObject * null)
452550
{
453551
const char *f;
@@ -544,10 +642,14 @@ static PyMethodDef DMIDataMethods[] = {
544642
{(char *)"pythonmap", dmidecode_set_pythonxmlmap, METH_O,
545643
(char *) "Use another python dict map definition. The default file is " PYTHON_XML_MAP},
546644

645+
{(char *)"xmlapi", dmidecode_xmlapi, METH_KEYWORDS,
646+
(char *) "Internal API for retrieving data as raw XML data"},
647+
547648
{NULL, NULL, 0, NULL}
548649
};
549650

550-
void destruct_options(void *ptr) {
651+
void destruct_options(void *ptr)
652+
{
551653
options *opt = (options *) ptr;
552654

553655
if( opt->mappingxml != NULL ) {

src/setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
"src/xmlpythonizer.c"
2323
],
2424
include_dirs = [ "/usr/include/libxml2" ],
25-
library_dirs = [ "/home/nima/dev-room/projects/dmidecode" ],
26-
libraries = [ "util", "xml2" ]
25+
library_dirs = [ "/home/nima/dev-room/projects/dmidecode", "/usr/lib64/python2.5/site-packages"],
26+
libraries = [ "util", "xml2", "xml2mod" ]
2727
)
2828
]
2929
)

0 commit comments

Comments
 (0)