Index: uspace/app/bdsh/exec.c
===================================================================
--- uspace/app/bdsh/exec.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/bdsh/exec.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -40,4 +40,5 @@
 #include <str.h>
 #include <fcntl.h>
+#include <str_error.h>
 
 #include "config.h"
@@ -120,9 +121,10 @@
 	free(found);
 
-	tid = task_spawn(tmp, (const char **) argv);
+	tid = task_spawn(tmp, (const char **) argv, &retval);
 	free(tmp);
 
 	if (tid == 0) {
-		cli_error(CL_EEXEC, "Cannot spawn `%s'.", cmd);
+		cli_error(CL_EEXEC, "%s: Cannot spawn `%s' (%s)", progname, cmd,
+		    str_error(retval));
 		return 1;
 	}
@@ -130,7 +132,8 @@
 	task_wait(tid, &texit, &retval);
 	if (texit != TASK_EXIT_NORMAL) {
-		printf("Command failed (unexpectedly terminated).\n");
+		printf("%s: Command failed (unexpectedly terminated)\n", progname);
 	} else if (retval != 0) {
-		printf("Command failed (return value %d).\n", retval);
+		printf("%s: Command failed (%s)\n",
+		    progname, str_error(retval));
 	}
 
Index: uspace/app/bdsh/scli.h
===================================================================
--- uspace/app/bdsh/scli.h	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/bdsh/scli.h	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -13,3 +13,5 @@
 } cliuser_t;
 
+extern const char *progname;
+
 #endif
Index: uspace/app/dummy_load/Makefile
===================================================================
--- uspace/app/dummy_load/Makefile	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
+++ uspace/app/dummy_load/Makefile	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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.
+#
+
+USPACE_PREFIX = ../..
+# BINARY = dummy_load
+
+SOURCES = \
+	dummy_load.c \
+	input.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/dummy_load/dummy_load.c
===================================================================
--- uspace/app/dummy_load/dummy_load.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
+++ uspace/app/dummy_load/dummy_load.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * 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 dummy_load
+ * @brief Dummy application to make some system load.
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdio.h>
+#include <task.h>
+#include <malloc.h>
+#include <ps.h>
+#include <str.h>
+#include <stdlib.h>
+#include "input.h"
+
+#define TASK_COUNT 50
+#define USPACE_CYCLES (1 << 26)
+#define SYSTEM_CYCLES (1 << 16)
+
+static void uspace_load()
+{
+	puts("u");
+	uint64_t volatile i;
+	for (i = 0; i < USPACE_CYCLES; ++i)
+		;
+}
+
+static int task_count;
+
+static void system_init()
+{
+	task_count = TASK_COUNT;
+	task_id_t *tasks = malloc(task_count * sizeof(task_id_t));
+	int result = get_task_ids(tasks, sizeof(task_id_t) * task_count);
+
+	while (result > task_count) {
+		task_count *= 2;
+		tasks = realloc(tasks, task_count * sizeof(task_id_t));
+		result = get_task_ids(tasks, sizeof(task_id_t) * task_count);
+	}
+
+	free(tasks);
+}
+
+static void system_load()
+{
+	puts("s");
+	task_id_t *tasks = malloc(task_count * sizeof(task_id_t));
+	int result;
+
+	uint64_t i;
+	for (i = 0; i < SYSTEM_CYCLES; ++i) {
+		result = get_task_ids(tasks, sizeof(task_id_t) * task_count);
+	}
+
+	free(tasks);
+}
+
+static void usage()
+{
+	printf("Usage: dummy_load [-u|-s|-r]\n");
+}
+
+int main(int argc, char *argv[])
+{
+	--argc; ++argv;
+	system_init();
+
+	char mode = 'r';
+	if (argc > 1) {
+		printf("Bad argument count!\n");
+		usage();
+		exit(1);
+	}
+
+	if (argc > 0) {
+		if (str_cmp(*argv, "-r") == 0) {
+			printf("Doing random load\n");
+			mode = 'r';
+		} else if (str_cmp(*argv, "-u") == 0) {
+			printf("Doing uspace load\n");
+			mode = 'u';
+		} else if (str_cmp(*argv, "-s") == 0) {
+			printf("Doing system load\n");
+			mode = 's';
+		} else {
+			usage();
+			exit(1);
+		}
+	} else {
+		mode = 'r';
+		printf("Doing random load\n");
+	}
+
+	bool system = false;
+	while (true) {
+		char c = tgetchar(0);
+		switch (c) {
+			case 'r':
+				mode = 'r';
+				break;
+			case 'u':
+				mode = 'u';
+				break;
+			case 's':
+				mode = 's';
+				break;
+			case 'q':
+				exit(0);
+				break;
+		}
+		switch (mode) {
+			case 'r':
+				if (system) {
+					system_load();
+				} else {
+					uspace_load();
+				}
+				system = !system;
+				break;
+			case 'u':
+				uspace_load();
+				break;
+			case 's':
+				system_load();
+				break;
+		}
+		fflush(stdout);
+	}
+
+	puts("\n");
+	fflush(stdout);
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/dummy_load/input.c
===================================================================
--- uspace/app/dummy_load/input.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
+++ uspace/app/dummy_load/input.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -0,0 +1,200 @@
+/*	$OpenBSD: input.c,v 1.12 2005/04/13 02:33:08 deraadt Exp $	*/
+/*    $NetBSD: input.c,v 1.3 1996/02/06 22:47:33 jtc Exp $    */
+
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek and Darren F. Provine.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ *	@(#)input.c	8.1 (Berkeley) 5/31/93
+ */
+
+/** @addtogroup dummy_load
+ * @{
+ */
+/** @file
+ */
+
+/*
+ * Top input.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <str.h>
+
+#include "input.h"
+
+#include <async.h>
+#include <vfs/vfs.h>
+#include <io/console.h>
+#include <ipc/console.h>
+
+#define USEC_COUNT 1000000
+
+/* return true iff the given timeval is positive */
+#define	TV_POS(tv) \
+	((tv)->tv_sec > 0 || ((tv)->tv_sec == 0 && (tv)->tv_usec > 0))
+
+/* subtract timeval `sub' from `res' */
+#define	TV_SUB(res, sub) \
+	(res)->tv_sec -= (sub)->tv_sec; \
+	(res)->tv_usec -= (sub)->tv_usec; \
+	if ((res)->tv_usec < 0) { \
+		(res)->tv_usec += 1000000; \
+		(res)->tv_sec--; \
+	}
+
+/* We will use a hack here - if lastchar is non-zero, it is
+ * the last character read. We will somehow simulate the select
+ * semantics.
+ */
+static aid_t getchar_inprog = 0;
+static char lastchar = '\0';
+
+/*
+ * Do a `read wait': select for reading from stdin, with timeout *tvp.
+ * On return, modify *tvp to reflect the amount of time spent waiting.
+ * It will be positive only if input appeared before the time ran out;
+ * otherwise it will be zero or perhaps negative.
+ *
+ * If tvp is nil, wait forever, but return if select is interrupted.
+ *
+ * Return 0 => no input, 1 => can read() from stdin
+ *
+ */
+int rwait(struct timeval *tvp)
+{
+	struct timeval starttv, endtv, *s;
+	static ipc_call_t charcall;
+	ipcarg_t rc;
+	
+	/*
+	 * Someday, select() will do this for us.
+	 * Just in case that day is now, and no one has
+	 * changed this, we use a temporary.
+	 */
+	if (tvp) {
+		(void) gettimeofday(&starttv, NULL);
+		endtv = *tvp;
+		s = &endtv;
+	} else
+		s = NULL;
+	
+	if (!lastchar) {
+again:
+		if (!getchar_inprog) {
+			getchar_inprog = async_send_0(fphone(stdin),
+			    CONSOLE_GET_EVENT, &charcall);
+		}
+		
+		if (!s)
+			async_wait_for(getchar_inprog, &rc);
+		else if (async_wait_timeout(getchar_inprog, &rc, s->tv_usec) == ETIMEOUT) {
+			tvp->tv_sec = 0;
+			tvp->tv_usec = 0;
+			return (0);
+		}
+		
+		getchar_inprog = 0;
+		if (rc) {
+			printf("End of file, bug?\n");
+			exit(1);
+		}
+		
+		if (IPC_GET_ARG1(charcall) == KEY_RELEASE)
+			goto again;
+		
+		lastchar = IPC_GET_ARG4(charcall);
+	}
+	
+	if (tvp) {
+		/* since there is input, we may not have timed out */
+		(void) gettimeofday(&endtv, NULL);
+		TV_SUB(&endtv, &starttv);
+		TV_SUB(tvp, &endtv);  /* adjust *tvp by elapsed time */
+	}
+	
+	return 1;
+}
+
+/*
+ * `sleep' for the current turn time (using select).
+ * Eat any input that might be available.
+ */
+void tsleep(unsigned int sec)
+{
+	struct timeval tv;
+	
+	tv.tv_sec = 0;
+	tv.tv_usec = sec * USEC_COUNT;
+	while (TV_POS(&tv))
+		if (rwait(&tv)) {
+			lastchar = '\0';
+		} else
+			break;
+}
+
+/*
+ * getchar with timeout.
+ */
+int tgetchar(unsigned int sec)
+{
+	static struct timeval timeleft;
+	char c;
+	
+	/*
+	 * Reset timeleft to USEC_COUNT whenever it is not positive.
+	 * In any case, wait to see if there is any input.  If so,
+	 * take it, and update timeleft so that the next call to
+	 * tgetchar() will not wait as long.  If there is no input,
+	 * make timeleft zero or negative, and return -1.
+	 *
+	 * Most of the hard work is done by rwait().
+	 */
+	if (!TV_POS(&timeleft)) {
+		timeleft.tv_sec = 0;
+		timeleft.tv_usec = sec * USEC_COUNT;
+	}
+	
+	if (!rwait(&timeleft))
+		return -1;
+	
+	c = lastchar;
+	lastchar = '\0';
+	return ((int) (unsigned char) c);
+}
+
+/** @}
+ */
Index: uspace/app/dummy_load/input.h
===================================================================
--- uspace/app/dummy_load/input.h	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
+++ uspace/app/dummy_load/input.h	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -0,0 +1,56 @@
+/*	$OpenBSD: input.h,v 1.5 2003/06/03 03:01:41 millert Exp $	*/
+/*	$NetBSD: input.h,v 1.2 1995/04/22 07:42:36 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek and Darren F. Provine.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ *	@(#)input.h	8.1 (Berkeley) 5/31/93
+ */
+
+/** @addtogroup dummy_load
+ * @{
+ */
+/** @file
+ */
+
+#ifndef TOP_INPUT_
+#define TOP_INPUT_
+
+#include <sys/time.h>
+
+extern int rwait(struct timeval *);
+extern int tgetchar(unsigned int sec);
+extern void tsleep(unsigned int sec);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/edit/edit.c
===================================================================
--- uspace/app/edit/edit.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/edit/edit.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -40,5 +40,5 @@
 #include <vfs/vfs.h>
 #include <io/console.h>
-#include <io/color.h>
+#include <io/style.h>
 #include <io/keycode.h>
 #include <errno.h>
@@ -100,5 +100,6 @@
 static bool cursor_visible;
 
-static int scr_rows, scr_columns;
+static ipcarg_t scr_rows;
+static ipcarg_t scr_columns;
 
 #define ROW_BUF_SIZE 4096
@@ -505,8 +506,8 @@
 	asprintf(&str, "%s: %s", prompt, init_value);
 	status_display(str);
-	console_goto(con, 1 + str_length(str), scr_rows - 1);
+	console_set_pos(con, 1 + str_length(str), scr_rows - 1);
 	free(str);
 
-	console_set_color(con, COLOR_WHITE, COLOR_BLACK, 0);
+	console_set_style(con, STYLE_INVERTED);
 
 	max_len = min(INFNAME_MAX_LEN, scr_columns - 4 - str_length(prompt));
@@ -552,5 +553,5 @@
 	str = wstr_to_astr(buffer);
 
-	console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+	console_set_style(con, STYLE_NORMAL);
 
 	return str;
@@ -671,5 +672,4 @@
 {
 	int sh_rows, rows;
-	int i, j;
 
 	sheet_get_num_rows(&doc.sh, &sh_rows);
@@ -678,11 +678,13 @@
 	/* Draw rows from the sheet. */
 
-	console_goto(con, 0, 0);
+	console_set_pos(con, 0, 0);
 	pane_row_range_display(0, rows);
 
 	/* Clear the remaining rows if file is short. */
-
+	
+	int i;
+	ipcarg_t j;
 	for (i = rows; i < pane.rows; ++i) {
-		console_goto(con, 0, i);
+		console_set_pos(con, 0, i);
 		for (j = 0; j < scr_columns; ++j)
 			putchar(' ');
@@ -736,5 +738,5 @@
 	/* Draw rows from the sheet. */
 
-	console_goto(con, 0, 0);
+	console_set_pos(con, 0, 0);
 	for (i = r0; i < r1; ++i) {
 		/* Starting point for row display */
@@ -756,9 +758,9 @@
 		    coord_cmp(&rbc, &csel_end) < 0) {
 			fflush(stdout);
-			console_set_color(con, COLOR_BLACK, COLOR_RED, 0);
+			console_set_style(con, STYLE_SELECTED);
 			fflush(stdout);
 		}
 
-		console_goto(con, 0, i);
+		console_set_pos(con, 0, i);
 		size = str_size(row_buf);
 		pos = 0;
@@ -767,5 +769,5 @@
 			if ((csel_start.row == rbc.row) && (csel_start.column == s_column)) {
 				fflush(stdout);
-				console_set_color(con, COLOR_BLACK, COLOR_RED, 0);
+				console_set_style(con, STYLE_SELECTED);
 				fflush(stdout);
 			}
@@ -773,5 +775,5 @@
 			if ((csel_end.row == rbc.row) && (csel_end.column == s_column)) {
 				fflush(stdout);
-				console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+				console_set_style(con, STYLE_NORMAL);
 				fflush(stdout);
 			}
@@ -793,5 +795,5 @@
 		if ((csel_end.row == rbc.row) && (csel_end.column == s_column)) {
 			fflush(stdout);
-			console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+			console_set_style(con, STYLE_NORMAL);
 			fflush(stdout);
 		}
@@ -807,5 +809,5 @@
 			putchar(' ');
 		fflush(stdout);
-		console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+		console_set_style(con, STYLE_NORMAL);
 	}
 
@@ -824,11 +826,11 @@
 	const char *fname = (doc.file_name != NULL) ? doc.file_name : "<unnamed>";
 
-	console_goto(con, 0, scr_rows - 1);
-	console_set_color(con, COLOR_WHITE, COLOR_BLACK, 0);
+	console_set_pos(con, 0, scr_rows - 1);
+	console_set_style(con, STYLE_INVERTED);
 	int n = printf(" %d, %d: File '%s'. Ctrl-Q Quit  Ctrl-S Save  "
 	    "Ctrl-E Save As", coord.row, coord.column, fname);
 	printf("%*s", scr_columns - 1 - n, "");
 	fflush(stdout);
-	console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+	console_set_style(con, STYLE_NORMAL);
 
 	pane.rflags |= REDRAW_CARET;
@@ -844,5 +846,5 @@
 
 	spt_get_coord(&caret_pt, &coord);
-	console_goto(con, coord.column - pane.sh_column,
+	console_set_pos(con, coord.column - pane.sh_column,
 	    coord.row - pane.sh_row);
 }
@@ -1149,9 +1151,9 @@
 static void status_display(char const *str)
 {
-	console_goto(con, 0, scr_rows - 1);
-	console_set_color(con, COLOR_WHITE, COLOR_BLACK, 0);
+	console_set_pos(con, 0, scr_rows - 1);
+	console_set_style(con, STYLE_INVERTED);
 	printf(" %*s ", -(scr_columns - 3), str);
 	fflush(stdout);
-	console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+	console_set_style(con, STYLE_NORMAL);
 
 	pane.rflags |= REDRAW_CARET;
Index: uspace/app/getterm/getterm.c
===================================================================
--- uspace/app/getterm/getterm.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/getterm/getterm.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -40,9 +40,12 @@
 #include <stdio.h>
 #include <task.h>
+#include <str_error.h>
 #include "version.h"
+
+#define APP_NAME  "getterm"
 
 static void usage(void)
 {
-	printf("Usage: getterm <terminal> <path>\n");
+	printf("Usage: %s <terminal> <path>\n", APP_NAME);
 }
 
@@ -76,8 +79,10 @@
 	args[1] = NULL;
 	
-	task_id_t id = task_spawn(fname, args);
+	int err;
+	task_id_t id = task_spawn(fname, args, &err);
 	
 	if (id == 0)
-		printf("Error spawning %s\n", fname);
+		printf("%s: Error spawning %s (%s)\n", APP_NAME, fname,
+		    str_error(err));
 	
 	return id;
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/init/init.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -48,7 +48,19 @@
 #include <str.h>
 #include <devmap.h>
+#include <str_error.h>
 #include "init.h"
 
+#define ROOT_DEVICE       "bd/initrd"
+#define ROOT_MOUNT_POINT  "/"
+
+#define DEVFS_FS_TYPE      "devfs"
 #define DEVFS_MOUNT_POINT  "/dev"
+
+#define SCRATCH_FS_TYPE      "tmpfs"
+#define SCRATCH_MOUNT_POINT  "/scratch"
+
+#define DATA_FS_TYPE      "fat"
+#define DATA_DEVICE       "bd/disk0"
+#define DATA_MOUNT_POINT  "/data"
 
 #define SRV_CONSOLE  "/srv/console"
@@ -57,5 +69,34 @@
 static void info_print(void)
 {
-	printf(NAME ": HelenOS init\n");
+	printf("%s: HelenOS init\n", NAME);
+}
+
+static bool mount_report(const char *desc, const char *mntpt,
+    const char *fstype, const char *dev, int rc)
+{
+	switch (rc) {
+	case EOK:
+		if (dev != NULL)
+			printf("%s: %s mounted on %s (%s at %s)\n", NAME, desc, mntpt,
+			    fstype, dev);
+		else
+			printf("%s: %s mounted on %s (%s)\n", NAME, desc, mntpt, fstype);
+		break;
+	case EBUSY:
+		printf("%s: %s already mounted on %s\n", NAME, desc, mntpt);
+		return false;
+	case ELIMIT:
+		printf("%s: %s limit exceeded\n", NAME, desc);
+		return false;
+	case ENOENT:
+		printf("%s: %s unknown type (%s)\n", NAME, desc, fstype);
+		return false;
+	default:
+		printf("%s: %s not mounted on %s (%s)\n", NAME, desc, mntpt,
+		    str_error(rc));
+		return false;
+	}
+	
+	return true;
 }
 
@@ -63,56 +104,20 @@
 {
 	const char *opts = "";
-	const char *root_dev = "bd/initrd";
 	
 	if (str_cmp(fstype, "tmpfs") == 0)
 		opts = "restore";
 	
-	int rc = mount(fstype, "/", root_dev, opts, IPC_FLAG_BLOCKING);
-	
-	switch (rc) {
-	case EOK:
-		printf(NAME ": Root filesystem mounted, %s at %s\n",
-		    fstype, root_dev);
-		break;
-	case EBUSY:
-		printf(NAME ": Root filesystem already mounted\n");
-		return false;
-	case ELIMIT:
-		printf(NAME ": Unable to mount root filesystem\n");
-		return false;
-	case ENOENT:
-		printf(NAME ": Unknown filesystem type (%s)\n", fstype);
-		return false;
-	default:
-		printf(NAME ": Error mounting root filesystem (%d)\n", rc);
-		return false;
-	}
-	
-	return true;
+	int rc = mount(fstype, ROOT_MOUNT_POINT, ROOT_DEVICE, opts,
+	    IPC_FLAG_BLOCKING);
+	return mount_report("Root filesystem", ROOT_MOUNT_POINT, fstype,
+	    ROOT_DEVICE, rc);
 }
 
 static bool mount_devfs(void)
 {
-	int rc = mount("devfs", DEVFS_MOUNT_POINT, "", "", IPC_FLAG_BLOCKING);
-	
-	switch (rc) {
-	case EOK:
-		printf(NAME ": Device filesystem mounted\n");
-		break;
-	case EBUSY:
-		printf(NAME ": Device filesystem already mounted\n");
-		return false;
-	case ELIMIT:
-		printf(NAME ": Unable to mount device filesystem\n");
-		return false;
-	case ENOENT:
-		printf(NAME ": Unknown filesystem type (devfs)\n");
-		return false;
-	default:
-		printf(NAME ": Error mounting device filesystem (%d)\n", rc);
-		return false;
-	}
-	
-	return true;
+	int rc = mount(DEVFS_FS_TYPE, DEVFS_MOUNT_POINT, "", "",
+	    IPC_FLAG_BLOCKING);
+	return mount_report("Device filesystem", DEVFS_MOUNT_POINT, DEVFS_FS_TYPE,
+	    NULL, rc);
 }
 
@@ -125,11 +130,13 @@
 		return;
 	
-	printf(NAME ": Spawning %s\n", fname);
+	printf("%s: Spawning %s\n", NAME, fname);
 	
 	argv[0] = fname;
 	argv[1] = NULL;
 	
-	if (!task_spawn(fname, argv))
-		printf(NAME ": Error spawning %s\n", fname);
+	int err;
+	if (!task_spawn(fname, argv, &err))
+		printf("%s: Error spawning %s (%s)\n", NAME, fname,
+		    str_error(err));
 }
 
@@ -145,24 +152,26 @@
 		return;
 	
-	printf(NAME ": Starting %s\n", fname);
+	printf("%s: Starting %s\n", NAME, fname);
 	
 	argv[0] = fname;
 	argv[1] = NULL;
 	
-	id = task_spawn(fname, argv);
+	id = task_spawn(fname, argv, &retval);
 	if (!id) {
-		printf(NAME ": Error spawning %s\n", fname);
+		printf("%s: Error spawning %s (%s)\n", NAME, fname,
+		    str_error(retval));
 		return;
 	}
-
+	
 	rc = task_wait(id, &texit, &retval);
 	if (rc != EOK) {
-		printf(NAME ": Error waiting for %s\n", fname);
+		printf("%s: Error waiting for %s (%s(\n", NAME, fname,
+		    str_error(retval));
 		return;
 	}
-
+	
 	if ((texit != TASK_EXIT_NORMAL) || (retval != 0)) {
-		printf(NAME ": Server %s failed to start (returned %d)\n",
-			fname, retval);
+		printf("%s: Server %s failed to start (%s)\n", NAME,
+			fname, str_error(retval));
 	}
 }
@@ -176,5 +185,5 @@
 	snprintf(hid_in, DEVMAP_NAME_MAXLEN, "%s/%s", DEVFS_MOUNT_POINT, dev);
 	
-	printf(NAME ": Spawning %s with %s\n", SRV_CONSOLE, hid_in);
+	printf("%s: Spawning %s %s\n", NAME, SRV_CONSOLE, hid_in);
 	
 	/* Wait for the input device to be ready */
@@ -187,8 +196,10 @@
 		argv[2] = NULL;
 		
-		if (!task_spawn(SRV_CONSOLE, argv))
-			printf(NAME ": Error spawning %s with %s\n", SRV_CONSOLE, hid_in);
+		if (!task_spawn(SRV_CONSOLE, argv, &rc))
+			printf("%s: Error spawning %s %s (%s)\n", NAME, SRV_CONSOLE,
+			    hid_in, str_error(rc));
 	} else
-		printf(NAME ": Error waiting on %s\n", hid_in);
+		printf("%s: Error waiting on %s (%s)\n", NAME, hid_in,
+		    str_error(rc));
 }
 
