Index: tools/checkers/clang.py
===================================================================
--- tools/checkers/clang.py	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ tools/checkers/clang.py	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -114,5 +114,5 @@
 	for job in jobs:
 		if (not clang(rootdir, job)):
-			print
+			print()
 			print("Failed job: %s" % job)
 			return
Index: tools/checkers/stanse.py
===================================================================
--- tools/checkers/stanse.py	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ tools/checkers/stanse.py	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -127,5 +127,5 @@
 	for job in jobs:
 		if (not stanse(rootdir, job)):
-			print
+			print()
 			print("Failed job: %s" % job)
 			return
Index: tools/checkers/vcc.py
===================================================================
--- tools/checkers/vcc.py	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ tools/checkers/vcc.py	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -204,9 +204,9 @@
 	for job in jobs:
 		if (not vcc(vcc_path, rootdir, job)):
-			print
+			print()
 			print("Failed job: %s" % job)
 			return
 	
-	print
+	print()
 	print("All jobs passed")
 
Index: tools/filldir.py
===================================================================
--- tools/filldir.py	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ tools/filldir.py	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -37,5 +37,5 @@
 
 if len(sys.argv) < 3:
-	print 'Usage: filldir <parent-dir> <count>'
+	print('Usage: filldir <parent-dir> <count>')
 	exit(2)
 
Index: tools/gentestfile.py
===================================================================
--- tools/gentestfile.py	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ tools/gentestfile.py	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -36,8 +36,8 @@
 
 if len(sys.argv) < 2:
-	print "Usage: gentestfile.py <count of 64-bit numbers to output>"
+	print("Usage: gentestfile.py <count of 64-bit numbers to output>")
 	exit()
 
-m = long(sys.argv[1])
+m = int(sys.argv[1])
 i = 0
 pow_2_64 = 2 ** 64
Index: tools/mkuimage.py
===================================================================
--- tools/mkuimage.py	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ tools/mkuimage.py	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -124,5 +124,5 @@
 	header.img_type = 2		# Kernel
 	header.compression = 0		# None
-	header.img_name = image_name
+	header.img_name = image_name.encode('ascii')
 
 	header_crc = calc_crc32(header.pack())
@@ -140,5 +140,5 @@
 	signed_crc = zlib.crc32(byteseq, 0)
 	if signed_crc < 0:
-		return (long(signed_crc) + (long(2) ** long(32))) # 2^32L
+		return signed_crc + (1 << 32)
 	else:
 		return signed_crc
@@ -148,8 +148,8 @@
 def print_syntax(cmd):
 	print("syntax: " + cmd + " [<options>] <raw_image> <uImage>")
-	print
+	print()
 	print("\traw_image\tInput image name (raw binary data)")
 	print("\tuImage\t\tOutput uImage name (U-Boot image)")
-	print
+	print()
 	print("options:")
 	print("\t-name <name>\tImage name (default: 'Noname')")
Index: tools/xstruct.py
===================================================================
--- tools/xstruct.py	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ tools/xstruct.py	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -32,15 +32,18 @@
 
 import struct
+import sys
 import types
 
+integer_types = (int, long) if sys.version < '3' else (int,)
+
 ranges = {
-	'B': ((int, long), 0x00, 0xff),
-	'H': ((int, long), 0x0000, 0xffff),
-	'L': ((int, long), 0x00000000, 0xffffffff),
-	'Q': ((int, long), 0x0000000000000000, 0xffffffffffffffff),
-	'b': ((int, long), -0x80, 0x7f),
-	'h': ((int, long), -0x8000, 0x7fff),
-	'l': ((int, long), -0x80000000, 0x7fffffff) ,
-	'q': ((int, long), -0x8000000000000000, 0x7fffffffffffffff),
+	'B': (integer_types, 0x00, 0xff),
+	'H': (integer_types, 0x0000, 0xffff),
+	'L': (integer_types, 0x00000000, 0xffffffff),
+	'Q': (integer_types, 0x0000000000000000, 0xffffffffffffffff),
+	'b': (integer_types, -0x80, 0x7f),
+	'h': (integer_types, -0x8000, 0x7fff),
+	'l': (integer_types, -0x80000000, 0x7fffffff) ,
+	'q': (integer_types, -0x8000000000000000, 0x7fffffffffffffff),
 }
 
