Skip to content

Commit e445d9f

Browse files
Andy Groverstratakis
authored andcommitted
python3: use tp_getset instead of tp_{get,set}attro
In testing, I was experiencing segfaults when _ethtool_etherinfo_getter() was being called with a NULL attr_o param. In trying to get it working I converted to tp_getset, and everything's working now. Signed-off-by: Andy Grover <agrover@redhat.com>
1 parent 340038f commit e445d9f

File tree

1 file changed

+83
-84
lines changed

1 file changed

+83
-84
lines changed

python-ethtool/etherinfo_obj.c

Lines changed: 83 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -77,88 +77,6 @@ static PyNetlinkIPaddress * get_last_ipv4_address(PyObject *addrlist)
7777
return NULL;
7878
}
7979

80-
/**
81-
* ethtool.etherinfo function for retrieving data from a Python object.
82-
*
83-
* @param self Pointer to the current PyEtherInfo device object
84-
* @param attr_o contains the object member request (which element to return)
85-
*
86-
* @return Returns a PyObject with the value requested on success, otherwise NULL
87-
*/
88-
PyObject *_ethtool_etherinfo_getter(PyEtherInfo *self, PyObject *attr_o)
89-
{
90-
char *attr = PyBytes_AsString(attr_o);
91-
PyNetlinkIPaddress *py_addr;
92-
PyObject *addrlist = NULL;
93-
94-
if( !self ) {
95-
PyErr_SetString(PyExc_AttributeError, "No data available");
96-
return NULL;
97-
}
98-
99-
if( strcmp(attr, "device") == 0 ) {
100-
if( self->device ) {
101-
Py_INCREF(self->device);
102-
return self->device;
103-
} else {
104-
return Py_INCREF(Py_None), Py_None;
105-
}
106-
} else if( strcmp(attr, "mac_address") == 0 ) {
107-
get_etherinfo_link(self);
108-
if( self->hwaddress ) {
109-
Py_INCREF(self->hwaddress);
110-
}
111-
return self->hwaddress;
112-
} else if( strcmp(attr, "ipv4_address") == 0 ) {
113-
addrlist = get_etherinfo_address(self, NLQRY_ADDR4);
114-
/* For compatiblity with old approach, return last IPv4 address: */
115-
py_addr = get_last_ipv4_address(addrlist);
116-
if (py_addr) {
117-
if (py_addr->local) {
118-
Py_INCREF(py_addr->local);
119-
return py_addr->local;
120-
}
121-
}
122-
Py_RETURN_NONE;
123-
} else if( strcmp(attr, "ipv4_netmask") == 0 ) {
124-
addrlist = get_etherinfo_address(self, NLQRY_ADDR4);
125-
py_addr = get_last_ipv4_address(addrlist);
126-
if (py_addr) {
127-
return PyLong_FromLong(py_addr->prefixlen);
128-
}
129-
return PyLong_FromLong(0);
130-
} else if( strcmp(attr, "ipv4_broadcast") == 0 ) {
131-
addrlist = get_etherinfo_address(self, NLQRY_ADDR4);
132-
py_addr = get_last_ipv4_address(addrlist);
133-
if (py_addr) {
134-
if (py_addr->ipv4_broadcast) {
135-
Py_INCREF(py_addr->ipv4_broadcast);
136-
return py_addr->ipv4_broadcast;
137-
}
138-
}
139-
Py_RETURN_NONE;
140-
} else {
141-
return PyObject_GenericGetAttr((PyObject *)self, attr_o);
142-
}
143-
}
144-
145-
/**
146-
* ethtool.etherinfo function for setting a value to a object member. This feature is
147-
* disabled by always returning -1, as the values are read-only by the user.
148-
*
149-
* @param self
150-
* @param attr_o
151-
* @param val_o
152-
*
153-
* @return Returns always -1 (failure).
154-
*/
155-
int _ethtool_etherinfo_setter(PyEtherInfo *self, PyObject *attr_o, PyObject *val_o)
156-
{
157-
PyErr_SetString(PyExc_AttributeError, "etherinfo member values are read-only.");
158-
return -1;
159-
}
160-
161-
16280
/**
16381
* Creates a human readable format of the information when object is being treated as a string
16482
*
@@ -272,6 +190,88 @@ static PyMethodDef _ethtool_etherinfo_methods[] = {
272190
{NULL} /**< No methods defined */
273191
};
274192

