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 <[email protected]>
---
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 <[email protected]>
+
+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 <[email protected]>");
+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
Hi Christopher,
2009/3/11 Christopher Brannon <[email protected]>:
> +/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.
> [...]
> +Examples
> +--------
> +cat /dev/time
> +# Produces: 1236121128 123612012877063000 495497 300,
> +# at time of writing on a test machine.
The last two numbers in the example seem suspicous to me. 300
nanoseconds per second?
I hope this helps,
Jochen
--
http://seehuhn.de/
Christopher Brannon ([email protected]) said:
> 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.
Given the general array of current interfaces in the kernel, isn't
read/write of textual parameters better suited to sysfs or procfs
than a character device?
Bill
Bill Nottingham wrote:
> Given the general array of current interfaces in the kernel, isn't
> read/write of textual parameters better suited to sysfs or procfs
> than a character device?
Procfs and Sysfs are used to control devices. Dev is used to access
them. Dev is the right place to fetch and set the time; having a text
interface is beside the point.
Christopher Brannon wrote:
> 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
> +===================
I would like to see this documentation also as time(4) manpage.
So maybe you can already format it in man/mdoc format.
ciao
cate
On Thu, Mar 12, 2009 at 4:00 AM, David Newall <[email protected]> wrote:
> Bill Nottingham wrote:
>> Given the general array of current interfaces in the kernel, isn't
>> read/write of textual parameters better suited to sysfs or procfs
>> than a character device?
>
> Procfs and Sysfs are used to control devices. ?Dev is used to access
> them. ?Dev is the right place to fetch and set the time; having a text
> interface is beside the point.
I also think we're aiming for compatibility with Plan 9 here, which
keeps this file in /dev
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at ?http://www.tux.org/lkml/
>
On Wed 2009-03-11 10:10:23, Christopher Brannon wrote:
> 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
nanoseconds per second?! Just use 123.456 notation.
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
On Sat, Mar 14, 2009 at 12:13 PM, Pavel Machek <[email protected]> wrote:
> On Wed 2009-03-11 10:10:23, Christopher Brannon wrote:
>> 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
>
> nanoseconds per second?! Just use 123.456 notation.
The point is to be close to Plan 9's interface, in which column 3 is
"something since boot" and column 4 is "somethings per second" to keep
programs portable.
>
> --
> (english) http://www.livejournal.com/~pavelmachek
> (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at ?http://www.tux.org/lkml/
>
On Tue 2009-03-17 11:15:09, J.R. Mauro wrote:
> On Sat, Mar 14, 2009 at 12:13 PM, Pavel Machek <[email protected]> wrote:
> > On Wed 2009-03-11 10:10:23, Christopher Brannon wrote:
> >> 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
> >
> > nanoseconds per second?! Just use 123.456 notation.
>
> The point is to be close to Plan 9's interface, in which column 3 is
> "something since boot" and column 4 is "somethings per second" to keep
> programs portable.
I don't think compatibility with Plan9 is worthy goal... especially
when Plan9's interface is unneccessarily ugly.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html