Index: kernel/generic/src/sysinfo/sysinfo.c
===================================================================
--- kernel/generic/src/sysinfo/sysinfo.c	(revision 560d79ff73b54aa14113d7a5215931b4a9443e94)
+++ kernel/generic/src/sysinfo/sysinfo.c	(revision 76f382b9b45e8460f46017535a7dbebc23d9e5e1)
@@ -678,22 +678,28 @@
 		root = &global_root;
 	
-	/* Try to find the item */
-	sysinfo_item_t *item = sysinfo_find_item(name, *root, NULL,
-	    dry_run);
+	sysinfo_item_t *subtree = NULL;
+	
+	if (name[0] != 0) {
+		/* Try to find the item */
+		sysinfo_item_t *item =
+		    sysinfo_find_item(name, *root, NULL, dry_run);
+		if ((item != NULL) &&
+		    (item->subtree_type == SYSINFO_SUBTREE_TABLE))
+			subtree = item->subtree.table;
+	} else
+		subtree = *root;
 	
 	sysinfo_return_t ret;
 	
-	if ((item != NULL) && (item->subtree_type == SYSINFO_SUBTREE_TABLE)) {
+	if (subtree != NULL) {
 		/*
-		 * Subtree found in the fixed sysinfo tree.
 		 * Calculate the size of subkeys.
 		 */
 		size_t size = 0;
-		for (sysinfo_item_t *cur = item->subtree.table; cur;
-		    cur = cur->next)
+		for (sysinfo_item_t *cur = subtree; cur; cur = cur->next)
 			size += str_size(cur->name) + 1;
 		
 		if (dry_run) {
-			ret.tag = SYSINFO_VAL_FUNCTION_DATA;
+			ret.tag = SYSINFO_VAL_DATA;
 			ret.data.data = NULL;
 			ret.data.size = size;
@@ -705,6 +711,5 @@
 			
 			size_t pos = 0;
-			for (sysinfo_item_t *cur = item->subtree.table; cur;
-			    cur = cur->next) {
+			for (sysinfo_item_t *cur = subtree; cur; cur = cur->next) {
 				str_cpy(names + pos, size - pos, cur->name);
 				pos += str_size(cur->name) + 1;
@@ -712,5 +717,5 @@
 			
 			/* Correct return value */
-			ret.tag = SYSINFO_VAL_FUNCTION_DATA;
+			ret.tag = SYSINFO_VAL_DATA;
 			ret.data.data = (void *) names;
 			ret.data.size = size;
Index: uspace/app/sysinfo/sysinfo.c
===================================================================
--- uspace/app/sysinfo/sysinfo.c	(revision 560d79ff73b54aa14113d7a5215931b4a9443e94)
+++ uspace/app/sysinfo/sysinfo.c	(revision 76f382b9b45e8460f46017535a7dbebc23d9e5e1)
@@ -37,32 +37,104 @@
 #include <stdio.h>
 #include <sysinfo.h>
+#include <malloc.h>
 #include <sys/types.h>
 
-static int print_item_val(char *ipath);
-static int print_item_data(char *ipath);
+static void dump_bytes_hex(char *data, size_t size)
+{
+	for (size_t i = 0; i < size; i++) {
+		if (i > 0)
+			putchar(' ');
+		printf("0x%02x", (uint8_t) data[i]);
+	}
+}
 
-static void dump_bytes_hex(char *data, size_t size);
-static void dump_bytes_text(char *data, size_t size);
+static void dump_bytes_text(char *data, size_t size)
+{
+	size_t offset = 0;
+	
+	while (offset < size) {
+		wchar_t c = str_decode(data, &offset, size);
+		printf("%lc", (wint_t) c);
+	}
+}
 
-static void print_syntax(void);
+static int print_item_val(char *ipath)
+{
+	sysarg_t value;
+	int rc = sysinfo_get_value(ipath, &value);
+	if (rc != EOK) {
+		printf("Error reading item '%s'.\n", ipath);
+		return rc;
+	}
+	
+	printf("%s -> %" PRIu64 " (0x%" PRIx64 ")\n", ipath,
+	    (uint64_t) value, (uint64_t) value);
+	
+	return EOK;
+}
+
+static int print_item_data(char *ipath)
+{
+	size_t size;
+	void *data = sysinfo_get_data(ipath, &size);
+	if (data == NULL) {
+		printf("Error reading item '%s'.\n", ipath);
+		return -1;
+	}
+	
+	printf("%s -> ", ipath);
+	dump_bytes_hex(data, size);
+	fputs(" ('", stdout);
+	dump_bytes_text(data, size);
+	fputs("')\n", stdout);
+	
+	return EOK;
+}
+
+static void print_keys(const char *path)
+{
+	size_t size;
+	char *keys = sysinfo_get_keys(path, &size);
+	if ((keys == NULL) || (size == 0))
+		return;
+	
+	size_t pos = 0;
+	while (pos < size) {
+		/* Process each key with sanity checks */
+		size_t cur_size = str_nsize(keys + pos, size - pos);
+		size_t path_size = str_size(path) + cur_size + 2;
+		char *cur_path = (char *) malloc(path_size);
+		if (cur_path == NULL)
+			break;
+		
+		if (path[0] != 0)
+			snprintf(cur_path, path_size, "%s.%s", path, keys + pos);
+		else
+			snprintf(cur_path, path_size, "%s", keys + pos);
+		
+		printf("%s\n", cur_path);
+		print_keys(cur_path);
+		
+		free(cur_path);
+		pos += cur_size + 1;
+	}
+	
+	free(keys);
+}
 
 int main(int argc, char *argv[])
 {
-	int rc;
-	char *ipath;
-	sysinfo_item_val_type_t tag;
-
 	if (argc != 2) {
-		print_syntax();
-		return 1;
+		/* Print keys */
+		print_keys("");
+		return 0;
 	}
-
-	ipath = argv[1];
-
-	tag = sysinfo_get_val_type(ipath);
-
+	
+	char *ipath = argv[1];
+	sysinfo_item_val_type_t tag = sysinfo_get_val_type(ipath);
+	
 	/* Silence warning */
-	rc = EOK;
-
+	int rc = 0;
+	
 	switch (tag) {
 	case SYSINFO_VAL_UNDEFINED:
@@ -82,72 +154,6 @@
 		break;
 	}
-
+	
 	return rc;
-}
-
-static int print_item_val(char *ipath)
-{
-	sysarg_t value;
-	int rc;
-
-	rc = sysinfo_get_value(ipath, &value);
-	if (rc != EOK) {
-		printf("Error reading item '%s'.\n", ipath);
-		return rc;
-	}
-
-	printf("%s -> %" PRIu64 " (0x%" PRIx64 ")\n", ipath,
-	    (uint64_t) value, (uint64_t) value);
-
-	return EOK;
-}
-
-static int print_item_data(char *ipath)
-{
-	void *data;
-	size_t size;
-
-	data = sysinfo_get_data(ipath, &size);
-	if (data == NULL) {
-		printf("Error reading item '%s'.\n", ipath);
-		return -1;
-	}
-
-	printf("%s -> ", ipath);
-	dump_bytes_hex(data, size);
-	fputs(" ('", stdout);
-	dump_bytes_text(data, size);
-	fputs("')\n", stdout);
-
-	return EOK;
-}
-
-static void dump_bytes_hex(char *data, size_t size)
-{
-	size_t i;
-
-	for (i = 0; i < size; ++i) {
-		if (i > 0) putchar(' ');
-		printf("0x%02x", (uint8_t) data[i]);
-	}
-}
-
-static void dump_bytes_text(char *data, size_t size)
-{
-	wchar_t c;
-	size_t offset;
-
-	offset = 0;
-
-	while (offset < size) {
-		c = str_decode(data, &offset, size);
-		printf("%lc", (wint_t) c);
-	}
-}
-
-
-static void print_syntax(void)
-{
-	printf("Syntax: sysinfo <item_path>\n");
 }
 
Index: uspace/lib/c/generic/sysinfo.c
===================================================================
--- uspace/lib/c/generic/sysinfo.c	(revision 560d79ff73b54aa14113d7a5215931b4a9443e94)
+++ uspace/lib/c/generic/sysinfo.c	(revision 76f382b9b45e8460f46017535a7dbebc23d9e5e1)
@@ -40,4 +40,68 @@
 #include <bool.h>
 
+/** Get sysinfo keys size
+ *
+ * @param path  Sysinfo path.
+ * @param value Pointer to store the keys size.
+ *
+ * @return EOK if the keys were successfully read.
+ *
+ */
+static int sysinfo_get_keys_size(const char *path, size_t *size)
+{
+	return (int) __SYSCALL3(SYS_SYSINFO_GET_KEYS_SIZE, (sysarg_t) path,
+	    (sysarg_t) str_size(path), (sysarg_t) size);
+}
+
+/** Get sysinfo keys
+ *
+ * @param path  Sysinfo path.
+ * @param value Pointer to store the keys size.
+ *
+ * @return Keys read from sysinfo or NULL if the
+ *         sysinfo item has no subkeys.
+ *         The returned non-NULL pointer should be
+ *         freed by free().
+ *
+ */
+char *sysinfo_get_keys(const char *path, size_t *size)
+{
+	/*
+	 * The size of the keys might change during time.
+	 * Unfortunatelly we cannot allocate the buffer
+	 * and transfer the keys as a single atomic operation.
+	 */
+	
+	/* Get the keys size */
+	int ret = sysinfo_get_keys_size(path, size);
+	if ((ret != EOK) || (size == 0)) {
+		/*
+		 * Item with no subkeys.
+		 */
+		*size = 0;
+		return NULL;
+	}
+	
+	char *data = malloc(*size);
+	if (data == NULL) {
+		*size = 0;
+		return NULL;
+	}
+	
+	/* Get the data */
+	size_t sz;
+	ret = __SYSCALL5(SYS_SYSINFO_GET_KEYS, (sysarg_t) path,
+	    (sysarg_t) str_size(path), (sysarg_t) data, (sysarg_t) *size,
+	    (sysarg_t) &sz);
+	if (ret == EOK) {
+		*size = sz;
+		return data;
+	}
+	
+	free(data);
+	*size = 0;
+	return NULL;
+}
+
 /** Get sysinfo item type
  *
Index: uspace/lib/c/include/sysinfo.h
===================================================================
--- uspace/lib/c/include/sysinfo.h	(revision 560d79ff73b54aa14113d7a5215931b4a9443e94)
+++ uspace/lib/c/include/sysinfo.h	(revision 76f382b9b45e8460f46017535a7dbebc23d9e5e1)
@@ -40,4 +40,5 @@
 #include <abi/sysinfo.h>
 
+extern char *sysinfo_get_keys(const char *, size_t *);
 extern sysinfo_item_val_type_t sysinfo_get_val_type(const char *);
 extern int sysinfo_get_value(const char *, sysarg_t *);
