Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/Makefile	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -71,8 +71,11 @@
 	generic/device/hw_res_parsed.c \
 	generic/device/char_dev.c \
+	generic/device/clock_dev.c \
+	generic/device/battery_dev.c \
 	generic/device/graph_dev.c \
 	generic/device/nic.c \
 	generic/device/pci.c \
 	generic/device/ahci.c \
+	generic/dlfcn.c \
 	generic/elf/elf_load.c \
 	generic/event.c \
@@ -101,4 +104,5 @@
 	generic/io/printf.c \
 	generic/io/log.c \
+	generic/io/logctl.c \
 	generic/io/klog.c \
 	generic/io/snprintf.c \
@@ -106,4 +110,5 @@
 	generic/io/vsnprintf.c \
 	generic/io/printf_core.c \
+	generic/io/con_srv.c \
 	generic/io/console.c \
 	generic/io/visualizer.c \
@@ -111,4 +116,7 @@
 	generic/iplink.c \
 	generic/iplink_srv.c \
+	generic/ieee_double.c \
+	generic/power_of_ten.c \
+	generic/double_to_str.c \
 	generic/malloc.c \
 	generic/sysinfo.c \
@@ -140,5 +148,4 @@
 ifeq ($(CONFIG_RTLD),y)
 	GENERIC_SOURCES += \
-		generic/dlfcn.c \
 		generic/rtld/rtld.c \
 		generic/rtld/dynamic.c \
Index: uspace/lib/c/arch/abs32le/_link.ld.in
===================================================================
--- uspace/lib/c/arch/abs32le/_link.ld.in	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/abs32le/_link.ld.in	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.text : {
@@ -30,4 +23,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/abs32le/include/types.h
===================================================================
--- uspace/lib/c/arch/abs32le/include/types.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/abs32le/include/types.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -47,4 +47,5 @@
 
 typedef uint32_t sysarg_t;
+typedef int32_t native_t;
 
 typedef int32_t ssize_t;
Index: uspace/lib/c/arch/amd64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/amd64/_link.ld.in	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/amd64/_link.ld.in	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -16,14 +16,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -35,4 +28,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/amd64/include/types.h
===================================================================
--- uspace/lib/c/arch/amd64/include/types.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/amd64/include/types.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -47,4 +47,5 @@
 
 typedef uint64_t sysarg_t;
+typedef int64_t native_t;
 
 typedef int64_t ssize_t;
Index: uspace/lib/c/arch/arm32/Makefile.common
===================================================================
--- uspace/lib/c/arch/arm32/Makefile.common	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/arm32/Makefile.common	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -28,5 +28,6 @@
 #
 
-GCC_CFLAGS += -ffixed-r9 -mtp=soft -fno-omit-frame-pointer -march=armv4
+BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
+GCC_CFLAGS += -ffixed-r9 -mtp=soft -fno-omit-frame-pointer -march=armv4 -mapcs-frame
 
 ENDIANESS = LE
Index: uspace/lib/c/arch/arm32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/arm32/_link.ld.in	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/arm32/_link.ld.in	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 8);
 	
 	.init : {
@@ -34,4 +27,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/arm32/include/types.h
===================================================================
--- uspace/lib/c/arch/arm32/include/types.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/arm32/include/types.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -48,4 +48,5 @@
 
 typedef uint32_t sysarg_t;
+typedef int32_t native_t;
 
 typedef int32_t ssize_t;
Index: uspace/lib/c/arch/ia32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia32/_link.ld.in	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/ia32/_link.ld.in	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -24,13 +24,4 @@
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-#if defined(LOADER) || defined(DLEXE)
-	.interp : {
-		*(.interp);
-	} :interp :text
-#endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -71,4 +62,11 @@
 	} :text
 #endif
+	
+#if defined(LOADER) || defined(DLEXE)
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
+	
 	. = . + 0x1000;
 	
Index: uspace/lib/c/arch/ia32/include/types.h
===================================================================
--- uspace/lib/c/arch/ia32/include/types.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/ia32/include/types.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -47,4 +47,5 @@
 
 typedef uint32_t sysarg_t;
+typedef int32_t native_t;
 
 typedef int32_t ssize_t;
Index: uspace/lib/c/arch/ia64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia64/_link.ld.in	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/ia64/_link.ld.in	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -15,13 +15,9 @@
 #ifdef LOADER
 	. = 0x800000000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
 	
-	/* Make sure the code is aligned reasonably */
+	/* Workaround proper alignment of the .init section */
 	. = ALIGN(., 16);
 	
@@ -34,4 +30,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/arch/ia64/include/types.h
===================================================================
--- uspace/lib/c/arch/ia64/include/types.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/ia64/include/types.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -57,4 +57,5 @@
 
 typedef uint64_t sysarg_t;
+typedef int64_t native_t;
 
 typedef int64_t ssize_t;
Index: uspace/lib/c/arch/mips32/Makefile.common
===================================================================
--- uspace/lib/c/arch/mips32/Makefile.common	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/mips32/Makefile.common	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -28,4 +28,5 @@
 
 GCC_CFLAGS += -msoft-float -mips3 -mabi=32
+BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
 
 ENDIANESS = LE
Index: uspace/lib/c/arch/mips32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/mips32/_link.ld.in	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/mips32/_link.ld.in	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70004000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -34,4 +27,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/arch/mips32/include/types.h
===================================================================
--- uspace/lib/c/arch/mips32/include/types.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/mips32/include/types.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -48,4 +48,5 @@
 
 typedef uint32_t sysarg_t;
+typedef int32_t native_t;
 
 typedef int32_t ssize_t;
Index: uspace/lib/c/arch/mips32eb/Makefile.common
===================================================================
--- uspace/lib/c/arch/mips32eb/Makefile.common	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/mips32eb/Makefile.common	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -28,4 +28,5 @@
 
 GCC_CFLAGS += -msoft-float -mips3 -mabi=32
+BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
 
 ENDIANESS = BE
Index: uspace/lib/c/arch/mips64/Makefile.common
===================================================================
--- uspace/lib/c/arch/mips64/Makefile.common	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/mips64/Makefile.common	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -28,4 +28,5 @@
 
 GCC_CFLAGS += -msoft-float -mips3 -mabi=64
+BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
 AFLAGS = -64
 
Index: uspace/lib/c/arch/mips64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/mips64/_link.ld.in	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/mips64/_link.ld.in	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -16,14 +16,7 @@
 #ifdef LOADER
 	. = 0x70004000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -35,4 +28,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/arch/mips64/include/types.h
===================================================================
--- uspace/lib/c/arch/mips64/include/types.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/mips64/include/types.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -48,4 +48,5 @@
 
 typedef uint64_t sysarg_t;
+typedef int64_t native_t;
 
 typedef int64_t ssize_t;
Index: uspace/lib/c/arch/ppc32/Makefile.common
===================================================================
--- uspace/lib/c/arch/ppc32/Makefile.common	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/ppc32/Makefile.common	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -28,4 +28,5 @@
 
 GCC_CFLAGS += -mcpu=powerpc -msoft-float -m32
+BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
 AFLAGS = -a32
 