@@ -201,5 +212,5 @@
 	snprintf(term, DEVMAP_NAME_MAXLEN, "%s/%s", DEVFS_MOUNT_POINT, dev);
 	
-	printf(NAME ": Spawning %s with %s %s\n", APP_GETTERM, term, app);
+	printf("%s: Spawning %s %s %s\n", NAME, APP_GETTERM, term, app);
 	
 	/* Wait for the terminal device to be ready */
@@ -213,37 +224,24 @@
 		argv[3] = NULL;
 		
-		if (!task_spawn(APP_GETTERM, argv))
-			printf(NAME ": Error spawning %s with %s %s\n", APP_GETTERM,
-			    term, app);
+		if (!task_spawn(APP_GETTERM, argv, &rc))
+			printf("%s: Error spawning %s %s %s (%s)\n", NAME, APP_GETTERM,
+			    term, app, str_error(rc));
 	} else
-		printf(NAME ": Error waiting on %s\n", term);
-}
-
-static void mount_scratch(void)
-{
-	int rc;
-
-	printf("Trying to mount null/0 on /scratch... ");
-	fflush(stdout);
-
-	rc = mount("tmpfs", "/scratch", "null/0", "", 0);
-	if (rc == EOK)
-		printf("OK\n");
-	else
-		printf("Failed\n");
-}
-
-static void mount_data(void)
-{
-	int rc;
-
-	printf("Trying to mount bd/disk0 on /data... ");
-	fflush(stdout);
-
-	rc = mount("fat", "/data", "bd/disk0", "wtcache", 0);
-	if (rc == EOK)
-		printf("OK\n");
-	else
-		printf("Failed\n");
+		printf("%s: Error waiting on %s (%s)\n", NAME, term,
+		    str_error(rc));
+}
+
+static bool mount_scratch(void)
+{
+	int rc = mount(SCRATCH_FS_TYPE, SCRATCH_MOUNT_POINT, "", "", 0);
+	return mount_report("Scratch filesystem", SCRATCH_MOUNT_POINT,
+	    SCRATCH_FS_TYPE, NULL, rc);
+}
+
+static bool mount_data(void)
+{
+	int rc = mount(DATA_FS_TYPE, DATA_MOUNT_POINT, DATA_DEVICE, "wtcache", 0);
+	return mount_report("Data filesystem", DATA_MOUNT_POINT, DATA_FS_TYPE,
+	    DATA_DEVICE, rc);
 }
 
@@ -253,8 +251,8 @@
 	
 	if (!mount_root(STRING(RDFMT))) {
-		printf(NAME ": Exiting\n");
+		printf("%s: Exiting\n", NAME);
 		return -1;
 	}
