lkml.org 
[lkml]   [2009]   [Mar]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Date
Subject[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,
jiffies since boot, and jiffies 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@cox.net>
---
Documentation/time-device.txt | 49 ++++++++++++++++++
arch/um/Kconfig.char | 11 ++++
drivers/char/Kconfig | 11 ++++
drivers/char/Makefile | 2 +
drivers/char/devtime.c | 112 +++++++++++++++++++++++++++++++++++++++++
5 files changed, 185 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..6294732
--- /dev/null
+++ b/Documentation/time-device.txt
@@ -0,0 +1,49 @@
+/dev/time for Linux
+===================
+
+Christopher M. Brannon <cmbrannon@cox.net>
+
+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,
+jiffies since boot, and jiffies per second.
+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..5e4ca66
--- /dev/null
+++ b/drivers/char/devtime.c
@@ -0,0 +1,112 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/time.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+
+MODULE_AUTHOR("Christopher Brannon <cmbrannon79@gmail.com>");
+MODULE_LICENSE("GPL");
+
+const long long NS_PER_SEC = 1000000000;
+const long long NS_PER_USEC = 1000;
+const size_t 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 timeval tv;
+ long long nanos;
+
+/* jiffies isn't 0 at boot time; its value is INITIAL_JIFFIES. */
+ u64 ticks = get_jiffies_64() - INITIAL_JIFFIES;
+
+ do_gettimeofday(&tv);
+ nanos = tv.tv_sec * NS_PER_SEC + tv.tv_usec * NS_PER_USEC;
+ count =
+ scnprintf(buffer, bufsize, "%ld %lld %llu %d\n", tv.tv_sec, nanos,
+ ticks, HZ);
+ return count;
+}
+
+static int text2time(char *buffer)
+{
+ struct timespec tv;
+ int result = strict_strtol(buffer, 10, &tv.tv_sec);
+ if ((result == 0) && (tv.tv_sec > 0)) {
+ tv.tv_nsec = 0;
+ do_settimeofday(&tv);
+ } 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.1.3


\
 
 \ /
  Last update: 2009-03-04 05:31    [W:2.541 / U:0.096 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site