Index: uspace/app/bdsh/Makefile
===================================================================
--- uspace/app/bdsh/Makefile	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ uspace/app/bdsh/Makefile	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -48,4 +48,6 @@
 	cmds/modules/cp/cp.c \
 	cmds/modules/mv/mv.c \
+	cmds/modules/printf/printf.c \
+	cmds/modules/echo/echo.c \
 	cmds/modules/mount/mount.c \
 	cmds/modules/unmount/unmount.c \
Index: uspace/app/bdsh/TODO
===================================================================
--- uspace/app/bdsh/TODO	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ uspace/app/bdsh/TODO	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -30,6 +30,4 @@
 * Add wrappers for signal, sigaction to make ports to modules easier
 
-* Add 'echo' and 'printf' modules.
-
 Regarding POSIX:
 ----------------
Index: uspace/app/bdsh/cmds/builtins/cd/cd.c
===================================================================
--- uspace/app/bdsh/cmds/builtins/cd/cd.c	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ uspace/app/bdsh/cmds/builtins/cd/cd.c	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -63,4 +63,13 @@
 	argc = cli_count_args(argv);
 
+	/* Handle cd -- -. Override to switch to a directory named '-' */
+	bool hyphen_override = false;
+	if (argc == 3) {
+		if(!str_cmp(argv[1], "--")) {
+			hyphen_override = true;
+			argc--;
+		}
+	}
+
 	/* We don't yet play nice with whitespace, a getopt implementation should
 	 * protect "quoted\ destination" as a single argument. Its not our job to
@@ -79,8 +88,32 @@
 	}
 
-	/* We have the correct # of arguments
-     * TODO: handle tidle (~) expansion? */
+	/* We have the correct # of arguments */
+	// TODO: handle tidle (~) expansion? */
 