-
+	
 	/* Make sure tmpfs is running. */
 	if (str_cmp(STRING(RDFMT), "tmpfs") != 0) {
@@ -266,8 +264,8 @@
 	
 	if (!mount_devfs()) {
-		printf(NAME ": Exiting\n");
+		printf("%s: Exiting\n", NAME);
 		return -2;
 	}
-
+	
 	mount_scratch();
 	
@@ -278,5 +276,5 @@
 	srv_start("/srv/adb_ms");
 	srv_start("/srv/char_ms");
-
+	
 	spawn("/srv/fb");
 	spawn("/srv/kbd");
@@ -284,5 +282,5 @@
 	
 	spawn("/srv/clip");
-
+	
 	/*
 	 * Start these synchronously so that mount_data() can be
@@ -295,5 +293,5 @@
 	(void) srv_start;
 #endif
-
+	
 #ifdef CONFIG_MOUNT_DATA
 	mount_data();
@@ -301,5 +299,5 @@
 	(void) mount_data;
 #endif
-
+	
 	getterm("term/vc0", "/app/bdsh");
 	getterm("term/vc1", "/app/bdsh");
@@ -309,5 +307,5 @@
 	getterm("term/vc5", "/app/bdsh");
 	getterm("term/vc6", "/app/klog");
-
+	
 	return 0;
 }
Index: uspace/app/klog/klog.c
===================================================================
--- uspace/app/klog/klog.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/klog/klog.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -64,5 +64,10 @@
 int main(int argc, char *argv[])
 {
-	size_t klog_pages = sysinfo_value("klog.pages");
+	size_t klog_pages;
+	if (sysinfo_get_value("klog.pages", &klog_pages) != EOK) {
+		printf("%s: Error getting klog address\n", NAME);
+		return -1;
+	}
+	
 	size_t klog_size = klog_pages * PAGE_SIZE;
 	klog_length = klog_size / sizeof(wchar_t);
@@ -70,5 +75,5 @@
 	klog = (wchar_t *) as_get_mappable_page(klog_size);
 	if (klog == NULL) {
-		printf(NAME ": Error allocating memory area\n");
+		printf("%s: Error allocating memory area\n", NAME);
 		return -1;
 	}
@@ -77,10 +82,10 @@
 	    klog_size, SERVICE_MEM_KLOG);
 	if (res != EOK) {
-		printf(NAME ": Error initializing memory area\n");
+		printf("%s: Error initializing memory area\n", NAME);
 		return -1;
 	}
 	
 	if (event_subscribe(EVENT_KLOG, 0) != EOK) {
-		printf(NAME ": Error registering klog notifications\n");
+		printf("%s: Error registering klog notifications\n", NAME);
 		return -1;
 	}
Index: uspace/app/netecho/Makefile
===================================================================
--- uspace/app/netecho/Makefile	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/netecho/Makefile	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -35,5 +35,4 @@
 SOURCES = \
 	netecho.c \
-	parse.c \
 	print_error.c
 
Index: uspace/app/netecho/netecho.c
===================================================================
--- uspace/app/netecho/netecho.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/netecho/netecho.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -40,4 +40,5 @@
 #include <str.h>
 #include <task.h>
+#include <arg_parse.h>
 
 #include <in.h>
@@ -46,6 +47,6 @@
 #include <socket.h>
 #include <net_err.h>
-
-#include "parse.h"
+#include <socket_parse.h>
+
 #include "print_error.h"
 
@@ -128,8 +129,4 @@
 	int value;
 
-	// print the program label
-	printf("Task %d - ", task_get_id());
-	printf("%s\n", NAME);
-
 	// parse the command line arguments
 	for(index = 1; index < argc; ++ index){
@@ -137,11 +134,11 @@
 			switch(argv[index][1]){
 				case 'b':
-					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &backlog, "accepted sockets queue size", 0));
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &backlog, 0));
 					break;
 				case 'c':
-					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &count, "message count", 0));
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &count, 0));
 					break;
 				case 'f':
-					ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "protocol family", 0, parse_protocol_family));
+					ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &family, 0, socket_parse_protocol_family));
 					break;
 				case 'h':
@@ -150,16 +147,16 @@
 					break;
 				case 'p':
-					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "port number", 0));
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 0));
 					port = (uint16_t) value;
 					break;
 				case 'r':
-					ERROR_PROPAGATE(parse_parameter_string(argc, argv, &index, &reply, "reply string", 0));
+					ERROR_PROPAGATE(arg_parse_string(argc, argv, &index, &reply, 0));
 					break;
 				case 's':
-					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "receive size", 0));
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 0));
 					size = (value >= 0) ? (size_t) value : 0;
 					break;
 				case 't':
-					ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &value, "socket type", 0, parse_socket_type));
+					ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &value, 0, socket_parse_socket_type));
 					type = (sock_type_t) value;
 					break;
@@ -170,27 +167,26 @@
 				case '-':
 					if(str_lcmp(argv[index] + 2, "backlog=", 6) == 0){
-						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &backlog, "accepted sockets queue size", 8));
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &backlog, 8));
 					}else if(str_lcmp(argv[index] + 2, "count=", 6) == 0){
-						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &count, "message count", 8));
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &count, 8));
 					}else if(str_lcmp(argv[index] + 2, "family=", 7) == 0){
-						ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "protocol family", 9, parse_protocol_family));
+						ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &family, 9, socket_parse_protocol_family));
 					}else if(str_lcmp(argv[index] + 2, "help", 5) == 0){
 						echo_print_help();
 						return EOK;
 					}else if(str_lcmp(argv[index] + 2, "port=", 5) == 0){
-						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "port number", 7));
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 7));
 						port = (uint16_t) value;
 					}else if(str_lcmp(argv[index] + 2, "reply=", 6) == 0){
-						ERROR_PROPAGATE(parse_parameter_string(argc, argv, &index, &reply, "reply string", 8));
+						ERROR_PROPAGATE(arg_parse_string(argc, argv, &index, &reply, 8));
 					}else if(str_lcmp(argv[index] + 2, "size=", 5) == 0){
-						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "receive size", 7));
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 7));
 						size = (value >= 0) ? (size_t) value : 0;
 					}else if(str_lcmp(argv[index] + 2, "type=", 5) == 0){
-						ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &value, "socket type", 7, parse_socket_type));
+						ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &value, 7, socket_parse_socket_type));
 						type = (sock_type_t) value;
 					}else if(str_lcmp(argv[index] + 2, "verbose", 8) == 0){
 						verbose = 1;
 					}else{
-						print_unrecognized(index, argv[index] + 2);
 						echo_print_help();
 						return EINVAL;
@@ -198,10 +194,8 @@
 					break;
 				default:
-					print_unrecognized(index, argv[index] + 1);
 					echo_print_help();
 					return EINVAL;
 			}
 		}else{
-			print_unrecognized(index, argv[index]);
 			echo_print_help();
 			return EINVAL;
Index: uspace/app/netecho/parse.c
===================================================================
--- uspace/app/netecho/parse.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ 	(revision )
@@ -1,123 +1,0 @@
-/*
- * Copyright (c) 2009 Lukas Mejdrech
- * 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 net_app
- *  @{
- */
-
-/** @file
- *  Generic application parsing functions implementation.
- */
-
-#include <stdio.h>
-#include <str.h>
-
-#include <socket.h>
-#include <net_err.h>
-
-#include "parse.h"
-
-int parse_address_family(const char * name){
-	if(str_lcmp(name, "AF_INET", 7) == 0){
-		return AF_INET;
-	}else if(str_lcmp(name, "AF_INET6", 8) == 0){
-		return AF_INET6;
-	}
-	return EAFNOSUPPORT;
-}
-
-int parse_parameter_int(int argc, char ** argv, int * index, int * value, const char * name, int offset){
-	char * rest;
-
-	if(offset){
-		*value = strtol(argv[*index] + offset, &rest, 10);
-	}else if((*index) + 1 < argc){
-		++ (*index);
-		*value = strtol(argv[*index], &rest, 10);
-	}else{
-		fprintf(stderr, "Command line error: missing %s\n", name);
-		return EINVAL;
-	}
-	if(rest && (*rest)){
-		fprintf(stderr, "Command line error: %s unrecognized (%d: %s)\n", name, * index, argv[*index]);
-		return EINVAL;
-	}
-	return EOK;
-}
-
-int parse_parameter_name_int(int argc, char ** argv, int * index, int * value, const char * name, int offset, int (*parse_value)(const char * value)){
-	ERROR_DECLARE;
-
-	char * parameter;
-
-	ERROR_PROPAGATE(parse_parameter_string(argc, argv, index, &parameter, name, offset));
-	*value = (*parse_value)(parameter);
-	if((*value) == ENOENT){
-		fprintf(stderr, "Command line error: unrecognized %s value (%d: %s)\n", name, * index, parameter);
-		return ENOENT;
-	}
-	return EOK;
-}
-
-int parse_parameter_string(int argc, char ** argv, int * index, char ** value, const char * name, int offset){
-	if(offset){
-		*value = argv[*index] + offset;
-	}else if((*index) + 1 < argc){
-		++ (*index);
-		*value = argv[*index];
-	}else{
-		fprintf(stderr, "Command line error: missing %s\n", name);
-		return EINVAL;
-	}
-	return EOK;
-}
-
-int parse_protocol_family(const char * name){
-	if(str_lcmp(name, "PF_INET", 7) == 0){
-		return PF_INET;
-	}else if(str_lcmp(name, "PF_INET6", 8) == 0){
-		return PF_INET6;
-	}
-	return EPFNOSUPPORT;
-}
-
-int parse_socket_type(const char * name){
-	if(str_lcmp(name, "SOCK_DGRAM", 11) == 0){
-		return SOCK_DGRAM;
-	}else if(str_lcmp(name, "SOCK_STREAM", 12) == 0){
-		return SOCK_STREAM;
-	}
-	return ESOCKTNOSUPPORT;
-}
-
-void print_unrecognized(int index, const char * parameter){
-	fprintf(stderr, "Command line error: unrecognized argument (%d: %s)\n", index, parameter);
-}
-
-/** @}
- */
Index: uspace/app/netecho/parse.h
===================================================================
--- uspace/app/netecho/parse.h	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ 	(revision )
@@ -1,120 +1,0 @@
-/*
- * Copyright (c) 2009 Lukas Mejdrech
- * 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 net_app
- *  @{
- */
-
-/** @file
- *  Generic command line arguments parsing functions.
- */
-
-#ifndef __NET_APP_PARSE__
-#define __NET_APP_PARSE__
-
-#include <socket.h>
-
-/** Translates the character string to the address family number.
- *  @param[in] name The address family name.
- *  @returns The corresponding address family number.
- *  @returns EAFNOSUPPORTED if the address family is not supported.
- */
-extern int parse_address_family(const char * name);
-
-/** Parses the next parameter as an integral number.
- *  The actual parameter is pointed by the index.
- *  Parses the offseted actual parameter value if the offset is set or the next one if not.
- *  @param[in] argc The total number of the parameters.
- *  @param[in] argv The parameters.
- *  @param[in,out] index The actual parameter index. The index is incremented by the number of processed parameters.
- *  @param[out] value The parsed parameter value.
- *  @param[in] name The parameter name to be printed on errors.
- *  @param[in] offset The value offset in the actual parameter. If not set, the next parameter is parsed instead.
- *  @returns EOK on success.
- *  @returns EINVAL if the parameter is missing.
- *  @returns EINVAL if the parameter is in wrong format.
- */
-extern int parse_parameter_int(int argc, char ** argv, int * index, int * value, const char * name, int offset);
-
-/** Parses the next named parameter as an integral number.
- *  The actual parameter is pointed by the index.
- *  Uses the offseted actual parameter if the offset is set or the next one if not.
- *  Translates the parameter using the parse_value function.
- *  Increments the actual index by the number of processed parameters.
- *  @param[in] argc The total number of the parameters.
- *  @param[in] argv The parameters.
- *  @param[in,out] index The actual parameter index. The index is incremented by the number of processed parameters.
- *  @param[out] value The parsed parameter value.
- *  @param[in] name The parameter name to be printed on errors.
- *  @param[in] offset The value offset in the actual parameter. If not set, the next parameter is parsed instead.
- *  @param[in] parse_value The translation function to parse the named value.
- *  @returns EOK on success.
- *  @returns EINVAL if the parameter is missing.
- *  @returns ENOENT if the parameter name has not been found.
- */
-extern int parse_parameter_name_int(int argc, char ** argv, int * index, int * value, const char * name, int offset, int (*parse_value)(const char * value));
-
-/** Parses the next parameter as a character string.
- *  The actual parameter is pointed by the index.
- *  Uses the offseted actual parameter value if the offset is set or the next one if not.
- *  Increments the actual index by the number of processed parameters.
- *  @param[in] argc The total number of the parameters.
- *  @param[in] argv The parameters.
- *  @param[in,out] index The actual parameter index. The index is incremented by the number of processed parameters.
- *  @param[out] value The parsed parameter value.
- *  @param[in] name The parameter name to be printed on errors.
- *  @param[in] offset The value offset in the actual parameter. If not set, the next parameter is parsed instead.
- *  @returns EOK on success.
- *  @returns EINVAL if the parameter is missing.
- */
-extern int parse_parameter_string(int argc, char ** argv, int * index, char ** value, const char * name, int offset);
-
-/** Translates the character string to the protocol family number.
- *  @param[in] name The protocol family name.
- *  @returns The corresponding protocol family number.
- *  @returns EPFNOSUPPORTED if the protocol family is not supported.
- */
-extern int parse_protocol_family(const char * name);
-
-/** Translates the character string to the socket type number.
- *  @param[in] name The socket type name.
- *  @returns The corresponding socket type number.
- *  @returns ESOCKNOSUPPORTED if the socket type is not supported.
- */
-extern int parse_socket_type(const char * name);
-
-/** Prints the parameter unrecognized message and the application help.
- *  @param[in] index The index of the parameter.
- *  @param[in] parameter The parameter name.
- */
-extern void print_unrecognized(int index, const char * parameter);
-
-#endif
-
-/** @}
- */
Index: uspace/app/nettest1/Makefile
===================================================================
--- uspace/app/nettest1/Makefile	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/nettest1/Makefile	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -36,5 +36,4 @@
 	nettest1.c \
 	nettest.c \
-	parse.c \
 	print_error.c
 
Index: uspace/app/nettest1/nettest1.c
===================================================================
--- uspace/app/nettest1/nettest1.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/nettest1/nettest1.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -40,4 +40,5 @@
 #include <task.h>
 #include <time.h>
+#include <arg_parse.h>
 
 #include <in.h>
@@ -46,7 +47,7 @@
 #include <socket.h>
 #include <net_err.h>
+#include <socket_parse.h>
 
 #include "nettest.h"
-#include "parse.h"
 #include "print_error.h"
 
@@ -105,8 +106,4 @@
 	struct timeval time_after;
 
-	// print the program label
-	printf("Task %d - ", task_get_id());
-	printf("%s\n", NAME);
-
 	// parse the command line arguments
 	// stop before the last argument if it does not start with the minus sign ('-')
@@ -117,5 +114,5 @@
 				// short options with only one letter
 				case 'f':
-					ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "protocol family", 0, parse_protocol_family));
+					ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &family, 0, socket_parse_protocol_family));
 					break;
 				case 'h':
@@ -124,19 +121,19 @@
 					break;
 				case 'm':
-					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &messages, "message count", 0));
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &messages, 0));
 					break;
 				case 'n':
-					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &sockets, "socket count", 0));
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &sockets, 0));
 					break;
 				case 'p':
-					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "port number", 0));
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 0));
 					port = (uint16_t) value;
 					break;
 				case 's':
-					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "packet size", 0));
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 0));
 					size = (value >= 0) ? (size_t) value : 0;
 					break;
 				case 't':
-					ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &value, "socket type", 0, parse_socket_type));
+					ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &value, 0, socket_parse_socket_type));
 					type = (sock_type_t) value;
 					break;