Index: uspace/lib/c/arch/ppc32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ppc32/_link.ld.in	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/ppc32/_link.ld.in	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -16,14 +16,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 4);
 	
 	.init : {
@@ -35,4 +28,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/ppc32/include/types.h
===================================================================
--- uspace/lib/c/arch/ppc32/include/types.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/ppc32/include/types.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -47,4 +47,5 @@
 
 typedef uint32_t sysarg_t;
+typedef int32_t native_t;
 
 typedef int32_t ssize_t;
Index: uspace/lib/c/arch/sparc64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/sparc64/_link.ld.in	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/sparc64/_link.ld.in	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70004000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -34,4 +27,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/arch/sparc64/include/types.h
===================================================================
--- uspace/lib/c/arch/sparc64/include/types.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/arch/sparc64/include/types.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -47,4 +47,5 @@
 
 typedef uint64_t sysarg_t;
+typedef int64_t native_t;
 
 typedef int64_t ssize_t;
Index: uspace/lib/c/generic/adt/hash_table.c
===================================================================
--- uspace/lib/c/generic/adt/hash_table.c	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/generic/adt/hash_table.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -62,10 +62,10 @@
 
 
-static size_t round_up_size(size_t size);
-static bool alloc_table(size_t bucket_cnt, list_t **pbuckets);
-static void clear_items(hash_table_t *h);
-static void resize(hash_table_t *h, size_t new_bucket_cnt);
-static void grow_if_needed(hash_table_t *h);
-static void shrink_if_needed(hash_table_t *h);
+static size_t round_up_size(size_t);
+static bool alloc_table(size_t, list_t **);
+static void clear_items(hash_table_t *);
+static void resize(hash_table_t *, size_t);
+static void grow_if_needed(hash_table_t *);
+static void shrink_if_needed(hash_table_t *);
 
 /* Dummy do nothing callback to invoke in place of remove_callback == NULL. */
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/generic/async.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -416,6 +416,6 @@
 	.key_hash = client_key_hash,
 	.key_equal = client_key_equal,
-	.equal = 0,
-	.remove_callback = 0
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
@@ -452,6 +452,6 @@
 	.key_hash = conn_key_hash,
 	.key_equal = conn_key_equal,
-	.equal = 0,
-	.remove_callback = 0
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
@@ -628,5 +628,5 @@
 	
 	if (usecs) {
-		gettimeofday(&conn->wdata.to_event.expires, NULL);
+		getuptime(&conn->wdata.to_event.expires);
 		tv_add(&conn->wdata.to_event.expires, usecs);
 	} else
@@ -947,5 +947,5 @@
 {
 	struct timeval tv;
-	gettimeofday(&tv, NULL);
+	getuptime(&tv);
 	
 	futex_down(&async_futex);
@@ -1004,5 +1004,5 @@
 			
 			struct timeval tv;
-			gettimeofday(&tv, NULL);
+			getuptime(&tv);
 			
 			if (tv_gteq(&tv, &waiter->to_event.expires)) {
@@ -1309,5 +1309,5 @@
 		timeout = 0;
 
-	gettimeofday(&msg->wdata.to_event.expires, NULL);
+	getuptime(&msg->wdata.to_event.expires);
 	tv_add(&msg->wdata.to_event.expires, timeout);
 	
@@ -1391,5 +1391,5 @@
 	msg->wdata.fid = fibril_get_id();
 	
-	gettimeofday(&msg->wdata.to_event.expires, NULL);
+	getuptime(&msg->wdata.to_event.expires);
 	tv_add(&msg->wdata.to_event.expires, timeout);
 	
Index: uspace/lib/c/generic/device/battery_dev.c
===================================================================
--- uspace/lib/c/generic/device/battery_dev.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/generic/device/battery_dev.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ /** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/dev_iface.h>
+#include <device/battery_dev.h>
+#include <errno.h>
+#include <async.h>
+#include <time.h>
+
+/** Read the current battery status from the device
+ *
+ * @param sess     Session of the device
+ * @param status   Current status of the battery
+ *
+ * @return         EOK on success or a negative error code
+ */
+int
+battery_status_get(async_sess_t *sess, battery_status_t *batt_status)
+{
+	sysarg_t status;
+
+	async_exch_t *exch = async_exchange_begin(sess);
+
+	int const rc = async_req_1_1(exch, DEV_IFACE_ID(BATTERY_DEV_IFACE),
+	    BATTERY_STATUS_GET, &status);
+
+	async_exchange_end(exch);
+
+	if (rc == EOK)
+		*batt_status = (battery_status_t) status;
+
+	return rc;
+}
+
+/** Read the current battery charge level from the device
+ *
+ * @param sess     Session of the device
+ * @param level    Battery charge level (0 - 100)
+ *
+ * @return         EOK on success or a negative error code
+ */
+int
+battery_charge_level_get(async_sess_t *sess, int *level)
+{
+	sysarg_t charge_level;
+
+	async_exch_t *exch = async_exchange_begin(sess);
+
+	int const rc = async_req_1_1(exch, DEV_IFACE_ID(BATTERY_DEV_IFACE),
+	    BATTERY_CHARGE_LEVEL_GET, &charge_level);
+
+	async_exchange_end(exch);
+
+	if (rc == EOK)
+		*level = (int) charge_level;
+
+	return rc;
+}
+
+/** @}
+ */
+
Index: uspace/lib/c/generic/device/clock_dev.c
===================================================================
--- uspace/lib/c/generic/device/clock_dev.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/generic/device/clock_dev.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ /** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/dev_iface.h>
+#include <device/clock_dev.h>
+#include <errno.h>
+#include <async.h>
+#include <time.h>
+
+/** Read the current time from the device
+ *
+ * @param sess     Session of the device
+ * @param t        The current time that will be read from the device
+ *
+ * @return         EOK on success or a negative error code
+ */
+int
+clock_dev_time_get(async_sess_t *sess, struct tm *t)
+{
+	aid_t req;
+	int ret;
+
+	async_exch_t *exch = async_exchange_begin(sess);
+
+	req = async_send_1(exch, DEV_IFACE_ID(CLOCK_DEV_IFACE),
+	    CLOCK_DEV_TIME_GET, NULL);
+	ret = async_data_read_start(exch, t, sizeof(*t));
+
+	async_exchange_end(exch);
+
+	sysarg_t rc;
+	if (ret != EOK) {
+		async_forget(req);
+		return ret;
+	}
+
+	async_wait_for(req, &rc);
+	return (int)rc;
+}
+
+/** Set the current time
+ *
+ * @param sess   Session of the device
+ * @param t      The current time that will be written to the device
+ *
+ * @return       EOK on success or a negative error code
+ */
+int
+clock_dev_time_set(async_sess_t *sess, struct tm *t)
+{
+	aid_t req;
+	int ret;
+
+	async_exch_t *exch = async_exchange_begin(sess);
+
+	req = async_send_1(exch, DEV_IFACE_ID(CLOCK_DEV_IFACE),
+	    CLOCK_DEV_TIME_SET, NULL);
+	ret = async_data_write_start(exch, t, sizeof(*t));
+
+	async_exchange_end(exch);
+
+	sysarg_t rc;
+	if (ret != EOK) {
+		async_forget(req);
+		return ret;
+	}
+
+	async_wait_for(req, &rc);
+	return (int)rc;
+}
+
+/** @}
+ */
+
Index: uspace/lib/c/generic/dlfcn.c
===================================================================
--- uspace/lib/c/generic/dlfcn.c	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/generic/dlfcn.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -38,4 +38,6 @@
 #include <stdlib.h>
 #include <dlfcn.h>
+
+#ifdef CONFIG_RTLD
 
 #include <rtld/module.h>
@@ -87,4 +89,18 @@
 }
 
+#else /* CONFIG_RTLD not defined */
+
+void *dlopen(const char *path, int flag)
+{
+	return NULL;
+}
+
+void *dlsym(void *mod, const char *sym_name)
+{
+	return NULL;
+}
+
+#endif
+
 /** @}
  */
Index: uspace/lib/c/generic/double_to_str.c
===================================================================
--- uspace/lib/c/generic/double_to_str.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/generic/double_to_str.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,785 @@
+/*
+ * Copyright (c) 2012 Adam Hraska
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <double_to_str.h>
+
+#include "private/power_of_ten.h"
+#include <ieee_double.h>
+
+#include <stdint.h>
+#include <assert.h>
+#include <bool.h>
+
+/*
+ * Floating point numbers are converted from their binary representation
+ * into a decimal string using the algorithm described in:
+ *   Printing floating-point numbers quickly and accurately with integers
+ *   Loitsch, 2010
+ */
+
+/** The computation assumes a significand of 64 bits. */
+static const int significand_width = 64;
+
+/* Scale exponents to interval [alpha, gamma] to simplify conversion. */
+static const int alpha = -59;
+static const int gamma = -32;
+
+
+/** Returns true if the most-significant bit of num.significand is set. */
+static bool is_normalized(fp_num_t num)
+{
+	assert(8*sizeof(num.significand) == significand_width);
+
+	/* Normalized == most significant bit of the significand is set. */
+	return (num.significand & (1ULL << (significand_width - 1))) != 0;
+}
+
+/** Returns a normalized num with the MSbit set. */
+static fp_num_t normalize(fp_num_t num)
+{
+	const uint64_t top10bits = 0xffc0000000000000ULL;
+
+	/* num usually comes from ieee_double with top 10 bits zero. */
+	while (0 == (num.significand & top10bits)) {
+		num.significand <<= 10;
+		num.exponent -= 10;
+	}
+
+	while (!is_normalized(num)) {
+		num.significand <<= 1;
+		--num.exponent;
+	}
+
+	return num;
+}
+
+
+/** Returns x * y with an error of less than 0.5 ulp. */
+static fp_num_t multiply(fp_num_t x, fp_num_t y)
+{
+	assert(/* is_normalized(x) && */ is_normalized(y));
+	
+	const uint32_t low_bits = -1;
+
+	uint64_t a, b, c, d;
+	a = x.significand >> 32;
+	b = x.significand & low_bits;
+	c = y.significand >> 32;
+	d = y.significand & low_bits;
+
+	uint64_t bd, ad, bc, ac;
+	bd = b * d;
+	ad = a * d;
+	
+	bc = b * c;
+	ac = a * c;
+
+	/* Denote 32 bit parts of x a y as: x == a b, y == c d. Then:
+	 *        a  b    
+	 *  *     c  d
+	 *  ----------
+	 *       ad bd .. multiplication of 32bit parts results in 64bit parts
+	 *  + ac bc
+	 *  ----------
+	 *       [b|d] .. Depicts 64 bit intermediate results and how
+	 *     [a|d]      the 32 bit parts of these results overlap and
+	 *     [b|c]      contribute to the final result.
+	 *  +[a|c]
+	 *  ----------
+	 *   [ret]
+	 *  [tmp]
+	 */
+	uint64_t tmp = (bd >> 32) + (ad & low_bits) + (bc & low_bits);
+
+	/* Round upwards. */
+	tmp += 1U << 31;
+
+	fp_num_t ret;
+	ret.significand = ac + (bc >> 32) + (ad >> 32) + (tmp >> 32);
+	ret.exponent = x.exponent + y.exponent + significand_width;
+	
+	return ret;			
+}
+
+
+/** Returns a - b. Both must have the same exponent. */
+static fp_num_t subtract(fp_num_t a, fp_num_t b)
+{
+	assert(a.exponent == b.exponent);
+	assert(a.significand >= b.significand);
+
+	fp_num_t result;
+	
+	result.significand = a.significand - b.significand;
+	result.exponent = a.exponent;
+
+	return result;
+}
+
+
+/** Returns the interval [low, high] of numbers that convert to binary val. */
+static void get_normalized_bounds(ieee_double_t val, fp_num_t *high, 
+	fp_num_t *low, fp_num_t *val_dist)
+{
+	/* 
+	 * Only works if val comes directly from extract_ieee_double without
+	 * being manipulated in any way (eg it must not be normalized). 
+	 */
+	assert(!is_normalized(val.pos_val));
+
+	high->significand = (val.pos_val.significand << 1) + 1;
+	high->exponent = val.pos_val.exponent - 1;
+
+	/* val_dist = high - val */
+	val_dist->significand = 1;
+	val_dist->exponent = val.pos_val.exponent - 1;
+
+	/* Distance from both lower and upper bound is the same. */
+	if (!val.is_accuracy_step) {
+		low->significand = (val.pos_val.significand << 1) - 1;
+		low->exponent = val.pos_val.exponent - 1;
+	} else {
+		low->significand = (val.pos_val.significand << 2) - 1;
+		low->exponent = val.pos_val.exponent - 2;
+	}
+
+	*high = normalize(*high);
+
+	/* 
+	 * Lower bound may not be normalized if subtracting 1 unit
+	 * reset the most-significant bit to 0. 
+	 */
+	low->significand = low->significand << (low->exponent - high->exponent);
+	low->exponent = high->exponent;
+
+	val_dist->significand = 
+		val_dist->significand << (val_dist->exponent - high->exponent);
+	val_dist->exponent = high->exponent;
+}
+
+/** Determines the interval of numbers that have the binary representation 
+ *  of val.
+ * 
+ * Numbers in the range [scaled_upper_bound - bounds_delta, scaled_upper_bound]
+ * have the same double binary representation as val. 
+ *
+ * Bounds are scaled by 10^scale so that alpha <= exponent <= gamma.
+ * Moreover, scaled_upper_bound is normalized.
+ *
+ * val_dist is the scaled distance from val to the upper bound, ie
+ * val_dist == (upper_bound - val) * 10^scale
+ */
+static void calc_scaled_bounds(ieee_double_t val, fp_num_t *scaled_upper_bound, 
+	fp_num_t *bounds_delta, fp_num_t *val_dist, int *scale)
+{
+	fp_num_t upper_bound, lower_bound;
+
+	get_normalized_bounds(val, &upper_bound, &lower_bound, val_dist);
+
+	assert(upper_bound.exponent == lower_bound.exponent);
+	assert(is_normalized(upper_bound));
+	assert(normalize(val.pos_val).exponent == upper_bound.exponent);
+
+	/* 
+	 * Find such a cached normalized power of 10 that if multiplied
+	 * by upper_bound the binary exponent of upper_bound almost vanishes, 
+	 * ie:
+	 *   upper_scaled := upper_bound * 10^scale
+	 *   alpha <= upper_scaled.exponent <= gamma
+	 *   alpha <= upper_bound.exponent + pow_10.exponent + 64 <= gamma
+	 */
+	fp_num_t scaling_power_of_10;
+	int lower_bin_exp = alpha - upper_bound.exponent - significand_width;
+
+	get_power_of_ten(lower_bin_exp, &scaling_power_of_10, scale);
+
+	int scale_exp = scaling_power_of_10.exponent;
+	assert(alpha <= upper_bound.exponent + scale_exp + significand_width);
+	assert(upper_bound.exponent + scale_exp + significand_width <= gamma);
+
+	fp_num_t upper_scaled = multiply(upper_bound, scaling_power_of_10);
+	fp_num_t lower_scaled = multiply(lower_bound, scaling_power_of_10);
+	*val_dist = multiply(*val_dist, scaling_power_of_10);
+
+	assert(alpha <= upper_scaled.exponent && upper_scaled.exponent <= gamma);
+
+	/* 
+	 * Any value between lower and upper bound would be represented
+	 * in binary as the double val originated from. The bounds were
+	 * however scaled by an imprecise power of 10 (error less than 
+	 * 1 ulp) so the scaled bounds have an error of less than 1 ulp. 
+	 * Conservatively round the lower bound up and the upper bound 
+	 * down by 1 ulp just to be on the safe side. It avoids pronouncing
+	 * produced decimal digits as correct if such a decimal number
+	 * is close to the bounds to within 1 ulp. 
+	 */
+	upper_scaled.significand -= 1;
+	lower_scaled.significand += 1;
+
+	*bounds_delta = subtract(upper_scaled, lower_scaled);
+	*scaled_upper_bound = upper_scaled;
+}
+
+
+/** Rounds the last digit of buf so that it is closest to the converted number.*/
+static void round_last_digit(uint64_t rest, uint64_t w_dist, uint64_t delta,
+	uint64_t digit_val_diff, char *buf, int len)
+{
+	/*
+	 *  | <------- delta -------> |
+	 *  |    | <---- w_dist ----> |
+	 *  |    |       | <- rest -> |
+	 *  |    |       |            |
+	 *  |    |       ` buffer     |
+	 *  |    ` w                  ` upper
+	 *  ` lower
+	 *
+	 * delta = upper - lower .. conservative/safe interval
+	 * w_dist = upper - w    
+	 * upper = "number represented by digits in buf" + rest
+	 * 
+	 * Changing buf[len - 1] changes the value represented by buf 
+	 * by digit_val_diff * scaling, where scaling is shared by
+	 * all parameters. 
+	 *
+	 */
+
+	/* Current number in buf is greater than the double being converted */
+	bool cur_greater_w = rest < w_dist;
+	/* Rounding down by one would keep buf in between bounds (in safe rng). */
+	bool next_in_val_rng = cur_greater_w && (rest + digit_val_diff < delta);
+	/* Rounding down by one would bring buf closer to the processed number. */
+	bool next_closer = next_in_val_rng 
+		&& (rest + digit_val_diff < w_dist || rest - w_dist < w_dist - rest);
+
+	/* Of the shortest strings pick the one that is closest to the actual 
+	   floating point number. */
+	while (next_closer) {
+		assert('0' < buf[len - 1]);
+		assert(0 < digit_val_diff);
+
+		--buf[len - 1];
+		rest += digit_val_diff;
+
+		cur_greater_w = rest < w_dist;
+		next_in_val_rng = cur_greater_w && (rest + digit_val_diff < delta);
+		next_closer = next_in_val_rng 
+			&& (rest + digit_val_diff < w_dist || rest - w_dist < w_dist - rest);
+	}
+}
+
+
+/** Generates the shortest accurate decimal string representation.
+ *
+ * Outputs (mostly) the shortest accurate string representation 
+ * for the number scaled_upper - val_dist. Numbers in the interval
+ * [scaled_upper - delta, scaled_upper] have the same binary
+ * floating point representation and will therefore share the
+ * shortest string representation (up to the rounding of the last
+ * digit to bring the shortest string also the closest to the
+ * actual number). 
+ *
+ * @param scaled_upper Scaled upper bound of numbers that have the
+ *              same binary representation as the converted number.
+ *              Scaled by 10^-scale so that alpha <= exponent <= gamma.
+ * @param delta scaled_upper - delta is the lower bound of numbers
+ *              that share the same binary representation in double.
+ * @param val_dist scaled_upper - val_dist is the number whose
+ *              decimal string we're generating.
+ * @param scale Decimal scaling of the value to convert (ie scaled_upper).
+ * @param buf   Buffer to store the string representation. Must be large 
+ *              enough to store all digits and a null terminator. At most
+ *              MAX_DOUBLE_STR_LEN digits will be written (not counting
+ *              the null terminator).
+ * @param buf_size Size of buf in bytes. 
+ * @param dec_exponent Will be set to the decimal exponent of the number 
+ *              string in buf.
+ *
+ * @return Number of digits; negative on failure (eg buffer too small).
+ */
+static int gen_dec_digits(fp_num_t scaled_upper, fp_num_t delta, 
+	fp_num_t val_dist, int scale, char *buf, size_t buf_size, int *dec_exponent)
+{
+	/* 
+	 * The integral part of scaled_upper is 5 to 32 bits long while 
+	 * the remaining fractional part is 59 to 32 bits long because:
+	 * -59 == alpha <= scaled_upper.e <= gamma == -32
+	 *
+	 *  | <------- delta -------> |
+	 *  |    | <--- val_dist ---> |
+	 *  |    |    |<- remainder ->|
+	 *  |    |    |               |
+	 *  |    |    ` buffer        |
+	 *  |    ` val                ` upper
+	 *  ` lower
+	 *
+	 */ 
+	assert(scaled_upper.significand != 0);
+	assert(alpha <= scaled_upper.exponent && scaled_upper.exponent <= gamma);
+	assert(scaled_upper.exponent == delta.exponent);
+	assert(scaled_upper.exponent == val_dist.exponent);
+	assert(val_dist.significand <= delta.significand);
+
+	/* We'll produce at least one digit and a null terminator. */
+	if (buf_size < 2) {
+		return -1;
+	}
+
+	/* one is number 1 encoded with the same exponent as scaled_upper */
+	fp_num_t one;
+	one.significand = ((uint64_t) 1) << (-scaled_upper.exponent);
+	one.exponent = scaled_upper.exponent;
+
+	/*
+	 * Extract the integral part of scaled_upper. 
+	 *  upper / one == upper >> -one.e 
+	 */
+	uint32_t int_part = (uint32_t)(scaled_upper.significand >> (-one.exponent));
+	
+	/* 
+	 * Fractional part of scaled_upper.
+	 *  upper % one == upper & (one.f - 1) 
+	 */
+	uint64_t frac_part = scaled_upper.significand & (one.significand - 1);
+
+	/*
+	 * The integral part of upper has at least 5 bits (64 + alpha) and 
+	 * at most 32 bits (64 + gamma). The integral part has at most 10 
+	 * decimal digits, so kappa <= 10. 
+	 */
+	int kappa = 10;
+	uint32_t div = 1000000000;
+	size_t len = 0;
+
+	/* Produce decimal digits for the integral part of upper. */
+	while (kappa > 0) {
+		int digit = int_part / div;
+		int_part %= div;
+
+		--kappa;
+
+		/* Skip leading zeros. */
+		if (digit != 0 || len != 0) {
+			/* Current length + new digit + null terminator <= buf_size */
+			if (len + 2 <= buf_size) {
+				buf[len] = '0' + digit;
+				++len;
+			} else {
+				return -1;
+			}
+		}
+
+		/* 
+		 * Difference between the so far produced decimal number and upper
+		 * is calculated as: remaining_int_part * one + frac_part 
+		 */
+		uint64_t remainder = (((uint64_t)int_part) << -one.exponent) + frac_part;
+
+		/* The produced decimal number would convert back to upper. */
+		if (remainder <= delta.significand) {
+			assert(0 < len && len < buf_size);
+			*dec_exponent = kappa - scale;
+			buf[len] = '\0';
+
+			/* Of the shortest representations choose the numerically closest. */
+			round_last_digit(remainder, val_dist.significand, delta.significand,
+				(uint64_t)div << (-one.exponent), buf, len);
+			return len;
+		}
+
+		div /= 10;
+	}
+
+	/* Generate decimal digits for the fractional part of upper. */
+	do {
+		/*
+		 * Does not overflow because at least 5 upper bits were
+		 * taken by the integral part and are now unused in frac_part. 
+		 */
+		frac_part *= 10;
+		delta.significand *= 10;
+		val_dist.significand *= 10;
+
+		/* frac_part / one */
+		int digit = (int)(frac_part >> (-one.exponent));
+		
+		/* frac_part %= one */
+		frac_part &= one.significand - 1;
+
+		--kappa;
+
+		/* Skip leading zeros. */
+		if (digit == 0 && len == 0) {
+			continue;
+		}
+
+		/* Current length + new digit + null terminator <= buf_size */
+		if (len + 2 <= buf_size) {
+			buf[len] = '0' + digit;
+			++len;
+		} else {
+			return -1;
+		}
+	} while (frac_part > delta.significand);
+
+	assert(0 < len && len < buf_size);
+
+	*dec_exponent = kappa - scale;
+	buf[len] = '\0';
+
+	/* Of the shortest representations choose the numerically closest one. */
+	round_last_digit(frac_part, val_dist.significand, delta.significand, 
+		one.significand, buf, len);
+
+	return len;
+}
+
+/** Produce a string for 0.0 */
+static int zero_to_str(char *buf, size_t buf_size, int *dec_exponent)
+{
+	if (2 <= buf_size) {
+		buf[0] = '0';
+		buf[1] = '\0';
+		*dec_exponent = 0;
+		return 1;
+	} else {
+		return -1;
+	}
+}
+
+
+/** Converts a non-special double into its shortest accurate string 
+ *  representation.
+ *
+ * Produces an accurate string representation, ie the string will 
+ * convert back to the same binary double (eg via strtod). In the
+ * vast majority of cases (99%) the string will be the shortest such
+ * string that is also the closest to the value of any shortest
+ * string representations. Therefore, no trailing zeros are ever
+ * produced.
+ *
+ * Conceptually, the value is: buf * 10^dec_exponent
+ *
+ * Never outputs trailing zeros.
+ *
+ * @param ieee_val Binary double description to convert. Must be the product
+ *                 of extract_ieee_double and it must not be a special number.
+ * @param buf      Buffer to store the string representation. Must be large 
+ *                 enough to store all digits and a null terminator. At most
+ *                 MAX_DOUBLE_STR_LEN digits will be written (not counting
+ *                 the null terminator).
+ * @param buf_size Size of buf in bytes.
+ * @param dec_exponent Will be set to the decimal exponent of the number 
+ *                 string in buf.
+ *
+ * @return The number of printed digits. A negative value indicates
+ *         an error: buf too small (or ieee_val.is_special).
+ */
+int double_to_short_str(ieee_double_t ieee_val, char *buf, size_t buf_size, 
+	int *dec_exponent)
+{
+	/* The whole computation assumes 64bit significand. */
+	assert(sizeof(ieee_val.pos_val.significand) == sizeof(uint64_t));
+
+	if (ieee_val.is_special) {
+		return -1;
+	}
+
+	/* Zero cannot be normalized. Handle it here. */
+	if (0 == ieee_val.pos_val.significand) {
+		return zero_to_str(buf, buf_size, dec_exponent);
+	}
+
+	fp_num_t scaled_upper_bound;
+	fp_num_t delta;
+	fp_num_t val_dist;
+	int scale;
+
+	calc_scaled_bounds(ieee_val, &scaled_upper_bound, 
+		&delta, &val_dist, &scale);
+
+	int len = gen_dec_digits(scaled_upper_bound, delta, val_dist, scale, 
+		buf, buf_size, dec_exponent);
+
+	assert(len <= MAX_DOUBLE_STR_LEN);
+	return len;
+}
+
+/** Generates a fixed number of decimal digits of w_scaled.
+ *
+ * double == w_scaled * 10^-scale, where alpha <= w_scaled.e <= gamma
+ *
+ * @param w_scaled Scaled number by 10^-scale so that
+ *              alpha <= exponent <= gamma
+ * @param scale Decimal scaling of the value to convert (ie w_scaled).
+ * @param signif_d_cnt Maximum number of significant digits to output. 
+ *              Negative if as many as possible are requested.
+ * @param frac_d_cnt   Maximum number of fractional digits to output.
+ *              Negative if as many as possible are requested.
+ *              Eg. if 2 then 1.234 -> "1.23"; if 2 then 3e-9 -> "0".
+ * @param buf   Buffer to store the string representation. Must be large 
+ *              enough to store all digits and a null terminator. At most
+ *              MAX_DOUBLE_STR_LEN digits will be written (not counting
+ *              the null terminator).
+ * @param buf_size Size of buf in bytes. 
+ *
+ * @return Number of digits; negative on failure (eg buffer too small).
+ */
+static int gen_fixed_dec_digits(fp_num_t w_scaled, int scale, int signif_d_cnt, 
+	int frac_d_cnt, char *buf, size_t buf_size, int *dec_exponent)
+{
+	/* We'll produce at least one digit and a null terminator. */
+	if (0 == signif_d_cnt || buf_size < 2) {
+		return -1;
+	}
+
+	/* 
+	 * The integral part of w_scaled is 5 to 32 bits long while the 
+	 * remaining fractional part is 59 to 32 bits long because:
+	 * -59 == alpha <= w_scaled.e <= gamma == -32
+	 * 
+	 * Therefore:
+	 *  | 5..32 bits | 32..59 bits | == w_scaled == w * 10^scale
+	 *  |  int_part  |  frac_part  |
+	 *  |0 0  ..  0 1|0 0   ..  0 0| == one == 1.0
+	 *  |      0     |0 0   ..  0 1| == w_err == 1 * 2^w_scaled.e  
+	*/
+	assert(alpha <= w_scaled.exponent && w_scaled.exponent <= gamma);
+	assert(0 != w_scaled.significand);
+
+	/* 
+	 * Scaling the number being converted by 10^scale introduced
+	 * an error of less that 1 ulp. The actual value of w_scaled
+	 * could lie anywhere between w_scaled.signif +/- w_err. 
+	 * Scale the error locally as we scale the fractional part
+	 * of w_scaled.
+	 */
+	uint64_t w_err = 1;
+
+	/* one is number 1.0 encoded with the same exponent as w_scaled */
+	fp_num_t one;
+	one.significand = ((uint64_t) 1) << (-w_scaled.exponent);
+	one.exponent = w_scaled.exponent;
+
+	/* Extract the integral part of w_scaled. 
+	   w_scaled / one == w_scaled >> -one.e */
+	uint32_t int_part = (uint32_t)(w_scaled.significand >> (-one.exponent));
+
+	/* Fractional part of w_scaled.
+	   w_scaled % one == w_scaled & (one.f - 1) */
+	uint64_t frac_part = w_scaled.significand & (one.significand - 1);
+
+	size_t len = 0;
+	/* 
+	 * The integral part of w_scaled has at least 5 bits (64 + alpha = 5) 
+	 * and at most 32 bits (64 + gamma = 32). The integral part has 
+	 * at most 10 decimal digits, so kappa <= 10. 
+	 */
+	int kappa = 10;
+	uint32_t div = 1000000000;
+
+	int rem_signif_d_cnt = signif_d_cnt;
+	int rem_frac_d_cnt = 
+		(frac_d_cnt >= 0) ? (kappa - scale + frac_d_cnt) : INT_MAX;
+
+	/* Produce decimal digits for the integral part of w_scaled. */
+	while (kappa > 0 && rem_signif_d_cnt != 0 && rem_frac_d_cnt > 0) {
+		int digit = int_part / div;
+		int_part %= div;
+
+		div /= 10;
+		--kappa;
+		--rem_frac_d_cnt;
+
+		/* Skip leading zeros. */
+		if (digit == 0 && len == 0) {
+			continue;
+		}
+
+		/* Current length + new digit + null terminator <= buf_size */
+		if (len + 2 <= buf_size) {
+			buf[len] = '0' + digit;
+			++len;
+			--rem_signif_d_cnt;
+		} else {
+			return -1;
+		}
+	}
+
+	/* Generate decimal digits for the fractional part of w_scaled. */
+	while (w_err <= frac_part && rem_signif_d_cnt != 0 && rem_frac_d_cnt > 0) {
+		/*
+		 * Does not overflow because at least 5 upper bits were
+		 * taken by the integral part and are now unused in frac_part. 
+		 */
+		frac_part *= 10;
+		w_err *= 10;
+
+		/* frac_part / one */
+		int digit = (int)(frac_part >> (-one.exponent));
+		
+		/* frac_part %= one */
+		frac_part &= one.significand - 1;
+
+		--kappa;
+		--rem_frac_d_cnt;
+
+		/* Skip leading zeros. */
+		if (digit == 0 && len == 0) {
+			continue;
+		}
+
+		/* Current length + new digit + null terminator <= buf_size */
+		if (len + 2 <= buf_size) {
+			buf[len] = '0' + digit;
+			++len;
+			--rem_signif_d_cnt;
+		} else {
+			return -1;
+		}
+	};
+
+	assert(/* 0 <= len && */ len < buf_size);
+
+	if (0 < len) {
+		*dec_exponent = kappa - scale;
+		assert(frac_d_cnt < 0 || -frac_d_cnt <= *dec_exponent);
+	} else {
+		/* 
+		 * The number of fractional digits was too limiting to produce 
+		 * any digits. 
+		 */
+		assert(rem_frac_d_cnt <= 0 || w_scaled.significand == 0);
+		*dec_exponent = 0;
+		buf[0] = '0';
+		len = 1;
+	}
+
+	if (len < buf_size) {
+		buf[len] = '\0';
+		assert(signif_d_cnt < 0 || (int)len <= signif_d_cnt);
+		return len;
+	} else {
+		return -1;
+	}
+}
+
+
+/** Converts a non-special double into its string representation.
+ *
+ * Conceptually, the truncated double value is: buf * 10^dec_exponent
+ *
+ * Conversion errors are tracked, so all produced digits except the
+ * last one are accurate. Garbage digits are never produced.
+ * If the requested number of digits cannot be produced accurately 
+ * due to conversion errors less digits are produced than requested 
+ * and the last digit has an error of +/- 1 (so if '7' is the last
+ * converted digit it might have been converted to any of '6'..'8'
+ * had the conversion been completely precise). 
+ *
+ * If no error occurs at least one digit is output. 
+ *
+ * The conversion stops once the requested number of significant or 
+ * fractional digits is reached or the conversion error is too large 
+ * to generate any more digits (whichever happens first).
+ *
+ * Any digits following the first (most-significant) digit (this digit
+ * included) are counted as significant digits; eg:
+ *   1.4,    4 signif -> "1400" * 10^-3, ie 1.400
+ *   1000.3, 1 signif -> "1" * 10^3      ie 1000
+ *   0.003,  2 signif -> "30" * 10^-4    ie 0.003
+ *   9.5     1 signif -> "9" * 10^0,     ie 9
+ *
+ * Any digits following the decimal point are counted as fractional digits.
+ * This includes the zeros that would appear between the decimal point
+ * and the first non-zero fractional digit. If fewer fractional digits
+ * are requested than would allow to place the most-significant digit
+ * a "0" is output. Eg:
+ *   1.4,   3 frac -> "1400" * 10^-3,   ie 1.400
+ *   12.34  4 frac -> "123400" * 10^-4, ie 12.3400
+ *   3e-99  4 frac -> "0" * 10^0,       ie 0
+ *   0.009  2 frac -> "0" * 10^-2,      ie 0
+ *
+ * @param ieee_val Binary double description to convert. Must be the product
+ *                 of extract_ieee_double and it must not be a special number.
+ * @param signif_d_cnt Maximum number of significant digits to produce.
+ *                 The output is not rounded. 
+ *                 Set to a negative value to generate as many digits
+ *                 as accurately possible.
+ * @param frac_d_cnt Maximum number of fractional digits to produce including
+ *                 any zeros immediately trailing the decimal point. 
+ *                 The output is not rounded. 
+ *                 Set to a negative value to generate as many digits
+ *                 as accurately possible.
+ * @param buf      Buffer to store the string representation. Must be large 
+ *                 enough to store all digits and a null terminator. At most
+ *                 MAX_DOUBLE_STR_LEN digits will be written (not counting
+ *                 the null terminator).
+ * @param buf_size Size of buf in bytes.
+ * @param dec_exponent Set to the decimal exponent of the number string 
+ *                 in buf.
+ *
+ * @return The number of output digits. A negative value indicates
+ *         an error: buf too small (or ieee_val.is_special, or 
+ *         signif_d_cnt == 0).
+ */
+int double_to_fixed_str(ieee_double_t ieee_val, int signif_d_cnt,
+	int frac_d_cnt, char *buf, size_t buf_size, int *dec_exponent)
+{
+	/* The whole computation assumes 64bit significand. */
+	assert(sizeof(ieee_val.pos_val.significand) == sizeof(uint64_t));
+
+	if (ieee_val.is_special) {
+		return -1;
+	}
+
+	/* Zero cannot be normalized. Handle it here. */
+	if (0 == ieee_val.pos_val.significand) {
+		return zero_to_str(buf, buf_size, dec_exponent);
+	}
+
+	/* Normalize and scale. */
+	fp_num_t w = normalize(ieee_val.pos_val);
+
+	int lower_bin_exp = alpha - w.exponent - significand_width;
+
+	int scale;
+	fp_num_t scaling_power_of_10;
+
+	get_power_of_ten(lower_bin_exp, &scaling_power_of_10, &scale);
+
+	fp_num_t w_scaled = multiply(w, scaling_power_of_10);
+
+	/* Produce decimal digits from the scaled number. */
+	int len = gen_fixed_dec_digits(w_scaled, scale, signif_d_cnt, frac_d_cnt, 
+		buf, buf_size, dec_exponent);
+
+	assert(len <= MAX_DOUBLE_STR_LEN);
+	return len;
+}
+
Index: uspace/lib/c/generic/fibril_synch.c
===================================================================
--- uspace/lib/c/generic/fibril_synch.c	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/generic/fibril_synch.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -379,5 +379,5 @@
 	futex_down(&async_futex);
 	if (timeout) {
-		gettimeofday(&wdata.to_event.expires, NULL);
+		getuptime(&wdata.to_event.expires);
 		tv_add(&wdata.to_event.expires, timeout);
 		async_insert_timeout(&wdata);
Index: uspace/lib/c/generic/ieee_double.c
===================================================================
--- uspace/lib/c/generic/ieee_double.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/generic/ieee_double.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2012 Adam Hraska
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ieee_double.h>
+
+#include <assert.h>
+
+/** Returns an easily processible description of the double val.
+ */
+ieee_double_t extract_ieee_double(double val)
+{
+	const uint64_t significand_mask = 0xfffffffffffffULL;
+	const uint64_t exponent_mask = 0x7ff0000000000000ULL;
+	const int exponent_shift = 64 - 11 - 1;
+	const uint64_t sign_mask = 0x8000000000000000ULL;
+	
+	const int special_exponent = 0x7ff;
+	const int denormal_exponent = 0;
+	const uint64_t hidden_bit = (1ULL << 52);
+	const int exponent_bias = 1075;
+
+	assert(sizeof(val) == sizeof(uint64_t));
+
+	union {
+		uint64_t num;
+		double val;
+	} bits;
+
+	bits.val = val;
+
+	/* 
+	 * Extract the binary ieee representation of the double. 
+	 * Relies on integers having the same endianness as doubles.
+	 */
+	uint64_t num = bits.num;	
+
+	ieee_double_t ret;
+
+	/* Determine the sign. */
+	ret.is_negative = ((num & sign_mask) != 0);
+
+	/* Extract the exponent. */
+	int raw_exponent = (num & exponent_mask) >> exponent_shift;
+
+	/* The extracted raw significand may not contain the hidden bit */
+	uint64_t raw_significand = num & significand_mask;
+
+	ret.is_special = (raw_exponent == special_exponent);
+
+	/* NaN or infinity */
+	if (ret.is_special) {
+		ret.is_infinity = (raw_significand == 0);
+		ret.is_nan = (raw_significand != 0);
+
+		/* These are not valid for special numbers but init them anyway. */
+		ret.is_denormal = true;
+		ret.is_accuracy_step = false;
+		ret.pos_val.significand = 0;
+		ret.pos_val.exponent = 0;
+	} else {
+		ret.is_infinity = false;
+		ret.is_nan = false;
+
+		ret.is_denormal = (raw_exponent == denormal_exponent);
+
+		/* Denormal or zero. */
+		if (ret.is_denormal) {
+			ret.pos_val.significand = raw_significand;
+			ret.pos_val.exponent = 1 - exponent_bias;
+			ret.is_accuracy_step = false;
+		} else {
+			ret.pos_val.significand = raw_significand + hidden_bit;
+			ret.pos_val.exponent = raw_exponent - exponent_bias;
+
+			/* The predecessor is closer to val than the successor 
+			 * if val is a normal value of the form 2^k (hence
+			 * raw_significand == 0) with the only exception being 
+			 * the smallest normal (raw_exponent == 1). The smallest 
+			 * normal's predecessor is the largest denormal and denormals 
+			 * do not get an extra bit of precision because their exponent 
+			 * stays the same (ie it does not decrease from k to k-1).
+			 */
+			ret.is_accuracy_step = (raw_significand == 0) && (raw_exponent != 1);
+		}
+	}
+
+	return ret;
+}
+
Index: uspace/lib/c/generic/io/con_srv.c
===================================================================
--- uspace/lib/c/generic/io/con_srv.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/generic/io/con_srv.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/**
+ * @file
+ * @brief Console protocol server stub
+ */
+#include <errno.h>
+#include <ipc/console.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <io/con_srv.h>
+
+static void con_read_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	void *buf;
+	size_t size;
+	int rc;
+	ipc_callid_t rcallid;
+
+	if (!async_data_read_receive(&rcallid, &size)) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	buf = malloc(size);
+	if (buf == NULL) {
+		async_answer_0(rcallid, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	if (srv->srvs->ops->read == NULL) {
+		async_answer_0(rcallid, ENOTSUP);
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->read(srv, buf, size);
+	if (rc < 0) {
+		async_answer_0(rcallid, rc);
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	async_data_read_finalize(rcallid, buf, size);
+	free(buf);
+
+	if (rc >= 0)
+		async_answer_1(callid, EOK, rc);
+	else
+		async_answer_0(callid, rc);
+}
+
+static void con_write_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	void *data;
+	size_t size;
+	int rc;
+
+	rc = async_data_write_accept(&data, false, 0, 0, 0, &size);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	if (srv->srvs->ops->write == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->write(srv, data, size);
+	free(data);
+
+	if (rc >= 0)
+		async_answer_1(callid, EOK, rc);
+	else
+		async_answer_0(callid, rc);
+}
+
+static void con_sync_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	if (srv->srvs->ops->sync == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->sync(srv);
+	async_answer_0(callid, EOK);
+}
+
+static void con_clear_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	if (srv->srvs->ops->clear == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->clear(srv);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_pos_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	sysarg_t col;
+	sysarg_t row;
+
+	col = IPC_GET_ARG1(*call);
+	row = IPC_GET_ARG2(*call);
+
+	if (srv->srvs->ops->set_pos == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_pos(srv, col, row);
+	async_answer_0(callid, EOK);
+}
+
+static void con_get_pos_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	sysarg_t col;
+	sysarg_t row;
+
+	if (srv->srvs->ops->get_pos == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_pos(srv, &col, &row);
+	async_answer_2(callid, rc, col, row);
+}
+
+static void con_get_size_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	sysarg_t cols;
+	sysarg_t rows;
+
+	if (srv->srvs->ops->get_size == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_size(srv, &cols, &rows);
+	async_answer_2(callid, rc, cols, rows);
+}
+
+static void con_get_color_cap_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	console_caps_t ccap;
+
+	if (srv->srvs->ops->get_color_cap == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_color_cap(srv, &ccap);
+	async_answer_1(callid, rc, (sysarg_t)ccap);
+}
+
+static void con_set_style_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	console_style_t style;
+
+	style = IPC_GET_ARG1(*call);
+
+	if (srv->srvs->ops->set_style == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_style(srv, style);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_color_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	console_color_t bgcolor;
+	console_color_t fgcolor;
+	console_color_attr_t flags;
+
+	bgcolor = IPC_GET_ARG1(*call);
+	fgcolor = IPC_GET_ARG2(*call);
+	flags = IPC_GET_ARG3(*call);
+
+	if (srv->srvs->ops->set_color == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_color(srv, bgcolor, fgcolor, flags);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_rgb_color_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	pixel_t bgcolor;
+	pixel_t fgcolor;
+
+	bgcolor = IPC_GET_ARG1(*call);
+	fgcolor = IPC_GET_ARG2(*call);
+
+	if (srv->srvs->ops->set_rgb_color == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_rgb_color(srv, bgcolor, fgcolor);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_cursor_visibility_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	bool show;
+
+	show = IPC_GET_ARG1(*call);
+
+	if (srv->srvs->ops->set_cursor_visibility == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_cursor_visibility(srv, show);
+	async_answer_0(callid, EOK);
+}
+
+static void con_get_event_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	kbd_event_t event;
+
+	if (srv->srvs->ops->get_event == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_event(srv, &event);
+	async_answer_4(callid, rc, event.type, event.key, event.mods, event.c);
+}
+
+static con_srv_t *con_srv_create(con_srvs_t *srvs)
+{
+	con_srv_t *srv;
+
+	srv = calloc(1, sizeof(*srv));
+	if (srv == NULL)
+		return NULL;
+
+	srv->srvs = srvs;
+	return srv;
+}
+
+void con_srvs_init(con_srvs_t *srvs)
+{
+	srvs->ops = NULL;
+	srvs->sarg = NULL;
+	srvs->abort_timeout = 0;
+	srvs->aborted = false;
+}
+
+int con_conn(ipc_callid_t iid, ipc_call_t *icall, con_srvs_t *srvs)
+{
+	con_srv_t *srv;
+	int rc;
+
+	/* Accept the connection */
+	async_answer_0(iid, EOK);
+
+	srv = con_srv_create(srvs);
+	if (srv == NULL)
+		return ENOMEM;
+
+/*	async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
+	if (sess == NULL)
+		return ENOMEM;
+
+	srv->client_sess = sess;
+*/
+	srv->client_sess = NULL;
+
+	rc = srvs->ops->open(srvs, srv);
+	if (rc != EOK)
+		return rc;
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = 0;
+
+		while (callid == 0) {
+			/* XXX Need to be able to abort immediately */
+			callid = async_get_call_timeout(&call,
+			    srvs->abort_timeout);
+
+			if (srv->srvs->aborted) {
+				if (callid != 0)
+					async_answer_0(callid, EINTR);
+				break;
+			}
+		}
+
+		if (callid == 0)
+			break;
+
+		sysarg_t method = IPC_GET_IMETHOD(call);
+
+		if (!method) {
+			/* The other side has hung up */
+			async_answer_0(callid, EOK);
+			break;
+		}
+
+		switch (method) {
+		case VFS_OUT_READ:
+			con_read_srv(srv, callid, &call);
+			break;
+		case VFS_OUT_WRITE:
+			con_write_srv(srv, callid, &call);
+			break;
+		case VFS_OUT_SYNC:
+			con_sync_srv(srv, callid, &call);
+			break;
+		case CONSOLE_CLEAR:
+			con_clear_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_POS:
+			con_set_pos_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_POS:
+			con_get_pos_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_SIZE:
+			con_get_size_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_COLOR_CAP:
+			con_get_color_cap_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_STYLE:
+			con_set_style_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_COLOR:
+			con_set_color_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_RGB_COLOR:
+			con_set_rgb_color_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_CURSOR_VISIBILITY:
+			con_set_cursor_visibility_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_EVENT:
+			con_get_event_srv(srv, callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+		}
+	}
+
+	rc = srvs->ops->close(srv);
+	free(srv);
+
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/io/console.c
===================================================================
--- uspace/lib/c/generic/io/console.c	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/generic/io/console.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -38,5 +38,4 @@
 #include <async.h>
 #include <errno.h>
-#include <stdio.h>
 #include <malloc.h>
 #include <vfs/vfs_sess.h>
@@ -126,5 +125,5 @@
 {
 	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
-	async_req_1_0(exch, CONSOLE_CURSOR_VISIBILITY, (show != false));
+	async_req_1_0(exch, CONSOLE_SET_CURSOR_VISIBILITY, (show != false));
 	async_exchange_end(exch);
 }
@@ -151,5 +150,5 @@
 {
 	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
-	async_req_2_0(exch, CONSOLE_GOTO, col, row);
+	async_req_2_0(exch, CONSOLE_SET_POS, col, row);
 	async_exchange_end(exch);
 }
Index: uspace/lib/c/generic/io/input.c
===================================================================
--- uspace/lib/c/generic/io/input.c	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/generic/io/input.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -143,6 +143,6 @@
 	x = IPC_GET_ARG1(*call);
 	y = IPC_GET_ARG2(*call);
-	max_x = IPC_GET_ARG2(*call);
-	max_y = IPC_GET_ARG3(*call);
+	max_x = IPC_GET_ARG3(*call);
+	max_y = IPC_GET_ARG4(*call);
 
 	rc = input->ev_ops->abs_move(input, x, y, max_x, max_y);
Index: uspace/lib/c/generic/io/log.c
===================================================================
--- uspace/lib/c/generic/io/log.c	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/generic/io/log.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -38,58 +38,190 @@
 #include <stdlib.h>
 #include <stdio.h>
-
+#include <async.h>
 #include <io/log.h>
-
-/** Serialization mutex for logging functions. */
-static FIBRIL_MUTEX_INITIALIZE(log_serializer);
-
-/** Current log level. */
-static log_level_t log_level;
-
-static FILE *log_stream;
-
+#include <ipc/logger.h>
+#include <ns.h>
+
+/** Id of the first log we create at logger. */
+static sysarg_t default_log_id;
+
+/** Log messages are printed under this name. */
 static const char *log_prog_name;
 
-/** Prefixes for individual logging levels. */
+/** Names of individual log levels. */
 static const char *log_level_names[] = {
-	[LVL_FATAL] = "Fatal error",
-	[LVL_ERROR] = "Error",
-	[LVL_WARN] = "Warning",
-	[LVL_NOTE] = "Note",
-	[LVL_DEBUG] = "Debug",
-	[LVL_DEBUG2] = "Debug2"
+	"fatal",
+	"error",
+	"warn",
+	"note",
+	"debug",
+	"debug2",
+	NULL
 };
 
+/** IPC session with the logger service. */
+static async_sess_t *logger_session;
+
+/** Maximum length of a single log message (in bytes). */
+#define MESSAGE_BUFFER_SIZE 4096
+
+/** Send formatted message to the logger service.
+ *
+ * @param session Initialized IPC session with the logger.
+ * @param log Log to use.
+ * @param level Verbosity level of the message.
+ * @param message The actual message.
+ * @return Error code of the conversion or EOK on success.
+ */
+static int logger_message(async_sess_t *session, log_t log, log_level_t level, char *message)
+{
+	async_exch_t *exchange = async_exchange_begin(session);
+	if (exchange == NULL) {
+		return ENOMEM;
+	}
+	if (log == LOG_DEFAULT)
+		log = default_log_id;
+
+	// FIXME: remove when all USB drivers use libc logging explicitly
+	str_rtrim(message, '\n');
+
+	aid_t reg_msg = async_send_2(exchange, LOGGER_WRITER_MESSAGE,
+	    log, level, NULL);
+	int rc = async_data_write_start(exchange, message, str_size(message));
+	sysarg_t reg_msg_rc;
+	async_wait_for(reg_msg, &reg_msg_rc);
+
+	async_exchange_end(exchange);
+
+	/*
+	 * Getting ENAK means no-one wants our message. That is not an
+	 * error at all.
+	 */
+	if (rc == ENAK)
+		rc = EOK;
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	return reg_msg_rc;
+}
+
+/** Get name of the log level.
+ *
+ * @param level The log level.
+ * @return String name or "unknown".
+ */
+const char *log_level_str(log_level_t level)
+{
+	if (level >= LVL_LIMIT)
+		return "unknown";
+	else
+		return log_level_names[level];
+}
+
+/** Convert log level name to the enum.
+ *
+ * @param[in] name Log level name or log level number.
+ * @param[out] level_out Where to store the result (set to NULL to ignore).
+ * @return Error code of the conversion or EOK on success.
+ */
+int log_level_from_str(const char *name, log_level_t *level_out)
+{
+	log_level_t level = LVL_FATAL;
+
+	while (log_level_names[level] != NULL) {
+		if (str_cmp(name, log_level_names[level]) == 0) {
+			if (level_out != NULL)
+				*level_out = level;
+			return EOK;
+		}
+		level++;
+	}
+
+	/* Maybe user specified number directly. */
+	char *end_ptr;
+	int level_int = strtol(name, &end_ptr, 0);
+	if ((end_ptr == name) || (str_length(end_ptr) != 0))
+		return EINVAL;
+	if (level_int < 0)
+		return ERANGE;
+	if (level_int >= (int) LVL_LIMIT)
+		return ERANGE;
+
+	if (level_out != NULL)
+		*level_out = (log_level_t) level_int;
+
+	return EOK;
+}
+
 /** Initialize the logging system.
  *
- * @param prog_name	Program name, will be printed as part of message
- * @param level		Minimum message level to print
- */
-int log_init(const char *prog_name, log_level_t level)
-{
-	assert(level < LVL_LIMIT);
-	log_level = level;
-
-	log_stream = stdout;
+ * @param prog_name Program name, will be printed as part of message
+ */
+int log_init(const char *prog_name)
+{
 	log_prog_name = str_dup(prog_name);
 	if (log_prog_name == NULL)
 		return ENOMEM;
 
+	logger_session = service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_LOGGER, LOGGER_INTERFACE_WRITER, 0);
+	if (logger_session == NULL) {
+		return ENOMEM;
+	}
+
+	default_log_id = log_create(prog_name, LOG_NO_PARENT);
+
 	return EOK;
 }
 
+/** Create a new (sub-) log.
+ *
+ * This function always returns a valid log_t. In case of errors,
+ * @c parent is returned and errors are silently ignored.
+ *
+ * @param name Log name under which message will be reported (appended to parents name).
+ * @param parent Parent log.
+ * @return Opaque identifier of the newly created log.
+ */
+log_t log_create(const char *name, log_t parent)
+{
+	async_exch_t *exchange = async_exchange_begin(logger_session);
+	if (exchange == NULL)
+		return parent;
+
+	if (parent == LOG_DEFAULT)
+		parent = default_log_id;
+
+	ipc_call_t answer;
+	aid_t reg_msg = async_send_1(exchange, LOGGER_WRITER_CREATE_LOG,
+	    parent, &answer);
+	int rc = async_data_write_start(exchange, name, str_size(name));
+	sysarg_t reg_msg_rc;
+	async_wait_for(reg_msg, &reg_msg_rc);
+
+	async_exchange_end(exchange);
+
+	if ((rc != EOK) || (reg_msg_rc != EOK))
+		return parent;
+
+	return IPC_GET_ARG1(answer);
+}
+
 /** Write an entry to the log.
  *
- * @param level		Message verbosity level. Message is only printed
- *			if verbosity is less than or equal to current
- *			reporting level.
- * @param fmt		Format string (no traling newline).
- */
-void log_msg(log_level_t level, const char *fmt, ...)
+ * The message is printed only if the verbosity level is less than or
+ * equal to currently set reporting level of the log.
+ *
+ * @param ctx Log to use (use LOG_DEFAULT if you have no idea what it means).
+ * @param level Severity level of the message.
+ * @param fmt Format string in printf-like format (without trailing newline).
+ */
+void log_msg(log_t ctx, log_level_t level, const char *fmt, ...)
 {
 	va_list args;
 
 	va_start(args, fmt);
-	log_msgv(level, fmt, args);
+	log_msgv(ctx, level, fmt, args);
 	va_end(args);
 }
@@ -97,25 +229,20 @@
 /** Write an entry to the log (va_list variant).
  *
- * @param level		Message verbosity level. Message is only printed
- *			if verbosity is less than or equal to current
- *			reporting level.
- * @param fmt		Format string (no trailing newline)
- */
-void log_msgv(log_level_t level, const char *fmt, va_list args)
+ * @param ctx Log to use (use LOG_DEFAULT if you have no idea what it means).
+ * @param level Severity level of the message.
+ * @param fmt Format string in printf-like format (without trailing newline).
+ * @param args Arguments.
+ */
+void log_msgv(log_t ctx, log_level_t level, const char *fmt, va_list args)
 {
 	assert(level < LVL_LIMIT);
 
-	/* Higher number means higher verbosity. */
-	if (level <= log_level) {
-		fibril_mutex_lock(&log_serializer);
-
-		fprintf(log_stream, "%s: %s: ", log_prog_name,
-		    log_level_names[level]);
-		vfprintf(log_stream, fmt, args);
-		fputc('\n', log_stream);
-		fflush(log_stream);
-
-		fibril_mutex_unlock(&log_serializer);
-	}
+	char *message_buffer = malloc(MESSAGE_BUFFER_SIZE);
+	if (message_buffer == NULL)
+		return;
+
+	vsnprintf(message_buffer, MESSAGE_BUFFER_SIZE, fmt, args);
+	logger_message(logger_session, ctx, level, message_buffer);
+	free(message_buffer);
 }
 
Index: uspace/lib/c/generic/io/logctl.c
===================================================================
--- uspace/lib/c/generic/io/logctl.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/generic/io/logctl.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+#include <io/logctl.h>
+#include <ipc/logger.h>
+#include <sysinfo.h>
+#include <ns.h>
+#include <str.h>
+
+/** IPC session with the logger service. */
+static async_sess_t *logger_session = NULL;
+
+static int start_logger_exchange(async_exch_t **exchange_out)
+{
+	assert(exchange_out != NULL);
+
+	if (logger_session == NULL) {
+		logger_session = service_connect_blocking(EXCHANGE_SERIALIZE,
+		    SERVICE_LOGGER, LOGGER_INTERFACE_CONTROL, 0);
+		if (logger_session == NULL)
+			return ENOMEM;
+	}
+
+	assert(logger_session != NULL);
+
+	async_exch_t *exchange = async_exchange_begin(logger_session);
+	if (exchange == NULL)
+		return ENOMEM;
+
+	*exchange_out = exchange;
+
+	return EOK;
+}
+
+/** Set default reported log level (global setting).
+ *
+ * This setting affects all logger clients whose reporting level was
+ * not yet changed.
+ *
+ * If logging level of client A is changed with logctl_set_log_level()
+ * to some level, this call will have no effect at that client's reporting
+ * level. Even if the actual value of the reporting level of client A is
+ * the same as current (previous) default log level.
+ *
+ * @param new_level New reported logging level.
+ * @return Error code of the conversion or EOK on success.
+ */
+int logctl_set_default_level(log_level_t new_level)
+{
+	async_exch_t *exchange = NULL;
+	int rc = start_logger_exchange(&exchange);
+	if (rc != EOK)
+		return rc;
+
+	rc = (int) async_req_1_0(exchange,
+	    LOGGER_CONTROL_SET_DEFAULT_LEVEL, new_level);
+
+	async_exchange_end(exchange);
+
+	return rc;
+}
+
+/** Set reported log level of a single log.
+ *
+ * @see logctl_set_default_level
+ *
+ * @param logname Log name.
+ * @param new_level New reported logging level.
+ * @return Error code of the conversion or EOK on success.
+ */
+int logctl_set_log_level(const char *logname, log_level_t new_level)
+{
+	async_exch_t *exchange = NULL;
+	int rc = start_logger_exchange(&exchange);
+	if (rc != EOK)
+		return rc;
+
+	aid_t reg_msg = async_send_1(exchange, LOGGER_CONTROL_SET_LOG_LEVEL,
+	    new_level, NULL);
+	rc = async_data_write_start(exchange, logname, str_size(logname));
+	sysarg_t reg_msg_rc;
+	async_wait_for(reg_msg, &reg_msg_rc);
+
+	async_exchange_end(exchange);
+
+	if (rc != EOK)
+		return rc;
+
+	return (int) reg_msg_rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/io/output.c
===================================================================
--- uspace/lib/c/generic/io/output.c	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/generic/io/output.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -37,4 +37,5 @@
 #include <as.h>
 #include <ipc/output.h>
+#include <io/concaps.h>
 #include <io/output.h>
 
Index: uspace/lib/c/generic/io/printf_core.c
===================================================================
--- uspace/lib/c/generic/io/printf_core.c	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/generic/io/printf_core.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -42,8 +42,16 @@
 #include <ctype.h>
 #include <str.h>
+#include <double_to_str.h>
+#include <ieee_double.h>
+#include <assert.h>
+#include <macros.h>
+
 
 /** show prefixes 0x or 0 */
 #define __PRINTF_FLAG_PREFIX       0x00000001
 
+/** show the decimal point even if no fractional digits present */
+#define __PRINTF_FLAG_DECIMALPT    0x00000001
+
 /** signed / unsigned number */
 #define __PRINTF_FLAG_SIGNED       0x00000002
@@ -66,4 +74,8 @@
 /** number has - sign */
 #define __PRINTF_FLAG_NEGATIVE     0x00000100
+
+/** don't print trailing zeros in the fractional part */
+#define __PRINTF_FLAG_NOFRACZEROS  0x00000200
+
 
 /**
@@ -110,4 +122,47 @@
 static const char invalch = U_SPECIAL;
 
+
+
+/** Unformatted double number string representation. */
+typedef struct {
+	/** Buffer with len digits, no sign or leading zeros. */
+	char *str;
+	/** Number of digits in str. */
+	int len;
+	/** Decimal exponent, ie number = str * 10^dec_exp */
+	int dec_exp;
+	/** True if negative. */
+	bool neg;
+} double_str_t;
+
+
+
+/** Returns the sign character or 0 if no sign should be printed. */
+static int get_sign_char(bool negative, uint32_t flags)
+{
+	if (negative) {
+		return '-';
+	} else if (flags & __PRINTF_FLAG_SHOWPLUS) {
+		return '+';
+	} else if (flags & __PRINTF_FLAG_SPACESIGN) {
+		return ' ';
+	} else {
+		return 0;
+	}
+}
+
+/** Prints count times character ch. */
+static int print_padding(char ch, int count, printf_spec_t *ps)
+{
+	for (int i = 0; i < count; ++i) {
+		if (ps->str_write(&ch, 1, ps->data) < 0) {
+			return -1;
+		}
+	}
+
+	return count;
+}
+
+
 /** Print one or more characters without adding newline.
  *
@@ -281,6 +336,7 @@
 		return printf_putstr(nullstr, ps);
 	
-	/* Print leading spaces. */
 	size_t strw = str_length(str);
+
+	/* Precision unspecified - print everything. */
 	if ((precision == 0) || (precision > strw))
 		precision = strw;
@@ -329,6 +385,7 @@
 		return printf_putstr(nullstr, ps);
 	
-	/* Print leading spaces. */
 	size_t strw = wstr_length(str);
+
+	/* Precision not specified - print everything. */
 	if ((precision == 0) || (precision > strw))
 		precision = strw;
@@ -377,4 +434,9 @@
     uint32_t flags, printf_spec_t *ps)
 {
+	/* Precision not specified. */
+	if (precision < 0) {
+		precision = 0;
+	}
+	
 	const char *digits;
 	if (flags & __PRINTF_FLAG_BIGCHARS)
@@ -525,4 +587,656 @@
 	
 	return ((int) counter);
+}
+
+/** Prints a special double (ie NaN, infinity) padded to width characters. */
+static int print_special(ieee_double_t val, int width, uint32_t flags, 
+	printf_spec_t *ps)
+{
+	assert(val.is_special);
+
+	char sign = get_sign_char(val.is_negative, flags);
+
+	const int str_len = 3;
+	const char *str;
+	
+	if (flags & __PRINTF_FLAG_BIGCHARS) {
+		str = val.is_infinity ? "INF" : "NAN";
+	} else {
+		str = val.is_infinity ? "inf" : "nan";
+	}
+
+	int padding_len = max(0, width - ((sign ? 1 : 0) + str_len));
+
+	int counter = 0;
+	int ret;
+
+	/* Leading padding. */
+	if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
+		if ((ret = print_padding(' ', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	if (sign) {
+		if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
+			return -1;
+		
+		counter += ret;
+	}
+
+	if ((ret = ps->str_write(str, str_len, ps->data)) < 0)
+		return -1;
+	
+	counter += ret;
+
+
+	/* Trailing padding. */
+	if (flags & __PRINTF_FLAG_LEFTALIGNED) {
+		if ((ret = print_padding(' ', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	return counter;
+}
+
+/** Trims trailing zeros but leaves a single "0" intact. */
+static void fp_trim_trailing_zeros(char *buf, int *len, int *dec_exp)
+{
+	/* Cut the zero off by adjusting the exponent. */
+	while (2 <= *len && '0' == buf[*len - 1]) {
+		--*len;
+		++*dec_exp;
+	}
+}
+
+/** Textually round up the last digit thereby eliminating it. */
+static void fp_round_up(char *buf, int *len, int *dec_exp)
+{
+	assert(1 <= *len);
+
+	char *last_digit = &buf[*len - 1];
+
+	int carry = ('5' <= *last_digit);
+
+	/* Cut the digit off by adjusting the exponent. */
+	--*len;
+	++*dec_exp;
+	--last_digit;
+
+	if (carry) {
+		/* Skip all the digits to cut off/round to zero. */
+		while (buf <= last_digit && '9' == *last_digit) {
+			--last_digit;
+		}
+
+		/* last_digit points to the last digit to round but not '9' */
+		if (buf <= last_digit) {
+			*last_digit += 1;
+			int new_len = last_digit - buf + 1;
+			*dec_exp += *len - new_len;
+			*len = new_len;
+		} else {
+			/* All len digits rounded to 0. */
+			buf[0] = '1';
+			*dec_exp += *len;
+			*len = 1;
+		}
+	} else {
+		/* The only digit was rounded to 0. */
+		if (last_digit < buf) {
+			buf[0] = '0';
+			*dec_exp = 0;
+			*len = 1;
+		}
+	}
+}
+
+
+/** Format and print the double string repressentation according 
+ *  to the %f specifier. 
+ */
+static int print_double_str_fixed(double_str_t *val_str, int precision, int width, 
+	uint32_t flags, printf_spec_t *ps)
+{
+	int len = val_str->len;
+	char *buf = val_str->str;
+	int dec_exp = val_str->dec_exp;
+
+	assert(0 < len);
+	assert(0 <= precision);
+	assert(0 <= dec_exp || -dec_exp <= precision);
+
+	/* Number of integral digits to print (at least leading zero). */
+	int int_len = max(1, len + dec_exp);
+
+	char sign = get_sign_char(val_str->neg, flags);
+
+	/* Fractional portion lengths. */
+	int last_frac_signif_pos = max(0, -dec_exp);
+	int leading_frac_zeros = max(0, last_frac_signif_pos - len);
+	int signif_frac_figs = min(last_frac_signif_pos, len);
+	int trailing_frac_zeros = precision - last_frac_signif_pos;
+	char *buf_frac = buf + len - signif_frac_figs;
+
+	if (flags & __PRINTF_FLAG_NOFRACZEROS) {
+		trailing_frac_zeros = 0;
+	}
+
+	int frac_len = leading_frac_zeros + signif_frac_figs + trailing_frac_zeros;
+
+	bool has_decimal_pt = (0 < frac_len) || (flags & __PRINTF_FLAG_DECIMALPT);
+
+	/* Number of non-padding chars to print. */
+	int num_len = (sign ? 1 : 0) + int_len + (has_decimal_pt ? 1 : 0) + frac_len;
+
+	int padding_len = max(0, width - num_len);
+	int ret = 0;
+	int counter = 0;
+
+	/* Leading padding and sign. */
+
+	if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) {
+		if ((ret = print_padding(' ', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	if (sign) {
+		if ((ret = ps->str_write(&sign, 1, ps->data)) < 0) 
+			return -1;
+		
+		counter += ret;
+	}
+
+	if (flags & __PRINTF_FLAG_ZEROPADDED) {
+		if ((ret = print_padding('0', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	/* Print the intergral part of the buffer. */
+
+	int buf_int_len = min(len, len + dec_exp);
+
+	if (0 < buf_int_len) {
+		if ((ret = ps->str_write(buf, buf_int_len, ps->data)) < 0) 
+			return -1;
+
+		counter += ret;
+
+		/* Print trailing zeros of the integral part of the number. */
+		if ((ret = print_padding('0', int_len - buf_int_len, ps)) < 0) 
+			return -1;
+	} else {
+		/* Single leading integer 0. */
+		char ch = '0';
+		if ((ret = ps->str_write(&ch, 1, ps->data)) < 0) 
+			return -1;
+	}
+
+	counter += ret;
+	
+	/* Print the decimal point and the fractional part. */
+	if (has_decimal_pt) {
+		char ch = '.';
+
+		if ((ret = ps->str_write(&ch, 1, ps->data)) < 0) 
+			return -1;
+		
+		counter += ret;
+
+		/* Print leading zeros of the fractional part of the number. */
+		if ((ret = print_padding('0', leading_frac_zeros, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+
+		/* Print significant digits of the fractional part of the number. */
+		if (0 < signif_frac_figs) {
+			if ((ret = ps->str_write(buf_frac, signif_frac_figs, ps->data)) < 0) 
+				return -1;
+
+			counter += ret;
+		}
+
+		/* Print trailing zeros of the fractional part of the number. */
+		if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	/* Trailing padding. */
+	if (flags & __PRINTF_FLAG_LEFTALIGNED) {
+		if ((ret = print_padding(' ', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	return counter;
+}
+
+
+/** Convert, format and print a double according to the %f specifier. 
+ *
+ * @param g     Double to print.
+ * @param precision Number of fractional digits to print. If 0 no
+ *              decimal point will be printed unless the flag
+ *              __PRINTF_FLAG_DECIMALPT is specified.
+ * @param width Minimum number of characters to display. Pads 
+ *              with '0' or ' ' depending on the set flags;
+ * @param flags Printf flags.
+ * @param ps    Printing functions.
+ *
+ * @return The number of characters printed; negative on failure.
+ */
+static int print_double_fixed(double g, int precision, int width, uint32_t flags, 
+	printf_spec_t *ps)
+{
+	if (flags & __PRINTF_FLAG_LEFTALIGNED) {
+		flags &= ~__PRINTF_FLAG_ZEROPADDED;
+	}
+
+	if (flags & __PRINTF_FLAG_DECIMALPT) {
+		flags &= ~__PRINTF_FLAG_NOFRACZEROS;
+	}
+
+	ieee_double_t val = extract_ieee_double(g);
+
+	if (val.is_special) {
+		return print_special(val, width, flags, ps);
+	} 
+
+	char buf[MAX_DOUBLE_STR_BUF_SIZE];
+	const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
+	double_str_t val_str;
+
+	val_str.str = buf;
+	val_str.neg = val.is_negative;
+
+	if (0 <= precision) {
+		/* 
+		 * Request one more digit so we can round the result. The last
+		 * digit it returns may have an error of at most +/- 1. 
+		 */
+		val_str.len = double_to_fixed_str(val, -1, precision + 1, buf, buf_size, 
+			&val_str.dec_exp);
+
+		/* 
+		 * Round using the last digit to produce precision fractional digits. 
+		 * If less than precision+1 fractional digits were output the last 
+		 * digit is definitely inaccurate so also round to get rid of it. 
+		 */
+		fp_round_up(buf, &val_str.len, &val_str.dec_exp);
+
+		/* Rounding could have introduced trailing zeros. */
+		if (flags & __PRINTF_FLAG_NOFRACZEROS) {
+			fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
+		}
+	} else {
+		/* Let the implementation figure out the proper precision. */
+		val_str.len = double_to_short_str(val, buf, buf_size, &val_str.dec_exp);
+		
+		/* Precision needed for the last significant digit. */
+		precision = max(0, -val_str.dec_exp);
+	}
+
+	return print_double_str_fixed(&val_str, precision, width, flags, ps);
+}
+
+/** Prints the decimal exponent part of a %e specifier formatted number. */
+static int print_exponent(int exp_val, uint32_t flags, printf_spec_t *ps)
+{
+	int counter = 0;
+	int ret;
+
+	char exp_ch = (flags & __PRINTF_FLAG_BIGCHARS) ? 'E' : 'e';
+
+	if ((ret = ps->str_write(&exp_ch, 1, ps->data)) < 0) 
+		return -1;
+	
+	counter += ret;
+
+	char exp_sign = (exp_val < 0) ? '-' : '+';
+
+	if ((ret = ps->str_write(&exp_sign, 1, ps->data)) < 0)
+		return -1;
+
+	counter += ret;
+
+	/* Print the exponent. */
+	exp_val = abs(exp_val);
+	
+	char exp_str[4] = { 0 };
+
+	exp_str[0] = '0' + exp_val / 100;
+	exp_str[1] = '0' + (exp_val % 100) / 10 ;
+	exp_str[2] = '0' + (exp_val % 10);
+	
+	int exp_len = (exp_str[0] == '0') ? 2 : 3;
+	const char *exp_str_start = &exp_str[3] - exp_len;
+
+	if ((ret = ps->str_write(exp_str_start, exp_len, ps->data)) < 0) 
+		return -1;
+
+	counter += ret;
+
+	return counter;
+}
+
+
+/** Format and print the double string repressentation according 
+ *  to the %e specifier. 
+ */
+static int print_double_str_scient(double_str_t *val_str, int precision, 
+	int width, uint32_t flags, printf_spec_t *ps)
+{
+	int len = val_str->len;
+	int dec_exp = val_str->dec_exp;
+	char *buf  = val_str->str;
+
+	assert(0 < len);
+
+	char sign = get_sign_char(val_str->neg, flags);
+	bool has_decimal_pt = (0 < precision) || (flags & __PRINTF_FLAG_DECIMALPT);
+	int dec_pt_len = has_decimal_pt ? 1 : 0;
+
+	/* Fractional part lengths. */
+	int signif_frac_figs = len - 1;
+	int trailing_frac_zeros = precision - signif_frac_figs;
+
+	if (flags & __PRINTF_FLAG_NOFRACZEROS) {
+		trailing_frac_zeros = 0;
+	}
+
+	int frac_len = signif_frac_figs + trailing_frac_zeros;
+
+	int exp_val = dec_exp + len - 1;
+	/* Account for exponent sign and 'e'; minimum 2 digits. */
+	int exp_len = 2 + (abs(exp_val) >= 100 ? 3 : 2);
+
+	/* Number of non-padding chars to print. */
+	int num_len = (sign ? 1 : 0) + 1 + dec_pt_len + frac_len + exp_len;
+
+	int padding_len = max(0, width - num_len);
+	int ret = 0;
+	int counter = 0;
+
+	if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) {
+		if ((ret = print_padding(' ', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	if (sign) {
+		if ((ret = ps->str_write(&sign, 1, ps->data)) < 0) 
+			return -1;
+		
+		counter += ret;
+	}
+
+	if (flags & __PRINTF_FLAG_ZEROPADDED) {
+		if ((ret = print_padding('0', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	/* Single leading integer. */
+	if ((ret = ps->str_write(buf, 1, ps->data)) < 0) 
+		return -1;
+
+	counter += ret;
+
+	/* Print the decimal point and the fractional part. */
+	if (has_decimal_pt) {
+		char ch = '.';
+
+		if ((ret = ps->str_write(&ch, 1, ps->data)) < 0) 
+			return -1;
+		
+		counter += ret;
+
+		/* Print significant digits of the fractional part of the number. */
+		if (0 < signif_frac_figs) {
+			if ((ret = ps->str_write(buf + 1, signif_frac_figs, ps->data)) < 0) 
+				return -1;
+
+			counter += ret;
+		}
+
+		/* Print trailing zeros of the fractional part of the number. */
+		if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	/* Print the exponent. */
+	if ((ret = print_exponent(exp_val, flags, ps)) < 0) 
+		return -1;
+
+	counter += ret;
+
+	if (flags & __PRINTF_FLAG_LEFTALIGNED) {
+		if ((ret = print_padding(' ', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	return counter;
+}
+
+
+/** Convert, format and print a double according to the %e specifier. 
+ *
+ * Note that if g is large, the output may be huge (3e100 prints 
+ * with at least 100 digits).
+ *
+ * %e style: [-]d.dddde+dd
+ *  left-justified:  [-]d.dddde+dd[space_pad]
+ *  right-justified: [space_pad][-][zero_pad]d.dddde+dd
+ *
+ * @param g     Double to print.
+ * @param precision Number of fractional digits to print, ie
+ *              precision + 1 significant digits to display. If 0 no
+ *              decimal point will be printed unless the flag
+ *              __PRINTF_FLAG_DECIMALPT is specified. If negative
+ *              the shortest accurate number will be printed.
+ * @param width Minimum number of characters to display. Pads 
+ *              with '0' or ' ' depending on the set flags;
+ * @param flags Printf flags.
+ * @param ps    Printing functions.
+ *
+ * @return The number of characters printed; negative on failure.
+ */
+static int print_double_scientific(double g, int precision, int width, 
+	uint32_t flags, printf_spec_t *ps)
+{
+	if (flags & __PRINTF_FLAG_LEFTALIGNED) {
+		flags &= ~__PRINTF_FLAG_ZEROPADDED;
+	}
+
+	ieee_double_t val = extract_ieee_double(g);
+
+	if (val.is_special) {
+		return print_special(val, width, flags, ps);
+	} 
+
+	char buf[MAX_DOUBLE_STR_BUF_SIZE];
+	const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
+	double_str_t val_str;
+
+	val_str.str = buf;
+	val_str.neg = val.is_negative;
+
+	if (0 <= precision) {
+		/* 
+		 * Request one more digit (in addition to the leading integer) 
+		 * so we can round the result. The last digit it returns may 
+		 * have an error of at most +/- 1. 
+		 */
+		val_str.len = double_to_fixed_str(val, precision + 2, -1, buf, buf_size, 
+			&val_str.dec_exp);
+
+		/* 
+		 * Round the extra digit to produce precision+1 significant digits. 
+		 * If less than precision+2 significant digits were returned the last 
+		 * digit is definitely inaccurate so also round to get rid of it. 
+		 */
+		fp_round_up(buf, &val_str.len, &val_str.dec_exp);
+
+		/* Rounding could have introduced trailing zeros. */
+		if (flags & __PRINTF_FLAG_NOFRACZEROS) {
+			fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
+		}
+	} else {
+		/* Let the implementation figure out the proper precision. */
+		val_str.len = double_to_short_str(val, buf, buf_size, &val_str.dec_exp);
+		
+		/* Use all produced digits. */
+		precision = val_str.len - 1;
+	}
+
+	return print_double_str_scient(&val_str, precision, width, flags, ps);
+}
+
+
+/** Convert, format and print a double according to the %g specifier. 
+ *
+ * %g style chooses between %f and %e. 
+ *
+ * @param g     Double to print.
+ * @param precision Number of significant digits to display; excluding
+ *              any leading zeros from this count. If negative
+ *              the shortest accurate number will be printed.
+ * @param width Minimum number of characters to display. Pads 
+ *              with '0' or ' ' depending on the set flags;
+ * @param flags Printf flags.
+ * @param ps    Printing functions.
+ *
+ * @return The number of characters printed; negative on failure.
+ */
+static int print_double_generic(double g, int precision, int width, 
+	uint32_t flags, printf_spec_t *ps)
+{
+	ieee_double_t val = extract_ieee_double(g);
+
+	if (val.is_special) {
+		return print_special(val, width, flags, ps);
+	} 
+
+	char buf[MAX_DOUBLE_STR_BUF_SIZE];
+	const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
+	int dec_exp;
+	int len;
+
+	/* Honor the user requested number of significant digits. */
+	if (0 <= precision) {
+		/* 
+		 * Do a quick and dirty conversion of a single digit to determine 
+		 * the decimal exponent.
+		 */
+		len = double_to_fixed_str(val, 1, -1, buf, buf_size, &dec_exp);
+		assert(0 < len);
+
+		precision = max(1, precision);
+
+		if (-4 <= dec_exp && dec_exp < precision) {
+			precision = precision - (dec_exp + 1);
+			return print_double_fixed(g, precision, width, 
+				flags | __PRINTF_FLAG_NOFRACZEROS, ps);
+		} else {
+			--precision;
+			return print_double_scientific(g, precision, width, 
+				flags | __PRINTF_FLAG_NOFRACZEROS, ps);
+		}
+	} else {
+		/* Convert to get the decimal exponent and digit count.*/
+		len = double_to_short_str(val, buf, buf_size, &dec_exp);
+		assert(0 < len);
+
+		if (flags & __PRINTF_FLAG_LEFTALIGNED) {
+			flags &= ~__PRINTF_FLAG_ZEROPADDED;
+		}
+
+		double_str_t val_str;
+		val_str.str = buf;
+		val_str.len = len;
+		val_str.neg = val.is_negative;
+		val_str.dec_exp = dec_exp;
+
+		int first_digit_pos = len + dec_exp;
+		int last_digit_pos = dec_exp;
+
+		/* The whole number (15 digits max) fits between dec places 15 .. -6 */
+		if (len <= 15 && -6 <= last_digit_pos && first_digit_pos <= 15) {
+			/* Precision needed for the last significant digit. */
+			precision = max(0, -val_str.dec_exp);
+			return print_double_str_fixed(&val_str, precision, width, flags, ps);
+		} else {
+			/* Use all produced digits. */
+			precision = val_str.len - 1;
+			return print_double_str_scient(&val_str, precision, width, flags, ps);
+		}
+	}
+}
+
+
+/** Convert, format and print a double according to the specifier. 
+ *
+ * Depending on the specifier it prints the double using the styles
+ * %g, %f or %e by means of print_double_generic(), print_double_fixed(),
+ * print_double_scientific().
+ *
+ * @param g     Double to print.
+ * @param spec  Specifier of the style to print in; one of: 'g','G','f','F',
+ *              'e','E'.
+ * @param precision Number of fractional digits to display. If negative
+ *              the shortest accurate number will be printed for style %g;
+ *              negative precision defaults to 6 for styles %f, %e.
+ * @param width Minimum number of characters to display. Pads 
+ *              with '0' or ' ' depending on the set flags;
+ * @param flags Printf flags.
+ * @param ps    Printing functions.
+ *
+ * @return The number of characters printed; negative on failure.
+ */
+static int print_double(double g, char spec, int precision, int width, 
+	uint32_t flags, printf_spec_t *ps)
+{
+	switch (spec) {
+	case 'F':
+		flags |= __PRINTF_FLAG_BIGCHARS;
+		/* Fall through.*/
+	case 'f':
+		precision = (precision < 0) ? 6 : precision;
+		return print_double_fixed(g, precision, width, flags, ps);
+
+	case 'E':
+		flags |= __PRINTF_FLAG_BIGCHARS;
+		/* Fall through.*/
+	case 'e':
+		precision = (precision < 0) ? 6 : precision;
+		return print_double_scientific(g, precision, width, flags, ps);
+
+	case 'G':
+		flags |= __PRINTF_FLAG_BIGCHARS;
+		/* Fall through.*/
+	case 'g':
+		return print_double_generic(g, precision, width, flags, ps);
+
+	default:
+		assert(false);
+		return -1;
+	}
 }
 
@@ -656,4 +1370,5 @@
 				case '#':
 					flags |= __PRINTF_FLAG_PREFIX;
+					flags |= __PRINTF_FLAG_DECIMALPT;
 					break;
 				case '-':
@@ -701,9 +1416,10 @@
 			
 			/* Precision and '*' operator */
-			int precision = 0;
+			int precision = -1;
 			if (uc == '.') {
 				i = nxt;
 				uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
 				if (isdigit(uc)) {
+					precision = 0;
 					while (true) {
 						precision *= 10;
@@ -723,6 +1439,6 @@
 					precision = (int) va_arg(ap, int);
 					if (precision < 0) {
-						/* Ignore negative precision */
-						precision = 0;
+						/* Ignore negative precision - use default instead */
+						precision = -1;
 					}
 				}
@@ -774,4 +1490,6 @@
 			 */
 			case 's':
+				precision = max(0,  precision);
+				
 				if (qualifier == PrintfQualifierLong)
 					retval = print_wstr(va_arg(ap, wchar_t *), width, precision, flags, ps);
@@ -797,4 +1515,25 @@
 					goto out;
 				};
+				
+				counter += retval;
+				j = nxt;
+				goto next_char;
+				
+			/*
+			 * Floating point values
+			 */
+			case 'G':
+			case 'g':
+			case 'F':
+			case 'f':
+			case 'E':
+			case 'e':
+				retval = print_double(va_arg(ap, double), uc, precision, 
+					width, flags, ps);
+				
+				if (retval < 0) {
+					counter = -counter;
+					goto out;
+				}
 				
 				counter += retval;
Index: uspace/lib/c/generic/power_of_ten.c
===================================================================
--- uspace/lib/c/generic/power_of_ten.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/generic/power_of_ten.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2012 Adam Hraska
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "private/power_of_ten.h"
+
+#include <ieee_double.h>
+#include <assert.h>
+
+/** Precomputed normalized rounded-up powers of 10^k.
+ *
+ * The powers were computed using arbitrary precision arithmetic
+ * and rounded up to the top 64 significant bits. Therefore:
+ *   10^dec_exp == significand * 2^bin_exp  +/- 0.5 ulp error
+ *
+ * The smallest interval of binary exponents computed by hand
+ * is [-1083, 987]. Add 200 (exponent change > 3 * 64 bits) 
+ * to both bounds just to be on the safe side; ie [-1283, 1187].
+ */
+static struct {
+	uint64_t significand;
+	int16_t bin_exp;
+	int16_t dec_exp;
+} fp_powers_of_10[] = {
+	{ 0xb8e1cbc28bef0b69ULL, -1286, -368 },
+	{ 0x89bf722840327f82ULL, -1259, -360 },
+	{ 0xcd42a11346f34f7dULL, -1233, -352 },
+	{ 0x98ee4a22ecf3188cULL, -1206, -344 },
+	{ 0xe3e27a444d8d98b8ULL, -1180, -336 },
+	{ 0xa9c98d8ccb009506ULL, -1153, -328 },
+	{ 0xfd00b897478238d1ULL, -1127, -320 },
+	{ 0xbc807527ed3e12bdULL, -1100, -312 },
+	{ 0x8c71dcd9ba0b4926ULL, -1073, -304 },
+	{ 0xd1476e2c07286faaULL, -1047, -296 },
+	{ 0x9becce62836ac577ULL, -1020, -288 },
+	{ 0xe858ad248f5c22caULL, -994, -280 },
+	{ 0xad1c8eab5ee43b67ULL, -967, -272 },
+	{ 0x80fa687f881c7f8eULL, -940, -264 },
+	{ 0xc0314325637a193aULL, -914, -256 },
+	{ 0x8f31cc0937ae58d3ULL, -887, -248 },
+	{ 0xd5605fcdcf32e1d7ULL, -861, -240 },
+	{ 0x9efa548d26e5a6e2ULL, -834, -232 },
+	{ 0xece53cec4a314ebeULL, -808, -224 },
+	{ 0xb080392cc4349dedULL, -781, -216 },
+	{ 0x8380dea93da4bc60ULL, -754, -208 },
+	{ 0xc3f490aa77bd60fdULL, -728, -200 },
+	{ 0x91ff83775423cc06ULL, -701, -192 },
+	{ 0xd98ddaee19068c76ULL, -675, -184 },
+	{ 0xa21727db38cb0030ULL, -648, -176 },
+	{ 0xf18899b1bc3f8ca2ULL, -622, -168 },
+	{ 0xb3f4e093db73a093ULL, -595, -160 },
+	{ 0x8613fd0145877586ULL, -568, -152 },
+	{ 0xc7caba6e7c5382c9ULL, -542, -144 },
+	{ 0x94db483840b717f0ULL, -515, -136 },
+	{ 0xddd0467c64bce4a1ULL, -489, -128 },
+	{ 0xa54394fe1eedb8ffULL, -462, -120 },
+	{ 0xf64335bcf065d37dULL, -436, -112 },
+	{ 0xb77ada0617e3bbcbULL, -409, -104 },
+	{ 0x88b402f7fd75539bULL, -382, -96 },
+	{ 0xcbb41ef979346bcaULL, -356, -88 },
+	{ 0x97c560ba6b0919a6ULL, -329, -80 },
+	{ 0xe2280b6c20dd5232ULL, -303, -72 },
+	{ 0xa87fea27a539e9a5ULL, -276, -64 },
+	{ 0xfb158592be068d2fULL, -250, -56 },
+	{ 0xbb127c53b17ec159ULL, -223, -48 },
+	{ 0x8b61313bbabce2c6ULL, -196, -40 },
+	{ 0xcfb11ead453994baULL, -170, -32 },
+	{ 0x9abe14cd44753b53ULL, -143, -24 },
+	{ 0xe69594bec44de15bULL, -117, -16 },
+	{ 0xabcc77118461cefdULL, -90, -8 },
+	{ 0x8000000000000000ULL, -63, 0 },
+	{ 0xbebc200000000000ULL, -37, 8 },
+	{ 0x8e1bc9bf04000000ULL, -10, 16 },
+	{ 0xd3c21bcecceda100ULL, 16, 24 },
+	{ 0x9dc5ada82b70b59eULL, 43, 32 },
+	{ 0xeb194f8e1ae525fdULL, 69, 40 },
+	{ 0xaf298d050e4395d7ULL, 96, 48 },
+	{ 0x82818f1281ed44a0ULL, 123, 56 },
+	{ 0xc2781f49ffcfa6d5ULL, 149, 64 },
+	{ 0x90e40fbeea1d3a4bULL, 176, 72 },
+	{ 0xd7e77a8f87daf7fcULL, 202, 80 },
+	{ 0xa0dc75f1778e39d6ULL, 229, 88 },
+	{ 0xefb3ab16c59b14a3ULL, 255, 96 },
+	{ 0xb2977ee300c50fe7ULL, 282, 104 },
+	{ 0x850fadc09923329eULL, 309, 112 },
+	{ 0xc646d63501a1511eULL, 335, 120 },
+	{ 0x93ba47c980e98ce0ULL, 362, 128 },
+	{ 0xdc21a1171d42645dULL, 388, 136 },
+	{ 0xa402b9c5a8d3a6e7ULL, 415, 144 },
+	{ 0xf46518c2ef5b8cd1ULL, 441, 152 },
+	{ 0xb616a12b7fe617aaULL, 468, 160 },
+	{ 0x87aa9aff79042287ULL, 495, 168 },
+	{ 0xca28a291859bbf93ULL, 521, 176 },
+	{ 0x969eb7c47859e744ULL, 548, 184 },
+	{ 0xe070f78d3927556bULL, 574, 192 },
+	{ 0xa738c6bebb12d16dULL, 601, 200 },
+	{ 0xf92e0c3537826146ULL, 627, 208 },
+	{ 0xb9a74a0637ce2ee1ULL, 654, 216 },
+	{ 0x8a5296ffe33cc930ULL, 681, 224 },
+	{ 0xce1de40642e3f4b9ULL, 707, 232 },
+	{ 0x9991a6f3d6bf1766ULL, 734, 240 },
+	{ 0xe4d5e82392a40515ULL, 760, 248 },
+	{ 0xaa7eebfb9df9de8eULL, 787, 256 },
+	{ 0xfe0efb53d30dd4d8ULL, 813, 264 },
+	{ 0xbd49d14aa79dbc82ULL, 840, 272 },
+	{ 0x8d07e33455637eb3ULL, 867, 280 },
+	{ 0xd226fc195c6a2f8cULL, 893, 288 },
+	{ 0x9c935e00d4b9d8d2ULL, 920, 296 },
+	{ 0xe950df20247c83fdULL, 946, 304 },
+	{ 0xadd57a27d29339f6ULL, 973, 312 },
+	{ 0x81842f29f2cce376ULL, 1000, 320 },
+	{ 0xc0fe908895cf3b44ULL, 1026, 328 },
+	{ 0x8fcac257558ee4e6ULL, 1053, 336 },
+	{ 0xd6444e39c3db9b0aULL, 1079, 344 },
+	{ 0x9fa42700db900ad2ULL, 1106, 352 },
+	{ 0xede24ae798ec8284ULL, 1132, 360 },
+	{ 0xb13cc3832ef0c9acULL, 1159, 368 },
+	{ 0x840d57e2899d945fULL, 1186, 376 }
+};
+
+
+/** 
+ * Returns the smallest precomputed power of 10 such that 
+ *  binary_exp <= power_of_10.bin_exp
+ * where
+ *  10^decimal_exp = power_of_10.significand * 2^bin_exp 
+ * with an error of 0.5 ulp in the significand.
+ */
+void get_power_of_ten(int binary_exp, fp_num_t *power_of_10, int *decimal_exp)
+{
+	const int powers_count = sizeof(fp_powers_of_10) / sizeof(fp_powers_of_10[0]);
+	const int min_bin_exp = fp_powers_of_10[0].bin_exp;
+	const int max_bin_exp = fp_powers_of_10[powers_count - 1].bin_exp;
+	const int max_bin_exp_diff = 27;
+
+	assert(min_bin_exp <= binary_exp && binary_exp <= max_bin_exp);
+
+	/* 
+	 * Binary exponent difference between adjacent powers of 10 
+	 * is lg(10^8) = 26.575. The starting search index seed_idx
+	 * undershoots the actual position by less than 1.6%, ie it
+	 * skips 26.575/27 = 98.4% of all the smaller powers. This
+	 * translates to at most three extra tests. 
+	 */
+	int seed_idx = (binary_exp - min_bin_exp) / max_bin_exp_diff;
+
+	assert(fp_powers_of_10[seed_idx].bin_exp < binary_exp);
+
+	for (int i = seed_idx; i < powers_count; ++i) {
+		/* Found the smallest power of 10 with bin_exp >= binary_exp. */
+		if (binary_exp <= fp_powers_of_10[i].bin_exp) {
+			assert(fp_powers_of_10[i].bin_exp <= binary_exp + max_bin_exp_diff);
+
+			power_of_10->significand = fp_powers_of_10[i].significand;
+			power_of_10->exponent = fp_powers_of_10[i].bin_exp;
+			*decimal_exp = fp_powers_of_10[i].dec_exp;
+			return;
+		}
+	}
+
+	assert(false);
+}
+
Index: uspace/lib/c/generic/private/power_of_ten.h
===================================================================
--- uspace/lib/c/generic/private/power_of_ten.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/generic/private/power_of_ten.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012 Adam Hraska
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef POWER_OF_TEN_H_
+#define POWER_OF_TEN_H_
+
+/* Fwd decl. */
+struct fp_num_t_tag;
+
+extern void get_power_of_ten(int, struct fp_num_t_tag *, int *);
+
+#endif
Index: uspace/lib/c/generic/time.c
===================================================================
--- uspace/lib/c/generic/time.c	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/generic/time.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -1,4 +1,6 @@
 /*
  * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2011 Jiri Zarevucky
  * All rights reserved.
  *
@@ -43,5 +45,14 @@
 #include <ddi.h>
 #include <libc.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
 #include <unistd.h>
+#include <loc.h>
+#include <device/clock_dev.h>
+#include <malloc.h>
+
+#define ASCTIME_BUF_LEN 26
 
 /** Pointer to kernel shared variables with time */
@@ -52,4 +63,337 @@
 } *ktime = NULL;
 
+/* Helper functions ***********************************************************/
+
+#define HOURS_PER_DAY (24)
+#define MINS_PER_HOUR (60)
+#define SECS_PER_MIN (60)
+#define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY)
+#define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR)
+#define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY)
+
+/**
+ * Checks whether the year is a leap year.
+ *
+ * @param year Year since 1900 (e.g. for 1970, the value is 70).
+ * @return true if year is a leap year, false otherwise
+ */
+static bool _is_leap_year(time_t year)
+{
+	year += 1900;
+
+	if (year % 400 == 0)
+		return true;
+	if (year % 100 == 0)
+		return false;
+	if (year % 4 == 0)
+		return true;
+	return false;
+}
+
+/**
+ * Returns how many days there are in the given month of the given year.
+ * Note that year is only taken into account if month is February.
+ *
+ * @param year Year since 1900 (can be negative).
+ * @param mon Month of the year. 0 for January, 11 for December.
+ * @return Number of days in the specified month.
+ */
+static int _days_in_month(time_t year, time_t mon)
+{
+	assert(mon >= 0 && mon <= 11);
+
+	static int month_days[] =
+		{ 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+	if (mon == 1) {
+		year += 1900;
+		/* february */
+		return _is_leap_year(year) ? 29 : 28;
+	} else {
+		return month_days[mon];
+	}
+}
+
+/**
+ * For specified year, month and day of month, returns which day of that year
+ * it is.
+ *
+ * For example, given date 2011-01-03, the corresponding expression is:
+ *     _day_of_year(111, 0, 3) == 2
+ *
+ * @param year Year (year 1900 = 0, can be negative).
+ * @param mon Month (January = 0).
+ * @param mday Day of month (First day is 1).
+ * @return Day of year (First day is 0).
+ */
+static int _day_of_year(time_t year, time_t mon, time_t mday)
+{
+	static int mdays[] =
+	    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+	static int leap_mdays[] =
+	    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
+
+	return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1;
+}
+
+/**
+ * Integer division that rounds to negative infinity.
+ * Used by some functions in this file.
+ *
+ * @param op1 Dividend.
+ * @param op2 Divisor.
+ * @return Rounded quotient.
+ */
+static time_t _floor_div(time_t op1, time_t op2)
+{
+	if (op1 >= 0 || op1 % op2 == 0) {
+		return op1 / op2;
+	} else {
+		return op1 / op2 - 1;
+	}
+}
+
+/**
+ * Modulo that rounds to negative infinity.
+ * Used by some functions in this file.
+ *
+ * @param op1 Dividend.
+ * @param op2 Divisor.
+ * @return Remainder.
+ */
+static time_t _floor_mod(time_t op1, time_t op2)
+{
+	int div = _floor_div(op1, op2);
+
+	/* (a / b) * b + a % b == a */
+	/* thus, a % b == a - (a / b) * b */
+
+	int result = op1 - div * op2;
+	
+	/* Some paranoid checking to ensure I didn't make a mistake here. */
+	assert(result >= 0);
+	assert(result < op2);
+	assert(div * op2 + result == op1);
+	
+	return result;
+}
+
+/**
+ * Number of days since the Epoch.
+ * Epoch is 1970-01-01, which is also equal to day 0.
+ *
+ * @param year Year (year 1900 = 0, may be negative).
+ * @param mon Month (January = 0).
+ * @param mday Day of month (first day = 1).
+ * @return Number of days since the Epoch.
+ */
+static time_t _days_since_epoch(time_t year, time_t mon, time_t mday)
+{
+	return (year - 70) * 365 + _floor_div(year - 69, 4) -
+	    _floor_div(year - 1, 100) + _floor_div(year + 299, 400) +
+	    _day_of_year(year, mon, mday);
+}
+
+/**
+ * Seconds since the Epoch. see also _days_since_epoch().
+ * 
+ * @param tm Normalized broken-down time.
+ * @return Number of seconds since the epoch, not counting leap seconds.
+ */
+static time_t _secs_since_epoch(const struct tm *tm)
+{
+	return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) *
+	    SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR +
+	    tm->tm_min * SECS_PER_MIN + tm->tm_sec;
+}
+
+/**
+ * Which day of week the specified date is.
+ * 
+ * @param year Year (year 1900 = 0).
+ * @param mon Month (January = 0).
+ * @param mday Day of month (first = 1).
+ * @return Day of week (Sunday = 0).
+ */
+static int _day_of_week(time_t year, time_t mon, time_t mday)
+{
+	/* 1970-01-01 is Thursday */
+	return _floor_mod((_days_since_epoch(year, mon, mday) + 4), 7);
+}
+
+/**
+ * Normalizes the broken-down time and optionally adds specified amount of
+ * seconds.
+ * 
+ * @param tm Broken-down time to normalize.
+ * @param sec_add Seconds to add.
+ * @return 0 on success, -1 on overflow
+ */
+static int _normalize_time(struct tm *tm, time_t sec_add)
+{
+	// TODO: DST correction
+
+	/* Set initial values. */
+	time_t sec = tm->tm_sec + sec_add;
+	time_t min = tm->tm_min;
+	time_t hour = tm->tm_hour;
+	time_t day = tm->tm_mday - 1;
+	time_t mon = tm->tm_mon;
+	time_t year = tm->tm_year;
+
+	/* Adjust time. */
+	min += _floor_div(sec, SECS_PER_MIN);
+	sec = _floor_mod(sec, SECS_PER_MIN);
+	hour += _floor_div(min, MINS_PER_HOUR);
+	min = _floor_mod(min, MINS_PER_HOUR);
+	day += _floor_div(hour, HOURS_PER_DAY);
+	hour = _floor_mod(hour, HOURS_PER_DAY);
+
+	/* Adjust month. */
+	year += _floor_div(mon, 12);
+	mon = _floor_mod(mon, 12);
+
+	/* Now the difficult part - days of month. */
+	
+	/* First, deal with whole cycles of 400 years = 146097 days. */
+	year += _floor_div(day, 146097) * 400;
+	day = _floor_mod(day, 146097);
+	
+	/* Then, go in one year steps. */
+	if (mon <= 1) {
+		/* January and February. */
+		while (day > 365) {
+			day -= _is_leap_year(year) ? 366 : 365;
+			year++;
+		}
+	} else {
+		/* Rest of the year. */
+		while (day > 365) {
+			day -= _is_leap_year(year + 1) ? 366 : 365;
+			year++;
+		}
+	}
+	
+	/* Finally, finish it off month per month. */
+	while (day >= _days_in_month(year, mon)) {
+		day -= _days_in_month(year, mon);
+		mon++;
+		if (mon >= 12) {
+			mon -= 12;
+			year++;
+		}
+	}
+	
+	/* Calculate the remaining two fields. */
+	tm->tm_yday = _day_of_year(year, mon, day + 1);
+	tm->tm_wday = _day_of_week(year, mon, day + 1);
+	
+	/* And put the values back to the struct. */
+	tm->tm_sec = (int) sec;
+	tm->tm_min = (int) min;
+	tm->tm_hour = (int) hour;
+	tm->tm_mday = (int) day + 1;
+	tm->tm_mon = (int) mon;
+	
+	/* Casts to work around libc brain-damage. */
+	if (year > ((int)INT_MAX) || year < ((int)INT_MIN)) {
+		tm->tm_year = (year < 0) ? ((int)INT_MIN) : ((int)INT_MAX);
+		return -1;
+	}
+	
+	tm->tm_year = (int) year;
+	return 0;
+}
+
+/**
+ * Which day the week-based year starts on, relative to the first calendar day.
+ * E.g. if the year starts on December 31st, the return value is -1.
+ *
+ * @param Year since 1900.
+ * @return Offset of week-based year relative to calendar year.
+ */
+static int _wbyear_offset(int year)
+{
+	int start_wday = _day_of_week(year, 0, 1);
+	return _floor_mod(4 - start_wday, 7) - 3;
+}
+
+/**
+ * Returns week-based year of the specified time.
+ *
+ * @param tm Normalized broken-down time.
+ * @return Week-based year.
+ */
+static int _wbyear(const struct tm *tm)
+{
+	int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
+	if (day < 0) {
+		/* Last week of previous year. */
+		return tm->tm_year - 1;
+	}
+	if (day > 364 + _is_leap_year(tm->tm_year)) {
+		/* First week of next year. */
+		return tm->tm_year + 1;
+	}
+	/* All the other days are in the calendar year. */
+	return tm->tm_year;
+}
+
+/**
+ * Week number of the year, assuming weeks start on sunday.
+ * The first Sunday of January is the first day of week 1;
+ * days in the new year before this are in week 0.
+ *
+ * @param tm Normalized broken-down time.
+ * @return The week number (0 - 53).
+ */
+static int _sun_week_number(const struct tm *tm)
+{
+	int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7;
+	return (tm->tm_yday - first_day + 7) / 7;
+}
+
+/**
+ * Week number of the year, assuming weeks start on monday.
+ * If the week containing January 1st has four or more days in the new year,
+ * then it is considered week 1. Otherwise, it is the last week of the previous
+ * year, and the next week is week 1. Both January 4th and the first Thursday
+ * of January are always in week 1.
+ *
+ * @param tm Normalized broken-down time.
+ * @return The week number (1 - 53).
+ */
+static int _iso_week_number(const struct tm *tm)
+{
+	int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
+	if (day < 0) {
+		/* Last week of previous year. */
+		return 53;
+	}
+	if (day > 364 + _is_leap_year(tm->tm_year)) {
+		/* First week of next year. */
+		return 1;
+	}
+	/* All the other days give correct answer. */
+	return (day / 7 + 1);
+}
+
+/**
+ * Week number of the year, assuming weeks start on monday.
+ * The first Monday of January is the first day of week 1;
+ * days in the new year before this are in week 0. 
+ *
+ * @param tm Normalized broken-down time.
+ * @return The week number (0 - 53).
+ */
+static int _mon_week_number(const struct tm *tm)
+{
+	int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7;
+	return (tm->tm_yday - first_day + 7) / 7;
+}
+
+/******************************************************************************/
+
+
 /** Add microseconds to given timeval.
  *
@@ -139,4 +483,67 @@
  */
 int gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+	int rc;
+	struct tm t;
+	category_id_t cat_id;
+	size_t svc_cnt;
+	service_id_t *svc_ids = NULL;
+	service_id_t svc_id;
+	char *svc_name = NULL;
+
+	static async_sess_t *clock_conn = NULL;
+
+	if (tz) {
+		tz->tz_minuteswest = 0;
+		tz->tz_dsttime = DST_NONE;
+	}
+
+	if (clock_conn == NULL) {
+		rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING);
+		if (rc != EOK)
+			goto ret_uptime;
+
+		rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt);
+		if (rc != EOK)
+			goto ret_uptime;
+
+		if (svc_cnt == 0)
+			goto ret_uptime;
+
+		rc = loc_service_get_name(svc_ids[0], &svc_name);
+		if (rc != EOK)
+			goto ret_uptime;
+
+		rc = loc_service_get_id(svc_name, &svc_id, 0);
+		if (rc != EOK)
+			goto ret_uptime;
+
+		clock_conn = loc_service_connect(EXCHANGE_SERIALIZE,
+		    svc_id, IPC_FLAG_BLOCKING);
+		if (!clock_conn)
+			goto ret_uptime;
+	}
+
+	rc = clock_dev_time_get(clock_conn, &t);
+	if (rc != EOK)
+		goto ret_uptime;
+
+	tv->tv_usec = 0;
+	tv->tv_sec = mktime(&t);
+
+	free(svc_name);
+	free(svc_ids);
+
+	return EOK;
+
+ret_uptime:
+
+	free(svc_name);
+	free(svc_ids);
+
+	return getuptime(tv);
+}
+
+int getuptime(struct timeval *tv)
 {
 	if (ktime == NULL) {
@@ -160,9 +567,4 @@
 	}
 	
-	if (tz) {
-		tz->tz_minuteswest = 0;
-		tz->tz_dsttime = DST_NONE;
-	}
-	
 	sysarg_t s2 = ktime->seconds2;
 	
@@ -178,5 +580,5 @@
 	} else
 		tv->tv_sec = s1;
-	
+
 	return 0;
 }
@@ -229,4 +631,355 @@
 }
 
+/**
+ * This function first normalizes the provided broken-down time
+ * (moves all values to their proper bounds) and then tries to
+ * calculate the appropriate time_t representation.
+ *
+ * @param tm Broken-down time.
+ * @return time_t representation of the time, undefined value on overflow.
+ */
+time_t mktime(struct tm *tm)
+{
+	// TODO: take DST flag into account
+	// TODO: detect overflow
+
+	_normalize_time(tm, 0);
+	return _secs_since_epoch(tm);
+}
+
+/**
+ * Convert time and date to a string, based on a specified format and
+ * current locale.
+ * 
+ * @param s Buffer to write string to.
+ * @param maxsize Size of the buffer.
+ * @param format Format of the output.
+ * @param tm Broken-down time to format.
+ * @return Number of bytes written.
+ */
+size_t strftime(char *restrict s, size_t maxsize,
+    const char *restrict format, const struct tm *restrict tm)
+{
+	assert(s != NULL);
+	assert(format != NULL);
+	assert(tm != NULL);
+
+	// TODO: use locale
+	static const char *wday_abbr[] = {
+		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+	};
+	static const char *wday[] = {
+		"Sunday", "Monday", "Tuesday", "Wednesday",
+		"Thursday", "Friday", "Saturday"
+	};
+	static const char *mon_abbr[] = {
+		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+	};
+	static const char *mon[] = {
+		"January", "February", "March", "April", "May", "June", "July",
+		"August", "September", "October", "November", "December"
+	};
+	
+	if (maxsize < 1) {
+		return 0;
+	}
+	
+	char *ptr = s;
+	size_t consumed;
+	size_t remaining = maxsize;
+	
+	#define append(...) { \
+		/* FIXME: this requires POSIX-correct snprintf */ \
+		/*        otherwise it won't work with non-ascii chars */ \
+		consumed = snprintf(ptr, remaining, __VA_ARGS__); \
+		if (consumed >= remaining) { \
+			return 0; \
+		} \
+		ptr += consumed; \
+		remaining -= consumed; \
+	}
+	
+	#define recurse(fmt) { \
+		consumed = strftime(ptr, remaining, fmt, tm); \
+		if (consumed == 0) { \
+			return 0; \
+		} \
+		ptr += consumed; \
+		remaining -= consumed; \
+	}
+	
+	#define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \
+	    (((hour) == 0) ? 12 : (hour)))
+	
+	while (*format != '\0') {
+		if (*format != '%') {
+			append("%c", *format);
+			format++;
+			continue;
+		}
+		
+		format++;
+		if (*format == '0' || *format == '+') {
+			// TODO: padding
+			format++;
+		}
+		while (isdigit(*format)) {
+			// TODO: padding
+			format++;
+		}
+		if (*format == 'O' || *format == 'E') {
+			// TODO: locale's alternative format
+			format++;
+		}
+		
+		switch (*format) {
+		case 'a':
+			append("%s", wday_abbr[tm->tm_wday]); break;
+		case 'A':
+			append("%s", wday[tm->tm_wday]); break;
+		case 'b':
+			append("%s", mon_abbr[tm->tm_mon]); break;
+		case 'B':
+			append("%s", mon[tm->tm_mon]); break;
+		case 'c':
+			// TODO: locale-specific datetime format
+			recurse("%Y-%m-%d %H:%M:%S"); break;
+		case 'C':
+			append("%02d", (1900 + tm->tm_year) / 100); break;
+		case 'd':
+			append("%02d", tm->tm_mday); break;
+		case 'D':
+			recurse("%m/%d/%y"); break;
+		case 'e':
+			append("%2d", tm->tm_mday); break;
+		case 'F':
+			recurse("%+4Y-%m-%d"); break;
+		case 'g':
+			append("%02d", _wbyear(tm) % 100); break;
+		case 'G':
+			append("%d", _wbyear(tm)); break;
+		case 'h':
+			recurse("%b"); break;
+		case 'H':
+			append("%02d", tm->tm_hour); break;
+		case 'I':
+			append("%02d", TO_12H(tm->tm_hour)); break;
+		case 'j':
+			append("%03d", tm->tm_yday); break;
+		case 'k':
+			append("%2d", tm->tm_hour); break;
+		case 'l':
+			append("%2d", TO_12H(tm->tm_hour)); break;
+		case 'm':
+			append("%02d", tm->tm_mon); break;
+		case 'M':
+			append("%02d", tm->tm_min); break;
+		case 'n':
+			append("\n"); break;
+		case 'p':
+			append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break;
+		case 'P':
+			append("%s", tm->tm_hour < 12 ? "am" : "PM"); break;
+		case 'r':
+			recurse("%I:%M:%S %p"); break;
+		case 'R':
+			recurse("%H:%M"); break;
+		case 's':
+			append("%ld", _secs_since_epoch(tm)); break;
+		case 'S':
+			append("%02d", tm->tm_sec); break;
+		case 't':
+			append("\t"); break;
+		case 'T':
+			recurse("%H:%M:%S"); break;
+		case 'u':
+			append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
+			break;
+		case 'U':
+			append("%02d", _sun_week_number(tm)); break;
+		case 'V':
+			append("%02d", _iso_week_number(tm)); break;
+		case 'w':
+			append("%d", tm->tm_wday); break;
+		case 'W':
+			append("%02d", _mon_week_number(tm)); break;
+		case 'x':
+			// TODO: locale-specific date format
+			recurse("%Y-%m-%d"); break;
+		case 'X':
+			// TODO: locale-specific time format
+			recurse("%H:%M:%S"); break;
+		case 'y':
+			append("%02d", tm->tm_year % 100); break;
+		case 'Y':
+			append("%d", 1900 + tm->tm_year); break;
+		case 'z':
+			// TODO: timezone
+			break;
+		case 'Z':
+			// TODO: timezone
+			break;
+		case '%':
+			append("%%");
+			break;
+		default:
+			/* Invalid specifier, print verbatim. */
+			while (*format != '%') {
+				format--;
+			}
+			append("%%");
+			break;
+		}
+		format++;
+	}
+	
+	#undef append
+	#undef recurse
+	
+	return maxsize - remaining;
+}
+
+
+/** Converts a time value to a broken-down UTC time
+ *
+ * @param time    Time to convert
+ * @param result  Structure to store the result to
+ *
+ * @return        EOK or a negative error code
+ */
+int time_utc2tm(const time_t time, struct tm *restrict result)
+{
+	assert(result != NULL);
+
+	/* Set result to epoch. */
+	result->tm_sec = 0;
+	result->tm_min = 0;
+	result->tm_hour = 0;
+	result->tm_mday = 1;
+	result->tm_mon = 0;
+	result->tm_year = 70; /* 1970 */
+
+	if (_normalize_time(result, time) == -1)
+		return EOVERFLOW;
+
+	return EOK;
+}
+
+/** Converts a time value to a null terminated string of the form
+ *  "Wed Jun 30 21:49:08 1993\n" expressed in UTC.
+ *
+ * @param time   Time to convert.
+ * @param buf    Buffer to store the string to, must be at least
+ *               ASCTIME_BUF_LEN bytes long.
+ *
+ * @return       EOK or a negative error code.
+ */
+int time_utc2str(const time_t time, char *restrict buf)
+{
+	struct tm t;
+	int r;
+
+	if ((r = time_utc2tm(time, &t)) != EOK)
+		return r;
+
+	time_tm2str(&t, buf);
+	return EOK;
+}
+
+
+/**
+ * Converts broken-down time to a string in format
+ * "Sun Jan 1 00:00:00 1970\n". (Obsolete)
+ *
+ * @param timeptr Broken-down time structure.
+ * @param buf     Buffer to store string to, must be at least ASCTIME_BUF_LEN
+ *                bytes long.
+ */
+void time_tm2str(const struct tm *restrict timeptr, char *restrict buf)
+{
+	assert(timeptr != NULL);
+	assert(buf != NULL);
+
+	static const char *wday[] = {
+		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+	};
+	static const char *mon[] = {
+		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+	};
+
+	snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n",
+	    wday[timeptr->tm_wday],
+	    mon[timeptr->tm_mon],
+	    timeptr->tm_mday, timeptr->tm_hour,
+	    timeptr->tm_min, timeptr->tm_sec,
+	    1900 + timeptr->tm_year);
+}
+
+/**
+ * Converts a time value to a broken-down local time, expressed relative
+ * to the user's specified timezone.
+ *
+ * @param timer     Time to convert.
+ * @param result    Structure to store the result to.
+ *
+ * @return          EOK on success or a negative error code.
+ */
+int time_local2tm(const time_t time, struct tm *restrict result)
+{
+	// TODO: deal with timezone
+	// currently assumes system and all times are in GMT
+
+	/* Set result to epoch. */
+	result->tm_sec = 0;
+	result->tm_min = 0;
+	result->tm_hour = 0;
+	result->tm_mday = 1;
+	result->tm_mon = 0;
+	result->tm_year = 70; /* 1970 */
+
+	if (_normalize_time(result, time) == -1)
+		return EOVERFLOW;
+
+	return EOK;
+}
+
+/**
+ * Converts the calendar time to a null terminated string
+ * of the form "Wed Jun 30 21:49:08 1993\n" expressed relative to the
+ * user's specified timezone.
+ * 
+ * @param timer  Time to convert.
+ * @param buf    Buffer to store the string to. Must be at least
+ *               ASCTIME_BUF_LEN bytes long.
+ *
+ * @return       EOK on success or a negative error code.
+ */
+int time_local2str(const time_t time, char *buf)
+{
+	struct tm loctime;
+	int r;
+
+	if ((r = time_local2tm(time, &loctime)) != EOK)
+		return r;
+
+	time_tm2str(&loctime, buf);
+
+	return EOK;
+}
+
+/**
+ * Calculate the difference between two times, in seconds.
+ * 
+ * @param time1 First time.
+ * @param time0 Second time.
+ * @return Time in seconds.
+ */
+double difftime(time_t time1, time_t time0)
+{
+	return (double) (time1 - time0);
+}
+
 /** @}
  */
Index: uspace/lib/c/generic/tls.c
===================================================================
--- uspace/lib/c/generic/tls.c	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/generic/tls.c	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -42,4 +42,5 @@
 #include <str.h>
 #include <align.h>
+#include <unistd.h>
 
 /** Create TLS (Thread Local Storage) data structures.
@@ -57,4 +58,6 @@
 	
 	tcb = __alloc_tls(&data, tls_size);
+	if (!tcb)
+		return NULL;
 	
 	/*
@@ -89,5 +92,8 @@
 
 	result = malloc(sizeof(tcb_t) + size);
+	if (!result)
+		return NULL;
 	*data = ((void *)result) + sizeof(tcb_t);
+
 	return result;
 }
@@ -118,5 +124,6 @@
 	size = ALIGN_UP(size, &_tls_alignment);
 	*data = memalign((uintptr_t) &_tls_alignment, sizeof(tcb_t) + size);
-
+	if (!*data)
+		return NULL;
 	tcb = (tcb_t *) (*data + size);
 	tcb->self = tcb;
Index: uspace/lib/c/include/device/battery_dev.h
===================================================================
--- uspace/lib/c/include/device/battery_dev.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/include/device/battery_dev.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_DEVICE_BATTERY_DEV_H_
+#define LIBC_DEVICE_BATTERY_DEV_H_
+
+#include <async.h>
+
+typedef enum {
+	BATTERY_OK,
+	BATTERY_LOW,
+	BATTERY_NOT_PRESENT,
+} battery_status_t;
+
+typedef enum {
+	BATTERY_STATUS_GET = 0,
+	BATTERY_CHARGE_LEVEL_GET,
+} battery_dev_method_t;
+
+extern int battery_status_get(async_sess_t *, battery_status_t *);
+extern int battery_charge_level_get(async_sess_t *, int *);
+
+#endif
+
Index: uspace/lib/c/include/device/clock_dev.h
===================================================================
--- uspace/lib/c/include/device/clock_dev.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/include/device/clock_dev.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_DEVICE_CLOCK_DEV_H_
+#define LIBC_DEVICE_CLOCK_DEV_H_
+
+#include <async.h>
+#include <time.h>
+
+typedef enum {
+	CLOCK_DEV_TIME_GET = 0,
+	CLOCK_DEV_TIME_SET,
+} clock_dev_method_t;
+
+extern int clock_dev_time_get(async_sess_t *, struct tm *);
+extern int clock_dev_time_set(async_sess_t *, struct tm *);
+
+#endif
+
Index: uspace/lib/c/include/double_to_str.h
===================================================================
--- uspace/lib/c/include/double_to_str.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/include/double_to_str.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012 Adam Hraska
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DOUBLE_TO_STR_H_
+#define DOUBLE_TO_STR_H_
+
+#include <unistd.h>
+
+/** Maximum number of digits double_to_*_str conversion functions produce. 
+ *
+ * Both double_to_short_str and double_to_fixed_str generate digits out
+ * of a 64bit unsigned int number representation. The max number of 
+ * of digits is therefore 20. Add 1 to help users who forget to reserve
+ * space for a null terminator.
+ */
+#define MAX_DOUBLE_STR_LEN (20 + 1)
+
+/** Maximum buffer size needed to store the output of double_to_*_str 
+ *  functions. 
+ */
+#define MAX_DOUBLE_STR_BUF_SIZE  21
+
+/* Fwd decl.*/
+struct ieee_double_t_tag;
+
+extern int double_to_short_str(struct ieee_double_t_tag, char *, size_t, int *);
+extern int double_to_fixed_str(struct ieee_double_t_tag, int, int, char *,
+    size_t, int *);
+
+#endif 
Index: uspace/lib/c/include/ieee_double.h
===================================================================
--- uspace/lib/c/include/ieee_double.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/include/ieee_double.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2012 Adam Hraska
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IEEE_DOUBLE_H_
+#define IEEE_DOUBLE_H_
+
+#include <stdint.h>
+#include <bool.h>
+
+/** Represents a non-negative floating point number: significand * 2^exponent */
+typedef struct fp_num_t_tag {
+	/** Significand (aka mantissa). */
+	uint64_t significand;
+	/** Binary exponent. */
+	int exponent;
+} fp_num_t;
+
+/** Double number description according to IEEE 754. */
+typedef struct ieee_double_t_tag {
+	/** The number is a NaN or infinity. */
+	bool is_special;
+	/** Not a number. */
+	bool is_nan;
+	bool is_negative;
+	/** The number denoted infinity. */
+	bool is_infinity;
+	/** The number could not be represented as a normalized double. */
+	bool is_denormal;
+	/**
+	 * The predecessor double is closer than the successor. This happens 
+	 * if a normal number is of the form 2^k and it is not the smallest
+	 * normal number. 
+	 */
+	bool is_accuracy_step;
+	/** 
+	 * If !is_special the double's value is:
+	 *   pos_val.significand * 2^pos_val.exponent
+	 */
+	fp_num_t pos_val;
+} ieee_double_t;
+
+extern ieee_double_t extract_ieee_double(double);
+
+#endif
Index: uspace/lib/c/include/io/con_srv.h
===================================================================
--- uspace/lib/c/include/io/con_srv.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/include/io/con_srv.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_CON_SRV_H_
+#define LIBC_CON_SRV_H_
+
+#include <adt/list.h>
+#include <async.h>
+#include <fibril_synch.h>
+#include <io/color.h>
+#include <io/concaps.h>
+#include <io/kbd_event.h>
+#include <io/pixel.h>
+#include <io/style.h>
+#include <bool.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+typedef struct con_ops con_ops_t;
+
+/** Service setup (per sevice) */
+typedef struct {
+	con_ops_t *ops;
+	void *sarg;
+	/** Period to check for abort */
+	suseconds_t abort_timeout;
+	bool aborted;
+} con_srvs_t;
+
+/** Server structure (per client session) */
+typedef struct {
+	con_srvs_t *srvs;
+	async_sess_t *client_sess;
+	void *carg;
+} con_srv_t;
+
+typedef struct con_ops {
+	int (*open)(con_srvs_t *, con_srv_t *);
+	int (*close)(con_srv_t *);
+	int (*read)(con_srv_t *, void *, size_t);
+	int (*write)(con_srv_t *, void *, size_t);
+	void (*sync)(con_srv_t *);
+	void (*clear)(con_srv_t *);
+	void (*set_pos)(con_srv_t *, sysarg_t col, sysarg_t row);
+	int (*get_pos)(con_srv_t *, sysarg_t *, sysarg_t *);
+	int (*get_size)(con_srv_t *, sysarg_t *, sysarg_t *);
+	int (*get_color_cap)(con_srv_t *, console_caps_t *);
+	void (*set_style)(con_srv_t *, console_style_t);
+	void (*set_color)(con_srv_t *, console_color_t, console_color_t,
+	    console_color_attr_t);
+	void (*set_rgb_color)(con_srv_t *, pixel_t, pixel_t);
+	void (*set_cursor_visibility)(con_srv_t *, bool);
+	int (*get_event)(con_srv_t *, kbd_event_t *);
+} con_ops_t;
+
+extern void con_srvs_init(con_srvs_t *);
+
+extern int con_conn(ipc_callid_t, ipc_call_t *, con_srvs_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/io/concaps.h
===================================================================
--- uspace/lib/c/include/io/concaps.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/include/io/concaps.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libcipc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_IO_CONCAPS_H_
+#define LIBC_IO_CONCAPS_H_
+
+typedef enum {
+	CONSOLE_CAP_NONE = 0,
+	CONSOLE_CAP_STYLE = 1,
+	CONSOLE_CAP_INDEXED = 2,
+	CONSOLE_CAP_RGB = 4
+} console_caps_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/io/console.h
===================================================================
--- uspace/lib/c/include/io/console.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/include/io/console.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -37,4 +37,5 @@
 
 #include <sys/time.h>
+#include <io/concaps.h>
 #include <io/kbd_event.h>
 #include <io/keycode.h>
@@ -42,11 +43,4 @@
 #include <bool.h>
 #include <stdio.h>
-
-typedef enum {
-	CONSOLE_CAP_NONE = 0,
-	CONSOLE_CAP_STYLE = 1,
-	CONSOLE_CAP_INDEXED = 2,
-	CONSOLE_CAP_RGB = 4
-} console_caps_t;
 
 /** Console control structure. */
Index: uspace/lib/c/include/io/klog.h
===================================================================
--- uspace/lib/c/include/io/klog.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/include/io/klog.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -38,8 +38,10 @@
 #include <sys/types.h>
 #include <stdarg.h>
+#include <io/verify.h>
 
 extern size_t klog_write(const void *, size_t);
 extern void klog_update(void);
-extern int klog_printf(const char *, ...);
+extern int klog_printf(const char *, ...)
+    PRINTF_ATTRIBUTE(1, 2);
 extern int klog_vprintf(const char *, va_list);
 
Index: uspace/lib/c/include/io/log.h
===================================================================
--- uspace/lib/c/include/io/log.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/include/io/log.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -36,20 +36,46 @@
 
 #include <stdarg.h>
+#include <inttypes.h>
+#include <io/verify.h>
 
+/** Log message level. */
 typedef enum {
+	/** Fatal error, program is not able to recover at all. */
 	LVL_FATAL,
+	/** Serious error but the program can recover from it. */
 	LVL_ERROR,
+	/** Easily recoverable problem. */
 	LVL_WARN,
+	/** Information message that ought to be printed by default. */
 	LVL_NOTE,
+	/** Debugging purpose message. */
 	LVL_DEBUG,
+	/** More detailed debugging message. */
 	LVL_DEBUG2,
-
+	
 	/** For checking range of values */
 	LVL_LIMIT
 } log_level_t;
 
-extern int log_init(const char *, log_level_t);
-extern void log_msg(log_level_t, const char *, ...);
-extern void log_msgv(log_level_t, const char *, va_list);
+/** Log itself (logging target). */
+typedef sysarg_t log_t;
+/** Formatting directive for printing log_t. */
+#define PRIlogctx PRIxn
+
+/** Default log (target). */
+#define LOG_DEFAULT ((log_t) -1)
+
+/** Use when creating new top-level log. */
+#define LOG_NO_PARENT ((log_t) 0)
+
+extern const char *log_level_str(log_level_t);
+extern int log_level_from_str(const char *, log_level_t *);
+
+extern int log_init(const char *);
+extern log_t log_create(const char *, log_t);
+
+extern void log_msg(log_t, log_level_t, const char *, ...)
+    PRINTF_ATTRIBUTE(3, 4);
+extern void log_msgv(log_t, log_level_t, const char *, va_list);
 
 #endif
Index: uspace/lib/c/include/io/logctl.h
===================================================================
--- uspace/lib/c/include/io/logctl.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/include/io/logctl.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2011-2012 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+
+#ifndef LIBC_IO_LOGCTL_H_
+#define LIBC_IO_LOGCTL_H_
+
+#include <io/log.h>
+
+extern int logctl_set_default_level(log_level_t);
+extern int logctl_set_log_level(const char *, log_level_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/io/verify.h
===================================================================
--- uspace/lib/c/include/io/verify.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/include/io/verify.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_IO_VERIFY_H_
+#define LIBC_IO_VERIFY_H_
+
+#ifndef NVERIFY_PRINTF
+
+#define PRINTF_ATTRIBUTE(start, end) \
+	__attribute__((format(gnu_printf, start, end)))
+
+#else /* NVERIFY_PRINTF */
+
+#define PRINTF_ATTRIBUTE(start, end)
+
+#endif /* NVERIFY_PRINTF */
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/ipc/console.h
===================================================================
--- uspace/lib/c/include/ipc/console.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/include/ipc/console.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -43,10 +43,10 @@
 	CONSOLE_GET_EVENT,
 	CONSOLE_GET_POS,
-	CONSOLE_GOTO,
+	CONSOLE_SET_POS,
 	CONSOLE_CLEAR,
 	CONSOLE_SET_STYLE,
 	CONSOLE_SET_COLOR,
 	CONSOLE_SET_RGB_COLOR,
-	CONSOLE_CURSOR_VISIBILITY
+	CONSOLE_SET_CURSOR_VISIBILITY
 } console_request_t;
 
Index: uspace/lib/c/include/ipc/dev_iface.h
===================================================================
--- uspace/lib/c/include/ipc/dev_iface.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/include/ipc/dev_iface.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -54,4 +54,8 @@
 	/** Interface provided by USB HID devices. */
 	USBHID_DEV_IFACE,
+	/** Interface provided by Real Time Clock devices */
+	CLOCK_DEV_IFACE,
+	/** Interface provided by battery powered devices */
+	BATTERY_DEV_IFACE,
 	/** Interface provided by AHCI devices. */
 	AHCI_DEV_IFACE,
Index: uspace/lib/c/include/ipc/logger.h
===================================================================
--- uspace/lib/c/include/ipc/logger.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
+++ uspace/lib/c/include/ipc/logger.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+
+#ifndef LIBC_IPC_LOGGER_H_
+#define LIBC_IPC_LOGGER_H_
+
+#include <ipc/common.h>
+
+typedef enum {
+	/** Set (global) default displayed logging level.
+	 *
+	 * Arguments: new log level.
+	 * Returns: error code
+	 */
+	LOGGER_CONTROL_SET_DEFAULT_LEVEL = IPC_FIRST_USER_METHOD,
+	/** Set displayed level for given log.
+	 *
+	 * Arguments: new log level.
+	 * Returns: error code
+	 * Followed by: string with full log name.
+	 */
+	LOGGER_CONTROL_SET_LOG_LEVEL
+} logger_control_request_t;
+
+typedef enum {
+	/** Create new log.
+	 *
+	 * Arguments: parent log id (0 for top-level log).
+	 * Returns: error code, log id
+	 * Followed by: string with log name.
+	 */
+	LOGGER_WRITER_CREATE_LOG = IPC_FIRST_USER_METHOD,
+	/** Write a message to a given log.
+	 *
+	 * Arguments: log id, message severity level (log_level_t)
+	 * Returns: error code
+	 * Followed by: string with the message.
+	 */
+	LOGGER_WRITER_MESSAGE
+} logger_writer_request_t;
+
+typedef enum {
+	/** Interface for controlling logger behavior. */
+	LOGGER_INTERFACE_CONTROL,
+	/** Interface for servers writing to the log. */
+	LOGGER_INTERFACE_WRITER
+} logger_interface_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/ipc/services.h
===================================================================
--- uspace/lib/c/include/ipc/services.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/include/ipc/services.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -45,4 +45,5 @@
 	SERVICE_VFS        = FOURCC('v', 'f', 's', ' '),
 	SERVICE_LOC        = FOURCC('l', 'o', 'c', ' '),
+	SERVICE_LOGGER     = FOURCC('l', 'o', 'g', 'g'),
 	SERVICE_DEVMAN     = FOURCC('d', 'e', 'v', 'n'),
 	SERVICE_IRC        = FOURCC('i', 'r', 'c', ' '),
Index: uspace/lib/c/include/macros.h
===================================================================
--- uspace/lib/c/include/macros.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/include/macros.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -38,4 +38,6 @@
 #define min(a, b)  ((a) < (b) ? (a) : (b))
 #define max(a, b)  ((a) > (b) ? (a) : (b))
+#define abs(a)     ((a) >= 0 ? (a) : (-a))
+
 
 #define KiB2SIZE(kb)  ((kb) << 10)
Index: uspace/lib/c/include/stdio.h
===================================================================
--- uspace/lib/c/include/stdio.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/include/stdio.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -39,15 +39,5 @@
 #include <stdarg.h>
 #include <str.h>
-
-#ifndef NVERIFY_PRINTF
-
-#define PRINTF_ATTRIBUTE(start, end) \
-	__attribute__((format(gnu_printf, start, end)))
-
-#else /* NVERIFY_PRINTF */
-
-#define PRINTF_ATTRIBUTE(start, end)
-
-#endif /* NVERIFY_PRINTF */
+#include <io/verify.h>
 
 #define EOF  (-1)
Index: uspace/lib/c/include/sys/time.h
===================================================================
--- uspace/lib/c/include/sys/time.h	(revision 205832be3aac366938f4e110d02825acf0142693)
+++ uspace/lib/c/include/sys/time.h	(revision dcb07513e66a1ecb603d6f380ffee05fa3b4e187)
@@ -1,4 +1,6 @@
 /*
  * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2011 Jiri Zarevucky
  * All rights reserved.
  *
@@ -39,4 +41,5 @@
 
 #define DST_NONE 0
+#define ASCTIME_BUF_LEN 26
 
 typedef long time_t;
@@ -45,4 +48,16 @@
 typedef uint32_t useconds_t;
 typedef uint32_t mseconds_t;
+
+struct tm {
+	int tm_sec;         /* Seconds [0,60]. */
+	int tm_min;         /* Minutes [0,59]. */
+	int tm_hour;        /* Hour [0,23]. */
+	int tm_mday;        /* Day of month [1,31]. */
+	int tm_mon;         /* Month of year [0,11]. */
+	int tm_year;        /* Years since 1900. */
+	int tm_wday;        /* Day of week [0,6] (Sunday = 0). */
+	int tm_yday;        /* Day of year [0,365]. */
+	int tm_isdst;       /* Daylight Savings flag. */
+};
 
 struct timeval {
@@ -61,6 +76,17 @@
 extern int tv_gteq(struct timeval *tv1, struct timeval *tv2);
 extern int gettimeofday(struct timeval *tv, struct timezone *tz);
+extern int getuptime(struct timeval *tv);
 
 extern void udelay(useconds_t);
+
+extern time_t mktime(struct tm *tm);
+extern int time_utc2tm(const time_t time, struct tm *result);
+extern int time_utc2str(const time_t time, char *buf);
+extern void time_tm2str(const struct tm *timeptr, char *buf);
+extern int time_local2tm(const time_t time, struct tm *result);
+extern int time_local2str(const time_t time, char *buf);
+extern double difftime(time_t time1, time_t time0);
+extern size_t strftime(char *restrict s, size_t maxsize,
+    const char *restrict format, const struct tm *restrict tm);
 
 #endif