-	rc = chdir(argv[1]);
+	/* Handle 'cd -' first. */
+	if (!str_cmp(argv[1], "-") && !hyphen_override) {
+		char *buffer = (char *) malloc(PATH_MAX);
+		if (!buffer) {
+			cli_error(CL_ENOMEM, "Cannot switch to previous directory");
+			return CMD_FAILURE;
+		}
+		memset(buffer, 0, PATH_MAX);
+		getprevwd(buffer, PATH_MAX);
+		if (*buffer == '\0') {
+			cli_error(CL_EFAIL, "No previous directory to switch to");
+			free(buffer);
+			return CMD_FAILURE;
+		} else {
+			rc = chdir(buffer);
+			free(buffer);
+		}
+	} else if (hyphen_override) {
+		/* Handles 'cd -- <dirname>'.
+		 * Override for directory named '-'.
+		 */
+		rc = chdir(argv[2]);
+	} else {
+		rc = chdir(argv[1]);
+	}
 
 	if (rc == 0) {
Index: uspace/app/bdsh/cmds/modules/cat/cat.h
===================================================================
--- uspace/app/bdsh/cmds/modules/cat/cat.h	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ uspace/app/bdsh/cmds/modules/cat/cat.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -4,6 +4,4 @@
 /* Prototypes for the cat command, excluding entry points */
 
-static unsigned int cat_file(const char *, size_t, bool, off64_t, off64_t, bool);
-
 #endif /* CAT_H */
 
Index: uspace/app/bdsh/cmds/modules/cp/cp.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cp/cp.c	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ uspace/app/bdsh/cmds/modules/cp/cp.c	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -30,4 +30,6 @@
 #include <stdlib.h>
 #include <unistd.h>
+#include <io/console.h>
+#include <io/keycode.h>
 #include <getopt.h>
 #include <str.h>
@@ -46,8 +48,10 @@
 
 static const char *cmdname = "cp";
+static console_ctrl_t *con;
 
 static struct option const long_options[] = {
 	{ "buffer", required_argument, 0, 'b' },
 	{ "force", no_argument, 0, 'f' },
+	{ "interactive", no_argument, 0, 'i'},
 	{ "recursive", no_argument, 0, 'r' },
 	{ "help", no_argument, 0, 'h' },
@@ -139,6 +143,39 @@
 }
 
+static bool get_user_decision(bool bdefault, const char *message, ...)
+{
+	va_list args;
+
+	va_start(args, message);
+	vprintf(message, args);
+	va_end(args);
+
+	while (true) {
+		kbd_event_t ev;
+		console_flush(con);
+		console_get_kbd_event(con, &ev);
+		if ((ev.type != KEY_PRESS)
+		    || (ev.mods & (KM_CTRL | KM_ALT)) != 0) {
+			continue;
+		}
+
+		switch(ev.key) {
+		case KC_Y:
+			printf("y\n");
+			return true;
+		case KC_N:
+			printf("n\n");
+			return false;
+		case KC_ENTER:
+			printf("%c\n", bdefault ? 'Y' : 'N');
+			return bdefault;
+		default:
+			break;
+		}
+	}
+}
+
 static int64_t do_copy(const char *src, const char *dest,
-    size_t blen, int vb, int recursive, int force)
+    size_t blen, int vb, int recursive, int force, int interactive)
 {
 	int r = -1;
@@ -192,8 +229,9 @@
 			/* e.g. cp file_name existing_file */
 
-			/* dest already exists, if force is set we will
-			 * try to remove it.
+			/* dest already exists, 
+			 * if force is set we will try to remove it.
+			 * if interactive is set user input is required.
 			 */
-			if (force) {
+			if (force && !interactive) {
 				if (unlink(dest_path)) {
 					printf("Unable to remove %s\n",
@@ -201,6 +239,21 @@
 					goto exit;
 				}
+			} else if (!force && interactive) {
+				bool overwrite = get_user_decision(false,
+				    "File already exists: %s. Overwrite? [y/N]: ",
+				    dest_path);
+				if (overwrite) {
+					printf("Overwriting file: %s\n", dest_path);
+					if (unlink(dest_path)) {
+						printf("Unable to remove %s\n", dest_path);
+						goto exit;
+					}
+				} else {
+					printf("Not overwriting file: %s\n", dest_path);
+					r = 0;
+					goto exit;
+				}
 			} else {
-				printf("file already exists: %s\n", dest_path);
+				printf("File already exists: %s\n", dest_path);
 				goto exit;
 			}
@@ -302,5 +355,5 @@
 			/* Recursively call do_copy() */
 			r = do_copy(src_dent, dest_dent, blen, vb, recursive,
-			    force);
+			    force, interactive);
 			if (r)
 				goto exit;
@@ -315,5 +368,4 @@
 	return r;
 }
-
 
 static int64_t copy_file(const char *src, const char *dest,
@@ -380,5 +432,6 @@
 	    "  -v, --version    Print version information and exit\n"
 	    "  -V, --verbose    Be annoyingly noisy about what's being done\n"
-	    "  -f, --force      Do not complain when <dest> exists\n"
+	    "  -f, --force      Do not complain when <dest> exists (overrides a previous -i)\n"
+	    "  -i, --interactive Ask what to do when <dest> exists (overrides a previous -f)\n"
 	    "  -r, --recursive  Copy entire directories\n"
 	    "  -b, --buffer ## Set the read buffer size to ##\n";
@@ -397,12 +450,13 @@
 	unsigned int argc, verbose = 0;
 	int buffer = 0, recursive = 0;
-	int force = 0;
+	int force = 0, interactive = 0;
 	int c, opt_ind;
 	int64_t ret;
 
+	con = console_init(stdin, stdout);
 	argc = cli_count_args(argv);
 
 	for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
-		c = getopt_long(argc, argv, "hvVfrb:", long_options, &opt_ind);
+		c = getopt_long(argc, argv, "hvVfirb:", long_options, &opt_ind);
 		switch (c) { 
 		case 'h':
@@ -416,5 +470,10 @@
 			break;
 		case 'f':
+			interactive = 0;
 			force = 1;
+			break;
+		case 'i':
+			force = 0;
+			interactive = 1;
 			break;
 		case 'r':
@@ -426,4 +485,5 @@
 				    "(should be a number greater than zero)\n",
 				    cmdname);
+				console_done(con);
 				return CMD_FAILURE;
 			}
@@ -442,9 +502,12 @@
 		printf("%s: invalid number of arguments. Try %s --help\n",
 		    cmdname, cmdname);
+		console_done(con);
 		return CMD_FAILURE;
 	}
 
 	ret = do_copy(argv[optind], argv[optind + 1], buffer, verbose,
-	    recursive, force);
+	    recursive, force, interactive);
+
+	console_done(con);
 
 	if (ret == 0)
