libudev: record and export "age" of device record
authorKay Sievers <kay.sievers@vrfy.org>
Wed, 15 Dec 2010 07:57:46 +0000 (08:57 +0100)
committerKay Sievers <kay.sievers@vrfy.org>
Wed, 15 Dec 2010 07:58:46 +0000 (08:58 +0100)
configure.ac
libudev/docs/libudev-sections.txt
libudev/exported_symbols
libudev/libudev-device-private.c
libudev/libudev-device.c
libudev/libudev-private.h
libudev/libudev-util.c
libudev/libudev.h
libudev/libudev.pc.in
udev/udev-event.c

index e82b9b8..7fda8bb 100644 (file)
@@ -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])
index 0564776..7db9c1b 100644 (file)
@@ -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>
index 9e77fb1..2e6a9b7 100644 (file)
@@ -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
index 36824a7..3afa82e 100644 (file)
@@ -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;
index 66f8063..16bee19 100644 (file)
@@ -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.
index f7b4f90..f95be53 100644 (file)
@@ -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
index 6c309af..51dd017 100644 (file)
@@ -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;
+}
index 087991c..0abd7c8 100644 (file)
@@ -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);
 
 /*
index 677d53a..f75794c 100644 (file)
@@ -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}
index 4d38c5b..100a79c 100644 (file)
@@ -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);