@@ -147,22 +144,21 @@
 				case '-':
 					if(str_lcmp(argv[index] + 2, "family=", 7) == 0){
-						ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "protocol family", 9, parse_protocol_family));
+						ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &family, 9, socket_parse_protocol_family));
 					}else if(str_lcmp(argv[index] + 2, "help", 5) == 0){
 						nettest1_print_help();
 						return EOK;
 					}else if(str_lcmp(argv[index] + 2, "messages=", 6) == 0){
-						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &messages, "message count", 8));
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &messages, 8));
 					}else if(str_lcmp(argv[index] + 2, "sockets=", 6) == 0){
-						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &sockets, "socket count", 8));
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &sockets, 8));
 					}else if(str_lcmp(argv[index] + 2, "port=", 5) == 0){
-						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "port number", 7));
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 7));
 						port = (uint16_t) value;
 					}else if(str_lcmp(argv[index] + 2, "type=", 5) == 0){
-						ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &value, "socket type", 7, parse_socket_type));
+						ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &value, 7, socket_parse_socket_type));
 						type = (sock_type_t) value;
 					}else if(str_lcmp(argv[index] + 2, "verbose", 8) == 0){
 						verbose = 1;
 					}else{
-						print_unrecognized(index, argv[index] + 2);
 						nettest1_print_help();
 						return EINVAL;
@@ -170,10 +166,8 @@
 					break;
 				default:
-					print_unrecognized(index, argv[index] + 1);
 					nettest1_print_help();
 					return EINVAL;
 			}
 		}else{
-			print_unrecognized(index, argv[index]);
 			nettest1_print_help();
 			return EINVAL;
Index: uspace/app/nettest1/parse.c
===================================================================
--- uspace/app/nettest1/parse.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ 	(revision )
@@ -1,1 +1,0 @@
-../netecho/parse.c
Index: uspace/app/nettest1/parse.h
===================================================================
--- uspace/app/nettest1/parse.h	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ 	(revision )
@@ -1,1 +1,0 @@
-../netecho/parse.h
Index: uspace/app/nettest2/Makefile
===================================================================
--- uspace/app/nettest2/Makefile	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/nettest2/Makefile	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -36,5 +36,4 @@
 	nettest2.c \
 	nettest.c \
-	parse.c \
 	print_error.c
 
Index: uspace/app/nettest2/nettest2.c
===================================================================
--- uspace/app/nettest2/nettest2.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/nettest2/nettest2.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -40,4 +40,5 @@
 #include <task.h>
 #include <time.h>
+#include <arg_parse.h>
 
 #include <in.h>
@@ -46,7 +47,7 @@
 #include <socket.h>
 #include <net_err.h>
+#include <socket_parse.h>
 
 #include "nettest.h"
-#include "parse.h"
 #include "print_error.h"
 
@@ -105,7 +106,4 @@
 	struct timeval time_after;
 
-	printf("Task %d - ", task_get_id());
-	printf("%s\n", NAME);
-
 	// parse the command line arguments
 	// stop before the last argument if it does not start with the minus sign ('-')
@@ -116,5 +114,5 @@
 				// short options with only one letter
 				case 'f':
-					ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "protocol family", 0, parse_protocol_family));
+					ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &family, 0, socket_parse_protocol_family));
 					break;
 				case 'h':
@@ -123,19 +121,19 @@
 					break;
 				case 'm':
-					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &messages, "message count", 0));
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &messages, 0));
 					break;
 				case 'n':
-					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &sockets, "socket count", 0));
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &sockets, 0));
 					break;
 				case 'p':
-					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "port number", 0));
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 0));
 					port = (uint16_t) value;
 					break;
 				case 's':
-					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "packet size", 0));
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 0));
 					size = (value >= 0) ? (size_t) value : 0;
 					break;
 				case 't':
-					ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &value, "socket type", 0, parse_socket_type));
+					ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &value, 0, socket_parse_socket_type));
 					type = (sock_type_t) value;
 					break;
