Skip to content

Commit

Permalink
Include udev properties in emulated netlink messages
Browse files Browse the repository at this point in the history
Current systemd by and large does not read the /uevent file any more,
but entirely relies on udevd sending the properties in the udev netlink
events.

Pass the properties to uevent_sender_send(), massage them from a
newline separated (as in our uevent file) to a nul separated (as
expected by the udev netlink message) array. In Testbed.uevent(), read
the current properties from the /uevent file.

This is all rather hackish right now and cries for a more thorough
rewrite. But this is a relatively unintrusive and quick bandaid which
helps users for the time being.

Test this both with the libudev and with the gudev (through Python) APIs.

Fixes martinpitt#164
  • Loading branch information
martinpitt committed Jan 18, 2022
1 parent 14875e8 commit b781cf6
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 7 deletions.
16 changes: 15 additions & 1 deletion src/uevent_sender.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ append_property(char *array, size_t size, size_t offset, const char *name, const
/* this mirrors the code from systemd/src/libsystemd/sd-device/device-monitor.c,
* device_monitor_send_device() */
void
uevent_sender_send(uevent_sender * sender, const char *devpath, const char *action)
uevent_sender_send(uevent_sender * sender, const char *devpath, const char *action, const char *properties)
{
char buffer[1024];
size_t buffer_len = 0;
Expand Down Expand Up @@ -261,6 +261,20 @@ uevent_sender_send(uevent_sender * sender, const char *devpath, const char *acti
if (devtype)
buffer_len += append_property(buffer, sizeof buffer, buffer_len, "DEVTYPE=", devtype);

/* append udevd (userland) properties, replace \n with \0 */
/* FIXME: more sensible API */
size_t properties_len = properties ? strlen(properties) : 0;
if (properties_len > 0) {
size_t prop_ofs = buffer_len;
buffer_len += append_property(buffer, sizeof buffer, buffer_len, properties, "");
for (size_t i = prop_ofs; i < buffer_len - 1; ++i)
if (buffer[i] == '\n')
buffer[i] = '\0';
/* avoid empty property at the end from final line break */
if (properties[strlen(properties) - 1] == '\n')
--buffer_len;
}

/* add versioned header */
memset(&nlh, 0x00, sizeof(struct udev_monitor_netlink_header));
memcpy(nlh.prefix, "libudev", 8);
Expand Down
2 changes: 1 addition & 1 deletion src/uevent_sender.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ typedef struct _uevent_sender uevent_sender;

uevent_sender *uevent_sender_open(const char *rootpath);
void uevent_sender_close(uevent_sender * sender);
void uevent_sender_send(uevent_sender * sender, const char *devpath, const char *action);
void uevent_sender_send(uevent_sender * sender, const char *devpath, const char *action, const char *properties);

#endif /* __UEVENT_SENDER_H */
2 changes: 1 addition & 1 deletion src/uevent_sender.vapi
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ namespace UeventSender {
public class sender {
[CCode (cname="uevent_sender_open")]
public sender (string rootpath);
public void send (string devpath, string action);
public void send (string devpath, string action, string properties);
}
}
10 changes: 9 additions & 1 deletion src/umockdev.vala
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,15 @@ public class Testbed: GLib.Object {
assert(this.ev_sender != null);
}
debug("umockdev_testbed_uevent: sending uevent %s for device %s", action, devpath);
this.ev_sender.send(devpath, action);

var uevent_path = Path.build_filename(this.root_dir, devpath, "uevent");
var properties = "";
try {
FileUtils.get_contents(uevent_path, out properties);
} catch (FileError e) {
debug("uevent: devpath %s has no uevent file: %s", devpath, e.message);
}
this.ev_sender.send(devpath, action, properties);
}

/**
Expand Down
4 changes: 4 additions & 0 deletions tests/test-umockdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -614,12 +614,16 @@ t_testbed_uevent_libudev(UMockdevTestbedFixture * fixture, UNUSED_DATA)
g_assert(device != NULL);
g_assert_cmpstr(udev_device_get_syspath(device), ==, syspath);
g_assert_cmpstr(udev_device_get_action(device), ==, "add");
g_assert_cmpstr(udev_device_get_sysattr_value(device, "idVendor"), ==, "0815");
g_assert_cmpstr(udev_device_get_property_value(device, "ID_INPUT"), ==, "1");
udev_device_unref(device);

device = udev_monitor_receive_device(kernel_mon);
g_assert(device != NULL);
g_assert_cmpstr(udev_device_get_syspath(device), ==, syspath);
g_assert_cmpstr(udev_device_get_action(device), ==, "add");
g_assert_cmpstr(udev_device_get_sysattr_value(device, "idVendor"), ==, "0815");
g_assert_cmpstr(udev_device_get_property_value(device, "ID_INPUT"), ==, "1");
udev_device_unref(device);

udev_monitor_unref(udev_mon);
Expand Down
13 changes: 10 additions & 3 deletions tests/test-umockdev.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def test_set_property(self):
def test_uevent(self):
'''testbed uevent()'''

counter = [0, 0, 0, None] # add, remove, change, last device
counter = [0, 0, 0, None, None, None] # add, remove, change, last device, idVendor, ID_INPUT

def on_uevent(client, action, device, counters):
if action == 'add':
Expand All @@ -138,9 +138,13 @@ def on_uevent(client, action, device, counters):
counters[1] += 1
else:
assert action == 'change'
self.assertEqual(device.get_sysfs_attr('idVendor'), '0815')
self.assertEqual(device.get_property('ID_INPUT'), '1')
counters[2] += 1

counters[3] = device.get_sysfs_path()
counters[4] = device.get_sysfs_attr('idVendor')
counters[5] = device.get_property('ID_INPUT')

syspath = self.testbed.add_device('pci', 'mydev', None, ['idVendor', '0815'], ['ID_INPUT', '1'])
self.assertNotEqual(syspath, None)
Expand All @@ -155,14 +159,17 @@ def on_uevent(client, action, device, counters):
self.testbed.uevent(syspath, 'add')
GLib.timeout_add(500, mainloop.quit)
mainloop.run()
self.assertEqual(counter, [1, 0, 0, syspath])
self.assertEqual(counter, [1, 0, 0, syspath, '0815', '1'])

counter[0] = 0
counter[3] = None
counter[4] = None
counter[5] = None

self.testbed.uevent(syspath, 'change')
GLib.timeout_add(500, mainloop.quit)
mainloop.run()
self.assertEqual(counter, [0, 0, 1, syspath])
self.assertEqual(counter, [0, 0, 1, syspath, '0815', '1'])

def test_add_from_string(self):
self.assertTrue(self.testbed.add_from_string ('''P: /devices/dev1
Expand Down

0 comments on commit b781cf6

Please sign in to comment.