Index: boot/arch/ia32/Makefile.inc
===================================================================
--- boot/arch/ia32/Makefile.inc	(revision fa81b5f14309167116c03cb0dcbb21d3997cfa18)
+++ boot/arch/ia32/Makefile.inc	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -50,5 +50,6 @@
 	$(USPACEDIR)/app/tester/tester \
 	$(USPACEDIR)/app/cli/cli \
-	$(USPACEDIR)/app/klog/klog
+	$(USPACEDIR)/app/klog/klog \
+	$(USPACEDIR)/app/bdsh/bdsh
 
 build: $(BASE)/image.iso
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision fa81b5f14309167116c03cb0dcbb21d3997cfa18)
+++ uspace/Makefile	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -51,5 +51,6 @@
 	app/cli \
 	app/klog \
-	app/init
+	app/init \
+	app/bdsh
 
 ifeq ($(ARCH), amd64)
Index: uspace/app/bdsh/AUTHORS
===================================================================
--- uspace/app/bdsh/AUTHORS	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/AUTHORS	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,17 @@
+
+Written by Tim Post <echo@echoreply.us> to serve as a primitive shell
+for HelenOS, or as a template to make a command line interface that
+offers shell like creature comforts.
+
+This program was mostly written from scratch, some existing code was
+used from other various free software projects:
+
+* Based on the HelenOS testing sub-system written by Martin Decky
+
+* cli_strtok() and cli_strtok_r() (util.c) were adapted from the FreeBSD
+  strtok() and strtok_r() functions written by Wes Peters.
+
+* read_line() (input.c) was written by Jiri Svoboda
+
+Individual author copyrights are listed in the headers of each file.
+
Index: uspace/app/bdsh/LICENSE
===================================================================
--- uspace/app/bdsh/LICENSE	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/LICENSE	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,28 @@
+Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+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.
+
+Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
Index: uspace/app/bdsh/Makefile
===================================================================
--- uspace/app/bdsh/Makefile	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/Makefile	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,137 @@
+# Copyright (c) 2005,  Martin Decky
+# All rights reserved.
+# Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+# 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.
+#
+# Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+
+include ../../../version
+include ../../Makefile.config
+
+LIBC_PREFIX = ../../lib/libc
+SOFTINT_PREFIX = ../../lib/softint
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+CFLAGS += -I../../srv/kbd/include
+
+LIBS = $(LIBC_PREFIX)/libc.a
+DEFS += -DRELEASE=\"$(RELEASE)\"
+
+ifdef REVISION
+	DEFS += "-DREVISION=\"$(TIMESTAMP)\""
+endif
+
+ifdef TIMESTAMP
+	DEFS += "-DTIMESTAMP=\"$(TIMESTAMP)\""
+endif
+
+PROGRAM = bdsh
+
+# Any directory that cleaning targets should know about
+SUBDIRS = \
+	./ \
+	cmds/ \
+	cmds/modules/ \
+	cmds/modules/help/ \
+	cmds/modules/quit/ \
+	cmds/modules/mkdir/ \
+	cmds/modules/rm/ \
+	cmds/modules/cat/ \
+	cmds/modules/touch/ \
+	cmds/modules/ls/ \
+	cmds/modules/mount/ \
+	cmds/builtins/ \
+	cmds/builtins/pwd/ \
+	cmds/builtins/cd/ \
+	lib/
+
+SOURCES = \
+	cmds/modules/help/help.c \
+	cmds/modules/quit/quit.c \
+	cmds/modules/mkdir/mkdir.c \
+	cmds/modules/rm/rm.c \
+	cmds/modules/cat/cat.c \
+	cmds/modules/touch/touch.c \
+	cmds/modules/ls/ls.c \
+	cmds/modules/mount/mount.c \
+	cmds/builtins/pwd/pwd.c \
+	cmds/builtins/cd/cd.c \
+	cmds/mod_cmds.c \
+	cmds/builtin_cmds.c \
+	errors.c \
+	input.c \
+	util.c \
+	exec.c \
+	scli.c
+
+CFLAGS += -I. -Icmds/ -Icmds/builtins -Icmds/modules -Ilib -Ilib/ustr
+
+OBJECTS = $(SOURCES:.c=.o)
+
+# For easy cleaning, *.o is already handled
+CLEANDIRS := $(addsuffix *~,$(SUBDIRS))
+CLEANDIRS += $(addsuffix *.bak,$(SUBDIRS))
+CLEANDIRS += $(addsuffix *.tmp,$(SUBDIRS))
+CLEANDIRS += $(addsuffix *.out,$(SUBDIRS))
+CLEANDIRS += $(addsuffix *.d,$(SUBDIRS))
+CLEANDIRS += $(addsuffix *.gch,$(SUBDIRS) )
+
+%.o: %.S
+	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
+
+%.o: %.s
+	$(AS) $(AFLAGS) $< -o $@
+
+%.o: %.c
+	$(CC) $(CFLAGS) $(INC) -c $< -o $@
+	@$(CC) -M $(CFLAGS) $(INC) $*.c > $*.d
+
+$(PROGRAM): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(ARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(PROGRAM).map
+
+# Everything else is a phony target
+.PHONY: all clean distclean depend disasm
+
+all: $(PROGRAM) disasm
+
+clean:
+	@-rm -f $(OBJECTS)
+	@-rm -f $(PROGRAM)
+	@-rm -f $(PROGRAM).map
+	@-rm -f $(PROGRAM).disasm
+	@-rm -f $(CLEANDIRS)
+
+depend:
+	@echo ''
+
+disasm:
+	$(OBJDUMP) -d $(PROGRAM) >$(PROGRAM).disasm
+
+distclean: clean
+
+# Do not delete - dependencies
+-include $(OBJECTS:.o=.d)
Index: uspace/app/bdsh/TODO
===================================================================
--- uspace/app/bdsh/TODO	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/TODO	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,66 @@
+This is a very brain dead shell. It needs some love, coffee or perhaps beer.
+Currently, you can't even really call it a shell, its more of a CLI that
+offers some shell like creature comforts.
+
+This was written in a hurry to provide some means of testing persistent file
+systems in HelenOS. It does its job, its nowhere near complete but it is
+actively developed. If your reading this, its likely that you're looking for
+some functionality that is not yet present. Prior to filing a bug report,
+please make sure that what you want is not on the list below.
+
+A list of things to do:
+-----------------------
+
+* cmds/modules : ls_scope and rm_scope are basically carbon copies of each
+  other, put this in util.c and make it a shared function.
+
+* rm: add support for recursively removing directories and files therein
+
+* Better sanity checking in modules that take multiple arguments
+
+* Port an editor (vim?)
+
+* Finish cat
+
+* Feed task_spawn absolute paths if path doesn't begin with /
+
+* Some getopt / getopt_long implementation
+
+* Support basic redirection (i.e ls > foo.txt)
+
+* Expand wildcards (i.e. *.txt), don't worry about variables for now
+
+* Basic scripting
+
+* Hash previously found commands
+
+* Improve input, add history / etc (port libedit?)
+
+* Add wrappers for signal, sigaction to make ports to modules easier
+
+* Add 'echo' and 'printf' modules.
+
+Regarding POSIX:
+----------------
+POSIX is a standard for Unix-like operating systems. HelenOS is (mostly) just
+a kernel at this point with a few userspace programs that facilitate testing
+of the kernel and file systems.
+
+HelenOS is not a Unix-like operating system. HelenOS is its own thing, a modern
+microkernel OS and many directions are not yet set.
+
+Please do not e-mail me to point out that modular implementations that resemble
+typical core utilities do not conform to some POSIX standard, these are temporary
+and serve the useful purpose of testing persistent file systems.
+
+Contributing:
+-------------
+If you feel like doing any of the above to-do items, I am echo@echoreply.us. Please
+e-mail me and let me know your working on something so that I do not unwittingly
+duplicate your efforts. You can also e-mail the HelenOS list directly:
+
+HelenOS development mailing list <helenos-devel@lists.modry.cz>
+Subscribe here if you like: http://lists.modry.cz/cgi-bin/listinfo/helenos-devel
+
+Cheers and happy hacking!
+--Tim
Index: uspace/app/bdsh/cmds/builtin_cmds.c
===================================================================
--- uspace/app/bdsh/cmds/builtin_cmds.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/builtin_cmds.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,126 @@
+/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+ * 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.
+ *
+ * Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+/* Almost identical (for now) to mod_cmds.c , however this will not be the case
+ * soon as builtin_t is going to grow way beyond module_t */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "errors.h"
+#include "cmds.h"
+#include "builtin_aliases.h"
+
+extern volatile unsigned int cli_interactive;
+
+int builtin_is_restricted(int pos)
+{
+	builtin_t *cmd = builtins;
+	cmd += pos;
+
+	if (cli_interactive && cmd->restricted <= 0)
+		return 0;
+	if (!cli_interactive && cmd->restricted >= 0)
+		return 0;
+
+	return 1;
+}
+
+int is_builtin(const char *command)
+{
+	builtin_t *cmd;
+	unsigned int i = 0;
+
+	if (NULL == command)
+		return -2;
+
+	for (cmd = builtins; cmd->name != NULL; cmd++, i++) {
+		if (!strcmp(cmd->name, command))
+			return i;
+	}
+
+	return -1;
+}
+
+int is_builtin_alias(const char *command)
+{
+	unsigned int i = 0;
+
+	if (NULL == command)
+		return -1;
+
+	for(i=0; builtin_aliases[i] != NULL; i+=2) {
+		if (!strcmp(builtin_aliases[i], command))
+			return 1;
+	}
+
+	return 0;
+}
+
+char *alias_for_builtin(const char *command)
+{
+	unsigned int i = 0;
+
+	if (NULL == command)
+		return (char *)NULL;
+
+	for(i=0; builtin_aliases[i] != NULL; i++) {
+		if (!strcmp(builtin_aliases[i], command))
+			return (char *)builtin_aliases[++i];
+		i++;
+	}
+
+	return (char *)NULL;
+}
+
+int help_builtin(int builtin, unsigned int extended)
+{
+	builtin_t *cmd = builtins;
+
+	cmd += builtin;
+
+	if (NULL != cmd->help) {
+		cmd->help(extended);
+		return CL_EOK;
+	} else
+		return CL_ENOENT;
+}
+
+int run_builtin(int builtin, char *argv[], cliuser_t *usr)
+{
+	builtin_t *cmd = builtins;
+
+	cmd += builtin;
+
+	if (NULL != cmd->entry)
+		return((int)cmd->entry(argv, usr));
+
+	return CL_ENOENT;
+}
Index: uspace/app/bdsh/cmds/builtins/README
===================================================================
--- uspace/app/bdsh/cmds/builtins/README	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/builtins/README	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,16 @@
+Commands that need to modify the running user structure defined in scli.h 
+should reside here. They (will) have a slightly different prototype that
+allows passing the user structure to them for ease of modifications.
+
+Examples of what should be a built-in and not a module would be:
+
+cd     (the cwd needs to be updated)
+prompt (the prompt needs to be updated)
+enable (the euid needs to be updated)
+
+.... etc.
+
+Anything that does _not_ need to write to this structure should be included
+as a module, not a built in.
+
+For now, a skeleton directory of stuff that will exist lives here.
Index: uspace/app/bdsh/cmds/builtins/builtin_aliases.h
===================================================================
--- uspace/app/bdsh/cmds/builtins/builtin_aliases.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/builtins/builtin_aliases.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,11 @@
+#ifndef BUILTIN_ALIASES_H
+#define BUILTIN_ALIASES_H
+
+/* See modules/module_aliases.h for an explanation of this file */
+
+char *builtin_aliases[] = {
+	"chdir", "cd",
+	NULL, NULL
+};
+
+#endif
Index: uspace/app/bdsh/cmds/builtins/builtins.h
===================================================================
--- uspace/app/bdsh/cmds/builtins/builtins.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/builtins/builtins.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,15 @@
+#ifndef BUILTINS_H
+#define BUILTINS_H
+
+#include "config.h"
+
+#include "pwd/entry.h"
+#include "cd/entry.h"
+
+builtin_t builtins[] = {
+#include "pwd/pwd.def"
+#include "cd/cd.def"
+	{NULL, NULL, NULL, NULL}
+};
+
+#endif
Index: uspace/app/bdsh/cmds/builtins/cd/cd.c
===================================================================
--- uspace/app/bdsh/cmds/builtins/cd/cd.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/builtins/cd/cd.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,105 @@
+/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+ * 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.
+ *
+ * Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "util.h"
+#include "errors.h"
+#include "entry.h"
+#include "cmds.h"
+#include "cd.h"
+
+static char * cmdname = "cd";
+
+void * help_cmd_cd(unsigned int level)
+{
+	if (level == HELP_SHORT) {
+		printf("`%s' changes the current working directory.\n", cmdname);
+	} else {
+		printf(
+		"  %s <directory>\n"
+		"  Change directory to <directory>, e.g `%s /sbin'\n",
+			cmdname, cmdname);
+	}
+
+	return CMD_VOID;
+}
+
+/* This is a very rudamentary 'cd' command. It is not 'link smart' (yet) */
+
+int * cmd_cd(char **argv, cliuser_t *usr)
+{
+	int argc, rc = 0;
+
+	for (argc = 0; argv[argc] != NULL; 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
+	 * look for && || or redirection as the tokenizer should have done that
+	 * (currently, it does not) */
+
+	if (argc > 2) {
+		cli_error(CL_EFAIL, "Too many arguments to `%s'", cmdname);
+		return CMD_FAILURE;
+	}
+
+	if (argc < 2) {
+		printf("%s - no directory specified. Try `help %s extended'\n",
+			cmdname, cmdname);
+		return CMD_FAILURE;
+	}
+
+	/* We have the correct # of arguments
+     * TODO: handle tidle (~) expansion? */
+
+	rc = chdir(argv[1]);
+
+	if (rc == 0) {
+		return CMD_SUCCESS;
+	} else {
+		switch (rc) {
+		case ENOMEM:
+			cli_error(CL_EFAIL, "Destination path too long");
+			break;
+		case ENOENT:
+			cli_error(CL_ENOENT, "Invalid directory `%s'", argv[1]);
+			break;
+		default:
+			cli_error(CL_EFAIL, "Unable to change to `%s'", argv[1]);
+			break;
+		}
+	}
+
+	return CMD_FAILURE;
+}
Index: uspace/app/bdsh/cmds/builtins/cd/cd.def
===================================================================
--- uspace/app/bdsh/cmds/builtins/cd/cd.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/builtins/cd/cd.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,14 @@
+{
+	"cd",
+	"Change the current working directory",
+	&cmd_cd,
+	&help_cmd_cd,
+	-1
+},
+{
+	"chdir",
+	NULL,
+	&cmd_cd,
+	&help_cmd_cd,
+	-1
+},
Index: uspace/app/bdsh/cmds/builtins/cd/cd.h
===================================================================
--- uspace/app/bdsh/cmds/builtins/cd/cd.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/builtins/cd/cd.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,7 @@
+#ifndef CD_H
+#define CD_H
+
+/* Prototypes for the cd command (excluding entry points) */
+
+
+#endif
Index: uspace/app/bdsh/cmds/builtins/cd/entry.h
===================================================================
--- uspace/app/bdsh/cmds/builtins/cd/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/builtins/cd/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,12 @@
+#ifndef CD_ENTRY_H_
+#define CD_ENTRY_H_
+
+#include "scli.h"
+
+/* Entry points for the cd command */
+extern void * help_cmd_cd(unsigned int);
+extern int * cmd_cd(char **, cliuser_t *);
+
+#endif
+
+
Index: uspace/app/bdsh/cmds/builtins/pwd/entry.h
===================================================================
--- uspace/app/bdsh/cmds/builtins/pwd/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/builtins/pwd/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,12 @@
+#ifndef PWD_ENTRY_H
+#define PWD_ENTRY_H
+
+#include "scli.h"
+
+/* Entry points for the pwd command */
+extern void * help_cmd_pwd(unsigned int);
+extern int * cmd_pwd(char *[], cliuser_t *);
+
+#endif
+
+
Index: uspace/app/bdsh/cmds/builtins/pwd/pwd.c
===================================================================
--- uspace/app/bdsh/cmds/builtins/pwd/pwd.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/builtins/pwd/pwd.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,71 @@
+/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+ * 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.
+ *
+ * Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "errors.h"
+#include "entry.h"
+#include "cmds.h"
+#include "pwd.h"
+
+static char * cmdname = "pwd";
+
+void * help_cmd_pwd(unsigned int level)
+{
+	printf("`%s' prints your current working directory.\n", cmdname);
+	return CMD_VOID;
+}
+	
+int * cmd_pwd(char *argv[], cliuser_t *usr)
+{
+	char *buff;
+
+	buff = (char *) malloc(PATH_MAX);
+	if (NULL == buff) {
+		cli_error(CL_ENOMEM, "%s:", cmdname);
+		return CMD_FAILURE;
+	}
+
+	memset(buff, 0, sizeof(buff));
+	getcwd(buff, PATH_MAX);
+
+	if (! buff) {
+		cli_error(CL_EFAIL,
+			"Unable to determine the current working directory");
+		free(buff);
+		return CMD_FAILURE;
+	} else {
+		printf("%s\n", buff);
+		free(buff);
+		return CMD_SUCCESS;
+	}
+}
Index: uspace/app/bdsh/cmds/builtins/pwd/pwd.def
===================================================================
--- uspace/app/bdsh/cmds/builtins/pwd/pwd.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/builtins/pwd/pwd.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,7 @@
+{
+	"pwd",
+	"Prints the current working directory",
+	&cmd_pwd,
+	&help_cmd_pwd,
+	-1
+},
Index: uspace/app/bdsh/cmds/builtins/pwd/pwd.h
===================================================================
--- uspace/app/bdsh/cmds/builtins/pwd/pwd.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/builtins/pwd/pwd.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,6 @@
+#ifndef PWD_H_
+#define PWD_H_
+
+/* Prototypes for the pwd command (excluding entry points) */
+
+#endif
Index: uspace/app/bdsh/cmds/cmds.h
===================================================================
--- uspace/app/bdsh/cmds/cmds.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/cmds.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,73 @@
+#ifndef CMDS_H
+#define CMDS_H
+
+#include "config.h"
+#include "scli.h"
+
+/* Temporary to store strings */
+#define EXT_HELP      "extended"
+#define SHORT_HELP    "short"
+#define TEST_ANNOUNCE "Hello, this is :"
+
+/* Simple levels of help displays */
+#define HELP_SHORT 0
+#define HELP_LONG  1
+
+/* Acceptable buffer sizes (for strn functions) */
+/* TODO: Move me, other files duplicate these needlessly */
+#define BUFF_LARGE  1024
+#define BUFF_SMALL  255
+
+/* Return macros for int type entry points */
+#define CMD_FAILURE (int*)1
+#define CMD_SUCCESS 0
+#define CMD_VOID (void *)NULL
+
+/* Types for module command entry and help */
+typedef int * (* mod_entry_t)(char **);
+typedef void * (* mod_help_t)(unsigned int);
+
+/* Built-in commands need to be able to modify cliuser_t */
+typedef int * (* builtin_entry_t)(char **, cliuser_t *);
+typedef void * (* builtin_help_t)(unsigned int);
+
+/* Module structure */
+typedef struct {
+	char *name;         /* Name of the command */
+	char *desc;         /* Description of the command */
+	mod_entry_t entry;  /* Command (exec) entry function */
+	mod_help_t help;    /* Command (help) entry function */
+	int restricted;     /* Restricts to interactive/non-interactive only */
+} module_t;
+
+/* Builtin structure, same as modules except different types of entry points */
+typedef struct {
+	char *name;
+	char *desc;
+	builtin_entry_t entry;
+	builtin_help_t help;
+	int restricted;
+} builtin_t;
+
+/* Declared in cmds/modules/modules.h and cmds/builtins/builtins.h
+ * respectively */
+extern module_t modules[];
+extern builtin_t builtins[];
+
+/* Prototypes for module launchers */
+extern int module_is_restricted(int);
+extern int is_module(const char *);
+extern int is_module_alias(const char *);
+extern char * alias_for_module(const char *);
+extern int help_module(int, unsigned int);
+extern int run_module(int, char *[]);
+
+/* Prototypes for builtin launchers */
+extern int builtin_is_restricted(int);
+extern int is_builtin(const char *);
+extern int is_builtin_alias(const char *);
+extern char * alias_for_builtin(const char *);
+extern int help_builtin(int, unsigned int);
+extern int run_builtin(int, char *[], cliuser_t *);
+
+#endif
Index: uspace/app/bdsh/cmds/mknewcmd
===================================================================
--- uspace/app/bdsh/cmds/mknewcmd	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/mknewcmd	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,347 @@
+#!/bin/sh
+# Copyright (C) 2008 Tim Post - 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.
+#
+# Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+
+# Script to generate skeletal files for a new command
+# Uses `getopt', not quite a bash-ism but might be
+# lacking on some legacy systems.
+
+# If your shell does not support eval, shift (x) or
+# here-now documents, sorry :) 
+
+usage()
+{
+	def="$DEFAULT_COMMAND"
+	cat << EOF
+\`$PROGNAME' generates skeletal command files to simplify adding commands
+Usage: $PROGNAME [options] <location>
+Options:
+  -n, --name         Name of the command (default: ${def})
+  -d, --desc         Short (20 30 chars) description of the command
+                     (def: "The $def command")
+  -e, --entry        Entry function of the command (def: cmd_${def})
+  -h, --help-entry   Entry function for command help (def: help_cmd_${def})
+  -a, --alias        Alias (nickname) for this command (def: none)
+  -r, --restrict     Restriction level (interactive, non-interactive, both)
+                     (def: module is both, builtin is interactive only)
+  -t, --type         Type of command (module or builtin) (def: module)
+  -H, --help         This help summary
+  -V, --version      Print $PROGNAME version and exit normally
+
+Notes:
+  You must supply at least the name of the command.
+
+  If you do not specify a location (i.e. modules/foo), the command will be
+  created in modules/command_name or builtins/command_name depending on your
+  selection.
+
+  This script will only create skeletal files and inform you what headers
+  need to be modified to incorporate the command. You will also have to
+  manually update the main Makefile.
+
+  This script is intended only to be a convenience for developers. Example use:
+    $PROGNAME -n foo -d "Foo power" -a bar -r both -t module modules/foo
+
+  The example would generate a modular command named 'foo', which is also
+  reached by typing 'bar' and available in either interactive or noninteractive
+  mode.
+
+  Skeletal files do *not* depend on the autoconf generated "config.h" unless you
+  include it. This may or may not be desirable depending on your use.
+
+Report bugs to $PROGMAINT
+
+EOF
+}
+
+# Convert a string to all uppercase
+toupper()
+{
+	local str="$1"
+
+	echo "${str}" | tr 'a-z' 'A-Z'
+}
+
+# Template stored `here-now' style, this generates all files needed
+# for a new command according to arguments passed.
+generate_code()
+{
+	echo "Creating ${OUTDIR}/${CMDNAME}.def ..."
+	cat << EOF > ${OUTDIR}/${CMDNAME}.def
+{
+	"${CMDNAME}",
+	"${CMDDESC}",
+	&${CMDENTRY},
+	&${HELPENTRY},
+	${CMDRESTRICT}
+},
+
+EOF
+	[ -n "${CMDALIAS}" ] && cat << EOF >> ${OUTDIR}/${CMDNAME}.def
+{
+	"${CMDALIAS}",
+	NULL,
+	&${CMDENTRY},
+	&${HELPENTRY},
+	${CMDRESTRICT}
+},
+
+EOF
+	local defname=$(toupper "${CMDNAME}")
+	echo "Creating ${OUTDIR}/entry.h ..."
+	cat << EOF > ${OUTDIR}/entry.h
+#ifndef ${defname}_ENTRY_H
+#define ${defname}_ENTRY_H
+
+EOF
+	[ "${CMDTYPE}" = "module" ] && cat << EOF >> ${OUTDIR}/entry.h
+/* Entry points for the ${CMDNAME} command */
+extern int * ${CMDENTRY}(char **);
+extern void * ${HELPENTRY}(unsigned int);
+
+#endif /* ${defname}_ENTRY_H */
+
+EOF
+	[ "${CMDTYPE}" = "builtin" ] && cat << EOF >> ${OUTDIR}/entry.h
+/* Pick up cliuser_t */
+#include "scli.h"
+
+/* Entry points for the ${CMDNAME} command */
+extern int * ${CMDENTRY}(char **, cliuser_t *);
+extern void * ${HELPENTRY}(unsigned int);
+
+#endif /* ${defname}_ENTRY_H */
+
+EOF
+	echo "Creating ${OUTDIR}/${CMDNAME}.h ..."
+	cat << EOF > ${OUTDIR}/${CMDNAME}.h
+#ifndef ${defname}_H
+#define ${defname}_H
+
+/* Prototypes for the ${CMDNAME} command, excluding entry points */
+
+
+#endif /* ${defname}_H */
+
+EOF
+	echo "Creating ${OUTDIR}/${CMDNAME}.c ..."
+	cat << EOF > ${OUTDIR}/${CMDNAME}.c
+/* Automatically generated by ${PROGNAME} on ${TIMESTAMP}
+ * This is machine generated output. The author of ${PROGNAME} claims no
+ * copyright over the contents of this file. Where legally permitted, the
+ * contents herein are donated to the public domain.
+ *
+ * You should apply any license and copyright that you wish to this file,
+ * replacing this header in its entirety. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "config.h"
+#include "util.h"
+#include "errors.h"
+#include "entry.h"
+#include "${CMDNAME}.h"
+#include "cmds.h"
+
+static char *cmdname = "${CMDNAME}";
+
+/* Dispays help for ${CMDNAME} in various levels */
+void * ${HELPENTRY}(unsigned int level)
+{
+	printf("This is the %s help for '%s'.\n",
+		level ? EXT_HELP : SHORT_HELP, cmdname);
+	return CMD_VOID;
+}
+
+EOF
+	[ "${CMDTYPE}" = "module" ] && cat << EOF >> ${OUTDIR}/${CMDNAME}.c
+/* Main entry point for ${CMDNAME}, accepts an array of arguments */
+int * ${CMDENTRY}(char **argv)
+EOF
+	[ "${CMDTYPE}" = "builtin" ] && cat << EOF >> ${OUTDIR}/${CMDNAME}.c
+/* Main entry point for ${CMDNAME}, accepts an array of arguments and a
+ * pointer to the cliuser_t structure */
+int * ${CMDENTRY}(char **argv, cliuser_t *usr)
+EOF
+	cat << EOF >> ${OUTDIR}/${CMDNAME}.c
+{
+	unsigned int argc;
+	unsigned int i;
+
+	/* Count the arguments */
+	for (argc = 0; argv[argc] != NULL; argc ++);
+
+	printf("%s %s\n", TEST_ANNOUNCE, cmdname);
+	printf("%d arguments passed to %s", argc - 1, cmdname);
+
+	if (argc < 2) {
+		printf("\n");
+		return CMD_SUCCESS;
+	}
+
+	printf(":\n");
+	for (i = 1; i < argc; i++)
+		printf("[%d] -> %s\n", i, argv[i]);
+
+	return CMD_SUCCESS;
+}
+
+EOF
+	printf "Done.\n\nYou should now modify %ss/%ss.h and ../Makefile" \
+		"${CMDTYPE}" "${CMDTYPE}"
+	printf " to include your new command.\n"
+	[ -n "$CMDALIAS" ] &&  {
+		printf "\nYou should also modify %ss/%s_aliases.h and " \
+			"${CMDTYPE}" "${CMDTYPE}"
+		printf "add %s as an alias for %s\n" \
+			"${CMDALIAS}" "${CMDNAME}"
+	}
+	printf "\nOnce completed, re-run make\n\n"
+}
+
+# Main program
+
+TIMESTAMP="$(date)"
+PROGNAME=$(basename $0)
+PROGVER="0.0.1"
+PROGMAINT="Tim Post <echo@echoreply.us>"
+DEFAULT_COMMAND="cmdname"
+
+# We need at least one
+[ $# = 0 ] && usage && exit 1;
+
+TEMP=$(getopt -o n:d:e:h:a:r:t:HV \
+--long name:,desc:,entry:,help-entry:,alias:,restrict:,type:,help,version \
+-- "$@") || {
+	echo "Try $PROGNAME --help for help"
+}
+
+eval set -- "$TEMP"
+
+while true; do
+	case "$1" in
+	-n | --name)
+		CMDNAME="$2"
+		shift 2
+		continue
+	;;
+	-d | --desc)
+		CMDDESC="$2"
+		shift 2
+		continue
+	;;
+	-e | --entry)
+		CMDENTRY="$2"
+		shift 2
+		continue
+	;;
+	-h | --help-entry)
+		HELPENTRY="$2"
+		shift 2
+		continue
+	;;
+	-a | --alias)
+		CMDALIAS="$2"
+		shift 2
+		continue
+	;;
+	-r | --restrict)
+		CMDRESTRICT="$2"
+		shift 2
+		continue
+	;;
+	-t | --type)
+		CMDTYPE="$2"
+		shift 2
+		continue
+	;;
+	-H | --help)
+		usage
+		exit 0
+	;;
+	-V | --version)
+		echo "$PROGVER"
+		exit 0
+	;;
+	--)
+		break
+	;;
+	esac
+done
+
+# Pick up a location if one was specified
+eval set -- "$*"
+[ -n "$2" ] && OUTDIR="$2"
+
+# Fill in defaults for whatever was not specified
+[ -n "$CMDNAME" ] || CMDNAME="$DEFAULT_COMMAND"
+[ -n "$CMDDESC" ] || CMDDESC="The $CMDNAME command"
+[ -n "$CMDENTRY" ] || CMDENTRY="cmd_${CMDNAME}"
+[ -n "$HELPENTRY" ] || HELPENTRY="help_cmd_${CMDNAME}"
+[ -n "$CMDTYPE" ] || CMDTYPE="module"
+[ -n "$OUTDIR" ] || OUTDIR="${CMDTYPE}s/${CMDNAME}"
+
+# Builtins typically only need to be available in interactive mode,
+# set the default accordingly.
+[ -n "$CMDRESTRICT" ] || {
+	[ "$CMDTYPE" = "module" ] && CMDRESTRICT="both"
+	[ "$CMDTYPE" = "builtin" ] && CMDRESTRICT="interactive"
+}
+
+# Set the restriction level as the structure expects to see it
+case "$CMDRESTRICT" in
+	0 | both)
+		CMDRESTRICT="0"
+	;;
+	1 | non-interactive)
+		CMDRESTRICT="1"
+	;;
+	-1 | interactive)
+		CMDRESTRICT="-1"
+	;;
+	*)
+		usage
+		exit 1
+	;;
+esac
+
+# Do a little sanity
+[ -d $OUTDIR ] && {
+	echo "$OUTDIR already exists, remove it to proceed."
+	exit 1
+}
+
+mkdir -p ${OUTDIR} >/dev/null 2>&1 || {
+	echo "Could not create ${OUTDIR}, aborting!"
+	exit 1
+}
+
+# Generate the files and inform on how to include them based on options
+generate_code
+
+exit 0
+
Index: uspace/app/bdsh/cmds/mod_cmds.c
===================================================================
--- uspace/app/bdsh/cmds/mod_cmds.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/mod_cmds.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,156 @@
+/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+ * 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.
+ *
+ * Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+/* NOTES:
+ * module_* functions are pretty much identical to builtin_* functions at this
+ * point. On the surface, it would appear that making each function dual purpose
+ * would be economical.
+ *
+ * These are kept separate because the structures (module_t and builtin_t) may
+ * grow apart and become rather different, even though they're identical at this
+ * point.
+ *
+ * To keep things easy to hack, everything is separated. In reality this only adds
+ * 6 - 8 extra functions, but keeps each function very easy to read and modify. */
+
+/* TODO:
+ * Many of these could be unsigned, provided the modules and builtins themselves
+ * can follow suit. Long term goal. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "errors.h"
+#include "cmds.h"
+#include "module_aliases.h"
+
+extern volatile unsigned int cli_interactive;
+
+int module_is_restricted(int pos)
+{
+	/* Restriction Levels:
+	 * -1 -> Available only in interactive mode
+	 *  0 -> Available in any mode
+	 *  1 -> Available only in non-interactive mode */
+
+	module_t *mod = modules;
+	mod += pos;
+	/* We're interactive, and the module is OK to run */
+	if (cli_interactive && mod->restricted <= 0)
+		return 0;
+	/* We're not interactive, and the module is OK to run */
+	if (!cli_interactive && mod->restricted >= 0)
+		return 0;
+
+	/* Anything else is just a big fat no :) */
+	return 1;
+}
+
+/* Checks if an entry function matching command exists in modules[], if so
+ * its position in the array is returned */
+int is_module(const char *command)
+{
+	module_t *mod;
+	unsigned int i = 0;
+
+	if (NULL == command)
+		return -2;
+
+	for (mod = modules; mod->name != NULL; mod++, i++) {
+		if (!strcmp(mod->name, command))
+			return i;
+	}
+
+	return -1;
+}
+
+/* Checks if a module is an alias (sharing an entry point with another
+ * module). Returns 1 if so */
+int is_module_alias(const char *command)
+{
+	unsigned int i = 0;
+
+	if (NULL == command)
+		return -1;
+
+	for(i=0; mod_aliases[i] != NULL; i+=2) {
+		if (!strcmp(mod_aliases[i], command))
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Returns the name of the module that an alias points to */
+char *alias_for_module(const char *command)
+{
+	unsigned int i = 0;
+
+	if (NULL == command)
+		return (char *)NULL;
+
+	for(i=0; mod_aliases[i] != NULL; i++) {
+		if (!strcmp(mod_aliases[i], command))
+			return (char *)mod_aliases[++i];
+		i++;
+	}
+
+	return (char *)NULL;
+}
+
+
+/* Invokes the 'help' entry function for the module at position (int) module,
+ * which wants an unsigned int to determine brief or extended display. */
+int help_module(int module, unsigned int extended)
+{
+	module_t *mod = modules;
+
+	mod += module;
+
+	if (NULL != mod->help) {
+		mod->help(extended);
+		return CL_EOK;
+	} else
+		return CL_ENOENT;
+}
+
+/* Invokes the module entry point modules[module], passing argv[] as an argument
+ * stack. */
+int run_module(int module, char *argv[])
+{
+	module_t *mod = modules;
+
+	mod += module;
+
+	if (NULL != mod->entry)
+		return ((int)mod->entry(argv));
+
+	return CL_ENOENT;
+}
Index: uspace/app/bdsh/cmds/modules/README
===================================================================
--- uspace/app/bdsh/cmds/modules/README	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/README	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,8 @@
+Modules are commands or full programs (anything can be made into a module that can return
+int type) should go here. Note, modules do not update the structures containing user info
+such as the working directory, euid, etc.
+
+Stuff that needs to write to the user structures contained in scli.h should be made as
+built-in commands, not modules.
+
+
Index: uspace/app/bdsh/cmds/modules/cat/cat.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cat/cat.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/cat/cat.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,72 @@
+/* Automatically generated by mknewcmd on Wed Aug 13 15:41:09 PHT 2008
+ * This is machine generated output. The author of mknewcmd claims no
+ * copyright over the contents of this file. Where legally permitted, the
+ * contents herein are donated to the public domain.
+ *
+ * You should apply any license and copyright that you wish to this file,
+ * replacing this header in its entirety. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include "config.h"
+#include "util.h"
+#include "errors.h"
+#include "entry.h"
+#include "cat.h"
+#include "cmds.h"
+
+static char *cmdname = "cat";
+
+static struct option long_options[] = {
+	{ "help",		no_argument,		0,	'h' },
+	{ "version",	no_argument,		0,	'v' },
+	{ "file",		required_argument,	0,	'f' },
+	{ 0, 0, 0, 0 }
+};
+
+/* Dispays help for cat in various levels */
+void * help_cmd_cat(unsigned int level)
+{
+	printf("This is the %s help for '%s'.\n",
+		level ? EXT_HELP : SHORT_HELP, cmdname);
+	return CMD_VOID;
+}
+
+/* Main entry point for cat, accepts an array of arguments */
+int * cmd_cat(char **argv)
+{
+	unsigned int argc;
+	unsigned int i;
+	int c, opt_ind;
+
+	/* Count the arguments */
+	for (argc = 0; argv[argc] != NULL; argc ++);
+
+	printf("%s %s\n", TEST_ANNOUNCE, cmdname);
+	printf("%d arguments passed to %s\n", argc - 1, cmdname);
+
+	for (i = 1; i < argc; i++)
+		printf("[%d] -> %s\n", i, argv[i]);
+
+	for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
+		c = getopt_long(argc, argv, "f:hv", long_options, &opt_ind);
+		switch (c) {
+		case 'h':
+			help_cmd_cat(HELP_SHORT);
+			break;
+		case 'v':
+			printf("I have no version, sorry.\n");
+			break;
+		case 'f':
+			printf("File : %s\n", optarg);
+			break;
+		}
+	}
+
+	printf("argc = %d, optind = %d\n", argc, optind);
+
+	return CMD_SUCCESS;
+}
+
Index: uspace/app/bdsh/cmds/modules/cat/cat.def
===================================================================
--- uspace/app/bdsh/cmds/modules/cat/cat.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/cat/cat.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,8 @@
+{
+	"cat",
+	"The cat command",
+	&cmd_cat,
+	&help_cmd_cat,
+	0
+},
+
Index: uspace/app/bdsh/cmds/modules/cat/cat.h
===================================================================
--- uspace/app/bdsh/cmds/modules/cat/cat.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/cat/cat.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,8 @@
+#ifndef CAT_H
+#define CAT_H
+
+/* Prototypes for the cat command, excluding entry points */
+
+
+#endif /* CAT_H */
+
Index: uspace/app/bdsh/cmds/modules/cat/entry.h
===================================================================
--- uspace/app/bdsh/cmds/modules/cat/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/cat/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,9 @@
+#ifndef CAT_ENTRY_H
+#define CAT_ENTRY_H
+
+/* Entry points for the cat command */
+extern int * cmd_cat(char **);
+extern void * help_cmd_cat(unsigned int);
+
+#endif /* CAT_ENTRY_H */
+
Index: uspace/app/bdsh/cmds/modules/help/entry.h
===================================================================
--- uspace/app/bdsh/cmds/modules/help/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/help/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,8 @@
+#ifndef HELP_ENTRY_H_
+#define HELP_ENTRY_H_
+
+/* Entry points for the help command */
+extern void * help_cmd_help(unsigned int);
+extern int * cmd_help(char *[]);
+
+#endif
Index: uspace/app/bdsh/cmds/modules/help/help.c
===================================================================
--- uspace/app/bdsh/cmds/modules/help/help.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/help/help.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,165 @@
+/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+ * 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.
+ *
+ * Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "entry.h"
+#include "help.h"
+#include "cmds.h"
+#include "modules.h"
+#include "builtins.h"
+#include "errors.h"
+
+static char *cmdname = "help";
+extern const char *progname;
+extern unsigned int cli_interactive;
+
+#define HELP_IS_MODULE   1
+#define HELP_IS_BUILTIN  0
+#define HELP_IS_RUBBISH  -1
+
+volatile int mod_switch = -1;
+
+/* Just use a pointer here, no need for mod_switch */
+int is_mod_or_builtin(char *cmd)
+{
+	int rc = HELP_IS_RUBBISH;
+
+	rc = is_builtin(cmd);
+	if (rc > -1) {
+		mod_switch = rc;
+		return HELP_IS_BUILTIN;
+	}
+	rc = is_module(cmd);
+	if (rc > -1) {
+		mod_switch = rc;
+		return HELP_IS_MODULE;
+	}
+
+	return HELP_IS_RUBBISH;
+}
+
+void *help_cmd_help(unsigned int level)
+{
+	if (level == HELP_SHORT) {
+		printf(
+		"\n  %s [command] <extended>\n"
+		"  Use help [command] extended for detailed help on [command] "
+		", even `help'\n\n", cmdname);
+	} else {
+		printf(
+		"\n  `%s' - shows help for commands\n"
+		"  Examples:\n"
+		"   %s [command]           Show help for [command]\n"
+		"   %s [command] extended  Show extended help for [command]\n"
+		"\n  If no argument is given to %s, a list of commands are shown\n\n",
+		cmdname, cmdname, cmdname, cmdname);
+	}
+
+	return CMD_VOID;
+}
+
+int *cmd_help(char *argv[])
+{
+	module_t *mod;
+	builtin_t *cmd;
+	unsigned int i = 0;
+	int rc = 0;
+	int argc;
+	int level = HELP_SHORT;
+
+	for (argc = 0; argv[argc] != NULL; argc ++);
+
+	if (argc > 3) {
+		printf("\nToo many arguments to `%s', try:\n", cmdname);
+		help_cmd_help(HELP_SHORT);
+		return CMD_FAILURE;
+	}
+
+	if (argc == 3) {
+		if (!strcmp("extended", argv[2]))
+			level = HELP_LONG;
+		else
+			level = HELP_SHORT;
+	}
+
+	if (argc > 1) {
+		rc = is_mod_or_builtin(argv[1]);
+		switch (rc) {
+		case HELP_IS_RUBBISH:
+			printf("Invalid command %s\n", argv[1]);
+			return CMD_FAILURE;
+		case HELP_IS_MODULE:
+			help_module(mod_switch, level);
+			return CMD_SUCCESS;
+		case HELP_IS_BUILTIN:
+			help_builtin(mod_switch, level);
+			return CMD_SUCCESS;
+		}
+	}
+
+	printf("%sAvailable commands are:\n", cli_interactive ? "\n  " : "");
+	if (cli_interactive)
+		printf(
+			"  ------------------------------------------------------------\n");
+
+	/* First, show a list of built in commands that are available in this mode */
+	for (cmd = builtins; cmd->name != NULL; cmd++, i++) {
+		if (!builtin_is_restricted(i)) {
+			if (is_builtin_alias(cmd->name))
+				printf("   %-16s\tAlias for `%s'\n", cmd->name,
+					alias_for_builtin(cmd->name));
+			else
+				printf("   %-16s\t%s\n", cmd->name, cmd->desc);
+		}
+	}
+
+	i = 0;
+
+	/* Now, show a list of module commands that are available in this mode */
+	for (mod = modules; mod->name != NULL; mod++, i++) {
+		if (!module_is_restricted(i)) {
+			if (is_module_alias(mod->name))
+				printf("   %-16s\tAlias for `%s'\n", mod->name,
+					alias_for_module(mod->name));
+			else
+				printf("   %-16s\t%s\n", mod->name, mod->desc);
+		}
+	}
+
+	/* Provide  a little more information and inform them of history / line
+	 * editing features if they are present */
+	if (cli_interactive)
+		printf("\n  Try %s %s for more information on how `%s' works.\n\n",
+			cmdname, cmdname, cmdname);
+
+	return CMD_SUCCESS;
+}
Index: uspace/app/bdsh/cmds/modules/help/help.def
===================================================================
--- uspace/app/bdsh/cmds/modules/help/help.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/help/help.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,7 @@
+{
+	"help",
+	"Show help for commands",
+	&cmd_help,
+	&help_cmd_help,
+	0
+},
Index: uspace/app/bdsh/cmds/modules/help/help.h
===================================================================
--- uspace/app/bdsh/cmds/modules/help/help.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/help/help.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,7 @@
+#ifndef HELP_H
+#define HELP_H
+
+/* Prototypes for the help command (excluding entry points) */
+extern int is_mod_or_builtin(char *);
+
+#endif
Index: uspace/app/bdsh/cmds/modules/ls/entry.h
===================================================================
--- uspace/app/bdsh/cmds/modules/ls/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/ls/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,9 @@
+#ifndef LS_ENTRY_H
+#define LS_ENTRY_H
+
+/* Entry points for the ls command */
+extern int * cmd_ls(char **);
+extern void * help_cmd_ls(unsigned int);
+
+#endif /* LS_ENTRY_H */
+
Index: uspace/app/bdsh/cmds/modules/ls/ls.c
===================================================================
--- uspace/app/bdsh/cmds/modules/ls/ls.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/ls/ls.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,197 @@
+/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+ * 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.
+ *
+ * Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+/* NOTE:
+ * This is a bit of an ugly hack, working around the absence of fstat / etc.
+ * As more stuff is completed and exposed in libc, this will improve */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include "errors.h"
+#include "config.h"
+#include "util.h"
+#include "entry.h"
+#include "ls.h"
+#include "cmds.h"
+
+static char *cmdname = "ls";
+
+unsigned int ls_scope(const char *path)
+{
+	int fd;
+	DIR *dirp;
+
+	dirp = opendir(path);
+	if (dirp) {
+		closedir(dirp);
+		return LS_DIR;
+	}
+
+	fd = open(path, O_RDONLY);
+	if (fd > 0) {
+		close(fd);
+		return LS_FILE;
+	}
+
+	return LS_BOGUS;
+}
+
+void ls_scan_dir(const char *d, DIR *dirp)
+{
+	struct dirent *dp;
+	unsigned int scope;
+	char *buff;
+
+	if (! dirp)
+		return;
+
+	buff = (char *)malloc(PATH_MAX);
+	if (NULL == buff) {
+		cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
+		return;
+	}
+
+	while ((dp = readdir(dirp))) {
+		memset(buff, 0, sizeof(buff));
+		/* Don't worry if inserting a double slash, this will be fixed by
+		 * absolutize() later with subsequent calls to open() or readdir() */
+		snprintf(buff, PATH_MAX - 1, "%s/%s", d, dp->d_name);
+		scope = ls_scope(buff);
+		switch (scope) {
+		case LS_DIR:
+			ls_print_dir(dp->d_name);
+			break;
+		case LS_FILE:
+			ls_print_file(dp->d_name);
+			break;
+		case LS_BOGUS:
+			/* Odd chance it was deleted from the time readdir() found
+			 * it and the time that it was scoped */
+			printf("ls: skipping bogus node %s\n", dp->d_name);
+			break;
+		}
+	}
+
+	free(buff);
+
+	return;
+}
+
+/* ls_print_* currently does nothing more than print the entry.
+ * in the future, we will likely pass the absolute path, and
+ * some sort of ls_options structure that controls how each
+ * entry is printed and what is printed about it.
+ *
+ * Now we just print basic DOS style lists */
+
+void ls_print_dir(const char *d)
+{
+	printf("%-40s\t<DIR>\n", d);
+
+	return;
+}
+
+void ls_print_file(const char *f)
+{
+	printf("%-40s\n", f);
+
+	return;
+}
+
+void * help_cmd_ls(unsigned int level)
+{
+	if (level == HELP_SHORT) {
+		printf("`%s' lists files and directories.\n", cmdname);
+	} else {
+		help_cmd_ls(HELP_SHORT);
+		printf("  `%s' [path], if no path is given the current "
+				"working directory is used.\n", cmdname);
+	}
+
+	return CMD_VOID;
+}
+
+int * cmd_ls(char **argv)
+{
+	unsigned int argc;
+	unsigned int scope;
+	char *buff;
+	DIR *dirp;
+
+	/* Count the arguments */
+	for (argc = 0; argv[argc] != NULL; argc ++);
+
+	buff = (char *) malloc(PATH_MAX);
+	if (NULL == buff) {
+		cli_error(CL_ENOMEM, "%s: ", cmdname);
+		return CMD_FAILURE;
+	}
+	memset(buff, 0, sizeof(buff));
+
+	if (argc == 1)
+		getcwd(buff, PATH_MAX);
+	else
+		strncpy(buff, argv[1], PATH_MAX);
+
+	scope = ls_scope(buff);
+
+	switch (scope) {
+	case LS_BOGUS:
+		cli_error(CL_ENOENT, buff);
+		free(buff);
+		return CMD_FAILURE;
+	case LS_FILE:
+		ls_print_file(buff);
+		break;
+	case LS_DIR:
+		dirp = opendir(buff);
+		if (! dirp) {
+			/* May have been deleted between scoping it and opening it */
+			cli_error(CL_EFAIL, "Could not stat %s", buff);
+			free(buff);
+			return CMD_FAILURE;
+		}
+		ls_scan_dir(buff, dirp);
+		closedir(dirp);
+		break;
+	}
+
+	free(buff);
+
+	return CMD_SUCCESS;
+}
+
Index: uspace/app/bdsh/cmds/modules/ls/ls.def
===================================================================
--- uspace/app/bdsh/cmds/modules/ls/ls.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/ls/ls.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,16 @@
+{
+	"ls",
+	"The ls command",
+	&cmd_ls,
+	&help_cmd_ls,
+	0
+},
+
+{
+	"dir",
+	NULL,
+	&cmd_ls,
+	&help_cmd_ls,
+	0
+},
+
Index: uspace/app/bdsh/cmds/modules/ls/ls.h
===================================================================
--- uspace/app/bdsh/cmds/modules/ls/ls.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/ls/ls.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,18 @@
+#ifndef LS_H
+#define LS_H
+
+/* Various values that can be returned by ls_scope() */
+#define LS_BOGUS 0
+#define LS_FILE  1
+#define LS_DIR   2
+
+/* Protoypes for non entry points, intrinsic to ls. Stuff like ls_scope()
+ * is also duplicated in rm, while rm sort of duplicates ls_scan_dir().
+ * TODO make some more shared functions and don't expose the stuff below */
+extern unsigned int ls_scope(const char *);
+extern void ls_scan_dir(const char *, DIR *);
+extern void ls_print_dir(const char *);
+extern void ls_print_file(const char *);
+
+#endif /* LS_H */
+
Index: uspace/app/bdsh/cmds/modules/mkdir/entry.h
===================================================================
--- uspace/app/bdsh/cmds/modules/mkdir/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/mkdir/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,9 @@
+#ifndef MKDIR_ENTRY_H
+#define MKDIR_ENTRY_H
+
+/* Entry points for the mkdir command */
+extern int * cmd_mkdir(char **);
+extern void * help_cmd_mkdir(unsigned int);
+
+#endif /* MKDIR_ENTRY_H */
+
Index: uspace/app/bdsh/cmds/modules/mkdir/mkdir.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mkdir/mkdir.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/mkdir/mkdir.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,91 @@
+/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+ * 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.
+ *
+ * Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+/* TODO:
+ * Implement -p option when some type of getopt is ported */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "config.h"
+#include "errors.h"
+#include "entry.h"
+#include "mkdir.h"
+#include "cmds.h"
+
+static char *cmdname = "mkdir";
+
+/* Dispays help for mkdir in various levels */
+void * help_cmd_mkdir(unsigned int level)
+{
+	if (level == HELP_SHORT) {
+		printf("`%s' creates a new directory\n", cmdname);
+	} else {
+		help_cmd_mkdir(HELP_SHORT);
+		printf("  `%s' <directory>\n", cmdname);
+	}
+
+	return CMD_VOID;
+}
+
+/* Main entry point for mkdir, accepts an array of arguments */
+int * cmd_mkdir(char **argv)
+{
+	unsigned int argc;
+	DIR *dirp;
+
+	/* Count the arguments */
+	for (argc = 0; argv[argc] != NULL; argc ++);
+
+	if (argc != 2) {
+		printf("%s - incorrect number of arguments. Try `help %s extended'\n",
+			cmdname, cmdname);
+		return CMD_FAILURE;
+	}
+
+	dirp = opendir(argv[1]);
+	if (dirp) {
+		closedir(dirp);
+		cli_error(CL_EEXISTS, "Can not create directory %s", argv[1]);
+		return CMD_FAILURE;
+	}
+
+	if (mkdir(argv[1], 0) != 0) {
+		cli_error(CL_EFAIL, "Could not create %s", argv[1]);
+		return CMD_FAILURE;
+	}
+
+	return CMD_SUCCESS;
+}
+
Index: uspace/app/bdsh/cmds/modules/mkdir/mkdir.def
===================================================================
--- uspace/app/bdsh/cmds/modules/mkdir/mkdir.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/mkdir/mkdir.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,16 @@
+{
+	"mkdir",
+	"The mkdir command",
+	&cmd_mkdir,
+	&help_cmd_mkdir,
+	0
+},
+
+{
+	"md",
+	NULL,
+	&cmd_mkdir,
+	&help_cmd_mkdir,
+	0
+},
+
Index: uspace/app/bdsh/cmds/modules/mkdir/mkdir.h
===================================================================
--- uspace/app/bdsh/cmds/modules/mkdir/mkdir.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/mkdir/mkdir.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,8 @@
+#ifndef MKDIR_H
+#define MKDIR_H
+
+/* Prototypes for the mkdir command, excluding entry points */
+
+
+#endif /* MKDIR_H */
+
Index: uspace/app/bdsh/cmds/modules/module_aliases.h
===================================================================
--- uspace/app/bdsh/cmds/modules/module_aliases.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/module_aliases.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,22 @@
+#ifndef MODULE_ALIASES_H
+#define MODULE_ALIASES_H
+
+/* Modules that declare multiple names for themselves but use the
+ * same entry functions are aliases. This array helps to determine if
+ * a module is an alias, as such it can be invoked differently.
+ * format is alias , real_name */
+
+/* So far, this is only used in the help display but could be used to
+ * handle a module differently even prior to reaching its entry code.
+ * For instance, 'exit' could behave differently than 'quit', prior to
+ * the entry point being reached. */
+
+char *mod_aliases[] = {
+	"exit", "quit",
+	"md", "mkdir",
+	"del", "rm",
+	"dir", "ls",
+	NULL, NULL
+};
+
+#endif
Index: uspace/app/bdsh/cmds/modules/modules.h
===================================================================
--- uspace/app/bdsh/cmds/modules/modules.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/modules.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,45 @@
+#ifndef MODULES_H
+#define MODULES_H
+
+/* Each built in function has two files, one being an entry.h file which
+ * prototypes the run/help entry functions, the other being a .def file
+ * which fills the modules[] array according to the cmd_t structure
+ * defined in cmds.h.
+ *
+ * To add or remove a module, just make a new directory in cmds/modules
+ * for it and copy the 'show' example for basics, then include it here.
+ * (or reverse the process to remove one)
+ *
+ * NOTE: See module_ aliases.h as well, this is where aliases (commands that
+ * share an entry point with others) are indexed */
+
+#include "config.h"
+
+/* Prototypes for each module's entry (help/exec) points */
+
+#include "help/entry.h"
+#include "quit/entry.h"
+#include "mkdir/entry.h"
+#include "rm/entry.h"
+#include "cat/entry.h"
+#include "touch/entry.h"
+#include "ls/entry.h"
+#include "mount/entry.h"
+
+/* Each .def function fills the module_t struct with the individual name, entry
+ * point, help entry point, etc. You can use config.h to control what modules
+ * are loaded based on what libraries exist on the system. */
+
+module_t modules[] = {
+#include "help/help.def"
+#include "quit/quit.def"
+#include "mkdir/mkdir.def"
+#include "rm/rm.def"
+#include "cat/cat.def"
+#include "touch/touch.def"
+#include "ls/ls.def"
+#include "mount/mount.def"
+	{NULL, NULL, NULL, NULL}
+};
+
+#endif
Index: uspace/app/bdsh/cmds/modules/mount/entry.h
===================================================================
--- uspace/app/bdsh/cmds/modules/mount/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/mount/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,9 @@
+#ifndef MOUNT_ENTRY_H
+#define MOUNT_ENTRY_H
+
+/* Entry points for the mount command */
+extern int * cmd_mount(char **);
+extern void * help_cmd_mount(unsigned int);
+
+#endif /* MOUNT_ENTRY_H */
+
Index: uspace/app/bdsh/cmds/modules/mount/mount.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,51 @@
+/* Automatically generated by mknewcmd on Wed Aug 13 16:08:34 PHT 2008
+ * This is machine generated output. The author of mknewcmd claims no
+ * copyright over the contents of this file. Where legally permitted, the
+ * contents herein are donated to the public domain.
+ *
+ * You should apply any license and copyright that you wish to this file,
+ * replacing this header in its entirety. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "config.h"
+#include "util.h"
+#include "errors.h"
+#include "entry.h"
+#include "mount.h"
+#include "cmds.h"
+
+static char *cmdname = "mount";
+
+/* Dispays help for mount in various levels */
+void * help_cmd_mount(unsigned int level)
+{
+	printf("This is the %s help for '%s'.\n",
+		level ? EXT_HELP : SHORT_HELP, cmdname);
+	return CMD_VOID;
+}
+
+/* Main entry point for mount, accepts an array of arguments */
+int * cmd_mount(char **argv)
+{
+	unsigned int argc;
+	unsigned int i;
+
+	/* Count the arguments */
+	for (argc = 0; argv[argc] != NULL; argc ++);
+
+	printf("%s %s\n", TEST_ANNOUNCE, cmdname);
+	printf("%d arguments passed to %s", argc - 1, cmdname);
+
+	if (argc < 2) {
+		printf("\n");
+		return CMD_SUCCESS;
+	}
+
+	printf(":\n");
+	for (i = 1; i < argc; i++)
+		printf("[%d] -> %s\n", i, argv[i]);
+
+	return CMD_SUCCESS;
+}
+
Index: uspace/app/bdsh/cmds/modules/mount/mount.def
===================================================================
--- uspace/app/bdsh/cmds/modules/mount/mount.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/mount/mount.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,8 @@
+{
+	"mount",
+	"The mount command",
+	&cmd_mount,
+	&help_cmd_mount,
+	0
+},
+
Index: uspace/app/bdsh/cmds/modules/mount/mount.h
===================================================================
--- uspace/app/bdsh/cmds/modules/mount/mount.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/mount/mount.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,8 @@
+#ifndef MOUNT_H
+#define MOUNT_H
+
+/* Prototypes for the mount command, excluding entry points */
+
+
+#endif /* MOUNT_H */
+
Index: uspace/app/bdsh/cmds/modules/quit/entry.h
===================================================================
--- uspace/app/bdsh/cmds/modules/quit/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/quit/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,10 @@
+#ifndef QUIT_ENTRY_H_
+#define QUIT_ENTRY_H_
+
+/* Entry points for the quit command */
+extern void * help_cmd_quit(unsigned int);
+extern int * cmd_quit(char *[]);
+
+#endif
+
+
Index: uspace/app/bdsh/cmds/modules/quit/quit.c
===================================================================
--- uspace/app/bdsh/cmds/modules/quit/quit.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/quit/quit.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,56 @@
+/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+ * 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.
+ *
+ * Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "entry.h"
+#include "quit.h"
+#include "cmds.h"
+
+static char *cmdname = "quit";
+unsigned int cli_quit = 0;
+
+extern volatile int cli_lasterror;
+extern const char *progname;
+
+void * help_cmd_quit(unsigned int level)
+{
+	printf("Type `%s' to exit %s\n", cmdname, progname);
+	return CMD_VOID;
+}
+
+/* Quits the program and returns the status of whatever command
+ * came before invoking 'quit' */
+int * cmd_quit(char *argv[])
+{
+	/* Inform that we're outta here */
+	cli_quit = 1;
+	return CMD_SUCCESS;
+}
Index: uspace/app/bdsh/cmds/modules/quit/quit.def
===================================================================
--- uspace/app/bdsh/cmds/modules/quit/quit.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/quit/quit.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,14 @@
+{
+	"quit",
+	"Exit the console",
+	&cmd_quit,
+	&help_cmd_quit,
+	-1
+},
+{
+	"exit",
+	NULL,
+	&cmd_quit,
+	&help_cmd_quit,
+	-1
+},
Index: uspace/app/bdsh/cmds/modules/quit/quit.h
===================================================================
--- uspace/app/bdsh/cmds/modules/quit/quit.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/quit/quit.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,6 @@
+#ifndef QUIT_H
+#define QUIT_H
+
+/* Prototypes for the quit command (excluding entry points) */
+
+#endif
Index: uspace/app/bdsh/cmds/modules/rm/entry.h
===================================================================
--- uspace/app/bdsh/cmds/modules/rm/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/rm/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,9 @@
+#ifndef RM_ENTRY_H
+#define RM_ENTRY_H
+
+/* Entry points for the rm command */
+extern int * cmd_rm(char **);
+extern void * help_cmd_rm(unsigned int);
+
+#endif /* RM_ENTRY_H */
+
Index: uspace/app/bdsh/cmds/modules/rm/rm.c
===================================================================
--- uspace/app/bdsh/cmds/modules/rm/rm.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/rm/rm.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,253 @@
+/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+ * 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.
+ *
+ * Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <assert.h>
+#include <getopt.h>
+
+#include "config.h"
+#include "errors.h"
+#include "util.h"
+#include "entry.h"
+#include "rm.h"
+#include "cmds.h"
+
+static char *cmdname = "rm";
+#define RM_VERSION "0.0.1"
+
+static rm_job_t rm;
+
+static struct option long_options[] = {
+	{ "help", no_argument, 0, 'h' },
+	{ "version", no_argument, 0, 'v' },
+	{ "recursive", no_argument, 0, 'r' },
+	{ "force", no_argument, 0, 'f' },
+	{ "safe", no_argument, 0, 's' },
+	{ 0, 0, 0, 0 }
+};
+
+unsigned int rm_start(rm_job_t *rm)
+{
+	rm->recursive = 0;
+	rm->force = 0;
+	rm->safe = 0;
+
+	/* Make sure we can allocate enough memory to store
+	 * what is needed in the job structure */
+	if (NULL == (rm->nwd = (char *) malloc(PATH_MAX)))
+		return 0;
+	memset(rm->nwd, 0, sizeof(rm->nwd));
+
+	if (NULL == (rm->owd = (char *) malloc(PATH_MAX)))
+		return 0;
+	memset(rm->owd, 0, sizeof(rm->owd));
+
+	if (NULL == (rm->cwd = (char *) malloc(PATH_MAX)))
+		return 0;
+	memset(rm->cwd, 0, sizeof(rm->cwd));
+
+	chdir(".");
+
+	if (NULL == (getcwd(rm->owd, PATH_MAX)))
+		return 0;
+
+	return 1;
+}
+
+void rm_end(rm_job_t *rm)
+{
+	if (NULL != rm->nwd)
+		free(rm->nwd);
+
+	if (NULL != rm->owd)
+		free(rm->owd);
+
+	if (NULL != rm->cwd)
+		free(rm->cwd);
+
+	return;
+}
+
+unsigned int rm_recursive(const char *path)
+{
+	int rc;
+
+	/* First see if it will just go away */
+	rc = rmdir(path);
+	if (rc == 0)
+		return 0;
+
+	/* Its not empty, recursively scan it */
+	cli_error(CL_ENOTSUP,
+		"Can not remove %s, directory not empty", path);
+	return 1;
+}
+
+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;
+}
+
+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;
+}
+
+/* Dispays help for rm in various levels */
+void * help_cmd_rm(unsigned int level)
+{
+	if (level == HELP_SHORT) {
+		printf("`%s' removes files and directories.\n", cmdname);
+	} else {
+		help_cmd_rm(HELP_SHORT);
+		printf(
+		"Usage:  %s [options] <path>\n"
+		"Options:\n"
+		"  -h, --help       A short option summary\n"
+		"  -v, --version    Print version information and exit\n"
+		"  -r, --recursive  Recursively remove sub directories\n"
+		"  -f, --force      Do not prompt prior to removing files\n"
+		"  -s, --safe       Stop if directories change during removal\n\n"
+		"Currently, %s is under development, some options don't work.\n",
+		cmdname, cmdname);
+	}
+	return CMD_VOID;
+}
+
+/* Main entry point for rm, accepts an array of arguments */
+int * cmd_rm(char **argv)
+{
+	unsigned int argc;
+	unsigned int i, scope, ret = 0;
+	int c, opt_ind;
+	size_t len;
+	char *buff = NULL;
+
+	for (argc = 0; argv[argc] != NULL; argc ++);
+	if (argc < 2) {
+		cli_error(CL_EFAIL,
+			"%s: insufficient arguments. Try %s --help", cmdname, cmdname);
+		return CMD_FAILURE;
+	}
+
+	if (!rm_start(&rm)) {
+		cli_error(CL_ENOMEM, "%s: could not initialize", cmdname);
+		rm_end(&rm);
+		return CMD_FAILURE;
+	}
+
+	for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
+		c = getopt_long(argc, argv, "hvrfs", long_options, &opt_ind);
+		switch (c) {
+		case 'h':
+			help_cmd_rm(HELP_LONG);
+			return CMD_SUCCESS;
+		case 'v':
+			printf("%s\n", RM_VERSION);
+			return CMD_SUCCESS;
+		case 'r':
+			rm.recursive = 1;
+			break;
+		case 'f':
+			rm.force = 1;
+			break;
+		case 's':
+			rm.safe = 1;
+			break;
+		}
+	}
+
+	if (optind == argc) {
+		cli_error(CL_EFAIL,
+			"%s: insufficient arguments. Try %s --help", cmdname, cmdname);
+		rm_end(&rm);
+		return CMD_FAILURE;
+	}
+
+	i = optind;
+	while (NULL != argv[i]) {
+		len = strlen(argv[i]) + 2;
+		buff = (char *) realloc(buff, len);
+		assert(buff != NULL);
+		memset(buff, 0, sizeof(buff));
+		snprintf(buff, len, argv[i]);
+
+		scope = rm_scope(buff);
+		switch (scope) {
+		case RM_BOGUS: /* FIXME */
+		case RM_FILE:
+			ret += rm_single(buff);
+			break;
+		case RM_DIR:
+			if (! rm.recursive) {
+				printf("%s is a directory, use -r to remove it.\n", buff);
+				ret ++;
+			} else {
+				ret += rm_recursive(buff);
+			}
+			break;
+		}
+		i++;
+	}
+
+	if (NULL != buff)
+		free(buff);
+
+	rm_end(&rm);
+
+	if (ret)
+		return CMD_FAILURE;
+	else
+		return CMD_SUCCESS;
+}
+
Index: uspace/app/bdsh/cmds/modules/rm/rm.def
===================================================================
--- uspace/app/bdsh/cmds/modules/rm/rm.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/rm/rm.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,16 @@
+{
+	"rm",
+	"The rm command",
+	&cmd_rm,
+	&help_cmd_rm,
+	0
+},
+
+{
+	"del",
+	NULL,
+	&cmd_rm,
+	&help_cmd_rm,
+	0
+},
+
Index: uspace/app/bdsh/cmds/modules/rm/rm.h
===================================================================
--- uspace/app/bdsh/cmds/modules/rm/rm.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/rm/rm.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,43 @@
+#ifndef RM_H
+#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 */
+extern unsigned int rm_start(rm_job_t *);
+extern void rm_end(rm_job_t *rm);
+extern unsigned int rm_recursive(const char *);
+extern unsigned int rm_single(const char *);
+extern unsigned int rm_scope(const char *);
+
+#endif /* RM_H */
+
Index: uspace/app/bdsh/cmds/modules/touch/entry.h
===================================================================
--- uspace/app/bdsh/cmds/modules/touch/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/touch/entry.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,9 @@
+#ifndef TOUCH_ENTRY_H
+#define TOUCH_ENTRY_H
+
+/* Entry points for the touch command */
+extern int * cmd_touch(char **);
+extern void * help_cmd_touch(unsigned int);
+
+#endif /* TOUCH_ENTRY_H */
+
Index: uspace/app/bdsh/cmds/modules/touch/touch.c
===================================================================
--- uspace/app/bdsh/cmds/modules/touch/touch.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/touch/touch.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,108 @@
+/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+ * 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.
+ *
+ * Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+/* TODO: Options that people would expect, such as not creating the file if
+ * it doesn't exist, specifying the access time, etc */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/types.h>
+
+#include "config.h"
+#include "errors.h"
+#include "util.h"
+#include "entry.h"
+#include "touch.h"
+#include "cmds.h"
+
+static char *cmdname = "touch";
+
+/* Dispays help for touch in various levels */
+void * help_cmd_touch(unsigned int level)
+{
+	if (level == HELP_SHORT) {
+		printf("`%s' updates access times for files\n", cmdname);
+	} else {
+		help_cmd_touch(HELP_SHORT);
+		printf("  `%s' <file>, if the file does not exist it will be "
+				"created\n", cmdname);
+	}
+
+	return CMD_VOID;
+}
+
+/* Main entry point for touch, accepts an array of arguments */
+int * cmd_touch(char **argv)
+{
+	unsigned int argc, i = 0, ret = 0;
+	int fd;
+	char *buff = NULL;
+
+	DIR *dirp;
+
+	/* Count the arguments */
+	for (argc = 0; argv[argc] != NULL; argc ++);
+
+	if (argc == 1) {
+		printf("%s - incorrect number of arguments. Try `help %s extended'\n",
+			cmdname, cmdname);
+		return CMD_FAILURE;
+	}
+
+	for (i = 1; i < argc; i ++) {
+		buff = cli_strdup(argv[i]);
+		dirp = opendir(buff);
+		if (dirp) {
+			cli_error(CL_ENOTSUP, "%s is a directory", buff);
+			closedir(dirp);
+			ret ++;
+			continue;
+		}
+
+		fd = open(buff, O_RDWR | O_CREAT);
+		if (fd < 0) {
+			cli_error(CL_EFAIL, "Could not update / create %s ", buff);
+			ret ++;
+			continue;
+		} else
+			close(fd);
+
+		free(buff);
+	}
+
+	if (ret)
+		return CMD_FAILURE;
+	else
+		return CMD_SUCCESS;
+}
+
Index: uspace/app/bdsh/cmds/modules/touch/touch.def
===================================================================
--- uspace/app/bdsh/cmds/modules/touch/touch.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/touch/touch.def	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,8 @@
+{
+	"touch",
+	"The touch command",
+	&cmd_touch,
+	&help_cmd_touch,
+	0
+},
+
Index: uspace/app/bdsh/cmds/modules/touch/touch.h
===================================================================
--- uspace/app/bdsh/cmds/modules/touch/touch.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/cmds/modules/touch/touch.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,8 @@
+#ifndef TOUCH_H
+#define TOUCH_H
+
+/* Prototypes for the touch command, excluding entry points */
+
+
+#endif /* TOUCH_H */
+
Index: uspace/app/bdsh/config.h
===================================================================
--- uspace/app/bdsh/config.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/config.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,33 @@
+/* Various things that are used in many files
+ * Various temporary port work-arounds are addressed in __HELENOS__ , this
+ * serves as a convenience and later as a guide to make "phony.h" for future
+ * ports */
+
+/* Specific port work-arounds : */
+#define PATH_MAX 255
+#define EXIT_SUCCESS 0
+#define EXIT_FAILURE 0
+
+/* Work around for getenv() */
+#define PATH "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
+#define PATH_DELIM ":"
+
+/* Used in many places */
+#define SMALL_BUFLEN 256
+#define LARGE_BUFLEN 1024
+
+/* How many words (arguments) are permitted, how big can a whole
+ * sentence be? Similar to ARG_MAX */
+#define WORD_MAX 255
+#define INPUT_MAX 1024
+
+/* Leftovers from Autoconf */
+#define PACKAGE_MAINTAINER "Tim Post"
+#define PACKAGE_BUGREPORT "echo@echoreply.us"
+#define PACKAGE_NAME "bdsh"
+#define PACKAGE_STRING "The brain dead shell"
+#define PACKAGE_TARNAME "scli"
+#define PACKAGE_VERSION "0.0.1"
+
+
+
Index: uspace/app/bdsh/errors.c
===================================================================
--- uspace/app/bdsh/errors.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/errors.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,95 @@
+/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+ * 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.
+ *
+ * Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include "config.h"
+#include "errors.h"
+#include "errstr.h"
+
+/* Error printing, translation and handling functions */
+
+volatile int cli_lasterr = 0;
+extern volatile unsigned int cli_verbocity;
+
+/* Look up errno in cl_errors and return the corresponding string.
+ * Return NULL if not found */
+char *err2str(int errno)
+{
+
+	if (NULL != cl_errors[errno])
+		return cl_errors[errno];
+
+	return (char *)NULL;
+}
+
+/* Print an error report signifying errno, which is translated to
+ * its corresponding human readable string. If errno > 0, raise the
+ * cli_quit int that tells the main program loop to exit immediately */
+
+void cli_error(int errno, const char *fmt, ...)
+{
+	va_list vargs;
+	va_start(vargs, fmt);
+	vprintf(fmt, vargs);
+	va_end(vargs);
+
+	if (NULL != err2str(errno))
+		printf(" (%s)\n", err2str(errno));
+	else
+		printf(" (Unknown Error %d)\n", errno);
+
+	if (errno < 0)
+		exit(EXIT_FAILURE);
+
+}
+
+/* Just a smart printf(), print the string only if cli_verbocity is high */
+void cli_verbose(const char *fmt, ...)
+{
+	if (cli_verbocity) {
+		va_list vargs;
+
+		printf("[*] ");
+		va_start(vargs, fmt);
+		vprintf(fmt, vargs);
+		va_end(vargs);
+		printf("\n");
+	}
+	return;
+}
+
+
+
+
Index: uspace/app/bdsh/errors.h
===================================================================
--- uspace/app/bdsh/errors.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/errors.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,19 @@
+#ifndef ERRORS_H
+#define ERRORS_H
+
+/* Various error levels */
+#define CL_EFATAL   -1
+#define CL_EOK     0
+#define CL_EFAIL   1
+#define CL_EBUSY   2
+#define CL_ENOENT  3
+#define CL_ENOMEM  4
+#define CL_EPERM   5
+#define CL_ENOTSUP 6
+#define CL_EEXEC   7
+#define CL_EEXISTS 8
+
+extern char *err2str(int);
+extern void cli_error(int, const char *, ...);
+extern void cli_verbose(const char *, ...);
+#endif
Index: uspace/app/bdsh/errstr.h
===================================================================
--- uspace/app/bdsh/errstr.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/errstr.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,20 @@
+#ifndef ERRSTR_H
+#define ERRSTR_H
+
+/* Simple array to translate error codes to meaningful strings */
+
+static char *cl_errors[] = {
+	"Success",
+	"Failure",
+	"Busy",
+	"No Such Entry",
+	"Not Enough Memory",
+	"Permission Denied",
+	"Method Not Supported",
+	"Bad command or file name",
+	"Entry already exists",
+	NULL
+};
+
+#endif
+
Index: uspace/app/bdsh/exec.c
===================================================================
--- uspace/app/bdsh/exec.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/exec.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,126 @@
+/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+ * 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.
+ *
+ * Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+/* The VERY basics of execute in place support. These are buggy, leaky
+ * and not nearly done. Only here for beta testing!! You were warned!!
+ * TODO:
+ * Hash command lookups to save time
+ * Create a running pointer to **path and advance/rewind it as we go */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "config.h"
+#include "util.h"
+#include "exec.h"
+#include "errors.h"
+
+/* FIXME: Just have find_command() return an allocated string */
+char *found;
+
+/* work-around for access() */
+unsigned int try_access(const char *f)
+{
+	int fd;
+
+	fd = open(f, O_RDONLY);
+	if (fd > -1) {
+		close(fd);
+		return 0;
+	} else
+		return -1;
+}
+
+/* Returns the full path of "cmd" if cmd is found, else just hand back
+ * cmd as it was presented */
+char *find_command(char *cmd)
+{
+	char *path_orig, *path_tok;
+	char *path[PATH_MAX];
+	int n = 0, i = 0;
+	size_t x = strlen(cmd) + 2;
+
+	found = (char *)malloc(PATH_MAX);
+
+	/* The user has specified a full or relative path, just give it back. */
+	if (-1 != try_access(cmd)) {
+		return (char *) cmd;
+	}
+	path_orig = PATH;
+	path_tok = cli_strdup(path_orig);
+
+	/* Extract the PATH env to a path[] array */
+	path[n] = cli_strtok(path_tok, PATH_DELIM);
+	while (NULL != path[n]) {
+		if ((strlen(path[n]) + x ) > PATH_MAX) {
+			cli_error(CL_ENOTSUP,
+				"Segment %d of path is too large, search ends at segment %d",
+				n, n-1);
+			break;
+		}
+		path[++n] = cli_strtok(NULL, PATH_DELIM);
+	}
+
+	/* We now have n places to look for the command */
+	for (i=0; path[i]; i++) {
+		memset(found, 0, sizeof(found));
+		snprintf(found, PATH_MAX, "%s/%s", path[i], cmd);
+		if (-1 != try_access(found)) {
+			free(path_tok);
+			return (char *) found;
+		}
+	}
+
+	/* We didn't find it, just give it back as-is. */
+	free(path_tok);
+	return (char *) cmd;
+}
+
+unsigned int try_exec(char *cmd, char **argv)
+{
+	task_id_t tid;
+	char *tmp;
+
+	tmp = cli_strdup(find_command(cmd));
+	free(found);
+
+	tid = task_spawn((const char *)tmp, (const char **)argv);
+	free(tmp);
+
+	if (tid == 0) {
+		cli_error(CL_EEXEC, "Can not spawn %s", cmd);
+		return 1;
+	} else {
+		return 0;
+	}
+}
Index: uspace/app/bdsh/exec.h
===================================================================
--- uspace/app/bdsh/exec.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/exec.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,10 @@
+#ifndef EXEC_H
+#define EXEC_H
+
+#include <task.h>
+
+extern char *find_command(char *);
+extern unsigned int try_exec(char *, char **);
+extern unsigned int try_access(const char *);
+
+#endif
Index: uspace/app/bdsh/input.c
===================================================================
--- uspace/app/bdsh/input.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/input.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,162 @@
+/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+ * All rights reserved.
+ * Copyright (c) 2008, Jiri Svoboda - All Rights Reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <io/stream.h>
+
+#include "config.h"
+#include "util.h"
+#include "scli.h"
+#include "input.h"
+#include "errors.h"
+#include "exec.h"
+
+extern volatile unsigned int cli_interactive;
+
+/* More than a macro than anything */
+void cli_restricted(char *cmd)
+{
+	cli_verbose("%s is not available in %s mode\n", cmd,
+		cli_interactive ? "interactive" : "non-interactive");
+
+	return;
+}
+
+/* Tokenizes input from console, sees if the first word is a built-in, if so
+ * invokes the built-in entry point (a[0]) passing all arguments in a[] to
+ * the handler */
+int tok_input(cliuser_t *usr)
+{
+	char *cmd[WORD_MAX];
+	int n = 0, i = 0;
+	int rc = 0;
+	char *tmp;
+
+	if (NULL == usr->line)
+		return CL_EFAIL;
+
+	tmp = cli_strdup(usr->line);
+
+	/* Break up what the user typed, space delimited */
+
+	/* TODO: Protect things in quotes / ticks, expand wildcards */
+	cmd[n] = cli_strtok(tmp, " ");
+	while (cmd[n] && n < WORD_MAX) {
+		cmd[++n] = cli_strtok(NULL, " ");
+	}
+
+	/* We have rubbish */
+	if (NULL == cmd[0]) {
+		rc = CL_ENOENT;
+		goto finit;
+	}
+
+	/* Check what kind of command argv[0] might be, TODO: move this to
+	 * a function */
+	if ((i = (is_builtin(cmd[0]))) > -1) {
+		if (builtin_is_restricted(i)) {
+				rc = try_exec(cmd[0], cmd);
+				if (rc)
+					cli_restricted(cmd[0]);
+				goto finit;
+		}
+		rc = run_builtin(i, cmd, usr);
+		goto finit;
+	} else if ((i = (is_module(cmd[0]))) > -1) {
+		if (module_is_restricted(i)) {
+			rc = try_exec(cmd[0], cmd);
+			if (rc)
+				cli_restricted(cmd[0]);
+			goto finit;
+		}
+		rc = run_module(i, cmd);
+		goto finit;
+	} else {
+		rc = try_exec(cmd[0], cmd);
+		goto finit;
+	}
+
+finit:
+	if (NULL != usr->line) {
+		free(usr->line);
+		usr->line = (char *) NULL;
+	}
+	if (NULL != tmp)
+		free(tmp);
+
+	return rc;
+}
+
+/* Borrowed from Jiri Svoboda's 'cli' uspace app */
+void read_line(char *buffer, int n)
+{
+	char c;
+	int chars;
+
+	chars = 0;
+	while (chars < n - 1) {
+		c = getchar();
+		if (c < 0)
+			return;
+		if (c == '\n')
+			break;
+		if (c == '\b') {
+			if (chars > 0) {
+				putchar('\b');
+				--chars;
+			}
+			continue;
+		}
+		putchar(c);
+		buffer[chars++] = c;
+	}
+	putchar('\n');
+	buffer[chars] = '\0';
+}
+
+void get_input(cliuser_t *usr)
+{
+	char line[INPUT_MAX];
+	size_t len = 0;
+
+	printf("%s", usr->prompt);
+	read_line(line, INPUT_MAX);
+	len = strlen(line);
+	/* Make sure we don't have rubbish or a C/R happy user */
+	if (len == 0 || line[0] == '\n')
+		return;
+	usr->line = cli_strdup(line);
+
+	return;
+}
+
Index: uspace/app/bdsh/input.h
===================================================================
--- uspace/app/bdsh/input.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/input.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,12 @@
+#ifndef INPUT_H
+#define INPUT_H
+
+#include "cmds/cmds.h"
+
+/* prototypes */
+extern int tok_input(cliuser_t *);
+extern void get_input(cliuser_t *);
+extern void cli_restricted(char *);
+extern void read_line(char *, int);
+
+#endif
Index: uspace/app/bdsh/scli.c
===================================================================
--- uspace/app/bdsh/scli.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/scli.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,136 @@
+/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+ * 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.
+ *
+ * Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "config.h"
+#include "scli.h"
+#include "input.h"
+#include "util.h"
+#include "errors.h"
+#include "cmds/cmds.h"
+
+/* See scli.h */
+static cliuser_t usr;
+
+/* Modified by the 'quit' module, which is compiled before this */
+extern unsigned int cli_quit;
+
+/* Globals that are modified during start-up that modules/builtins should
+ * be aware of. */
+volatile unsigned int cli_interactive = 1;
+volatile unsigned int cli_verbocity = 1;
+
+/* The official name of this program
+ * (change to your liking in configure.ac and re-run autoconf) */
+const char *progname = PACKAGE_NAME;
+
+/* (re)allocates memory to store the current working directory, gets
+ * and updates the current working directory, formats the prompt string */
+unsigned int cli_set_prompt(cliuser_t *usr)
+{
+	usr->prompt = (char *) realloc(usr->prompt, PATH_MAX);
+	if (NULL == usr->prompt) {
+		cli_error(CL_ENOMEM, "Can not allocate prompt");
+		return 1;
+	}
+	memset(usr->prompt, 0, sizeof(usr->prompt));
+
+	usr->cwd = (char *) realloc(usr->cwd, PATH_MAX);
+	if (NULL == usr->cwd) {
+		cli_error(CL_ENOMEM, "Can not allocate cwd");
+		return 1;
+	}
+	memset(usr->cwd, 0, sizeof(usr->cwd));
+
+	usr->cwd = getcwd(usr->cwd, PATH_MAX - 1);
+
+	if (NULL == usr->cwd)
+		snprintf(usr->cwd, PATH_MAX, "(unknown)");
+
+	snprintf(usr->prompt,
+			PATH_MAX,
+			"%s # ",
+			usr->cwd);
+
+	return 0;
+}
+
+int cli_init(cliuser_t *usr)
+{
+	usr->line = (char *) NULL;
+	usr->name = "root";
+	usr->home = "/";
+	usr->cwd = (char *) NULL;
+	usr->prompt = (char *) NULL;
+	chdir(usr->home);
+	usr->lasterr = 0;
+	return (int) cli_set_prompt(usr);
+}
+
+/* Destructor */
+void cli_finit(cliuser_t *usr)
+{
+	if (NULL != usr->line)
+		free(usr->line);
+	if (NULL != usr->prompt)
+		free(usr->prompt);
+	if (NULL != usr->cwd)
+		free(usr->cwd);
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = 0;
+	int i = 0;
+
+	if (cli_init(&usr))
+		exit(EXIT_FAILURE);
+
+	printf("Welcome to %s - %s\nType `help' at any time for usage information.\n",
+		progname, PACKAGE_STRING);
+
+	while (!cli_quit) {
+		cli_set_prompt(&usr);
+		get_input(&usr);
+		if (NULL != usr.line) {
+			ret = tok_input(&usr);
+			usr.lasterr = ret;
+		}
+		i++;
+	}
+	goto finit;
+
+finit:
+	cli_finit(&usr);
+	return ret;
+}
Index: uspace/app/bdsh/scli.h
===================================================================
--- uspace/app/bdsh/scli.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/scli.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,20 @@
+#ifndef SCLI_H
+#define SCLI_H
+
+#include "config.h"
+#include <stdint.h>
+
+typedef struct {
+	char *name;
+	char *home;
+	char *line;
+	char *cwd;
+	char *prompt;
+	uint64_t lasterr;
+} cliuser_t;
+
+extern unsigned int cli_set_prompt(cliuser_t *usr);
+extern int cli_init(cliuser_t *usr);
+extern void cli_finit(cliuser_t *usr);
+
+#endif
Index: uspace/app/bdsh/util.c
===================================================================
--- uspace/app/bdsh/util.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/util.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,178 @@
+/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
+ * Copyright (C) 1998 by Wes Peters <wes@softweyr.com>
+ * Copyright (c) 1988, 1993 The Regents of the University of California.
+ * All rights reserved by all copyright holders.
+ *
+ * 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.
+ *
+ * Neither the name of the original program's authors 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+/* NOTES:
+ * 1 - Various functions were adapted from FreeBSD (copyright holders noted above)
+ *     these functions are identified with comments.
+ *
+ * 2 - Some of these have since appeared in libc. They remain here for various
+ *     reasons, such as the eventual integration of garbage collection for things
+ *     that allocate memory and don't automatically free it.
+ *
+ * 3 - Things that expect a pointer to an allocated string do _no_ sanity checking
+ *     if developing on a simulator with no debugger, take care :)
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "config.h"
+#include "errors.h"
+#include "util.h"
+
+/* some platforms do not have strdup, implement it here.
+ * Returns a pointer to an allocated string or NULL on failure */
+char * cli_strdup(const char *s1)
+{
+	size_t len = strlen(s1) + 1;
+	void *ret = malloc(len);
+
+	if (ret == NULL)
+		return (char *) NULL;
+
+	return (char *) memcpy(ret, s1, len);
+}
+
+/*
+ * Take a previously allocated string (s1), re-size it to accept s2 and copy
+ * the contents of s2 into s1.
+ * Return -1 on failure, or the length of the copied string on success.
+ */
+int cli_redup(char **s1, const char *s2)
+{
+	size_t len = strlen(s2) + 1;
+
+	if (! len)
+		return -1;
+
+	*s1 = realloc(*s1, len);
+
+	if (*s1 == NULL)
+		return -1;
+
+	memset(*s1, 0, sizeof(*s1));
+	memcpy(*s1, s2, len);
+	return (int) len;
+}
+
+/* An asprintf() for concantenating paths. Allocates the system PATH_MAX value,
+ * expands the formatted string and re-sizes the block s1 points to accordingly.
+ *
+ * Returns the length of the new s1 on success, -1 on failure. On failure, an
+ * attempt is made to return s1 unmodified for sanity, in this case 0 is returned.
+ * to indicate that s1 was not modified.
+ *
+ * FIXME: ugly hack to get around asprintf(), if you use this, CHECK ITS VALUE! */
+int cli_psprintf(char **s1, const char *fmt, ...)
+{
+	va_list ap;
+	size_t needed, base = PATH_MAX + 1;
+	char *tmp = (char *) malloc(base);
+
+	if (NULL == tmp)
+		return -1;
+
+	char *orig = *s1;
+
+	memset(tmp, 0, sizeof(tmp));
+	va_start(ap, fmt);
+	vsnprintf(tmp, base, fmt, ap);
+	va_end(ap);
+	needed = strlen(tmp) + 1;
+	*s1 = realloc(*s1, needed);
+	if (NULL == *s1) {
+		*s1 = realloc(*s1, strlen(orig) + 1);
+		if (NULL == *s1) {
+			free(tmp);
+			return -1;
+		}
+		memset(*s1, 0, sizeof(*s1));
+		memcpy(*s1, orig, strlen(orig) + 1);
+		free(tmp);
+		return 0;
+	}
+	memset(*s1, 0, sizeof(*s1));
+	memcpy(*s1, tmp, needed);
+	free(tmp);
+
+	return (int) needed;
+}
+	
+/* Ported from FBSD strtok.c 8.1 (Berkeley) 6/4/93 */
+char * cli_strtok_r(char *s, const char *delim, char **last)
+{
+	char *spanp, *tok;
+	int c, sc;
+
+	if (s == NULL && (s = *last) == NULL)
+		return (NULL);
+
+cont:
+	c = *s++;
+	for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
+		if (c == sc)
+			goto cont;
+	}
+
+	if (c == 0) {		/* no non-delimiter characters */
+		*last = NULL;
+		return (NULL);
+	}
+
+	tok = s - 1;
+
+	for (;;) {
+		c = *s++;
+		spanp = (char *)delim;
+		do {
+			if ((sc = *spanp++) == c) {
+				if (c == 0)
+					s = NULL;
+				else
+					s[-1] = '\0';
+				*last = s;
+				return (tok);
+			}
+		} while (sc != 0);
+	}
+}
+
+/* Ported from FBSD strtok.c 8.1 (Berkeley) 6/4/93 */
+char * cli_strtok(char *s, const char *delim)
+{
+	static char *last;
+
+	return (cli_strtok_r(s, delim, &last));
+}
Index: uspace/app/bdsh/util.h
===================================================================
--- uspace/app/bdsh/util.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/app/bdsh/util.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,11 @@
+#ifndef UTIL_H
+#define UTIL_H
+
+/* Internal string handlers */
+extern char * cli_strdup(const char *);
+extern int cli_redup(char **, const char *);
+extern int cli_psprintf(char **, const char *, ...);
+extern char * cli_strtok_r(char *, const char *, char **);
+extern char * cli_strtok(char *, const char *);
+
+#endif
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision fa81b5f14309167116c03cb0dcbb21d3997cfa18)
+++ uspace/app/init/init.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -127,4 +127,5 @@
 	// FIXME: spawn("/sbin/tester");
 	spawn("/sbin/klog");