Index: uspace/app/bdsh/cmds/modules/echo/echo.c
===================================================================
--- uspace/app/bdsh/cmds/modules/echo/echo.c	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
+++ uspace/app/bdsh/cmds/modules/echo/echo.c	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012 Alexander Prutkov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "config.h"
+#include "util.h"
+#include "errors.h"
+#include "entry.h"
+#include "echo.h"
+#include "cmds.h"
+#include "errno.h"
+
+static const char *cmdname = "echo";
+
+void help_cmd_echo(unsigned int level)
+{
+	if (level == HELP_SHORT) {
+		printf("`%s' prints arguments as they are, followed by a new line.\n", cmdname);
+	} else {
+		help_cmd_echo(HELP_SHORT);
+		printf("Usage:  %s [arg ...]\n", cmdname);
+	}
+
+	return;
+}
+
+/* Main entry point for echo, accepts an array of arguments */
+int cmd_echo(char **argv)
+{
+	unsigned int argc;
+
+	for (argc = 1; argv[argc] != NULL; argc ++) {
+		printf("%s ", argv[argc]);
+	}
+	printf("\n");
+	return CMD_SUCCESS;
+
+}
+
Index: uspace/app/bdsh/cmds/modules/echo/echo.h
===================================================================
--- uspace/app/bdsh/cmds/modules/echo/echo.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
+++ uspace/app/bdsh/cmds/modules/echo/echo.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -0,0 +1,8 @@
+#ifndef ECHO_H
+#define ECHO_H
+
+/* Prototypes for the echo command, excluding entry points */
+
+
+#endif /* ECHO_H */
+
Index: uspace/app/bdsh/cmds/modules/echo/echo_def.h
===================================================================
--- uspace/app/bdsh/cmds/modules/echo/echo_def.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
+++ uspace/app/bdsh/cmds/modules/echo/echo_def.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -0,0 +1,7 @@
+{
+	"echo",
+	"Prints arguments as they are",
+	&cmd_echo,
+	&help_cmd_echo,
+},
+
Index: uspace/app/bdsh/cmds/modules/echo/entry.h
===================================================================
--- uspace/app/bdsh/cmds/modules/echo/entry.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
+++ uspace/app/bdsh/cmds/modules/echo/entry.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -0,0 +1,9 @@
+#ifndef ECHO_ENTRY_H
+#define ECHO_ENTRY_H
+
+/* Entry points for the echo command */
+extern int cmd_echo(char **);
+extern void help_cmd_echo(unsigned int);
+
+#endif /* ECHO_ENTRY_H */
+
Index: uspace/app/bdsh/cmds/modules/help/help.h
===================================================================
--- uspace/app/bdsh/cmds/modules/help/help.h	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ uspace/app/bdsh/cmds/modules/help/help.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -3,5 +3,4 @@
 
 /* Prototypes for the help command (excluding entry points) */
-static int is_mod_or_builtin(char *);
 
 #endif
Index: uspace/app/bdsh/cmds/modules/mkdir/mkdir.h
===================================================================
--- uspace/app/bdsh/cmds/modules/mkdir/mkdir.h	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ uspace/app/bdsh/cmds/modules/mkdir/mkdir.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -4,5 +4,4 @@
 /* Prototypes for the mkdir command, excluding entry points */
 
-static unsigned int create_directory(const char *, unsigned int);
 #endif /* MKDIR_H */
 
Index: uspace/app/bdsh/cmds/modules/modules.h
===================================================================
--- uspace/app/bdsh/cmds/modules/modules.h	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ uspace/app/bdsh/cmds/modules/modules.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -61,4 +61,6 @@
 #include "unmount/entry.h"
 #include "kcon/entry.h"