@@ -146,22 +144,21 @@
 				case '-':
 					if(str_lcmp(argv[index] + 2, "family=", 7) == 0){
-						ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "protocol family", 9, parse_protocol_family));
+						ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &family, 9, socket_parse_protocol_family));
 					}else if(str_lcmp(argv[index] + 2, "help", 5) == 0){
 						nettest2_print_help();
 						return EOK;
 					}else if(str_lcmp(argv[index] + 2, "messages=", 6) == 0){
-						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &messages, "message count", 8));
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &messages, 8));
 					}else if(str_lcmp(argv[index] + 2, "sockets=", 6) == 0){
-						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &sockets, "socket count", 8));
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &sockets, 8));
 					}else if(str_lcmp(argv[index] + 2, "port=", 5) == 0){
-						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "port number", 7));
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 7));
 						port = (uint16_t) value;
 					}else if(str_lcmp(argv[index] + 2, "type=", 5) == 0){
-						ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &value, "socket type", 7, parse_socket_type));
+						ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &value, 7, socket_parse_socket_type));
 						type = (sock_type_t) value;
 					}else if(str_lcmp(argv[index] + 2, "verbose", 8) == 0){
 						verbose = 1;
 					}else{
-						print_unrecognized(index, argv[index] + 2);
 						nettest2_print_help();
 						return EINVAL;
@@ -169,10 +166,8 @@
 					break;
 				default:
-					print_unrecognized(index, argv[index] + 1);
 					nettest2_print_help();
 					return EINVAL;
 			}
 		}else{
-			print_unrecognized(index, argv[index]);
 			nettest2_print_help();
 			return EINVAL;
Index: uspace/app/nettest2/parse.c
===================================================================
--- uspace/app/nettest2/parse.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ 	(revision )
@@ -1,1 +1,0 @@
-../netecho/parse.c
Index: uspace/app/nettest2/parse.h
===================================================================
--- uspace/app/nettest2/parse.h	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ 	(revision )
@@ -1,1 +1,0 @@
-../netecho/parse.h
Index: uspace/app/ping/Makefile
===================================================================
--- uspace/app/ping/Makefile	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/ping/Makefile	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -35,5 +35,4 @@
 SOURCES = \
 	ping.c \
-	parse.c \
 	print_error.c
 
Index: uspace/app/ping/parse.c
===================================================================
--- uspace/app/ping/parse.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ 	(revision )
@@ -1,1 +1,0 @@
-../netecho/parse.c
Index: uspace/app/ping/parse.h
===================================================================
--- uspace/app/ping/parse.h	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ 	(revision )
@@ -1,1 +1,0 @@
-../netecho/parse.h
Index: uspace/app/ping/ping.c
===================================================================
--- uspace/app/ping/ping.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/ping/ping.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -28,9 +28,9 @@
 
 /** @addtogroup ping
- *  @{
+ * @{
  */
 
 /** @file
- *  Ping application.
+ * Packet Internet Network Grouper.
  */
 
@@ -41,4 +41,6 @@
 #include <ipc/ipc.h>
 #include <ipc/services.h>
+#include <str_error.h>
+#include <arg_parse.h>
 
 #include <icmp_api.h>
@@ -48,254 +50,349 @@
 #include <ip_codes.h>
 #include <socket_errno.h>
-#include <net_err.h>
-
-#include "parse.h"
+#include <socket_parse.h>
+
 #include "print_error.h"
 
-/** Echo module name.
- */
-#define NAME	"Ping"
-
-/** Module entry point.
- *  Reads command line parameters and pings.
- *  @param[in] argc The number of command line parameters.
- *  @param[in] argv The command line parameters.
- *  @returns EOK on success.
- */
-int main(int argc, char * argv[]);
-
-/** Prints the application help.
- */
-void ping_print_help(void);
-
-int main(int argc, char * argv[]){
-	ERROR_DECLARE;
-
-	size_t size			= 38;
-	int verbose			= 0;
-	int dont_fragment	= 0;
-	ip_ttl_t ttl		= 0;
-	ip_tos_t tos		= 0;
-	int count			= 3;
-	suseconds_t timeout	= 3000;
-	int family			= AF_INET;
-
-	socklen_t max_length				= sizeof(struct sockaddr_in6);
-	uint8_t address_data[max_length];
-	struct sockaddr * address			= (struct sockaddr *) address_data;
-	struct sockaddr_in * address_in		= (struct sockaddr_in *) address;
-	struct sockaddr_in6 * address_in6	= (struct sockaddr_in6 *) address;
-	socklen_t addrlen;
-	char address_string[INET6_ADDRSTRLEN];
-	uint8_t * address_start;
-	int icmp_phone;
-	struct timeval time_before;
-	struct timeval time_after;
-	int result;
-	int value;
-	int index;
-
-	// print the program label
-	printf("Task %d - ", task_get_id());
-	printf("%s\n", NAME);
-
-	// parse the command line arguments
-	// stop before the last argument if it does not start with the minus sign ('-')
-	for(index = 1; (index < argc - 1) || ((index == argc - 1) && (argv[index][0] == '-')); ++ index){
-		// options should start with the minus sign ('-')
-		if(argv[index][0] == '-'){
-			switch(argv[index][1]){
-				// short options with only one letter
-				case 'c':
-					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &count, "count", 0));
-					break;
-				case 'f':
-					ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "address family", 0, parse_address_family));
-					break;
-				case 'h':
-					ping_print_help();
-					return EOK;
-					break;
-				case 's':
-					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "packet size", 0));
-					size = (value >= 0) ? (size_t) value : 0;
-					break;
-				case 't':
-					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "timeout", 0));
-					timeout = (value >= 0) ? (suseconds_t) value : 0;
-					break;
-				case 'v':
-					verbose = 1;
-					break;
-				// long options with the double minus sign ('-')
-				case '-':
-					if(str_lcmp(argv[index] + 2, "count=", 6) == 0){
-						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &count, "received count", 8));
-					}else if(str_lcmp(argv[index] + 2, "dont_fragment", 13) == 0){
-						dont_fragment = 1;
-					}else if(str_lcmp(argv[index] + 2, "family=", 7) == 0){
-						ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "address family", 9, parse_address_family));
-					}else if(str_lcmp(argv[index] + 2, "help", 5) == 0){
-						ping_print_help();
-						return EOK;
-					}else if(str_lcmp(argv[index] + 2, "size=", 5) == 0){
-						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "packet size", 7));
-						size = (value >= 0) ? (size_t) value : 0;
-					}else if(str_lcmp(argv[index] + 2, "timeout=", 8) == 0){
-						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "timeout", 7));
-						timeout = (value >= 0) ? (suseconds_t) value : 0;
-					}else if(str_lcmp(argv[index] + 2, "tos=", 4) == 0){
-						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "type of service", 7));
-						tos = (value >= 0) ? (ip_tos_t) value : 0;
-					}else if(str_lcmp(argv[index] + 2, "ttl=", 4) == 0){
-						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "time to live", 7));
-						ttl = (value >= 0) ? (ip_ttl_t) value : 0;
-					}else if(str_lcmp(argv[index] + 2, "verbose", 8) == 0){
-						verbose = 1;
-					}else{
-						print_unrecognized(index, argv[index] + 2);
-						ping_print_help();
-						return EINVAL;
-					}
-					break;
-				default:
-					print_unrecognized(index, argv[index] + 1);
-					ping_print_help();
-					return EINVAL;
-			}
-		}else{
-			print_unrecognized(index, argv[index]);
-			ping_print_help();
-			return EINVAL;
-		}
-	}
-
-	// if not before the last argument containing the address
-	if(index >= argc){
-		printf("Command line error: missing address\n");
-		ping_print_help();
-		return EINVAL;
-	}
-
-	// prepare the address buffer
-	bzero(address_data, max_length);
-	switch(family){
-		case AF_INET:
-			address_in->sin_family = AF_INET;
-			address_start = (uint8_t *) &address_in->sin_addr.s_addr;
-			addrlen = sizeof(struct sockaddr_in);
+#define NAME  "ping"
+
+#define CL_OK           0
+#define CL_USAGE        -1
+#define CL_MISSING      -2
+#define CL_INVALID      -3
+#define CL_UNSUPPORTED  -4
+#define CL_ERROR        -5
+
+/** Ping configuration
+ *
+ */
+typedef struct {
+	bool verbose;               /**< Verbose printouts. */
+	size_t size;                /**< Outgoing packet size. */
+	unsigned int count;         /**< Number of packets to send. */
+	suseconds_t timeout;        /**< Reply wait timeout. */
+	int af;                     /**< Address family. */
+	ip_tos_t tos;               /**< Type of service. */
+	ip_ttl_t ttl;               /**< Time-to-live. */
+	bool fragments;             /**< Fragmentation. */
+	
+	char *dest_addr;            /**< Destination address. */
+	struct sockaddr_in dest;    /**< IPv4 destionation. */
+	struct sockaddr_in6 dest6;  /**< IPv6 destionation. */
+	
+	struct sockaddr *dest_raw;  /**< Raw destination address. */
+	socklen_t dest_len;         /**< Raw destination address length. */
+	
+	/** Converted address string. */
+	char dest_str[INET6_ADDRSTRLEN];
+} ping_config_t;
+
+
+static void usage(void)
+{
+	printf(
+	    "Usage: ping [-c count] [-s size] [-W timeout] [-f family] [-t ttl]\n" \
+	    "            [-Q tos] [--dont_fragment] destination\n" \
+	    "\n" \
+	    "Options:\n" \
+	    "\t-c count\n" \
+	    "\t--count=count\n" \
+	    "\t\tNumber of outgoing packets (default: 4)\n" \
+	    "\n" \
+	    "\t-s size\n" \
+	    "\t--size=bytes\n" \
+	    "\t\tOutgoing packet size (default: 56 bytes)\n" \
+	    "\n" \
+	    "\t-W timeout\n" \
+	    "\t--timeout=ms\n" \
+	    "\t\tReply wait timeout (default: 3000 ms)\n" \
+	    "\n" \
+	    "\t-f family\n" \
+	    "\t--family=family\n" \
+	    "\t\tDestination address family, AF_INET or AF_INET6 (default: AF_INET)\n" \
+	    "\n" \
+	    "\t-t ttl\n" \
+	    "\t--ttl=ttl\n" \
+	    "\t\tOutgoing packet time-to-live (default: 0)\n" \
+	    "\n" \
+	    "\t-Q tos\n" \
+	    "\t--tos=tos\n" \
+	    "\t\tOutgoing packet type of service (default: 0)\n" \
+	    "\n" \
+	    "\t--dont_fragment\n" \
+	    "\t\tDisable packet fragmentation (default: enabled)\n" \
+	    "\n" \
+	    "\t-v\n" \
+	    "\t--verbose\n" \
+	    "\t\tVerbose operation\n" \
+	    "\n" \
+	    "\t-h\n" \
+	    "\t--help\n" \
+	    "\t\tPrint this usage information\n"
+	);
+}
+
+static int args_parse(int argc, char *argv[], ping_config_t *config)
+{
+	if (argc < 2)
+		return CL_USAGE;
+	
+	int i;
+	int ret;
+	
+	for (i = 1; i < argc; i++) {
+		
+		/* Not an option */
+		if (argv[i][0] != '-')
 			break;
-		case AF_INET6:
-			address_in6->sin6_family = AF_INET6;
-			address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr;
-			addrlen = sizeof(struct sockaddr_in6);
+		
+		/* Options terminator */
+		if (str_cmp(argv[i], "--") == 0) {
+			i++;
+			break;
+		}
+		
+		int off;
+		
+		/* Usage */
+		if ((off = arg_parse_short_long(argv[i], "-h", "--help")) != -1)
+			return CL_USAGE;
+		
+		/* Verbose */
+		if ((off = arg_parse_short_long(argv[i], "-v", "--verbose")) != -1) {
+			config->verbose = true;
+			continue;
+		}
+		
+		/* Don't fragment */
+		if (str_cmp(argv[i], "--dont_fragment") == 0) {
+			config->fragments = false;
+			continue;
+		}
+		
+		/* Count */
+		if ((off = arg_parse_short_long(argv[i], "-c", "--count=")) != -1) {
+			int tmp;
+			ret = arg_parse_int(argc, argv, &i, &tmp, off);
+			
+			if ((ret != EOK) || (tmp < 0))
+				return i;
+			
+			config->count = (unsigned int) tmp;
+			continue;
+		}
+		
+		/* Outgoing packet size */
+		if ((off = arg_parse_short_long(argv[i], "-s", "--size=")) != -1) {
+			int tmp;
+			ret = arg_parse_int(argc, argv, &i, &tmp, off);
+			
+			if ((ret != EOK) || (tmp < 0))
+				return i;
+			
+			config->size = (size_t) tmp;
+			continue;
+		}
+		
+		/* Reply wait timeout */
+		if ((off = arg_parse_short_long(argv[i], "-W", "--timeout=")) != -1) {
+			int tmp;
+			ret = arg_parse_int(argc, argv, &i, &tmp, off);
+			
+			if ((ret != EOK) || (tmp < 0))
+				return i;
+			
+			config->timeout = (suseconds_t) tmp;
+			continue;
+		}
+		
+		/* Address family */
+		if ((off = arg_parse_short_long(argv[i], "-f", "--family=")) != -1) {
+			ret = arg_parse_name_int(argc, argv, &i, &config->af, off,
+			    socket_parse_address_family);
+			
+			if (ret != EOK)
+				return i;
+			
+			continue;
+		}
+		
+		/* Type of service */
+		if ((off = arg_parse_short_long(argv[i], "-Q", "--tos=")) != -1) {
+			int tmp;
+			ret = arg_parse_name_int(argc, argv, &i, &tmp, off,
+			    socket_parse_address_family);
+			
+			if ((ret != EOK) || (tmp < 0))
+				return i;
+			
+			config->tos = (ip_tos_t) tmp;
+			continue;
+		}
+		
+		/* Time to live */
+		if ((off = arg_parse_short_long(argv[i], "-t", "--ttl=")) != -1) {
+			int tmp;
+			ret = arg_parse_name_int(argc, argv, &i, &tmp, off,
+			    socket_parse_address_family);
+			
+			if ((ret != EOK) || (tmp < 0))
+				return i;
+			
+			config->ttl = (ip_ttl_t) tmp;
+			continue;
+		}
+	}
+	
+	if (i >= argc)
+		return CL_MISSING;
+	
+	config->dest_addr = argv[i];
+	
+	/* Resolve destionation address */
+	switch (config->af) {
+	case AF_INET:
+		config->dest_raw = (struct sockaddr *) &config->dest;
+		config->dest_len = sizeof(config->dest);
+		config->dest.sin_family = config->af;
+		ret = inet_pton(config->af, config->dest_addr,
+		    (uint8_t *) &config->dest.sin_addr.s_addr);
+		break;
+	case AF_INET6:
+		config->dest_raw = (struct sockaddr *) &config->dest6;
+		config->dest_len = sizeof(config->dest6);
+		config->dest6.sin6_family = config->af;
+		ret = inet_pton(config->af, config->dest_addr,
+		    (uint8_t *) &config->dest6.sin6_addr.s6_addr);
+		break;
+	default:
+		return CL_UNSUPPORTED;
+	}
+	
+	if (ret != EOK)
+		return CL_INVALID;
+	
+	/* Convert destination address back to string */
+	switch (config->af) {
+	case AF_INET:
+		ret = inet_ntop(config->af,
+		    (uint8_t *) &config->dest.sin_addr.s_addr,
+		    config->dest_str, sizeof(config->dest_str));
+		break;
+	case AF_INET6:
+		ret = inet_ntop(config->af,
+		    (uint8_t *) &config->dest6.sin6_addr.s6_addr,
+		    config->dest_str, sizeof(config->dest_str));
+		break;
+	default:
+		return CL_UNSUPPORTED;
+	}
+	
+	if (ret != EOK)
+		return CL_ERROR;
+	
+	return CL_OK;
+}
+
+int main(int argc, char *argv[])
+{
+	ping_config_t config;
+	
+	/* Default configuration */
+	config.verbose = false;
+	config.size = 56;
+	config.count = 4;
+	config.timeout = 3000;
+	config.af = AF_INET;
+	config.tos = 0;
+	config.ttl = 0;
+	config.fragments = true;
+	
+	int ret = args_parse(argc, argv, &config);
+	
+	switch (ret) {
+	case CL_OK:
+		break;
+	case CL_USAGE:
+		usage();
+		return 0;
+	case CL_MISSING:
+		fprintf(stderr, "%s: Destination address missing\n", NAME);
+		return 1;
+	case CL_INVALID:
+		fprintf(stderr, "%s: Destination address '%s' invalid or malformed\n",
+		    NAME, config.dest_addr);
+		return 2;
+	case CL_UNSUPPORTED:
+		fprintf(stderr, "%s: Destination address '%s' unsupported\n",
+		    NAME, config.dest_addr);
+		return 3;
+	case CL_ERROR:
+		fprintf(stderr, "%s: Destination address '%s' error\n",
+		    NAME, config.dest_addr);
+		return 4;
+	default:
+		fprintf(stderr, "%s: Unknown or invalid option '%s'\n", NAME,
+		    argv[ret]);
+		return 5;
+	}
+	
+	printf("PING %s (%s) %u(%u) bytes of data\n", config.dest_addr,
+	    config.dest_str, config.size, config.size);
+	
+	int icmp_phone = icmp_connect_module(SERVICE_ICMP, ICMP_CONNECT_TIMEOUT);
+	if (icmp_phone < 0) {
+		fprintf(stderr, "%s: Unable to connect to ICMP service (%s)\n", NAME,
+		    str_error(icmp_phone));
+		return icmp_phone;
+	}
+	
+	unsigned int seq;
+	for (seq = 0; seq < config.count; seq++) {
+		struct timeval t0;
+		ret = gettimeofday(&t0, NULL);
+		if (ret != EOK) {
+			fprintf(stderr, "%s: gettimeofday failed (%s)\n", NAME,
+			    str_error(ret));
+			
+			ipc_hangup(icmp_phone);
+			return ret;
+		}
+		
+		/* Ping! */
+		int result = icmp_echo_msg(icmp_phone, config.size, config.timeout,
+		    config.ttl, config.tos, !config.fragments, config.dest_raw,
+		    config.dest_len);
+		
+		struct timeval t1;
+		ret = gettimeofday(&t1, NULL);
+		if (ret != EOK) {
+			fprintf(stderr, "%s: gettimeofday failed (%s)\n", NAME,
+			    str_error(ret));
+			
+			ipc_hangup(icmp_phone);
+			return ret;
+		}
+		
+		suseconds_t elapsed = tv_sub(&t1, &t0);
+		
+		switch (result) {
+		case ICMP_ECHO:
+			printf("%u bytes from ? (?): icmp_seq=%u ttl=? time=%u.%04u\n",
+				config.size, seq, elapsed / 1000, elapsed % 1000);
+			break;
+		case ETIMEOUT:
+			printf("%u bytes from ? (?): icmp_seq=%u Timed out\n",
+				config.size, seq);
 			break;
 		default:
-			fprintf(stderr, "Address family is not supported\n");
-			return EAFNOSUPPORT;
-	}
-
-	// parse the last argument which should contain the address
-	if(ERROR_OCCURRED(inet_pton(family, argv[argc - 1], address_start))){
-		fprintf(stderr, "Address parse error %d\n", ERROR_CODE);
-		return ERROR_CODE;
-	}
-
-	// connect to the ICMP module
-	icmp_phone = icmp_connect_module(SERVICE_ICMP, ICMP_CONNECT_TIMEOUT);
-	if(icmp_phone < 0){
-		fprintf(stderr, "ICMP connect error %d\n", icmp_phone);
-		return icmp_phone;
-	}
-
-	// print the ping header
-	printf("PING %d bytes of data\n", size);
-	if(ERROR_OCCURRED(inet_ntop(address->sa_family, address_start, address_string, sizeof(address_string)))){
-		fprintf(stderr, "Address error %d\n", ERROR_CODE);
-	}else{
-		printf("Address %s:\n", address_string);
-	}
-
-	// do count times
-	while(count > 0){
-
-		// get the starting time
-		if(ERROR_OCCURRED(gettimeofday(&time_before, NULL))){
-			fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
-			// release the ICMP phone
-			ipc_hangup(icmp_phone);
-			return ERROR_CODE;
-		}
-
-		// request the ping
-		result = icmp_echo_msg(icmp_phone, size, timeout, ttl, tos, dont_fragment, address, addrlen);
-
-		// get the ending time
-		if(ERROR_OCCURRED(gettimeofday(&time_after, NULL))){
-			fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
-			// release the ICMP phone
-			ipc_hangup(icmp_phone);
-			return ERROR_CODE;
-		}
-
-		// print the result
-		switch(result){
-			case ICMP_ECHO:
-				printf("Ping round trip time %d miliseconds\n", tv_sub(&time_after, &time_before) / 1000);
-				break;
-			case ETIMEOUT:
-				printf("Timed out.\n");
-				break;
-			default:
-				print_error(stdout, result, NULL, "\n");
-		}
-		-- count;
-	}
-
-	if(verbose){
-		printf("Exiting\n");
-	}
-
-	// release the ICMP phone
+			print_error(stdout, result, NULL, "\n");
+		}
+	}
+	
 	ipc_hangup(icmp_phone);
-
-	return EOK;
+	
+	return 0;
 }
 
-void ping_print_help(void){
-	printf(
-		"Network Ping aplication\n" \
-		"Usage: ping [options] numeric_address\n" \
-		"Where options are:\n" \
-		"\n" \
-		"-c request_count | --count=request_count\n" \
-		"\tThe number of packets the application sends. The default is three (3).\n" \
-		"\n" \
-		"--dont_fragment\n" \
-		"\tDisable packet fragmentation.\n"
-		"\n" \
-		"-f address_family | --family=address_family\n" \
-		"\tThe given address family. Only the AF_INET and AF_INET6 are supported.\n"
-		"\n" \
-		"-h | --help\n" \
-		"\tShow this application help.\n"
-		"\n" \
-		"-s packet_size | --size=packet_size\n" \
-		"\tThe packet data size the application sends. The default is 38 bytes.\n" \
-		"\n" \
-		"-t timeout | --timeout=timeout\n" \
-		"\tThe number of miliseconds the application waits for a reply. The default is three thousands (3 000).\n" \
-		"\n" \
-		"--tos=tos\n" \
-		"\tThe type of service to be used.\n" \
-		"\n" \
-		"--ttl=ttl\n" \
-		"\tThe time to live to be used.\n" \
-		"\n" \
-		"-v | --verbose\n" \
-		"\tShow all output messages.\n"
-	);
-}
-
 /** @}
  */
Index: uspace/app/redir/redir.c
===================================================================
--- uspace/app/redir/redir.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/redir/redir.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -42,8 +42,12 @@
 #include <stdio.h>
 #include <task.h>
+#include <str_error.h>
+
+#define NAME  "redir"
 
 static void usage(void)
 {
-	printf("Usage: redir [-i <stdin>] [-o <stdout>] [-e <stderr>] -- <cmd> [args ...]\n");
+	printf("Usage: %s [-i <stdin>] [-o <stdout>] [-e <stderr>] -- <cmd> [args ...]\n",
+	    NAME);
 }
 
@@ -84,10 +88,12 @@
 	args[argc] = NULL;
 	
-	task_id_t id = task_spawn(argv[0], args);
+	int err;
+	task_id_t id = task_spawn(argv[0], args, &err);
 	
 	free(args);
 	
 	if (id == 0)
-		printf("Error spawning %s\n", argv[0]);
+		printf("%s: Error spawning %s (%s)\n", NAME, argv[0],
+		    str_error(err));
 	
 	return id;
Index: uspace/app/sbi/src/os/helenos.c
===================================================================
--- uspace/app/sbi/src/os/helenos.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/sbi/src/os/helenos.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -35,4 +35,5 @@
 #include <task.h>
 #include <tinput.h>
+#include <str_error.h>
 
 #include "os.h"
@@ -186,7 +187,8 @@
 	int retval;
 
-	tid = task_spawn(cmd[0], (char const * const *) cmd);
+	tid = task_spawn(cmd[0], (char const * const *) cmd, &retval);
 	if (tid == 0) {
-		printf("Error: Failed spawning '%s'.\n", cmd[0]);
+		printf("Error: Failed spawning '%s' (%s).\n", cmd[0],
+		    str_error(retval));
 		exit(1);
 	}
