diff options
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | libudev/docs/libudev-sections.txt | 1 | ||||
-rw-r--r-- | libudev/exported_symbols | 1 | ||||
-rw-r--r-- | libudev/libudev-device-private.c | 2 | ||||
-rw-r--r-- | libudev/libudev-device.c | 44 | ||||
-rw-r--r-- | libudev/libudev-private.h | 3 | ||||
-rw-r--r-- | libudev/libudev-util.c | 13 | ||||
-rw-r--r-- | libudev/libudev.h | 1 | ||||
-rw-r--r-- | libudev/libudev.pc.in | 2 | ||||
-rw-r--r-- | udev/udev-event.c | 7 |
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); |