+#include "printf/entry.h"
+#include "echo/entry.h"
 
 /* Each .def function fills the module_t struct with the individual name, entry
@@ -82,4 +84,6 @@
 #include "unmount/unmount_def.h"
 #include "kcon/kcon_def.h"
+#include "printf/printf_def.h"
+#include "echo/echo_def.h"
 
 	{NULL, NULL, NULL, NULL}
Index: uspace/app/bdsh/cmds/modules/printf/TODO
===================================================================
--- uspace/app/bdsh/cmds/modules/printf/TODO	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
+++ uspace/app/bdsh/cmds/modules/printf/TODO	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -0,0 +1,13 @@
+At this stage printf is very young and limited, as it hopefully
+will be developed along with BDSH. Functionality is heavily related
+on libc printf already available. BDSH printf implements only 3 format  
+flags, with no options/precision/width modifiers allowed. Also, 
+one output control is available - '\n'. '\' character stands
+as an escape character, i.e. every special character after it 
+will be treated as general char and will be printed out.
+What's missing:
+ * Error checking for format string.
+ * Add more output controls (\t \r ...)
+ * Add width/precision options for number printings
+ * Add more format flags (%f %b ...)
+ 
Index: uspace/app/bdsh/cmds/modules/printf/entry.h
===================================================================
--- uspace/app/bdsh/cmds/modules/printf/entry.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
+++ uspace/app/bdsh/cmds/modules/printf/entry.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -0,0 +1,9 @@
+#ifndef PRINTF_ENTRY_H
+#define PRINTF_ENTRY_H
+
+/* Entry points for the printf command */
+extern int cmd_printf(char **);
+extern void help_cmd_printf(unsigned int);
+
+#endif /* PRINTF_ENTRY_H */
+
Index: uspace/app/bdsh/cmds/modules/printf/printf.c
===================================================================
--- uspace/app/bdsh/cmds/modules/printf/printf.c	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
+++ uspace/app/bdsh/cmds/modules/printf/printf.c	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2012 Alexander Prutkov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "config.h"
+#include "util.h"
+#include "errors.h"
+#include "entry.h"
+#include "printf.h"
+#include "cmds.h"
+#include "str.h"
+
+static const char *cmdname = "printf";
+
+/* Dispays help for printf in various levels */
+void help_cmd_printf(unsigned int level)
+{
+	if (level == HELP_SHORT) {
+		printf("`%s' prints formatted data.\n", cmdname);
+	} else {
+		help_cmd_printf(HELP_SHORT);
+		printf(
+		    "Usage:  %s FORMAT [ARGS ...] \n"
+		    "Prints ARGS according to FORMAT. Number of expected arguments in\n"
+		    "FORMAT must be equals to the number of ARGS. Currently supported\n"
+		    "format flags are:\n",
+		    cmdname);
+	}
+
+	
+	return;
+}
+
+/** Print a formatted data with lib printf.
+ * 
+ * Currently available format flags are:
+ * '%d' - integer.
+ * '%u' - unsigned integer.
+ * '%s' - null-terminated string.
+ ***** 
+ * @param ch  formatted flag.
+ * @param arg string with data to print.
+ */
+static int print_arg(wchar_t ch, const char* arg)
+{
+	switch(ch) {
+	case 'd':
+		printf("%d", (int)(strtol(arg, NULL, 10)));
+		break;
+	case 'u':
+		printf("%u", (unsigned int)(strtoul(arg, NULL, 10)));
+		break;
+	case 's':
+		printf("%s", arg);
+		break;
+	default:
+		return CMD_FAILURE;
+	}
+	return CMD_SUCCESS;
+}
+
+/** Process a control character.
+ * 
+ * Currently available characters are:
+ * '\n' - new line.
+ ***** 
+ * @param ch  Control character.
+ */
+static int process_ctl(wchar_t ch)
+{
+	switch(ch) {
+	case 'n':
+		printf("\n");
+		break;
+	default:
+		return CMD_FAILURE;
+	}
+	return CMD_SUCCESS;
+}
+
+
+/** Prints formatted data. 
+ *
+ * Accepted format flags:
+ * %d - print an integer
+ * %u - print an unsigned integer
+ * %s - print a null terminated string
+ *****
+ * Accepted output controls:
+ * \n - new line
+ */
+int cmd_printf(char **argv)
+{
+	unsigned int argc;
+	char* fmt;
+	size_t pos, fmt_sz;
+	wchar_t ch;
+	bool esc_flag = false;
+	unsigned int carg;     // Current argument
+
+	/* Count the arguments */
+	for (argc = 0; argv[argc] != NULL; argc ++);
+
+	if (argc < 2) {
+		printf("Usage:  %s FORMAT [ARGS ...] \n", cmdname);
+		return CMD_SUCCESS;
+	}
+
+	fmt = argv[1];
+	fmt_sz = str_size(fmt);
+	pos = 0;
+	carg = 2;
+
+	while ((ch = str_decode(fmt, &pos, fmt_sz))) {
+		switch(ch) {
+
+		case '\\':
+			if (esc_flag) 
+				goto emit;
+			esc_flag = true;
+			break;
+
+		case '%':
+			if (esc_flag) 
+				goto emit;
+			ch = str_decode(fmt, &pos, fmt_sz);
+			if (!ch) { 
+				putchar('%');
+				break;
+			}
+			if (carg == argc) {
+				printf("\nBad parameter number. Aborted.\n");
+				return CMD_FAILURE;
+			}
+			print_arg(ch, argv[carg]);
+			++carg;
+			break;
+
+		default:
+			if (esc_flag) {
+				process_ctl(ch);
+				esc_flag = false;
+				break;
+			}
+			putchar(ch);	
+			break;
+
+		emit:
+			putchar(ch);
+			esc_flag = false;
+		}
+	}	
+
+	return CMD_SUCCESS;
+}
Index: uspace/app/bdsh/cmds/modules/printf/printf.h
===================================================================
--- uspace/app/bdsh/cmds/modules/printf/printf.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
+++ uspace/app/bdsh/cmds/modules/printf/printf.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -0,0 +1,8 @@
+#ifndef PRINTF_H
+#define PRINTF_H
+
+/* Prototypes for the printf command, excluding entry points */
+
+
+#endif /* PRINTF_H */
+
Index: uspace/app/bdsh/cmds/modules/printf/printf_def.h
===================================================================
--- uspace/app/bdsh/cmds/modules/printf/printf_def.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
+++ uspace/app/bdsh/cmds/modules/printf/printf_def.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -0,0 +1,7 @@
+{
+	"printf",
+	"Format and print data",
+	&cmd_printf,
+	&help_cmd_printf,
+},
+
Index: uspace/app/bdsh/cmds/modules/rm/rm.c
===================================================================
--- uspace/app/bdsh/cmds/modules/rm/rm.c	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ uspace/app/bdsh/cmds/modules/rm/rm.c	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -46,6 +46,4 @@
 #define RM_VERSION "0.0.1"
 