Index: uspace/app/sbi/src/run_expr.c
===================================================================
--- uspace/app/sbi/src/run_expr.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/sbi/src/run_expr.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -1434,4 +1434,6 @@
 		addr_prop->u.named->prop_d = deleg_p;
 		break;
+	default:
+		ritem = NULL;
 	}
 
Index: uspace/app/stats/Makefile
===================================================================
--- uspace/app/stats/Makefile	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
+++ uspace/app/stats/Makefile	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = stats
+
+SOURCES = \
+	stats.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/stats/stats.c
===================================================================
--- uspace/app/stats/stats.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
+++ uspace/app/stats/stats.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * 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 stats
+ * @brief Print system statistics.
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdio.h>
+#include <stats.h>
+#include <sys/time.h>
+#include <inttypes.h>
+#include <malloc.h>
+
+#define NAME  "sysstat"
+
+#define DAY     86400
+#define HOUR    3600
+#define MINUTE  60
+
+int main(int argc, char *argv[])
+{
+	struct timeval time;
+	if (gettimeofday(&time, NULL) != 0) {
+		fprintf(stderr, "%s: Cannot get time of day\n", NAME);
+		return -1;
+	}
+	
+	uint64_t sec = time.tv_sec;
+	printf("%02" PRIu64 ":%02" PRIu64 ":%02" PRIu64, (sec % DAY) / HOUR,
+	    (sec % HOUR) / MINUTE, sec % MINUTE);
+	
+	sysarg_t uptime = stats_get_uptime();
+	printf(", up %u days, %u hours, %u minutes, %u seconds", uptime / DAY,
+	    (uptime % DAY) / HOUR, (uptime % HOUR) / MINUTE, uptime % MINUTE);
+	
+	size_t count;
+	load_t *load = stats_get_load(&count);
+	if (load != NULL) {
+		printf(", load average: ");
+		
+		size_t i;
+		for (i = 0; i < count; i++) {
+			if (i > 0)
+				printf(" ");
+			
+			stats_print_load_fragment(load[i], 2);
+		}
+		
+		free(load);
+	}
+	
+	printf("\n");
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/tasks/Makefile
===================================================================
--- uspace/app/tasks/Makefile	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
+++ uspace/app/tasks/Makefile	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = tasks
+
+SOURCES = \
+	tasks.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/tasks/tasks.c
===================================================================
--- uspace/app/tasks/tasks.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
+++ uspace/app/tasks/tasks.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * Copyright (c) 2010 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 tasks
+ * @brief Task lister.
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdio.h>
+#include <task.h>
+#include <thread.h>
+#include <stats.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <inttypes.h>
+#include <bool.h>
+#include <str.h>
+#include <arg_parse.h>
+
+#define NAME  "tasks"
+
+#define TASK_COUNT    10
+#define THREAD_COUNT  50
+
+#define PRINT_LOAD1(x)  ((x) >> 11)
+#define PRINT_LOAD2(x)  (((x) & 0x7ff) / 2)
+
+static void list_tasks(void)
+{
+	size_t count;
+	stats_task_t *stats_tasks = stats_get_tasks(&count);
+	
+	if (stats_tasks == NULL) {
+		fprintf(stderr, "%s: Unable to get tasks\n", NAME);
+		return;
+	}
+	
+	printf("      ID  Threads      Mem       uCycles       kCycles   Name\n");
+	
+	size_t i;
+	for (i = 0; i < count; i++) {
+		uint64_t virtmem, ucycles, kcycles;
+		char vmsuffix, usuffix, ksuffix;
+		
+		order_suffix(stats_tasks[i].virtmem, &virtmem, &vmsuffix);
+		order_suffix(stats_tasks[i].ucycles, &ucycles, &usuffix);
+		order_suffix(stats_tasks[i].kcycles, &kcycles, &ksuffix);
+		
+		printf("%8" PRIu64 "%8u %8" PRIu64"%c %12"
+		    PRIu64 "%c %12" PRIu64 "%c %s\n", stats_tasks[i].task_id,
+		    stats_tasks[i].threads, virtmem, vmsuffix, ucycles, usuffix,
+		    kcycles, ksuffix, stats_tasks[i].name);
+	}
+	
+	free(stats_tasks);
+}
+
+static void list_threads(task_id_t task_id, bool all)
+{
+	size_t count;
+	stats_thread_t *stats_threads = stats_get_threads(&count);
+	
+	if (stats_threads == NULL) {
+		fprintf(stderr, "%s: Unable to get threads\n", NAME);
+		return;
+	}
+	
+	printf("    ID    State  CPU   Prio    [k]uCycles    [k]kcycles   Cycle fault\n");
+	size_t i;
+	for (i = 0; i < count; i++) {
+		if ((all) || (stats_threads[i].task_id == task_id)) {
+			uint64_t ucycles, kcycles;
+			char usuffix, ksuffix;
+			
+			order_suffix(stats_threads[i].ucycles, &ucycles, &usuffix);
+			order_suffix(stats_threads[i].kcycles, &kcycles, &ksuffix);
+			
+			if (stats_threads[i].on_cpu) {
+				printf("%8" PRIu64 " %-8s %4u %6d %12"
+				    PRIu64"%c %12" PRIu64"%c\n", stats_threads[i].thread_id,
+				    thread_get_state(stats_threads[i].state),
+				    stats_threads[i].cpu, stats_threads[i].priority,
+				    ucycles, usuffix, kcycles, ksuffix);
+			} else {
+				printf("%8" PRIu64 " %-8s ---- %6d %12"
+				    PRIu64"%c %12" PRIu64"%c\n", stats_threads[i].thread_id,
+				    thread_get_state(stats_threads[i].state),
+				    stats_threads[i].priority,
+				    ucycles, usuffix, kcycles, ksuffix);
+			}
+		}
+	}
+	
+	free(stats_threads);
+}
+
+static void print_load(void)
+{
+	size_t count;
+	load_t *load = stats_get_load(&count);
+	
+	if (load == NULL) {
+		fprintf(stderr, "%s: Unable to get load\n", NAME);
+		return;
+	}
+	
+	printf("%s: Load average: ", NAME);
+	
+	size_t i;
+	for (i = 0; i < count; i++) {
+		if (i > 0)
+			printf(" ");
+		
+		stats_print_load_fragment(load[i], 2);
+	}
+	
+	printf("\n");
+	
+	free(load);
+}
+
+static void list_cpus(void)
+{
+	size_t count;
+	stats_cpu_t *cpus = stats_get_cpus(&count);
+	
+	if (cpus == NULL) {
+		fprintf(stderr, "%s: Unable to get CPU statistics\n", NAME);
+		return;
+	}
+	
+	printf("%s: %u CPU(s) detected\n", NAME, count);
+	
+	size_t i;
+	for (i = 0; i < count; i++) {
+		if (cpus[i].active) {
+			printf("cpu%u: %" PRIu16 " MHz, busy ticks: "
+			    "%" PRIu64 ", idle ticks: %" PRIu64 "\n",
+			    cpus[i].id, cpus[i].frequency_mhz, cpus[i].busy_ticks,
+			    cpus[i].idle_ticks);
+		} else {
+			printf("cpu%u: inactive\n", cpus[i].id);
+		}
+	}
+	
+	free(cpus);
+}
+
+static void usage()
+{
+	printf(
+	    "Usage: tasks [-t task_id] [-a] [-l] [-c]\n" \
+	    "\n" \
+	    "Options:\n" \
+	    "\t-t task_id\n" \
+	    "\t--task=task_id\n" \
+	    "\t\tList threads of the given task\n" \
+	    "\n" \
+	    "\t-a\n" \
+	    "\t--all\n" \
+	    "\t\tList all threads\n" \
+	    "\n" \
+	    "\t-l\n" \
+	    "\t--load\n" \
+	    "\t\tPrint system load\n" \
+	    "\n" \
+	    "\t-c\n" \
+	    "\t--cpu\n" \
+	    "\t\tList CPUs\n" \
+	    "\n" \
+	    "\t-h\n" \
+	    "\t--help\n" \
+	    "\t\tPrint this usage information\n"
+	    "\n" \
+	    "Without any options all tasks are listed\n"
+	);
+}
+
+int main(int argc, char *argv[])
+{
+	bool toggle_tasks = true;
+	bool toggle_threads = false;
+	bool toggle_all = false;
+	bool toggle_load = false;
+	bool toggle_cpus = false;
+	
+	task_id_t task_id = 0;
+	
+	int i;
+	for (i = 1; i < argc; i++) {
+		int off;
+		
+		/* Usage */
+		if ((off = arg_parse_short_long(argv[i], "-h", "--help")) != -1) {
+			usage();
+			return 0;
+		}
+		
+		/* All threads */
+		if ((off = arg_parse_short_long(argv[i], "-a", "--all")) != -1) {
+			toggle_tasks = false;
+			toggle_threads = true;
+			toggle_all = true;
+			continue;
+		}
+		
+		/* Load */
+		if ((off = arg_parse_short_long(argv[i], "-l", "--load")) != -1) {
+			toggle_tasks = false;
+			toggle_load = true;
+			continue;
+		}
+		
+		/* CPUs */
+		if ((off = arg_parse_short_long(argv[i], "-c", "--cpus")) != -1) {
+			toggle_tasks = false;
+			toggle_cpus = true;
+			continue;
+		}
+		
+		/* Threads */
+		if ((off = arg_parse_short_long(argv[i], "-t", "--task=")) != -1) {
+			// TODO: Support for 64b range
+			int tmp;
+			int ret = arg_parse_int(argc, argv, &i, &tmp, off);
+			if (ret != EOK) {
+				printf("%s: Malformed task_id '%s'\n", NAME, argv[i]);
+				return -1;
+			}
+			
+			task_id = tmp;
+			
+			toggle_tasks = false;
+			toggle_threads = true;
+			continue;
+		}
+	}
+	
+	if (toggle_tasks)
+		list_tasks();
+	
+	if (toggle_threads)
+		list_threads(task_id, toggle_all);
+	
+	if (toggle_load)
+		print_load();
+	
+	if (toggle_cpus)
+		list_cpus();
+	
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/tester/console/console1.c
===================================================================
--- uspace/app/tester/console/console1.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/tester/console/console1.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -53,11 +53,17 @@
 		fflush(stdout);
 		console_set_style(fphone(stdout), STYLE_NORMAL);
-		printf("normal ");
+		printf(" normal ");
 		fflush(stdout);
 		console_set_style(fphone(stdout), STYLE_EMPHASIS);
-		printf("emphasized");
+		printf(" emphasized ");
+		fflush(stdout);
+		console_set_style(fphone(stdout), STYLE_INVERTED);
+		printf(" inverted ");
+		fflush(stdout);
+		console_set_style(fphone(stdout), STYLE_SELECTED);
+		printf(" selected ");
 		fflush(stdout);
 		console_set_style(fphone(stdout), STYLE_NORMAL);
-		printf(".\n");
+		printf("\n");
 		
 		unsigned int i;
@@ -73,5 +79,5 @@
 			}
 			fflush(stdout);
-			console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0);
+			console_set_style(fphone(stdout), STYLE_NORMAL);
 			putchar('\n');
 		}
@@ -86,5 +92,5 @@
 			}
 			fflush(stdout);
-			console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0);
+			console_set_style(fphone(stdout), STYLE_NORMAL);
 			putchar('\n');
 		}
@@ -94,5 +100,5 @@
 		for (i = 0; i < 255; i += 16) {
 			fflush(stdout);
-			console_set_rgb_color(fphone(stdout), 0xffffff, i << 16);
+			console_set_rgb_color(fphone(stdout), (255 - i) << 16, i << 16);
 			putchar('X');
 		}
@@ -103,5 +109,5 @@
 		for (i = 0; i < 255; i += 16) {
 			fflush(stdout);
-			console_set_rgb_color(fphone(stdout), 0xffffff, i << 8);
+			console_set_rgb_color(fphone(stdout), (255 - i) << 8, i << 8);
 			putchar('X');
 		}
@@ -112,9 +118,9 @@
 		for (i = 0; i < 255; i += 16) {
 			fflush(stdout);
-			console_set_rgb_color(fphone(stdout), 0xffffff, i);
+			console_set_rgb_color(fphone(stdout), 255 - i, i);
 			putchar('X');
 		}
 		fflush(stdout);
-		console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0);
+		console_set_style(fphone(stdout), STYLE_NORMAL);
 		putchar('\n');
 	}
Index: uspace/app/tetris/screen.c
===================================================================
--- uspace/app/tetris/screen.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/tetris/screen.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -53,7 +53,9 @@
 #include <vfs/vfs.h>
 #include <async.h>
+#include <bool.h>
+#include <io/console.h>
+#include <io/style.h>
 #include "screen.h"
 #include "tetris.h"
-#include <io/console.h>
 
 #define STOP  (B_COLS - 3)
@@ -63,5 +65,5 @@
 static int isset;               /* true => terminal is in game mode */
 
-static int use_color;		/* true => use colors */
+static bool use_color;          /* true => use colors */
 
 static const struct shape *lastshape;
@@ -81,5 +83,5 @@
 {
 	fflush(stdout);
-	console_set_rgb_color(fphone(stdout), 0xf0f0f0,
+	console_set_rgb_color(fphone(stdout), 0xffffff,
 	    use_color ? color : 0x000000);
 }
@@ -88,5 +90,5 @@
 {
 	fflush(stdout);
-	console_set_rgb_color(fphone(stdout), 0, 0xf0f0f0);
+	console_set_style(fphone(stdout), STYLE_NORMAL);
 }
 
@@ -118,8 +120,8 @@
 }
 
-void moveto(int r, int c)
+void moveto(ipcarg_t r, ipcarg_t c)
 {
 	fflush(stdout);
-	console_goto(fphone(stdout), c, r);
+	console_set_pos(fphone(stdout), c, r);
 }
 
@@ -131,13 +133,12 @@
 }
 