193+
static PyObject *get_device(PyObject *obj, void *info)
194+
{
195+
PyEtherInfo *self = (PyEtherInfo *) obj;
196+
197+
if( self->device ) {
198+
Py_INCREF(self->device);
199+
return self->device;
200+
}
201+
Py_RETURN_NONE;
202+
}
203+
204+
static PyObject *get_mac_addr(PyObject *obj, void *info)
205+
{
206+
PyEtherInfo *self = (PyEtherInfo *) obj;
207+
208+
get_etherinfo_link(self);
209+
if( self->hwaddress ) {
210+
Py_INCREF(self->hwaddress);
211+
}
212+
return self->hwaddress;
213+
}
214+
215+
static PyObject *get_ipv4_addr(PyObject *obj, void *info)
216+
{
217+
PyEtherInfo *self = (PyEtherInfo *) obj;
218+
PyObject *addrlist;
219+
PyNetlinkIPaddress *py_addr;
220+
221+
addrlist = get_etherinfo_address(self, NLQRY_ADDR4);
222+
/* For compatiblity with old approach, return last IPv4 address: */
223+
py_addr = get_last_ipv4_address(addrlist);
224+
if (py_addr) {
225+
if (py_addr->local) {
226+
Py_INCREF(py_addr->local);
227+
return py_addr->local;
228+
}
229+
}
230+
Py_RETURN_NONE;
231+
}
232+
233+
static PyObject *get_ipv4_mask(PyObject *obj, void *info)
234+
{
235+
PyEtherInfo *self = (PyEtherInfo *) obj;
236+
PyObject *addrlist;
237+
PyNetlinkIPaddress *py_addr;
238+
239+
addrlist = get_etherinfo_address(self, NLQRY_ADDR4);
240+
py_addr = get_last_ipv4_address(addrlist);
241+
if (py_addr) {
242+
return PyLong_FromLong(py_addr->prefixlen);
243+
}
244+
return PyLong_FromLong(0);
245+
}
246+
247+
static PyObject *get_ipv4_bcast(PyObject *obj, void *info)
248+
{
249+
PyEtherInfo *self = (PyEtherInfo *) obj;
250+
PyObject *addrlist;
251+
PyNetlinkIPaddress *py_addr;
252+
253+
addrlist = get_etherinfo_address(self, NLQRY_ADDR4);
254+
py_addr = get_last_ipv4_address(addrlist);
255+
if (py_addr) {
256+
if (py_addr->ipv4_broadcast) {
257+
Py_INCREF(py_addr->ipv4_broadcast);
258+
return py_addr->ipv4_broadcast;
259+
}
260+
}
261+
Py_RETURN_NONE;
262+
}
263+
264+
265+
static PyGetSetDef _ethtool_etherinfo_attributes[] = {
266+
{"device", get_device, NULL, "device", NULL},
267+
{"mac_address", get_mac_addr, NULL, "MAC address", NULL},
268+
{"ipv4_address", get_ipv4_addr, NULL, "IPv4 address", NULL},
269+
{"ipv4_netmask", get_ipv4_mask, NULL, "IPv4 netmask", NULL},
270+
{"ipv4_broadcast", get_ipv4_bcast, NULL, "IPv4 broadcast", NULL},
271+
{NULL},
272+
};
273+
274+
275275
/**
276276
* Definition of the functions a Python class/object requires.
277277
*
@@ -283,8 +283,7 @@ PyTypeObject PyEtherInfo_Type = {
283283
.tp_flags = Py_TPFLAGS_DEFAULT,
284284
.tp_dealloc = (destructor)_ethtool_etherinfo_dealloc,
285285
.tp_str = (reprfunc)_ethtool_etherinfo_str,
286-
.tp_getattro = (getattrofunc)_ethtool_etherinfo_getter,
287-
.tp_setattro = (setattrofunc)_ethtool_etherinfo_setter,
286+
.tp_getset = _ethtool_etherinfo_attributes,
288287
.tp_methods = _ethtool_etherinfo_methods,
289288
.tp_doc = "Contains information about a specific ethernet device"
290289
};

0 commit comments

Comments
 (0)