-static rm_job_t rm;
-
 static struct option const long_options[] = {
 	{ "help", no_argument, 0, 'h' },
@@ -57,4 +55,38 @@
 };
 
+/* Return values for rm_scope() */
+#define RM_BOGUS 0
+#define RM_FILE  1
+#define RM_DIR   2
+
+/* Flags for rm_update() */
+#define _RM_ENTRY   0
+#define _RM_ADVANCE 1
+#define _RM_REWIND  2
+#define _RM_EXIT    3
+
+/* A simple job structure */
+typedef struct {
+	/* Options set at run time */
+	unsigned int force;      /* -f option */
+	unsigned int recursive;  /* -r option */
+	unsigned int safe;       /* -s option */
+
+	/* Keeps track of the job in progress */
+	int advance; /* How far deep we've gone since entering */
+	DIR *entry;  /* Entry point to the tree being removed */
+	char *owd;   /* Where we were when we invoked rm */
+	char *cwd;   /* Current directory being transversed */
+	char *nwd;   /* Next directory to be transversed */
+
+	/* Counters */
+	int f_removed; /* Number of files unlinked */
+	int d_removed; /* Number of directories unlinked */
+} rm_job_t;
+
+static rm_job_t rm;
+
+static unsigned int rm_recursive(const char *);
+
 static unsigned int rm_start(rm_job_t *rm)
 {
@@ -95,4 +127,33 @@
 	if (NULL != rm->cwd)
 		free(rm->cwd);
+}
+
+static unsigned int rm_single(const char *path)
+{
+	if (unlink(path)) {
+		cli_error(CL_EFAIL, "rm: could not remove file %s", path);
+		return 1;
+	}
+	return 0;
+}
+
+static unsigned int rm_scope(const char *path)
+{
+	int fd;
+	DIR *dirp;
+
+	dirp = opendir(path);
+	if (dirp) {
+		closedir(dirp);
+		return RM_DIR;
+	}
+
+	fd = open(path, O_RDONLY);
+	if (fd > 0) {
+		close(fd);
+		return RM_FILE;
+	}
+
+	return RM_BOGUS;
 }
 
@@ -154,33 +215,4 @@
 
 	return ret + 1;