-static int get_display_color_sup(void)
-{
-	int rc;
-	int ccap;
-
-	rc = console_get_color_cap(fphone(stdout), &ccap);
+static bool get_display_color_sup(void)
+{
+	ipcarg_t ccap;
+	int rc = console_get_color_cap(fphone(stdout), &ccap);
+	
 	if (rc != 0)
-		return 0;
-
+		return false;
+	
 	return (ccap >= CONSOLE_CCAP_RGB);
 }
@@ -308,5 +309,5 @@
  * (We need its length in case we have to overwrite with blanks.)
  */
-void scr_msg(char *s, int set)
+void scr_msg(char *s, bool set)
 {
 	int l = str_size(s);
Index: uspace/app/tetris/screen.h
===================================================================
--- uspace/app/tetris/screen.h	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/tetris/screen.h	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -48,14 +48,16 @@
 
 #include <sys/types.h>
+#include <ipc/ipc.h>
 #include <async.h>
+#include <bool.h>
 
 typedef struct {
-	int ws_row;
-	int ws_col;
+	ipcarg_t ws_row;
+	ipcarg_t ws_col;
 } winsize_t;
 
 extern winsize_t winsize;
 
-extern void moveto(int r, int c);
+extern void moveto(ipcarg_t r, ipcarg_t c);
 extern void clear_screen(void);
 
@@ -65,5 +67,5 @@
 extern void scr_end(void);
 extern void scr_init(void);
-extern void scr_msg(char *, int);
+extern void scr_msg(char *, bool);
 extern void scr_set(void);
 extern void scr_update(void);
Index: uspace/app/top/Makefile
===================================================================
--- uspace/app/top/Makefile	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
+++ uspace/app/top/Makefile	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = top
+
+SOURCES = \
+	top.c \
+	screen.c \
+	input.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/top/input.c
===================================================================
--- uspace/app/top/input.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
+++ uspace/app/top/input.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -0,0 +1,200 @@
+/*	$OpenBSD: input.c,v 1.12 2005/04/13 02:33:08 deraadt Exp $	*/
+/*    $NetBSD: input.c,v 1.3 1996/02/06 22:47:33 jtc Exp $    */
+
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek and Darren F. Provine.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ *	@(#)input.c	8.1 (Berkeley) 5/31/93
+ */
+
+/** @addtogroup top
+ * @{
+ */
+/** @file
+ */
+
+/*
+ * Top input.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <str.h>
+
+#include "input.h"
+
+#include <async.h>
+#include <vfs/vfs.h>
+#include <io/console.h>
+#include <ipc/console.h>
+
+#define USEC_COUNT 1000000
+
+/* return true iff the given timeval is positive */
+#define	TV_POS(tv) \
+	((tv)->tv_sec > 0 || ((tv)->tv_sec == 0 && (tv)->tv_usec > 0))
+
+/* subtract timeval `sub' from `res' */
+#define	TV_SUB(res, sub) \
+	(res)->tv_sec -= (sub)->tv_sec; \
+	(res)->tv_usec -= (sub)->tv_usec; \
+	if ((res)->tv_usec < 0) { \
+		(res)->tv_usec += 1000000; \
+		(res)->tv_sec--; \
+	}
+
+/* We will use a hack here - if lastchar is non-zero, it is
+ * the last character read. We will somehow simulate the select
+ * semantics.
+ */
+static aid_t getchar_inprog = 0;
+static char lastchar = '\0';
+
+/*
+ * Do a `read wait': select for reading from stdin, with timeout *tvp.
+ * On return, modify *tvp to reflect the amount of time spent waiting.
+ * It will be positive only if input appeared before the time ran out;
+ * otherwise it will be zero or perhaps negative.
+ *
+ * If tvp is nil, wait forever, but return if select is interrupted.
+ *
+ * Return 0 => no input, 1 => can read() from stdin
+ *
+ */
+int rwait(struct timeval *tvp)
+{
+	struct timeval starttv, endtv, *s;
+	static ipc_call_t charcall;
+	ipcarg_t rc;
+	
+	/*
+	 * Someday, select() will do this for us.
+	 * Just in case that day is now, and no one has
+	 * changed this, we use a temporary.
+	 */
+	if (tvp) {
+		(void) gettimeofday(&starttv, NULL);
+		endtv = *tvp;
+		s = &endtv;
+	} else
+		s = NULL;
+	
+	if (!lastchar) {
+again:
+		if (!getchar_inprog) {
+			getchar_inprog = async_send_0(fphone(stdin),
+			    CONSOLE_GET_EVENT, &charcall);
+		}
+		
+		if (!s)
+			async_wait_for(getchar_inprog, &rc);
+		else if (async_wait_timeout(getchar_inprog, &rc, s->tv_usec) == ETIMEOUT) {
+			tvp->tv_sec = 0;
+			tvp->tv_usec = 0;
+			return (0);
+		}
+		
+		getchar_inprog = 0;
+		if (rc) {
+			printf("End of file, bug?\n");
+			exit(1);
+		}
+		
+		if (IPC_GET_ARG1(charcall) == KEY_RELEASE)
+			goto again;
+		
+		lastchar = IPC_GET_ARG4(charcall);
+	}
+	
+	if (tvp) {
+		/* since there is input, we may not have timed out */
+		(void) gettimeofday(&endtv, NULL);
+		TV_SUB(&endtv, &starttv);
+		TV_SUB(tvp, &endtv);  /* adjust *tvp by elapsed time */
+	}
+	
+	return 1;
+}
+
+/*
+ * `sleep' for the current turn time (using select).
+ * Eat any input that might be available.
+ */
+void tsleep(unsigned int sec)
+{
+	struct timeval tv;
+	
+	tv.tv_sec = 0;
+	tv.tv_usec = sec * USEC_COUNT;
+	while (TV_POS(&tv))
+		if (rwait(&tv)) {
+			lastchar = '\0';
+		} else
+			break;
+}
+
+/*
+ * getchar with timeout.
+ */
+int tgetchar(unsigned int sec)
+{
+	static struct timeval timeleft;
+	char c;
+	
+	/*
+	 * Reset timeleft to USEC_COUNT whenever it is not positive.
+	 * In any case, wait to see if there is any input.  If so,
+	 * take it, and update timeleft so that the next call to
+	 * tgetchar() will not wait as long.  If there is no input,
+	 * make timeleft zero or negative, and return -1.
+	 *
+	 * Most of the hard work is done by rwait().
+	 */
+	if (!TV_POS(&timeleft)) {
+		timeleft.tv_sec = 0;
+		timeleft.tv_usec = sec * USEC_COUNT;
+	}
+	
+	if (!rwait(&timeleft))
+		return -1;
+	
+	c = lastchar;
+	lastchar = '\0';
+	return ((int) (unsigned char) c);
+}
+
+/** @}
+ */
Index: uspace/app/top/input.h
===================================================================
--- uspace/app/top/input.h	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
+++ uspace/app/top/input.h	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -0,0 +1,56 @@
+/*	$OpenBSD: input.h,v 1.5 2003/06/03 03:01:41 millert Exp $	*/
+/*	$NetBSD: input.h,v 1.2 1995/04/22 07:42:36 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek and Darren F. Provine.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ *	@(#)input.h	8.1 (Berkeley) 5/31/93
+ */
+
+/** @addtogroup top
+ * @{
+ */
+/** @file
+ */
+
+#ifndef TOP_INPUT_
+#define TOP_INPUT_
+
+#include <sys/time.h>
+
+extern int rwait(struct timeval *);
+extern int tgetchar(unsigned int sec);
+extern void tsleep(unsigned int sec);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/top/screen.c
===================================================================
--- uspace/app/top/screen.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
+++ uspace/app/top/screen.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * Copyright (c) 2010 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 top
+ * @brief Top utility.
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdio.h>
+#include <ipc/ipc.h>
+#include <io/console.h>
+#include <io/style.h>
+#include <vfs/vfs.h>
+#include <stdarg.h>
+#include <stats.h>
+#include <inttypes.h>
+#include "screen.h"
+#include "top.h"
+
+static ipcarg_t warn_col = 0;
+static ipcarg_t warn_row = 0;
+
+static void screen_style_normal(void)
+{
+	fflush(stdout);
+	console_set_style(fphone(stdout), STYLE_NORMAL);
+}
+
+static void screen_style_inverted(void)
+{
+	fflush(stdout);
+	console_set_style(fphone(stdout), STYLE_INVERTED);
+}
+
+static void screen_moveto(ipcarg_t col, ipcarg_t row)
+{
+	fflush(stdout);
+	console_set_pos(fphone(stdout), col, row);
+}
+
+static void screen_get_pos(ipcarg_t *col, ipcarg_t *row)
+{
+	fflush(stdout);
+	console_get_pos(fphone(stdout), col, row);
+}
+
+static void screen_get_size(ipcarg_t *col, ipcarg_t *row)
+{
+	fflush(stdout);
+	console_get_size(fphone(stdout), col, row);
+}
+
+static void screen_restart(bool clear)
+{
+	screen_style_normal();
+	
+	if (clear) {
+		fflush(stdout);
+		console_clear(fphone(stdout));
+	}
+	
+	screen_moveto(0, 0);
+}
+
+static void screen_newline(void)
+{
+	ipcarg_t cols;
+	ipcarg_t rows;
+	screen_get_size(&cols, &rows);
+	
+	ipcarg_t c;
+	ipcarg_t r;
+	screen_get_pos(&c, &r);
+	
+	ipcarg_t i;
+	for (i = c + 1; i < cols; i++)
+		puts(" ");
+	
+	if (r + 1 < rows)
+		puts("\n");
+}
+
+void screen_init(void)
+{
+	fflush(stdout);
+	console_cursor_visibility(fphone(stdout), false);
+	
+	screen_restart(true);
+}
+
+void screen_done(void)
+{
+	screen_restart(true);
+	
+	fflush(stdout);
+	console_cursor_visibility(fphone(stdout), true);
+}
+
+static void print_float(fixed_float ffloat, unsigned int precision)
+{
+	printf("%2" PRIu64 ".", ffloat.upper / ffloat.lower);
+	
+	unsigned int i;
+	uint64_t rest = (ffloat.upper % ffloat.lower) * 10;
+	for (i = 0; i < precision; i++) {
+		printf("%" PRIu64, rest / ffloat.lower);
+		rest = (rest % ffloat.lower) * 10;
+	}
+}
+
+static inline void print_global_head(data_t *data)
+{
+	printf("top - %02lu:%02lu:%02lu up %u days, %02u:%02u:%02u, load average:",
+	    data->hours, data->minutes, data->seconds,
+	    data->udays, data->uhours, data->uminutes, data->useconds);
+	
+	size_t i;
+	for (i = 0; i < data->load_count; i++) {
+		puts(" ");
+		stats_print_load_fragment(data->load[i], 2);
+	}
+	
+	screen_newline();
+}
+
+static inline void print_task_summary(data_t *data)
+{
+	printf("tasks: %u total", data->tasks_count);
+	screen_newline();
+}
+
+static inline void print_thread_summary(data_t *data)
+{
+	size_t total = 0;
+	size_t running = 0;
+	size_t ready = 0;
+	size_t sleeping = 0;
+	size_t lingering = 0;
+	size_t other = 0;
+	size_t invalid = 0;
+	
+	size_t i;
+	for (i = 0; i < data->threads_count; i++) {
+		total++;
+		
+		switch (data->threads[i].state) {
+		case Running:
+			running++;
+			break;
+		case Ready:
+			ready++;
+			break;
+		case Sleeping:
+			sleeping++;
+			break;
+		case Lingering:
+			lingering++;
+			break;
+		case Entering:
+		case Exiting:
+			other++;
+			break;
+		default:
+			invalid++;
+		}
+	}
+	
+	printf("threads: %u total, %u running, %u ready, %u sleeping, %u lingering, "
+	    "%u other, %u invalid",
+	    total, running, ready, sleeping, lingering, other, invalid);
+	screen_newline();
+}
+
+static inline void print_cpu_info(data_t *data)
+{
+	size_t i;
+	for (i = 0; i < data->cpus_count; i++) {
+		if (data->cpus[i].active) {
+			printf("cpu%u (%4" PRIu16 " MHz): busy ticks: "
+			    "%" PRIu64 ", idle ticks: %" PRIu64,
+			    data->cpus[i].id, data->cpus[i].frequency_mhz,
+			    data->cpus[i].busy_ticks, data->cpus[i].idle_ticks);
+			puts(", idle: ");
+			print_float(data->cpus_perc[i].idle, 2);
+			puts("%, busy: ");
+			print_float(data->cpus_perc[i].busy, 2);
+			puts("%");
+		} else
+			printf("cpu%u inactive", data->cpus[i].id);
+		
+		screen_newline();
+	}
+}
+
+static inline void print_physmem_info(data_t *data)
+{
+	uint64_t total;
+	uint64_t unavail;
+	uint64_t used;
+	uint64_t free;
+	char total_suffix;
+	char unavail_suffix;
+	char used_suffix;
+	char free_suffix;
+	
+	order_suffix(data->physmem->total, &total, &total_suffix);
+	order_suffix(data->physmem->unavail, &unavail, &unavail_suffix);
+	order_suffix(data->physmem->used, &used, &used_suffix);
+	order_suffix(data->physmem->free, &free, &free_suffix);
+	
+	printf("memory: %" PRIu64 "%c total, %" PRIu64 "%c unavail, %"
+	    PRIu64 "%c used, %" PRIu64 "%c free", total, total_suffix,
+	    unavail, unavail_suffix, used, used_suffix, free, free_suffix);
+	screen_newline();
+}
+
+static inline void print_task_head(void)
+{
+	screen_style_inverted();
+	printf("      ID  Threads      Mem      %%Mem %%uCycles %%kCycles  Name");
+	screen_newline();
+	screen_style_normal();
+}
+
+static inline void print_tasks(data_t *data)
+{
+	ipcarg_t cols;
+	ipcarg_t rows;
+	screen_get_size(&cols, &rows);
+	
+	ipcarg_t col;
+	ipcarg_t row;
+	screen_get_pos(&col, &row);
+	
+	size_t i;
+	for (i = 0; (i < data->tasks_count) && (row < rows); i++, row++) {
+		uint64_t virtmem;
+		char virtmem_suffix;
+		order_suffix(data->tasks[i].virtmem, &virtmem, &virtmem_suffix);
+		
+		printf("%8" PRIu64 " %8u %8" PRIu64 "%c ", data->tasks[i].task_id,
+		    data->tasks[i].threads, virtmem, virtmem_suffix);
+		puts("   ");
+		print_float(data->tasks_perc[i].virtmem, 2);
+		puts("%   ");
+		print_float(data->tasks_perc[i].ucycles, 2);
+		puts("%   ");
+		print_float(data->tasks_perc[i].kcycles, 2);
+		printf("%% %s", data->tasks[i].name);
+		
+		screen_newline();
+	}
+	
+	while (row < rows) {
+		screen_newline();
+		row++;
+	}
+}
+
+static inline void print_ipc_head(void)
+{
+	screen_style_inverted();
+	printf("      ID Calls sent Calls recv Answs sent Answs recv  IRQn recv       Forw Name");
+	screen_newline();
+	screen_style_normal();
+}
+
+static inline void print_ipc(data_t *data)
+{
+	ipcarg_t cols;
+	ipcarg_t rows;
+	screen_get_size(&cols, &rows);
+	
+	ipcarg_t col;
+	ipcarg_t row;
+	screen_get_pos(&col, &row);
+	
+	size_t i;
+	for (i = 0; (i < data->tasks_count) && (row < rows); i++, row++) {
+		printf("%8" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64
+		     " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %s",
+		     data->tasks[i].task_id, data->tasks[i].ipc_info.call_sent,
+		     data->tasks[i].ipc_info.call_recieved,
+		     data->tasks[i].ipc_info.answer_sent,
+		     data->tasks[i].ipc_info.answer_recieved,
+		     data->tasks[i].ipc_info.irq_notif_recieved,
+		     data->tasks[i].ipc_info.forwarded, data->tasks[i].name);
+		
+		screen_newline();
+	}
+	
+	while (row < rows) {
+		screen_newline();
+		row++;
+	}
+}
+
+void print_data(data_t *data)
+{
+	screen_restart(false);
+	print_global_head(data);
+	print_task_summary(data);
+	print_thread_summary(data);
+	print_cpu_info(data);
+	print_physmem_info(data);
+	
+	/* Empty row for warnings */
+	screen_get_pos(&warn_col, &warn_row);
+	screen_newline();
+	
+	if (operation_type == OP_IPC) {
+		print_ipc_head();
+		print_ipc(data);
+	} else {
+		print_task_head();
+		print_tasks(data);
+	}
+	
+	fflush(stdout);
+}
+
+void print_warning(const char *fmt, ...)
+{
+	screen_moveto(warn_col, warn_row);
+	
+	va_list args;
+	va_start(args, fmt);
+	vprintf(fmt, args);
+	va_end(args);
+	
+	screen_newline();
+	fflush(stdout);
+}
+
+/** @}
+ */
Index: uspace/app/top/screen.h
===================================================================
--- uspace/app/top/screen.h	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
+++ uspace/app/top/screen.h	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * Copyright (c) 2010 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 top
+ * @{
+ */
+
+#ifndef TOP_SCREEN_H_
+#define TOP_SCREEN_H_
+
+#include "top.h"
+
+extern void screen_init(void);
+extern void screen_done(void);
+extern void print_data(data_t *);
+extern void print_warning(const char *, ...);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/app/top/top.c
===================================================================
--- uspace/app/top/top.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
+++ uspace/app/top/top.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * Copyright (c) 2010 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 top
+ * @brief Top utility.
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <task.h>
+#include <thread.h>
+#include <sys/time.h>
+#include <arch/barrier.h>
+#include <errno.h>
+#include "screen.h"
+#include "input.h"
+#include "top.h"
+
+#define NAME  "top"
+
+#define UPDATE_INTERVAL  1
+
+#define DAY     86400
+#define HOUR    3600
+#define MINUTE  60
+
+int operation_type;
+
+static const char *read_data(data_t *target)
+{
+	/* Initialize data */
+	target->load = NULL;
+	target->cpus = NULL;
+	target->cpus_perc = NULL;
+	target->tasks = NULL;
+	target->tasks_perc = NULL;
+	target->threads = NULL;
+	target->physmem = NULL;
+	
+	/* Get current time */
+	struct timeval time;
+	if (gettimeofday(&time, NULL) != EOK)
+		return "Cannot get time of day";
+	
+	target->hours = (time.tv_sec % DAY) / HOUR;
+	target->minutes = (time.tv_sec % HOUR) / MINUTE;
+	target->seconds = time.tv_sec % MINUTE;
+	
+	/* Get uptime */
+	sysarg_t uptime = stats_get_uptime();
+	target->udays = uptime / DAY;
+	target->uhours = (uptime % DAY) / HOUR;
+	target->uminutes = (uptime % HOUR) / MINUTE;
+	target->useconds = uptime % MINUTE;
+	
+	/* Get load */
+	target->load = stats_get_load(&(target->load_count));
+	if (target->load == NULL)
+		return "Cannot get system load";
+	
+	/* Get CPUs */
+	target->cpus = stats_get_cpus(&(target->cpus_count));
+	if (target->cpus == NULL)
+		return "Cannot get CPUs";
+	
+	target->cpus_perc =
+	    (perc_cpu_t *) calloc(target->cpus_count, sizeof(perc_cpu_t));
+	if (target->cpus_perc == NULL)
+		return "Not enough memory for CPU utilization";
+	
+	/* Get tasks */
+	target->tasks = stats_get_tasks(&(target->tasks_count));
+	if (target->tasks == NULL)
+		return "Cannot get tasks";
+	
+	target->tasks_perc =
+	    (perc_task_t *) calloc(target->tasks_count, sizeof(perc_task_t));
+	if (target->tasks_perc == NULL)
+		return "Not enough memory for task utilization";
+	
+	/* Get threads */
+	target->threads = stats_get_threads(&(target->threads_count));
+	if (target->threads == NULL)
+		return "Cannot get threads";
+	
+	/* Get physical memory */
+	target->physmem = stats_get_physmem();
+	if (target->physmem == NULL)
+		return "Cannot get physical memory";
+	
+	return NULL;
+}
+
+/** Computes percentage differencies from old_data to new_data
+ *
+ * @param old_data Pointer to old data strucutre.
+ * @param new_data Pointer to actual data where percetages are stored.
+ *
+ */
+static const char *compute_percentages(data_t *old_data, data_t *new_data)
+{
+	/* Allocate memory */
+	
+	uint64_t *ucycles_diff = calloc(new_data->tasks_count, sizeof(uint64_t));
+	if (ucycles_diff == NULL)
+		return "Not enough memory for user utilization";
+	
+	uint64_t *kcycles_diff = calloc(new_data->tasks_count, sizeof(uint64_t));
+	if (kcycles_diff == NULL) {
+		free(ucycles_diff);
+		return "Not enough memory for kernel utilization";
+	}
+	
+	/* For each CPU: Compute total ticks and divide it between
+	   user and kernel */
+	
+	size_t i;
+	for (i = 0; i < new_data->cpus_count; i++) {
+		uint64_t idle =
+		    new_data->cpus[i].idle_ticks - old_data->cpus[i].idle_ticks;
+		uint64_t busy =
+		    new_data->cpus[i].busy_ticks - old_data->cpus[i].busy_ticks;
+		uint64_t sum = idle + busy;
+		
+		FRACTION_TO_FLOAT(new_data->cpus_perc[i].idle, idle * 100, sum);
+		FRACTION_TO_FLOAT(new_data->cpus_perc[i].busy, busy * 100, sum);
+	}
+	
+	/* For all tasks compute sum and differencies of all cycles */
+	
+	uint64_t virtmem_total = 1;  /* Must NOT be zero */
+	uint64_t ucycles_total = 1;  /* Must NOT be zero */
+	uint64_t kcycles_total = 1;  /* Must NOT be zero */
+	
+	for (i = 0; i < new_data->tasks_count; i++) {
+		/* Match task with the previous instance */
+		
+		bool found = false;
+		size_t j;
+		for (j = 0; j < old_data->tasks_count; j++) {
+			if (new_data->tasks[i].task_id == old_data->tasks[j].task_id) {
+				found = true;
+				break;
+			}
+		}
+		
+		if (!found) {
+			/* This is newly borned task, ignore it */
+			ucycles_diff[i] = 0;
+			kcycles_diff[i] = 0;
+			continue;
+		}
+		
+		ucycles_diff[i] =
+		    new_data->tasks[i].ucycles - old_data->tasks[j].ucycles;
+		kcycles_diff[i] =
+		    new_data->tasks[i].kcycles - old_data->tasks[j].kcycles;
+		
+		virtmem_total += new_data->tasks[i].virtmem;
+		ucycles_total += ucycles_diff[i];
+		kcycles_total += kcycles_diff[i];
+	}
+	
+	/* For each task: Compute percential change */
+	
+	for (i = 0; i < new_data->tasks_count; i++) {
+		FRACTION_TO_FLOAT(new_data->tasks_perc[i].virtmem,
+		    new_data->tasks[i].virtmem * 100, virtmem_total);
+		FRACTION_TO_FLOAT(new_data->tasks_perc[i].ucycles,
+		    ucycles_diff[i] * 100, ucycles_total);
+		FRACTION_TO_FLOAT(new_data->tasks_perc[i].kcycles,
+		    kcycles_diff[i] * 100, kcycles_total);
+	}
+	
+	/* Cleanup */
+	
+	free(ucycles_diff);
+	free(kcycles_diff);
+	
+	return NULL;
+}
+
+static void free_data(data_t *target)
+{
+	if (target->load != NULL)
+		free(target->load);
+	
+	if (target->cpus != NULL)
+		free(target->cpus);
+	
+	if (target->cpus_perc != NULL)
+		free(target->cpus_perc);
+	
+	if (target->tasks != NULL)
+		free(target->tasks);
+	
+	if (target->tasks_perc != NULL)
+		free(target->tasks_perc);
+	
+	if (target->threads != NULL)
+		free(target->threads);
+	
+	if (target->physmem != NULL)
+		free(target->physmem);
+}
+
+int main(int argc, char *argv[])
+{
+	data_t data;
+	data_t data_prev;
+	const char *ret = NULL;
+	
+	screen_init();
+	printf("Reading initial data...\n");
+	
+	if ((ret = read_data(&data_prev)) != NULL)
+		goto out;
+	
+	/* Compute some rubbish to have initialised values */
+	if ((ret = compute_percentages(&data_prev, &data_prev)) != NULL)
+		goto out;
+	
+	/* And paint screen until death */
+	operation_type = OP_TASKS;
+	while (true) {
+		int c = tgetchar(UPDATE_INTERVAL);
+		if (c < 0) {
+			if ((ret = read_data(&data)) != NULL) {
+				free_data(&data);
+				goto out;
+			}
+			
+			if ((ret = compute_percentages(&data_prev, &data)) != NULL) {
+				free_data(&data);
+				goto out;
+			}
+			
+			print_data(&data);
+			free_data(&data_prev);
+			data_prev = data;
+			
+			continue;
+		}
+		
+		switch (c) {
+			case 'q':
+				goto out;
+			case 'i':
+				print_warning("Showing IPC statistics");
+				operation_type = OP_IPC;
+				break;
+			case 't':
+				print_warning("Showing task statistics");
+				operation_type = OP_TASKS;
+				break;
+			default:
+				print_warning("Unknown command: %c", c);
+				break;
+		}
+	}
+	
+out:
+	screen_done();
+	free_data(&data_prev);
+	
+	if (ret != NULL) {
+		fprintf(stderr, "%s: %s\n", NAME, ret);
+		return 1;
+	}
+	
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/top/top.h
===================================================================
--- uspace/app/top/top.h	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
+++ uspace/app/top/top.h	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * Copyright (c) 2010 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 top
+ * @{
+ */
+
+#ifndef TOP_TOP_H_
+#define TOP_TOP_H_
+
+#include <task.h>
+#include <stats.h>
+#include <time.h>
+
+#define FRACTION_TO_FLOAT(float, a, b) { \
+	(float).upper = (a); \
+	(float).lower = (b); \
+}
+
+#define OP_TASKS  1
+#define OP_IPC    2
+
+extern int operation_type;
+
+typedef struct {
+	uint64_t upper;
+	uint64_t lower;
+} fixed_float;
+
+typedef struct {
+	fixed_float idle;
+	fixed_float busy;
+} perc_cpu_t;
+
+typedef struct {
+	fixed_float ucycles;
+	fixed_float kcycles;
+	fixed_float virtmem;
+} perc_task_t;
+
+typedef struct {
+	time_t hours;
+	time_t minutes;
+	time_t seconds;
+	
+	sysarg_t udays;
+	sysarg_t uhours;
+	sysarg_t uminutes;
+	sysarg_t useconds;
+	
+	size_t load_count;
+	load_t *load;
+	
+	size_t cpus_count;
+	stats_cpu_t *cpus;
+	perc_cpu_t *cpus_perc;
+	
+	size_t tasks_count;
+	stats_task_t *tasks;
+	perc_task_t *tasks_perc;
+	
+	size_t threads_count;
+	stats_thread_t *threads;
+	
+	stats_physmem_t *physmem;
+} data_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/app/trace/syscalls.c
===================================================================
--- uspace/app/trace/syscalls.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/trace/syscalls.c	(revision f4f866c362e11c16ac8b6212e491af00b0bed2f2)
@@ -75,6 +75,9 @@
     [SYS_PREEMPT_CONTROL] = { "preempt_control",	1,	V_ERRNO },
 
-    [SYS_SYSINFO_VALID] = { "sysinfo_valid",		2,	V_HASH },
-    [SYS_SYSINFO_VALUE] = { "sysinfo_value",		2,	V_HASH },
+    [SYS_SYSINFO_GET_TAG] = { "sysinfo_get_tag",		2,	V_INTEGER },
+    [SYS_SYSINFO_GET_VALUE] = { "sysinfo_get_value",		3,	V_ERRNO },
+    [SYS_SYSINFO_GET_DATA_SIZE] = { "sysinfo_get_data_size",	3,	V_ERRNO },
+    [SYS_SYSINFO_GET_DATA] = { "sysinfo_get_data",		4,	V_ERRNO },
+
     [SYS_DEBUG_ENABLE_CONSOLE] = { "debug_enable_console", 0,	V_ERRNO },
     [SYS_IPC_CONNECT_KBOX] = { "ipc_connect_kbox",	1,	V_ERRNO }
