chiark / gitweb /
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 e82b9b8e9974dfa88c370c2136739665d2008143..7fda8bba47b6217b7c91aab7b4bdaa7e1a551965 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 05647768fbd596d071e9f0990d2aa78028a86bf0..7db9c1bba953353258b7d3696dd9ccd59926eff8 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 9e77fb1be10ae8a936be220d88f5461d979ce0f4..2e6a9b7dc0a4da5dac4c01849b603a2bfcead49a 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 36824a747859896be19e3123351b37027b9b5229..3afa82e04f40b3869caf0afbb2a82daa93c71267 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 66f806316f55d75143f4d7a2e2242f99bcad805b..16bee19dff4cca9463aab0b24e44fd593d1d12e0 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);
@@ -1094,6 +1098,44 @@ unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device)
        return udev_device->seqnum;
 }
 
+/**
+ * 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
@@ -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 f7b4f90519ce4a352cbe861fc9084ea557f49522..f95be53df7e4561ddcb9f5d47e6a32c875c3542f 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 6c309afd0536798fe3a1e81dffb2b68d4bb7a591..51dd017467c6ea577825ceee35ceb1663d31cf0c 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 087991caf46144cb8c5e6ce69ae30dd7ad15d38b..0abd7c8b0e3dfbc22b26cb9ec59c65fd95fdf2de 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 677d53a97e6058f06b6f535a215d4f2628eb80c7..f75794ceb83b289c3bc020560679a595aeb84663 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 4d38c5b893effab649237417b044f8e17c6b1c76..100a79c1e84e1435b0c11fa8e29dbcc44f86217d 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);