-}
-
-static unsigned int rm_single(const char *path)
-{
-	if (unlink(path)) {
-		cli_error(CL_EFAIL, "rm: could not remove file %s", path);
-		return 1;
-	}
-	return 0;
-}
-
-static unsigned int rm_scope(const char *path)
-{
-	int fd;
-	DIR *dirp;
-
-	dirp = opendir(path);
-	if (dirp) {
-		closedir(dirp);
-		return RM_DIR;
-	}
-
-	fd = open(path, O_RDONLY);
-	if (fd > 0) {
-		close(fd);
-		return RM_FILE;
-	}
-
-	return RM_BOGUS;
 }
 
Index: uspace/app/bdsh/cmds/modules/rm/rm.h
===================================================================
--- uspace/app/bdsh/cmds/modules/rm/rm.h	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ uspace/app/bdsh/cmds/modules/rm/rm.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -2,41 +2,5 @@
 #define RM_H
 
-/* Return values for rm_scope() */
-#define RM_BOGUS 0
-#define RM_FILE  1
-#define RM_DIR   2
-
-/* Flags for rm_update() */
-#define _RM_ENTRY   0
-#define _RM_ADVANCE 1
-#define _RM_REWIND  2
-#define _RM_EXIT    3
-
-/* A simple job structure */
-typedef struct {
-	/* Options set at run time */
-	unsigned int force;      /* -f option */
-	unsigned int recursive;  /* -r option */
-	unsigned int safe;       /* -s option */
-
-	/* Keeps track of the job in progress */
-	int advance; /* How far deep we've gone since entering */
-	DIR *entry;  /* Entry point to the tree being removed */
-	char *owd;   /* Where we were when we invoked rm */
-	char *cwd;   /* Current directory being transversed */
-	char *nwd;   /* Next directory to be transversed */
-
-	/* Counters */
-	int f_removed; /* Number of files unlinked */
-	int d_removed; /* Number of directories unlinked */
-} rm_job_t;
-
-
 /* Prototypes for the rm command, excluding entry points */
-static unsigned int rm_start(rm_job_t *);
-static void rm_end(rm_job_t *rm);
-static unsigned int rm_recursive(const char *);
-static unsigned int rm_single(const char *);
-static unsigned int rm_scope(const char *);
 
 #endif /* RM_H */
Index: uspace/app/bdsh/cmds/modules/sleep/sleep.c
===================================================================
--- uspace/app/bdsh/cmds/modules/sleep/sleep.c	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ uspace/app/bdsh/cmds/modules/sleep/sleep.c	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -27,6 +27,8 @@
  */
 
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include "config.h"
 #include "util.h"
@@ -41,7 +43,68 @@
 void help_cmd_sleep(unsigned int level)
 {
-	printf("This is the %s help for '%s'.\n",
-		level ? EXT_HELP : SHORT_HELP, cmdname);
+	if (level == HELP_SHORT) {
+		printf("`%s' pauses for a given time interval\n", cmdname);
+	} else {
+		help_cmd_sleep(HELP_SHORT);
+		printf(
+		    "Usage:  %s <duration>\n"
+		    "The duration is a decimal number of seconds.\n",
+		    cmdname);
+	}
+
 	return;
+}
+
+/** Convert string containing decimal seconds to useconds_t.
+ *
+ * @param nptr   Pointer to string.
+ * @param result Result of the conversion.
+ * @return EOK if conversion was successful.
+ */
+static int decimal_to_useconds(const char *nptr, useconds_t *result)
+{
+	int ret;
+	uint64_t whole_seconds;
+	uint64_t frac_seconds;
+	char *endptr;
+
+	/* Check for whole seconds */
+	if (*nptr == '.') {
+		whole_seconds = 0;
+		endptr = (char *)nptr;
+	} else {
+		ret = str_uint64_t(nptr, &endptr, 10, false, &whole_seconds);
+		if (ret != EOK)
+			return ret;
+	}
+
+	/* Check for fractional seconds */
+	if (*endptr == '\0') {
+		frac_seconds = 0;
+	} else if (*endptr == '.' && endptr[1] == '\0') {
+		frac_seconds = 0;
+	} else if (*endptr == '.') {
+		nptr = endptr + 1;
+		ret = str_uint64_t(nptr, &endptr, 10, true, &frac_seconds);
+		if (ret != EOK)
+			return ret;
+
+		int ndigits = endptr - nptr;
+		for (; ndigits < 6; ndigits++) 
+			frac_seconds *= 10;
+		for (; ndigits > 6; ndigits--)
+			frac_seconds /= 10;
+	} else {
+		return EINVAL;
+	}
+
+	/* Check for overflow */
+	useconds_t total = whole_seconds * 1000000 + frac_seconds;
+	if (total / 1000000 != whole_seconds)
+		return EOVERFLOW;
+
+	*result = total;
+
+	return EOK;
 }
 
