[PATCH] /dev/time for Linux, inspired by Plan 9



Under Plan 9 from Bell Labs, one queries or sets the system clock by
reading or writing text strings to a special file named /dev/time.
I implemented such a facility for Linux. A read of /dev/time produces
four decimal numbers: epoch seconds, nanoseconds since start of epoch,
nanoseconds since boot, and nanoseconds per second. Writing a decimal number
to /dev/time sets the system clock to the given number of epoch seconds.
Anyone who is permitted to write to /dev/time may set the clock.
Granting this privilege becomes as easy as modifying groups and file
permissions.

Signed-off-by: Christopher Brannon <cmbrannon@xxxxxxx>
---
Documentation/time-device.txt | 51 +++++++++++++++++
arch/um/Kconfig.char | 11 ++++
drivers/char/Kconfig | 11 ++++
drivers/char/Makefile | 2 +
drivers/char/devtime.c | 124 +++++++++++++++++++++++++++++++++++++++++
5 files changed, 199 insertions(+), 0 deletions(-)
create mode 100644 Documentation/time-device.txt
create mode 100644 drivers/char/devtime.c

diff --git a/Documentation/time-device.txt b/Documentation/time-device.txt
new file mode 100644
index 0000000..c3145a0
--- /dev/null
+++ b/Documentation/time-device.txt
@@ -0,0 +1,51 @@
+/dev/time for Linux
+===================
+
+Christopher M. Brannon <cmbrannon@xxxxxxx>
+
+Inspiration
+-----------
+This document describes an implementation for the Linux kernel of a facility
+that is provided by the Plan 9 operating system from Bell Laboratories [1].
+
+Functionality
+-------------
+/dev/time provides a file-based interface to the system clock.
+Using this interface, one can query or set the system clock by reading or
+writing text strings. A read of /dev/time yields four decimal integers:
+seconds since start of epoch, nanoseconds since start of epoch,
+nanoseconds since boot, and nanoseconds per second.
+The fourth value is redundant; it is kept in order to be faithful to the
+original interface.
+Writing a decimal number n to /dev/time sets the system clock to the
+date and time which is n seconds greater than January 1, 1970, 00:00:00 GMT.
+
+Examples
+--------
+cat /dev/time
+# Produces: 1236121128 123612012877063000 495497 300,
+# at time of writing on a test machine.
+echo 287604960 > /dev/time
+# sets the clock to the approximate time of my birth.
+
+Use Case
+--------
+Traditionally, super-user privileges were required in order to set the
+system clock under Linux.
+Since the advent of capabilities, any process having the CAP_SYS_TIME
+capability may perform this operation.
+The /dev/time device ties privileges to file permissions. If a user
+can write to /dev/time, then he can set the system clock.
+
+Difference from Plan 9
+-----------------------
+This implementation differs from Plan 9 in one respect. the Plan 9
+Programmer's Manual exactly specifies the format of data read from the
+device, including the widths of the four numeric fields [1]. This Linux
+implementation does not pad values with whitespace, so the four fields
+are of variable width.
+
+References
+----------
+[1] Plan 9 Programmers Manual, section 3.
+http://plan9.bell-labs.com/magic/man2html/3/cons
diff --git a/arch/um/Kconfig.char b/arch/um/Kconfig.char
index 70dabd1..7d0da78 100644
--- a/arch/um/Kconfig.char
+++ b/arch/um/Kconfig.char
@@ -236,4 +236,15 @@ config MMAPPER
This driver allows a host file to be used as emulated IO memory inside
UML.

+config DEVTIME
+ tristate "/dev/time virtual device support."
+ depends on EXPERIMENTAL
+ help
+ This device provides a file-based interface to the system clock.
+ The interface is based on the /dev/time device used in the
+ Plan 9 operating system from Bell Labs.
+ See <file:Documentation/time-device.txt> for a full description.
+ To compile this driver as a module, choose M here: the
+ module will be called devtime.
+
endmenu
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 735bbe2..5bad918 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -97,6 +97,17 @@ config DEVKMEM
kind of kernel debugging operations.
When in doubt, say "N".

+config DEVTIME
+ tristate "/dev/time virtual device support."
+ depends on EXPERIMENTAL
+ help
+ This device provides a file-based interface to the system clock.
+ The interface is based on the /dev/time device used in the
+ Plan 9 operating system from Bell Labs.
+ See <file:Documentation/time-device.txt> for a full description.
+ To compile this driver as a module, choose M here: the
+ module will be called devtime.
+
config SERIAL_NONSTANDARD
bool "Non-standard serial port support"
depends on HAS_IOMEM
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 9caf5b5..aba7403 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -111,6 +111,8 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o
obj-$(CONFIG_JS_RTC) += js-rtc.o
js-rtc-y = rtc.o

+obj-$(CONFIG_DEVTIME) += devtime.o
+
# Files generated that shall be removed upon make clean
clean-files := consolemap_deftbl.c defkeymap.c

