summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--libudev/docs/libudev-sections.txt1
-rw-r--r--libudev/exported_symbols1
-rw-r--r--libudev/libudev-device-private.c2
-rw-r--r--libudev/libudev-device.c44
-rw-r--r--libudev/libudev-private.h3
-rw-r--r--libudev/libudev-util.c13
-rw-r--r--libudev/libudev.h1
-rw-r--r--libudev/libudev.pc.in2
-rw-r--r--udev/udev-event.c7
10 files changed, 74 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac
index e82b9b8e99..7fda8bba47 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,6 +12,8 @@ GTK_DOC_CHECK(1.10)
AC_PREFIX_DEFAULT([/usr])
AC_PATH_PROG([XSLTPROC], [xsltproc])
+AC_SEARCH_LIBS([clock_gettime], [rt], [], [AC_MSG_ERROR([POSIX RT library not found])])
+
AC_ARG_WITH([rootlibdir],
AS_HELP_STRING([--with-rootlibdir=DIR], [rootfs directory to install shared libraries]),
[], [with_rootlibdir=$libdir])
diff --git a/libudev/docs/libudev-sections.txt b/libudev/docs/libudev-sections.txt
index 05647768fb..7db9c1bba9 100644
--- a/libudev/docs/libudev-sections.txt
+++ b/libudev/docs/libudev-sections.txt
@@ -55,6 +55,7 @@ udev_device_get_devnum
udev_device_get_action
udev_device_get_sysattr_value
udev_device_get_seqnum
+udev_device_get_usec_since_initialized
</SECTION>
<SECTION>
diff --git a/libudev/exported_symbols b/libudev/exported_symbols
index 9e77fb1be1..2e6a9b7dc0 100644
--- a/libudev/exported_symbols
+++ b/libudev/exported_symbols
@@ -37,6 +37,7 @@ udev_device_get_action
udev_device_get_driver
udev_device_get_devnum
udev_device_get_seqnum
+udev_device_get_usec_since_initialized
udev_device_get_sysattr_value
udev_enumerate_new
udev_enumerate_ref
diff --git a/libudev/libudev-device-private.c b/libudev/libudev-device-private.c
index 36824a7478..3afa82e04f 100644
--- a/libudev/libudev-device-private.c
+++ b/libudev/libudev-device-private.c
@@ -147,6 +147,8 @@ int udev_device_update_db(struct udev_device *udev_device)
fprintf(f, "L:%i\n", udev_device_get_devlink_priority(udev_device));
if (udev_device_get_watch_handle(udev_device) >= 0)
fprintf(f, "W:%i\n", udev_device_get_watch_handle(udev_device));
+ if (udev_device_get_usec_initialized(udev_device) > 0)
+ fprintf(f, "I:%llu\n", udev_device_get_usec_initialized(udev_device));
udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) {
if (!udev_list_entry_get_flags(list_entry))
continue;
diff --git a/libudev/libudev-device.c b/libudev/libudev-device.c
index 66f806316f..16bee19dff 100644
--- a/libudev/libudev-device.c
+++ b/libudev/libudev-device.c
@@ -63,6 +63,7 @@ struct udev_device {
struct udev_list_node sysattr_list;
struct udev_list_node tags_list;
unsigned long long int seqnum;
+ unsigned long long int usec_initialized;
int event_timeout;
int timeout;
int devlink_priority;
@@ -284,6 +285,9 @@ int udev_device_read_db(struct udev_device *udev_device)
case 'W':
udev_device_set_watch_handle(udev_device, atoi(val));
break;
+ case 'I':
+ udev_device_set_usec_initialized(udev_device, strtoull(val, NULL, 10));
+ break;
}
}
fclose(f);
@@ -1095,6 +1099,44 @@ unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device)
}
/**
+ * udev_device_get_usec_since_initialized:
+ * @udev_device: udev device
+ *
+ * Return the number of microseconds passed since udev set up the
+ * device for the first time.
+ *
+ * This is only implemented for devices with need to store properties
+ * in the udev database. All other devices return 0 here.
+ *
+ * Returns: the number of microseconds since the device was first seen.
+ **/
+unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device)
+{
+ unsigned long long now;
+
+ if (udev_device == NULL)
+ return 0;
+ if (!udev_device->info_loaded)
+ udev_device_read_db(udev_device);
+ if (udev_device->usec_initialized == 0)
+ return 0;
+ now = usec_monotonic();
+ if (now == 0)
+ return 0;
+ return now - udev_device->usec_initialized;
+}
+
+unsigned long long udev_device_get_usec_initialized(struct udev_device *udev_device)
+{
+ return udev_device->usec_initialized;
+}
+
+void udev_device_set_usec_initialized(struct udev_device *udev_device, unsigned long long usec_initialized)
+{
+ udev_device->usec_initialized = usec_initialized;
+}
+
+/**
* udev_device_get_sysattr_value:
* @udev_device: udev device
* @sysattr: attribute name
@@ -1318,7 +1360,7 @@ const char *udev_device_get_id_filename(struct udev_device *udev_device)
* device node permissions and context, or has renamed a network
* device.
*
- * For now, this is only implemented for devices with a device node
+ * This is only implemented for devices with a device node
* or network interfaces. All other devices return 1 here.
*
* Returns: 1 if the device is set up. 0 otherwise.
diff --git a/libudev/libudev-private.h b/libudev/libudev-private.h
index f7b4f90519..f95be53df7 100644
--- a/libudev/libudev-private.h
+++ b/libudev/libudev-private.h
@@ -98,6 +98,8 @@ int udev_device_get_event_timeout(struct udev_device *udev_device);
int udev_device_set_event_timeout(struct udev_device *udev_device, int event_timeout);
int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum);
int udev_device_set_seqnum(struct udev_device *udev_device, unsigned long long int seqnum);
+unsigned long long udev_device_get_usec_initialized(struct udev_device *udev_device);
+void udev_device_set_usec_initialized(struct udev_device *udev_device, unsigned long long usec_initialized);
int udev_device_get_devlink_priority(struct udev_device *udev_device);
int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio);
int udev_device_get_watch_handle(struct udev_device *udev_device);
@@ -224,6 +226,7 @@ int util_run_program(struct udev *udev, const char *command, char **envp,
const sigset_t *sigmask, bool reset_prio);
int util_resolve_subsys_kernel(struct udev *udev, const char *string,
char *result, size_t maxsize, int read_value);
+unsigned long long usec_monotonic(void);
/* libudev-selinux-private.c */
#ifndef WITH_SELINUX
diff --git a/libudev/libudev-util.c b/libudev/libudev-util.c
index 6c309afd05..51dd017467 100644
--- a/libudev/libudev-util.c
+++ b/libudev/libudev-util.c
@@ -18,6 +18,7 @@
#include <dirent.h>
#include <ctype.h>
#include <fcntl.h>
+#include <time.h>
#include <sys/stat.h>
#include "libudev.h"
@@ -553,3 +554,15 @@ uint64_t util_string_bloom64(const char *str)
bits |= 1LLU << ((hash >> 18) & 63);
return bits;
}
+
+#define USEC_PER_SEC 1000000ULL
+#define NSEC_PER_USEC 1000ULL
+unsigned long long usec_monotonic(void)
+{
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
+ return 0;
+ return (unsigned long long) ts.tv_sec * USEC_PER_SEC +
+ (unsigned long long) ts.tv_nsec / NSEC_PER_USEC;
+}
diff --git a/libudev/libudev.h b/libudev/libudev.h
index 087991caf4..0abd7c8b0e 100644
--- a/libudev/libudev.h
+++ b/libudev/libudev.h
@@ -97,6 +97,7 @@ const char *udev_device_get_driver(struct udev_device *udev_device);
dev_t udev_device_get_devnum(struct udev_device *udev_device);
const char *udev_device_get_action(struct udev_device *udev_device);
unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device);
+unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device);
const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr);
/*
diff --git a/libudev/libudev.pc.in b/libudev/libudev.pc.in
index 677d53a97e..f75794ceb8 100644
--- a/libudev/libudev.pc.in
+++ b/libudev/libudev.pc.in
@@ -6,6 +6,6 @@ includedir=@prefix@/include
Name: libudev
Description: Library to access udev device information
Version: @VERSION@
-Libs: -L${libdir} -ludev
+Libs: -L${libdir} -ludev -lrt
Libs.private:
Cflags: -I${includedir}
diff --git a/udev/udev-event.c b/udev/udev-event.c
index 4d38c5b893..100a79c1e8 100644
--- a/udev/udev-event.c
+++ b/udev/udev-event.c
@@ -643,6 +643,13 @@ int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules)
err = udev_node_add(dev, event->mode, event->uid, event->gid);
}
+ /* preserve old, or get new initialization timestamp */
+ if (event->dev_db != NULL && udev_device_get_usec_initialized(event->dev_db) > 0)
+ udev_device_set_usec_initialized(event->dev, udev_device_get_usec_initialized(event->dev_db));
+ else
+ udev_device_set_usec_initialized(event->dev, usec_monotonic());
+
+ /* (re)write database file */
udev_device_update_db(dev);
udev_device_tag_index(dev, event->dev_db, true);
udev_device_set_is_initialized(dev);