summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Gundersen <teg@jklm.no>2014-12-09 12:06:12 +0100
committerTom Gundersen <teg@jklm.no>2014-12-11 13:54:19 +0100
commit167c2c6c530c3c48a0c615e2742cef3150a0f27c (patch)
tree6502192e3bc359e9cde3d3748f19a9951f0241da
parent713a85ef55a336832c17cfe5df752f940c39326d (diff)
sd-device: monitor - request kernel timestamps
-rw-r--r--src/libsystemd/sd-device/device-monitor.c82
-rw-r--r--src/libsystemd/sd-device/device-monitor.h12
2 files changed, 70 insertions, 24 deletions
diff --git a/src/libsystemd/sd-device/device-monitor.c b/src/libsystemd/sd-device/device-monitor.c
index c9e9dff46..f21b9295a 100644
--- a/src/libsystemd/sd-device/device-monitor.c
+++ b/src/libsystemd/sd-device/device-monitor.c
@@ -114,8 +114,9 @@ static int monitor_new(DeviceMonitor **ret) {
return 0;
}
-int device_monitor_new_from_netlink(DeviceMonitor **ret, int fd, sd_event *event, int priority) {
+int device_monitor_new_from_netlink(DeviceMonitor **ret, int fd, sd_event *_event, int priority) {
_cleanup_device_monitor_unref_ DeviceMonitor *monitor = NULL;
+ _cleanup_event_unref_ sd_event *event = NULL;
int r;
assert_return(ret, -EINVAL);
@@ -124,6 +125,14 @@ int device_monitor_new_from_netlink(DeviceMonitor **ret, int fd, sd_event *event
if (r < 0)
return r;
+ if (_event)
+ event = sd_event_ref(_event);
+ else {
+ r = sd_event_default(&event);
+ if (r < 0)
+ return r;
+ }
+
if (fd < 0) {
fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
if (fd < 0)
@@ -136,15 +145,9 @@ int device_monitor_new_from_netlink(DeviceMonitor **ret, int fd, sd_event *event
monitor->snl.nl.nl_family = AF_NETLINK;
monitor->snl.nl.nl_groups = UDEV_MONITOR_KERNEL;
- if (event)
- monitor->event = sd_event_ref(event);
- else {
- r = sd_event_default(&monitor->event);
- if (r < 0)
- return r;
- }
-
monitor->priority = priority;
+ monitor->event = event;
+ event = NULL;
*ret = monitor;
monitor = NULL;
@@ -165,13 +168,15 @@ int device_monitor_set_receive_buffer_size(DeviceMonitor *monitor, int size) {
return 0;
}
-static int monitor_receive_device(DeviceMonitor *monitor, sd_device **ret, uint64_t *seqnum, DeviceAction *action, const char **devpath_old) {
+static int monitor_receive_device(DeviceMonitor *monitor, sd_device **ret,
+ usec_t *_timestamp, uint64_t *seqnum, DeviceAction *action, const char **devpath_old) {
_cleanup_strv_free_ char **properties = NULL;
struct iovec iov = {
.iov_base = monitor->buf,
.iov_len = sizeof(monitor->buf),
};
- char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+ char cred_msg[CMSG_SPACE(sizeof(struct ucred)) +
+ CMSG_SPACE(sizeof(struct timeval))];
union sockaddr_union snl;
struct msghdr smsg = {
.msg_iov = &iov,
@@ -182,7 +187,8 @@ static int monitor_receive_device(DeviceMonitor *monitor, sd_device **ret, uint6
.msg_namelen = sizeof(snl),
};
struct cmsghdr *cmsg;
- struct ucred *cred;
+ struct ucred *ucred;
+ usec_t timestamp = 0;
ssize_t buflen;
size_t bufpos;
int r;
@@ -218,15 +224,37 @@ static int monitor_receive_device(DeviceMonitor *monitor, sd_device **ret, uint6
}
}
- cmsg = CMSG_FIRSTHDR(&smsg);
- if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
+ for (cmsg = CMSG_FIRSTHDR(&smsg); cmsg; cmsg = CMSG_NXTHDR(&smsg, cmsg)) {
+ if (cmsg->cmsg_level != SOL_SOCKET) {
+ log_warning("device-monitor: got unexpected sockopt level");
+ continue;
+ }
+
+ if (cmsg->cmsg_type == SCM_CREDENTIALS) {
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
+ log_warning("device-monitor: wrong ucred size");
+ continue;
+ }
+
+ ucred = (struct ucred*) CMSG_DATA(cmsg);
+ } else if (cmsg->cmsg_type == SO_TIMESTAMP) {
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct timeval))) {
+ log_warning("device-monitor: wrong timeval size");
+ continue;
+ }
+
+ timestamp = timeval_load((struct timeval*)CMSG_DATA(cmsg));
+ } else
+ log_warning("device-monitor: got unexpected sockopt");
+ }
+
+ if (!ucred) {
log_debug("device-monitor: no sender credentials received, message ignored\n");
return 0;
}
- cred = (struct ucred *)CMSG_DATA(cmsg);
- if (cred->uid != 0) {
- log_debug("device-monitor: sender uid=%d, message ignored\n", cred->uid);
+ if (ucred->uid != 0) {
+ log_debug("device-monitor: sender uid=%d, message ignored\n", ucred->uid);
return 0;
}
@@ -247,27 +275,28 @@ static int monitor_receive_device(DeviceMonitor *monitor, sd_device **ret, uint6
if (r < 0)
return r;
+ *_timestamp = timestamp;
+
return 1;
}
static int device_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ DeviceMonitorEvent event = {};
DeviceMonitor *monitor = userdata;
- _cleanup_device_unref_ sd_device *device = NULL;
- uint64_t seqnum;
- DeviceAction action;
- const char *devpath_old = NULL;
int r;
assert(monitor);
- r = monitor_receive_device(monitor, &device, &seqnum, &action, &devpath_old);
+ r = monitor_receive_device(monitor, &event.device, &event.timestamp, &event.seqnum, &event.action, &event.devpath_old);
if (r < 0) {
return 1;
} else if (r == 0)
return 1;
if (monitor->callback)
- monitor->callback(monitor, device, seqnum, action, devpath_old, monitor->userdata);
+ monitor->callback(monitor, &event, monitor->userdata);
+
+ sd_device_unref(event.device);
return 1;
}
@@ -307,6 +336,13 @@ int device_monitor_start(DeviceMonitor *monitor) {
if (r < 0)
return -errno;
+ /* use kernel timestamping for improved debugging */
+ r = setsockopt(monitor->fd, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on));
+ if (r < 0) {
+ log_warning("could not set TIMESTAMP: %m");
+ return -errno;
+ }
+
r = sd_event_add_io(monitor->event, &source, monitor->fd, EPOLLIN, device_handler, monitor);
if (r < 0)
return r;
diff --git a/src/libsystemd/sd-device/device-monitor.h b/src/libsystemd/sd-device/device-monitor.h
index a28a8d732..785daa5a2 100644
--- a/src/libsystemd/sd-device/device-monitor.h
+++ b/src/libsystemd/sd-device/device-monitor.h
@@ -38,7 +38,17 @@ typedef enum DeviceAction {
_DEVICE_ACTION_INVALID = -1,
} DeviceAction;
-typedef void (*device_monitor_cb_t)(DeviceMonitor *monitor, sd_device *device, uint64_t seqnum, DeviceAction action, const char *devpath_old, void *userdata);
+typedef struct DeviceMonitorEvent {
+ sd_device *device;
+
+ DeviceAction action;
+ uint64_t seqnum;
+ const char *devpath_old;
+
+ usec_t timestamp;
+} DeviceMonitorEvent;
+
+typedef void (*device_monitor_cb_t)(DeviceMonitor *monitor, DeviceMonitorEvent *event, void *userdata);
DeviceMonitor *device_monitor_ref(DeviceMonitor *monitor);
DeviceMonitor *device_monitor_unref(DeviceMonitor *monitor);