@@ -49,21 +112,24 @@
 int cmd_sleep(char **argv)
 {
+	int ret;
 	unsigned int argc;
-	unsigned int i;
+	useconds_t duration;
 
 	/* Count the arguments */
-	for (argc = 0; argv[argc] != NULL; argc ++);
+	argc = cli_count_args(argv);
 
-	printf("%s %s\n", TEST_ANNOUNCE, cmdname);
-	printf("%d arguments passed to %s", argc - 1, cmdname);
-
-	if (argc < 2) {
-		printf("\n");
-		return CMD_SUCCESS;
+	if (argc != 2) {
+		printf("%s - incorrect number of arguments. Try `help %s'\n",
+		    cmdname, cmdname);
+		return CMD_FAILURE;
 	}
 
-	printf(":\n");
-	for (i = 1; i < argc; i++)
-		printf("[%d] -> %s\n", i, argv[i]);
+	ret = decimal_to_useconds(argv[1], &duration);
+	if (ret != EOK) {
+		printf("%s - invalid duration.\n", cmdname);
+		return CMD_FAILURE;
+	}
+
+	(void) usleep(duration);
 
 	return CMD_SUCCESS;
Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -58,9 +58,16 @@
 static async_sess_t *vfs_sess = NULL;
 
+/* Current (working) directory. */
 static FIBRIL_MUTEX_INITIALIZE(cwd_mutex);
-
 static int cwd_fd = -1;
 static char *cwd_path = NULL;
 static size_t cwd_size = 0;
+
+/* Previous directory. */
+static FIBRIL_MUTEX_INITIALIZE(pwd_mutex);
+static int pwd_fd = -1;
+static char *pwd_path = NULL;
+static size_t pwd_size = 0;
+
 
 /** Start an async exchange on the VFS session.
@@ -751,11 +758,21 @@
 	fibril_mutex_lock(&cwd_mutex);
 	
-	if (cwd_fd >= 0)
-		close(cwd_fd);
-	
-	
-	if (cwd_path)
-		free(cwd_path);
-	
+
+	fibril_mutex_lock(&pwd_mutex);
+
+	if (pwd_fd >= 0)
+		close(pwd_fd);
+
+
+	if (pwd_path)
+		free(pwd_path);
+
+
+	pwd_fd = cwd_fd;
+	pwd_path = cwd_path;
+	pwd_size = cwd_size;
+
+	fibril_mutex_unlock(&pwd_mutex);
+
 	cwd_fd = fd;
 	cwd_path = abs;
@@ -781,4 +798,23 @@
 	fibril_mutex_unlock(&cwd_mutex);
 	
+	return buf;
+}
+
+
+char *getprevwd(char *buf, size_t size)
+{
+	if (size == 0)
+		return NULL;
+
+	fibril_mutex_lock(&pwd_mutex);
+
+	if ((pwd_size == 0) || (size < pwd_size + 1)) {
+		fibril_mutex_unlock(&pwd_mutex);
+		return NULL;
+	}
+
+	str_cpy(buf, size, pwd_path);
+	fibril_mutex_unlock(&pwd_mutex);
+
 	return buf;
 }
Index: uspace/lib/c/include/unistd.h
===================================================================
--- uspace/lib/c/include/unistd.h	(revision d21e935c48590982d3b2557f2fe140922a9a4ba4)
+++ uspace/lib/c/include/unistd.h	(revision f2b3d3ea3dc1fbb7a2312b326613bcc88a3bfaf5)
@@ -58,5 +58,5 @@
 #define getpagesize()  (PAGE_SIZE)
 
-extern int dup2(int oldfd, int newfd);
+extern int dup2(int, int);
 
 extern ssize_t write(int, const void *, size_t);
@@ -73,5 +73,6 @@
 extern int unlink(const char *);
 
-extern char *getcwd(char *buf, size_t);
+extern char *getcwd(char *, size_t);
+extern char *getprevwd(char *, size_t);
 extern int rmdir(const char *);
 extern int chdir(const char *);