+	spawn("/sbin/bdsh");
 	
 	return 0;
Index: uspace/lib/libc/Makefile
===================================================================
--- uspace/lib/libc/Makefile	(revision fa81b5f14309167116c03cb0dcbb21d3997cfa18)
+++ uspace/lib/libc/Makefile	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -71,4 +71,5 @@
 	generic/ipc.c \
 	generic/async.c \
+	generic/getopt.c \
 	generic/libadt/list.o \
 	generic/libadt/hash_table.o \
Index: uspace/lib/libc/generic/getopt.c
===================================================================
--- uspace/lib/libc/generic/getopt.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/lib/libc/generic/getopt.c	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,478 @@
+/*	$NetBSD: getopt_long.c,v 1.21.4.1 2008/01/09 01:34:14 matt Exp $	*/
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/* Ported to HelenOS August 2008 by Tim Post <echo@echoreply.us> */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <err.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* HelenOS Port : We're incorporating only the modern getopt_long with wrappers
+ * to keep legacy getopt() usage from breaking. All references to REPLACE_GETOPT
+ * are dropped, we just include the code */
+
+int	opterr = 1;		/* if error message should be printed */
+int	optind = 1;		/* index into parent argv vector */
+int	optopt = '?';		/* character checked for validity */
+int	optreset;		/* reset getopt */
+char *optarg;		/* argument associated with option */
+
+
+#define IGNORE_FIRST	(*options == '-' || *options == '+')
+#define PRINT_ERROR	((opterr) && ((*options != ':') \
+				      || (IGNORE_FIRST && options[1] != ':')))
+/*HelenOS Port - POSIXLY_CORRECT is always false */
+#define IS_POSIXLY_CORRECT 0
+#define PERMUTE         (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
+/* XXX: GNU ignores PC if *options == '-' */
+#define IN_ORDER        (!IS_POSIXLY_CORRECT && *options == '-')
+
+/* return values */
+#define	BADCH	(int)'?'
+#define	BADARG		((IGNORE_FIRST && options[1] == ':') \
+			 || (*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#define	EMSG	""
+
+static int getopt_internal(int, char **, const char *);
+static int gcd(int, int);
+static void permute_args(int, int, int, char **);
+
+static const char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1;   /* first option after non options (for permute) */
+
+/* Error messages */
+
+/* HelenOS Port: Calls to warnx() were eliminated (as we have no stderr that
+ * may be redirected) and replaced with printf. As such, error messages now
+ * end in a newline */
+
+static const char recargchar[] = "option requires an argument -- %c\n";
+static const char recargstring[] = "option requires an argument -- %s\n";
+static const char ambig[] = "ambiguous option -- %.*s\n";
+static const char noarg[] = "option doesn't take an argument -- %.*s\n";
+static const char illoptchar[] = "unknown option -- %c\n";
+static const char illoptstring[] = "unknown option -- %s\n";
+
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(a, b)
+	int a;
+	int b;
+{
+	int c;
+
+	c = a % b;
+	while (c != 0) {
+		a = b;
+		b = c;
+		c = a % b;
+	}
+	   
+	return b;
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(panonopt_start, panonopt_end, opt_end, nargv)
+	int panonopt_start;
+	int panonopt_end;
+	int opt_end;
+	char **nargv;
+{
+	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+	char *swap;
+
+	assert(nargv != NULL);
+
+	/*
+	 * compute lengths of blocks and number and size of cycles
+	 */
+	nnonopts = panonopt_end - panonopt_start;
+	nopts = opt_end - panonopt_end;
+	ncycle = gcd(nnonopts, nopts);
+	cyclelen = (opt_end - panonopt_start) / ncycle;
+
+	for (i = 0; i < ncycle; i++) {
+		cstart = panonopt_end+i;
+		pos = cstart;
+		for (j = 0; j < cyclelen; j++) {
+			if (pos >= panonopt_end)
+				pos -= nnonopts;
+			else
+				pos += nopts;
+			swap = nargv[pos];
+			nargv[pos] = nargv[cstart];
+			nargv[cstart] = swap;
+		}
+	}
+}
+
+/*
+ * getopt_internal --
+ *	Parse argc/argv argument vector.  Called by user level routines.
+ *  Returns -2 if -- is found (can be long option or end of options marker).
+ */
+static int
+getopt_internal(nargc, nargv, options)
+	int nargc;
+	char **nargv;
+	const char *options;
+{
+	char *oli;				/* option letter list index */
+	int optchar;
+
+	assert(nargv != NULL);
+	assert(options != NULL);
+
+	optarg = NULL;
+
+	/*
+	 * XXX Some programs (like rsyncd) expect to be able to
+	 * XXX re-initialize optind to 0 and have getopt_long(3)
+	 * XXX properly function again.  Work around this braindamage.
+	 */
+	if (optind == 0)
+		optind = 1;
+
+	if (optreset)
+		nonopt_start = nonopt_end = -1;
+start:
+	if (optreset || !*place) {		/* update scanning pointer */
+		optreset = 0;
+		if (optind >= nargc) {          /* end of argument vector */
+			place = EMSG;
+			if (nonopt_end != -1) {
+				/* do permutation, if we have to */
+				permute_args(nonopt_start, nonopt_end,
+				    optind, nargv);
+				optind -= nonopt_end - nonopt_start;
+			}
+			else if (nonopt_start != -1) {
+				/*
+				 * If we skipped non-options, set optind
+				 * to the first of them.
+				 */
+				optind = nonopt_start;
+			}
+			nonopt_start = nonopt_end = -1;
+			return -1;
+		}
+		if ((*(place = nargv[optind]) != '-')
+		    || (place[1] == '\0')) {    /* found non-option */
+			place = EMSG;
+			if (IN_ORDER) {
+				/*
+				 * GNU extension: 
+				 * return non-option as argument to option 1
+				 */
+				optarg = nargv[optind++];
+				return INORDER;
+			}
+			if (!PERMUTE) {
+				/*
+				 * if no permutation wanted, stop parsing
+				 * at first non-option
+				 */
+				return -1;
+			}
+			/* do permutation */
+			if (nonopt_start == -1)
+				nonopt_start = optind;
+			else if (nonopt_end != -1) {
+				permute_args(nonopt_start, nonopt_end,
+				    optind, nargv);
+				nonopt_start = optind -
+				    (nonopt_end - nonopt_start);
+				nonopt_end = -1;
+			}
+			optind++;
+			/* process next argument */
+			goto start;
+		}
+		if (nonopt_start != -1 && nonopt_end == -1)
+			nonopt_end = optind;
+		if (place[1] && *++place == '-') {	/* found "--" */
+			place++;
+			return -2;
+		}
+	}
+	if ((optchar = (int)*place++) == (int)':' ||
+	    (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
+		/* option letter unknown or ':' */
+		if (!*place)
+			++optind;
+		if (PRINT_ERROR)
+			printf(illoptchar, optchar);
+		optopt = optchar;
+		return BADCH;
+	}
+	if (optchar == 'W' && oli[1] == ';') {		/* -W long-option */
+		/* XXX: what if no long options provided (called by getopt)? */
+		if (*place) 
+			return -2;
+
+		if (++optind >= nargc) {	/* no arg */
+			place = EMSG;
+			if (PRINT_ERROR)
+				printf(recargchar, optchar);
+			optopt = optchar;
+			return BADARG;
+		} else				/* white space */
+			place = nargv[optind];
+		/*
+		 * Handle -W arg the same as --arg (which causes getopt to
+		 * stop parsing).
+		 */
+		return -2;
+	}
+	if (*++oli != ':') {			/* doesn't take argument */
+		if (!*place)
+			++optind;
+	} else {				/* takes (optional) argument */
+		optarg = NULL;
+		if (*place)			/* no white space */
+			optarg = *place;
+		/* XXX: disable test for :: if PC? (GNU doesn't) */
+		else if (oli[1] != ':') {	/* arg not optional */
+			if (++optind >= nargc) {	/* no arg */
+				place = EMSG;
+				if (PRINT_ERROR)
+					printf(recargchar, optchar);
+				optopt = optchar;
+				return BADARG;
+			} else
+				optarg = nargv[optind];
+		}
+		place = EMSG;
+		++optind;
+	}
+	/* dump back option letter */
+	return optchar;
+}
+
+/*
+ * getopt --
+ *	Parse argc/argv argument vector.
+ */
+int
+getopt(nargc, nargv, options)
+	int nargc;
+	char * const *nargv;
+	const char *options;
+{
+	int retval;
+
+	assert(nargv != NULL);
+	assert(options != NULL);
+
+	retval = getopt_internal(nargc, (char **)nargv, options);
+	if (retval == -2) {
+		++optind;
+		/*
+		 * We found an option (--), so if we skipped non-options,
+		 * we have to permute.
+		 */
+		if (nonopt_end != -1) {
+			permute_args(nonopt_start, nonopt_end, optind,
+				       (char **)nargv);
+			optind -= nonopt_end - nonopt_start;
+		}
+		nonopt_start = nonopt_end = -1;
+		retval = -1;
+	}
+	return retval;
+}
+
+/*
+ * getopt_long --
+ *	Parse argc/argv argument vector.
+ */
+int
+getopt_long(nargc, nargv, options, long_options, idx)
+	int nargc;
+	char * const *nargv;
+	const char *options;
+	const struct option *long_options;
+	int *idx;
+{
+	int retval;
+
+#define IDENTICAL_INTERPRETATION(_x, _y)				\
+	(long_options[(_x)].has_arg == long_options[(_y)].has_arg &&	\
+	 long_options[(_x)].flag == long_options[(_y)].flag &&		\
+	 long_options[(_x)].val == long_options[(_y)].val)
+
+	assert(nargv != NULL);
+	assert(options != NULL);
+	assert(long_options != NULL);
+	/* idx may be NULL */
+
+	retval = getopt_internal(nargc, (char **)nargv, options);
+	if (retval == -2) {
+		char *current_argv, *has_equal;
+		size_t current_argv_len;
+		int i, ambiguous, match;
+
+		current_argv = (char *)place;
+		match = -1;
+		ambiguous = 0;
+
+		optind++;
+		place = EMSG;
+
+		if (*current_argv == '\0') {		/* found "--" */
+			/*
+			 * We found an option (--), so if we skipped
+			 * non-options, we have to permute.
+			 */
+			if (nonopt_end != -1) {
+				permute_args(nonopt_start, nonopt_end,
+				    optind, (char **)nargv);
+				optind -= nonopt_end - nonopt_start;
+			}
+			nonopt_start = nonopt_end = -1;
+			return -1;
+		}
+		if ((has_equal = strchr(current_argv, '=')) != NULL) {
+			/* argument found (--option=arg) */
+			current_argv_len = has_equal - current_argv;
+			has_equal++;
+		} else
+			current_argv_len = strlen(current_argv);
+	    
+		for (i = 0; long_options[i].name; i++) {
+			/* find matching long option */
+			if (strncmp(current_argv, long_options[i].name,
+			    current_argv_len))
+				continue;
+
+			if (strlen(long_options[i].name) ==
+			    (unsigned)current_argv_len) {
+				/* exact match */
+				match = i;
+				ambiguous = 0;
+				break;
+			}
+			if (match == -1)		/* partial match */
+				match = i;
+			else if (!IDENTICAL_INTERPRETATION(i, match))
+				ambiguous = 1;
+		}
+		if (ambiguous) {
+			/* ambiguous abbreviation */
+			if (PRINT_ERROR)
+				printf(ambig, (int)current_argv_len,
+				     current_argv);
+			optopt = 0;
+			return BADCH;
+		}
+		if (match != -1) {			/* option found */
+		        if (long_options[match].has_arg == no_argument
+			    && has_equal) {
+				if (PRINT_ERROR)
+					printf(noarg, (int)current_argv_len,
+					     current_argv);
+				/*
+				 * XXX: GNU sets optopt to val regardless of
+				 * flag
+				 */
+				if (long_options[match].flag == NULL)
+					optopt = long_options[match].val;
+				else
+					optopt = 0;
+				return BADARG;
+			}
+			if (long_options[match].has_arg == required_argument ||
+			    long_options[match].has_arg == optional_argument) {
+				if (has_equal)
+					optarg = has_equal;
+				else if (long_options[match].has_arg ==
+				    required_argument) {
+					/*
+					 * optional argument doesn't use
+					 * next nargv
+					 */
+					optarg = nargv[optind++];
+				}
+			}
+			if ((long_options[match].has_arg == required_argument)
+			    && (optarg == NULL)) {
+				/*
+				 * Missing argument; leading ':'
+				 * indicates no error should be generated
+				 */
+				if (PRINT_ERROR)
+					printf(recargstring, current_argv);
+				/*
+				 * XXX: GNU sets optopt to val regardless
+				 * of flag
+				 */
+				if (long_options[match].flag == NULL)
+					optopt = long_options[match].val;
+				else
+					optopt = 0;
+				--optind;
+				return BADARG;
+			}
+		} else {			/* unknown option */
+			if (PRINT_ERROR)
+				printf(illoptstring, current_argv);
+			optopt = 0;
+			return BADCH;
+		}
+		if (long_options[match].flag) {
+			*long_options[match].flag = long_options[match].val;
+			retval = 0;
+		} else 
+			retval = long_options[match].val;
+		if (idx)
+			*idx = match;
+	}
+	return retval;
+#undef IDENTICAL_INTERPRETATION
+}
+
Index: uspace/lib/libc/include/getopt.h
===================================================================
--- uspace/lib/libc/include/getopt.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
+++ uspace/lib/libc/include/getopt.h	(revision 216d6fc606ae06cb619154c1ca9763af0f2c1978)
@@ -0,0 +1,71 @@
+/*	$NetBSD: getopt.h,v 1.10.6.1 2008/05/18 12:30:09 yamt Exp $	*/
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/* Ported to HelenOS August 2008 by Tim Post <echo@echoreply.us> */
+
+#ifndef _GETOPT_H_
+#define _GETOPT_H_
+
+#include <unistd.h>
+
+/*
+ * Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions
+ */
+#define no_argument        0
+#define required_argument  1
+#define optional_argument  2
+
+struct option {
+	/* name of long option */
+	const char *name;
+	/*
+	 * one of no_argument, required_argument, and optional_argument:
+	 * whether option takes an argument
+	 */
+	int has_arg;
+	/* if not NULL, set *flag to val when option found */
+	int *flag;
+	/* if flag not NULL, value to set *flag to; else return value */
+	int val;
+};
+
+/* HelenOS Port - These need to be exposed for legacy getopt() */
+extern char *optarg;
+extern int optind, opterr, optopt;
+extern int optreset;
+
+int getopt_long(int, char * const *, const char *,
+    const struct option *, int *);
+
+/* HelenOS Port : Expose legacy getopt() */
+int	 getopt(int, char * const [], const char *);
+
+#endif /* !_GETOPT_H_ */