diff --git a/drivers/char/devtime.c b/drivers/char/devtime.c
new file mode 100644
index 0000000..0349ea8
--- /dev/null
+++ b/drivers/char/devtime.c
@@ -0,0 +1,124 @@
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/ktime.h>
+#include <linux/time.h>
+#include <linux/uaccess.h>
+
+MODULE_AUTHOR("Christopher Brannon <cmbrannon79@xxxxxxxxx>");
+MODULE_LICENSE("GPL");
+
+#define NS_PER_SEC 1000000000
+#define TIME_BUFSIZE 256
+
+static ssize_t time_read(struct file *, char __user *, size_t, loff_t *);
+static ssize_t time_write(struct file *, const char __user *, size_t,
+ loff_t *);
+
+static const struct file_operations time_fops = {
+ .owner = THIS_MODULE,
+ .read = time_read,
+ .write = time_write,
+};
+
+static struct miscdevice timedev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "time",
+ .fops = &time_fops
+};
+
+static int time2text(char *buffer, size_t bufsize)
+{
+ int count = 0;
+ struct timespec abs_time;
+ struct timespec boot_time;
+ s64 abs_nanos; /* nanoseconds since epoch */
+ s64 boot_nanos; /* nanoseconds since boot */
+
+ getnstimeofday(&abs_time);
+
+ /*
+ * The next two lines calculate uptime and store it in boot_time.
+ * Taken from fs/proc/uptime.c.
+ */
+ do_posix_clock_monotonic_gettime(&boot_time);
+ monotonic_to_bootbased(&boot_time);
+
+ /* Convert both time structs to nanoseconds. */
+ boot_nanos = timespec_to_ns(&boot_time);
+ abs_nanos = timespec_to_ns(&abs_time);
+
+ count =
+ scnprintf(buffer, bufsize, "%ld %lld %lld %d\n", abs_time.tv_sec,
+ abs_nanos, boot_nanos, NS_PER_SEC);
+
+ return count;
+}
+
+static int text2time(char *buffer)
+{
+ struct timespec ts;
+ int result = strict_strtol(buffer, 10, &ts.tv_sec);
+ if ((result == 0) && (ts.tv_sec > 0)) {
+ ts.tv_nsec = 0;
+ do_settimeofday(&ts);
+ } else
+ result = -EINVAL; /* only positive longs are valid. */
+ return result;
+}
+
+static ssize_t
+time_read(struct file *f, char __user * buffer, size_t count, loff_t *offset)
+{
+ int result = 0;
+ if (*offset != 0)
+ result = 0;
+ else {
+ char tmpbuf[TIME_BUFSIZE];
+ int timetextlen = time2text(tmpbuf, TIME_BUFSIZE);
+ unsigned long readcount = min(count, (size_t) timetextlen);
+ if (timetextlen <= 0)
+ return -EAGAIN;
+ if (!copy_to_user(buffer, tmpbuf, readcount)) {
+ *offset += readcount;
+ result = readcount;
+ } else
+ result = -EFAULT;
+ }
+ return result;
+}
+
+static ssize_t
+time_write(struct file *f, const char __user * buffer, size_t count,
+ loff_t *offset)
+{
+ unsigned int result = 0;
+ char tmpbuf[TIME_BUFSIZE];
+
+ if (*offset != 0)
+ return -EINVAL;
+ if (count > ((size_t) TIME_BUFSIZE - 1))
+ return -EINVAL; /* Likely trying to feed bogus data anyway. */
+ result = copy_from_user(tmpbuf, buffer, count);
+ if (result)
+ return -EFAULT;
+ tmpbuf[count] = '\0';
+ if (text2time(tmpbuf))
+ return -EINVAL;
+ return count;
+}
+
+static int __init time_init(void)
+{
+ return misc_register(&timedev);
+}
+
+static void __exit time_exit(void)
+{
+ misc_deregister(&timedev);
+}
+
+module_init(time_init);
+module_exit(time_exit);
--
1.6.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



Relevant Pages

  • Re: [PATCH] /dev/time for Linux, inspired by Plan 9
    ... reading or writing text strings to a special file named /dev/time. ... epoch seconds, nanoseconds since start of epoch, ... nanoseconds since boot, and nanoseconds per second. ... to /dev/time sets the system clock to the given number of epoch seconds. ...
    (Linux-Kernel)
  • [PATCH] /dev/time for Linux, inspired by Plan 9
    ... reading or writing text strings to a special file named /dev/time. ... epoch seconds, nanoseconds since start of epoch, ... /dev/time sets the system clock to the given number of epoch seconds. ... +that is provided by the Plan 9 operating system from Bell Laboratories. ...
    (Linux-Kernel)
  • Re: HowTo calibrate system clock frequency using NTP
    ... increased by about half a second per day (measured with Plan B). ... (Or calibrating them on a test ... While the system on the test bench, I wanted to measure the time drift in order to calibrate the system clock. ...
    (comp.protocols.time.ntp)
  • Re: [PATCH] i386: Selectable Frequency of the Timer Interrupt
    ... Con Kolivas wrote: ... >>fact is that all the timeouts we ever get from user space aren't in that ... today the jiffie is 999849 nanoseconds) and this too is only accurate ... signals it gives and the system clock you would see the itimer drifting by ...
    (Linux-Kernel)
  • Re: Read System Clock in Windows
    ... Moikel said: ... I'm writing a program that requires that I generate random numbers. ... I want to use the system clock as a seed ... rjh at above domain ...
    (comp.lang.c)