Index: uspace/app/bdsh/cmds/modules/cp/cp.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cp/cp.c	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/app/bdsh/cmds/modules/cp/cp.c	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -33,4 +33,6 @@
 #include <str.h>
 #include <fcntl.h>
+#include <sys/stat.h>
+#include <dirent.h>
 #include "config.h"
 #include "util.h"
@@ -55,4 +57,37 @@
 };
 
+typedef enum {
+	TYPE_NONE,
+	TYPE_FILE,
+	TYPE_DIR
+} dentry_type_t;
+
+static int64_t copy_file(const char *src, const char *dest,
+    size_t blen, int vb);
+
+/** Get the type of a directory entry.
+ *
+ * @param path	Path of the directory entry.
+ *
+ * @return TYPE_DIR if the dentry is a directory.
+ * @return TYPE_FILE if the dentry is a file.
+ * @return TYPE_NONE if the dentry does not exists.
+ */
+static dentry_type_t get_type(const char *path)
+{
+	struct stat s;
+
+	int r = stat(path, &s);
+
+	if (r)
+		return TYPE_NONE;
+	else if (s.is_directory)
+		return TYPE_DIR;
+	else if (s.is_file)
+		return TYPE_FILE;
+
+	return TYPE_NONE;
+}
+
 static int strtoint(const char *s1)
 {
@@ -67,4 +102,218 @@
 	return (int) t1;
 }
+
+/** Get the last component of a path.
+ *
+ * e.g. /data/a  ---> a
+ *
+ * @param path	Pointer to the path.
+ *
+ * @return	Pointer to the last component or to the path itself.
+ */
+static char *get_last_path_component(char *path)
+{
+	char *ptr;
+
+	ptr = str_rchr(path, '/');
+	if (!ptr)
+		return path;
+	else
+		return ptr + 1;
+}
+
+/** Merge two paths together.
+ *
+ * e.g. (path1 = /data/dir, path2 = a/b) --> /data/dir/a/b
+ *
+ * @param path1		Path to which path2 will be appended.
+ * @param path1_size	Size of the path1 buffer.
+ * @param path2		Path that will be appended to path1.
+ */
+static void merge_paths(char *path1, size_t path1_size, char *path2)
+{
+	const char *delim = "/";
+
+	str_rtrim(path1, '/');
+	str_append(path1, path1_size, delim);
+	str_append(path1, path1_size, path2);
+}
+
+static int64_t do_copy(const char *src, const char *dest,
+    size_t blen, int vb, int recursive, int force)
+{
+	int r = -1;
+	char dest_path[PATH_MAX];
+	char src_path[PATH_MAX];
+	DIR *dir = NULL;
+	struct dirent *dp;
+
+	dentry_type_t src_type = get_type(src);
+	dentry_type_t dest_type = get_type(dest);
+
+	const size_t src_len = str_size(src);
+
+	if (src_type == TYPE_FILE) {
+		char *src_fname;
+
+		/* Initialize the src_path with the src argument */
+		str_cpy(src_path, src_len + 1, src);
+		str_rtrim(src_path, '/');
+		
+		/* Get the last component name from the src path */
+		src_fname = get_last_path_component(src_path);
+		
+		/* Initialize dest_path with the dest argument */
+		str_cpy(dest_path, PATH_MAX, dest);
+
+		if (dest_type == TYPE_DIR) {
+			/* e.g. cp file_name /data */
+			/* e.g. cp file_name /data/ */
+			
+			/* dest is a directory,
+			 * append the src filename to it.
+			 */
+			merge_paths(dest_path, PATH_MAX, src_fname);
+			dest_type = get_type(dest_path);
+		} else if (dest_type == TYPE_NONE) {
+			if (dest_path[str_size(dest_path) - 1] == '/') {
+				/* e.g. cp /textdemo /data/dirnotexists/ */
+
+				printf("The dest directory %s does not exists",
+				    dest_path);
+				goto exit;
+			}
+		}
+
+		if (dest_type == TYPE_DIR) {
+			printf("Cannot overwrite existing directory %s\n",
+			    dest_path);
+			goto exit;
+		} else if (dest_type == TYPE_FILE) {
+			/* e.g. cp file_name existing_file */
+
+			/* dest already exists, if force is set we will
+			 * try to remove it.
+			 */
+			if (force) {
+				if (unlink(dest_path)) {
+					printf("Unable to remove %s\n",
+					    dest_path);
+					goto exit;
+				}
+			} else {
+				printf("file already exists: %s\n", dest_path);
+				goto exit;
+			}
+		}
+
+		/* call copy_file and exit */
+		r = (copy_file(src, dest_path, blen, vb) < 0);
+
+	} else if (src_type == TYPE_DIR) {
+		/* e.g. cp -r /x/srcdir /y/destdir/ */
+
+		if (!recursive) {
+			printf("Cannot copy the %s directory without the "
+			    "-r option\n", src);
+			goto exit;
+		} else if (dest_type == TYPE_FILE) {
+			printf("Cannot overwrite a file with a directory\n");
+			goto exit;
+		}
+
+		char *src_dirname;
+
+		/* Initialize src_path with the content of src */
+		str_cpy(src_path, src_len + 1, src);
+		str_rtrim(src_path, '/');
+
+		src_dirname = get_last_path_component(src_path);
+
+		str_cpy(dest_path, PATH_MAX, dest);
+
+		switch (dest_type) {
+		case TYPE_DIR:
+			if (str_cmp(src_dirname, "..") &&
+			    str_cmp(src_dirname, ".")) {
+				/* The last component of src_path is
+				 * not '.' or '..'
+				 */
+				merge_paths(dest_path, PATH_MAX, src_dirname);
+
+				if (mkdir(dest_path, 0) == -1) {
+					printf("Unable to create "
+					    "dest directory %s\n", dest_path);
+					goto exit;
+				}
+			}
+			break;
+		default:
+		case TYPE_NONE:
+			/* dest does not exists, this means the user wants
+			 * to specify the name of the destination directory
+			 *
+			 * e.g. cp -r /src /data/new_dir_src
+			 */
+			if (mkdir(dest_path, 0)) {
+				printf("Unable to create "
+				    "dest directory %s\n", dest_path);
+				goto exit;
+			}
+			break;
+		}
+
+		dir = opendir(src);
+		if (!dir) {
+			/* Something strange is happening... */
+			printf("Unable to open src %s directory\n", src);
+			goto exit;
+		}
+
+		/* Copy every single directory entry of src into the
+		 * destination directory.
+		 */
+		while ((dp = readdir(dir))) {
+			struct stat src_s;
+			struct stat dest_s;
+
+			char src_dent[PATH_MAX];
+			char dest_dent[PATH_MAX];
+
+			str_cpy(src_dent, PATH_MAX, src);
+			merge_paths(src_dent, PATH_MAX, dp->d_name);
+
+			str_cpy(dest_dent, PATH_MAX, dest_path);
+			merge_paths(dest_dent, PATH_MAX, dp->d_name);
+
+			/* Check if we are copying a directory into itself */
+			stat(src_dent, &src_s);
+			stat(dest_path, &dest_s);
+
+			if (dest_s.index == src_s.index &&
+			    dest_s.fs_handle == src_s.fs_handle) {
+				printf("Cannot copy a directory "
+				    "into itself\n");
+				goto exit;
+			}
+
+			if (vb)
+				printf("copy %s %s\n", src_dent, dest_dent);
+
+			/* Recursively call do_copy() */
+			r = do_copy(src_dent, dest_dent, blen, vb, recursive,
+			    force);
+			if (r)
+				goto exit;
+
+		}
+	} else
+		printf("Unable to open source file %s\n", src);
+
+exit:
+	if (dir)
+		closedir(dir);
+	return r;
+}
+
 
 static int64_t copy_file(const char *src, const char *dest,
@@ -127,17 +376,16 @@
 	static char helpfmt[] =
 	    "Usage:  %s [options] <source> <dest>\n"
-	    "Options: (* indicates not yet implemented)\n"
+	    "Options:\n"
 	    "  -h, --help       A short option summary\n"
 	    "  -v, --version    Print version information and exit\n"
-	    "* -V, --verbose    Be annoyingly noisy about what's being done\n"
-	    "* -f, --force      Do not complain when <dest> exists\n"
-	    "* -r, --recursive  Copy entire directories\n"
-	    "  -b, --buffer ## Set the read buffer size to ##\n"
-	    "Currently, %s is under development, some options may not work.\n";
+	    "  -V, --verbose    Be annoyingly noisy about what's being done\n"
+	    "  -f, --force      Do not complain when <dest> exists\n"
+	    "  -r, --recursive  Copy entire directories\n"
+	    "  -b, --buffer ## Set the read buffer size to ##\n";
 	if (level == HELP_SHORT) {
 		printf("`%s' copies files and directories\n", cmdname);
 	} else {
 		help_cmd_cp(HELP_SHORT);
-		printf(helpfmt, cmdname, cmdname);
+		printf(helpfmt, cmdname);
 	}
 
@@ -148,5 +396,6 @@
 {
 	unsigned int argc, verbose = 0;
-	int buffer = 0;
+	int buffer = 0, recursive = 0;
+	int force = 0;
 	int c, opt_ind;
 	int64_t ret;
@@ -167,6 +416,8 @@
 			break;
 		case 'f':
+			force = 1;
 			break;
 		case 'r':
+			recursive = 1;
 			break;
 		case 'b':
@@ -194,10 +445,8 @@
 	}
 
-	ret = copy_file(argv[optind], argv[optind + 1], buffer, verbose);
-
-	if (verbose)
-		printf("%" PRId64 " bytes copied\n", ret);
-
-	if (ret >= 0)
+	ret = do_copy(argv[optind], argv[optind + 1], buffer, verbose,
+	    recursive, force);
+
+	if (ret == 0)
 		return CMD_SUCCESS;
 	else
Index: uspace/app/bdsh/cmds/modules/mount/mount.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mount/mount.c	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -30,6 +30,8 @@
 #include <stdlib.h>
 #include <vfs/vfs.h>
+#include <adt/list.h>
 #include <errno.h>
 #include <getopt.h>
+#include <inttypes.h>
 #include "config.h"
 #include "util.h"
@@ -60,4 +62,35 @@
 	}
 	return;
+}
+
+static void print_mtab_list(void)
+{
+	LIST_INITIALIZE(mtab_list);
+	get_mtab_list(&mtab_list);
+
+	mtab_ent_t *old_ent = NULL;
+
+	list_foreach(mtab_list, cur) {
+		mtab_ent_t *mtab_ent = list_get_instance(cur, mtab_ent_t,
+		    link);
+
+		if (old_ent)
+			free(old_ent);
+
+		old_ent = mtab_ent;
+
+		printf("%s", mtab_ent->fs_name);
+		if (mtab_ent->instance)
+			printf("/%d", mtab_ent->instance);
+		printf(" on %s ", mtab_ent->mp);
+
+		if (str_size(mtab_ent->opts) > 0)
+			printf("opts=%s ", mtab_ent->opts);
+
+		printf("(service=%" PRIun ")\n", mtab_ent->service_id);
+	}
+
+	if (old_ent)
+		free(old_ent);
 }
 
@@ -94,8 +127,12 @@
 		t_argv = &argv[0];
 
-	if ((argc < 3) || (argc > 5)) {
+	if ((argc == 2) || (argc > 5)) {
 		printf("%s: invalid number of arguments. Try `mount --help'\n",
 		    cmdname);
 		return CMD_FAILURE;
+	}
+	if (argc == 1) {
+		print_mtab_list();
+		return CMD_SUCCESS;
 	}
 	if (argc > 3)
Index: uspace/dist/src/c/demos/tetris/screen.c
===================================================================
--- uspace/dist/src/c/demos/tetris/screen.c	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/dist/src/c/demos/tetris/screen.c	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -95,6 +95,6 @@
 {
 	console_flush(console);
-	console_set_rgb_color(console, 0xffffff,
-	    use_color ? color : 0x000000);
+	console_set_rgb_color(console, use_color ? color : 0x000000,
+	    0xffffff);
 }
 
@@ -153,5 +153,5 @@
 		return false;
 	
-	return (ccap >= CONSOLE_CCAP_RGB);
+	return ((ccap & CONSOLE_CAP_RGB) == CONSOLE_CAP_RGB);
 }
 
Index: uspace/drv/bus/pci/pciintel/pci.c
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.c	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/drv/bus/pci/pciintel/pci.c	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -78,4 +78,7 @@
 #define PCI_BUS_FROM_FUN(fun) ((fun)->busptr)
 
+/** Max is 47, align to something nice. */
+#define ID_MAX_STR_LEN 50
+
 static hw_resource_list_t *pciintel_get_resources(ddf_fun_t *fnode)
 {
@@ -225,6 +228,5 @@
 	fibril_mutex_lock(&bus->conf_mutex);
 	
-	uint32_t conf_addr;
-	conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
+	const uint32_t conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
 	void *addr = bus->conf_data_port + (reg & 3);
 	
@@ -311,24 +313,76 @@
 void pci_fun_create_match_ids(pci_fun_t *fun)
 {
-	char *match_id_str;
 	int rc;
-	
-	asprintf(&match_id_str, "pci/ven=%04x&dev=%04x",
+	char match_id_str[ID_MAX_STR_LEN];
+
+	/* Vendor ID & Device ID, length(incl \0) 22 */
+	rc = snprintf(match_id_str, ID_MAX_STR_LEN, "pci/ven=%04x&dev=%04x",
 	    fun->vendor_id, fun->device_id);
-
-	if (match_id_str == NULL) {
-		ddf_msg(LVL_ERROR, "Out of memory creating match ID.");
-		return;
+	if (rc < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
+		    str_error(rc));
 	}
 
 	rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 90);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed adding match ID: %s",
+		ddf_msg(LVL_ERROR, "Failed adding match ID: %s", str_error(rc));
+	}
+
+	/* Class, subclass, prog IF, revision, length(incl \0) 47 */
+	rc = snprintf(match_id_str, ID_MAX_STR_LEN,
+	    "pci/class=%02x&subclass=%02x&progif=%02x&revision=%02x",
+	    fun->class_code, fun->subclass_code, fun->prog_if, fun->revision);
+	if (rc < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
 		    str_error(rc));
 	}
-	
-	free(match_id_str);
-	
-	/* TODO add more ids (with subsys ids, using class id etc.) */
+
+	rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 70);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed adding match ID: %s", str_error(rc));
+	}
+
+	/* Class, subclass, prog IF, length(incl \0) 35 */
+	rc = snprintf(match_id_str, ID_MAX_STR_LEN,
+	    "pci/class=%02x&subclass=%02x&progif=%02x",
+	    fun->class_code, fun->subclass_code, fun->prog_if);
+	if (rc < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
+		    str_error(rc));
+	}
+
+	rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 60);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed adding match ID: %s", str_error(rc));
+	}
+
+	/* Class, subclass, length(incl \0) 25 */
+	rc = snprintf(match_id_str, ID_MAX_STR_LEN,
+	    "pci/class=%02x&subclass=%02x",
+	    fun->class_code, fun->subclass_code);
+	if (rc < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
+		    str_error(rc));
+	}
+
+	rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 50);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed adding match ID: %s", str_error(rc));
+	}
+
+	/* Class, length(incl \0) 13 */
+	rc = snprintf(match_id_str, ID_MAX_STR_LEN, "pci/class=%02x",
+	    fun->class_code);
+	if (rc < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
+		    str_error(rc));
+	}
+
+	rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 40);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed adding match ID: %s", str_error(rc));
+	}
+
+	/* TODO add subsys ids, but those exist only in header type 0 */
 }
 
@@ -481,8 +535,4 @@
 		for (fnum = 0; multi && fnum < 8; fnum++) {
 			pci_fun_init(fun, bus_num, dnum, fnum);
-			fun->vendor_id = pci_conf_read_16(fun,
-			    PCI_VENDOR_ID);
-			fun->device_id = pci_conf_read_16(fun,
-			    PCI_DEVICE_ID);
 			if (fun->vendor_id == 0xffff) {
 				/*
@@ -511,4 +561,5 @@
 			
 			fnode = ddf_fun_create(bus->dnode, fun_inner, fun_name);
+			free(fun_name);
 			if (fnode == NULL) {
 				ddf_msg(LVL_ERROR, "Failed creating function.");
@@ -516,5 +567,4 @@
 			}
 			
-			free(fun_name);
 			fun->fnode = fnode;
 			
@@ -691,4 +741,10 @@
 	fun->dev = dev;
 	fun->fn = fn;
+	fun->vendor_id = pci_conf_read_16(fun, PCI_VENDOR_ID);
+	fun->device_id = pci_conf_read_16(fun, PCI_DEVICE_ID);
+	fun->class_code = pci_conf_read_8(fun, PCI_BASE_CLASS);
+	fun->subclass_code = pci_conf_read_8(fun, PCI_SUB_CLASS);
+	fun->prog_if = pci_conf_read_8(fun, PCI_PROG_IF);
+	fun->revision = pci_conf_read_8(fun, PCI_REVISION_ID);
 }
 
@@ -711,15 +767,11 @@
 bool pci_alloc_resource_list(pci_fun_t *fun)
 {
-	fun->hw_resources.resources =
-	    (hw_resource_t *) malloc(PCI_MAX_HW_RES * sizeof(hw_resource_t));
-	return fun->hw_resources.resources != NULL;
+	fun->hw_resources.resources = fun->resources;
+	return true;
 }
 
 void pci_clean_resource_list(pci_fun_t *fun)
 {
-	if (fun->hw_resources.resources != NULL) {
-		free(fun->hw_resources.resources);
-		fun->hw_resources.resources = NULL;
-	}
+	fun->hw_resources.resources = NULL;
 }
 
Index: uspace/drv/bus/pci/pciintel/pci.h
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.h	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/drv/bus/pci/pciintel/pci.h	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -60,5 +60,10 @@
 	int vendor_id;
 	int device_id;
+	uint8_t class_code;
+	uint8_t subclass_code;
+	uint8_t prog_if;
+	uint8_t revision;
 	hw_resource_list_t hw_resources;
+	hw_resource_t resources[PCI_MAX_HW_RES];
 } pci_fun_t;
 
Index: uspace/lib/c/generic/str.c
===================================================================
--- uspace/lib/c/generic/str.c	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/lib/c/generic/str.c	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -839,4 +839,58 @@
 	
 	return NULL;
+}
+
+/** Removes specified trailing characters from a string.
+ *
+ * @param str String to remove from.
+ * @param ch  Character to remove.
+ */
+void str_rtrim(char *str, wchar_t ch)
+{
+	size_t off = 0;
+	size_t pos = 0;
+	wchar_t c;
+	bool update_last_chunk = true;
+	char *last_chunk = NULL;
+
+	while ((c = str_decode(str, &off, STR_NO_LIMIT))) {
+		if (c != ch) {
+			update_last_chunk = true;
+			last_chunk = NULL;
+		} else if (update_last_chunk) {
+			update_last_chunk = false;
+			last_chunk = (str + pos);
+		}
+		pos = off;
+	}
+
+	if (last_chunk)
+		*last_chunk = '\0';
+}
+
+/** Removes specified leading characters from a string.
+ *
+ * @param str String to remove from.
+ * @param ch  Character to remove.
+ */
+void str_ltrim(char *str, wchar_t ch)
+{
+	wchar_t acc;
+	size_t off = 0;
+	size_t pos = 0;
+	size_t str_sz = str_size(str);
+
+	while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
+		if (acc != ch)
+			break;
+		else
+			pos = off;
+	}
+
+	if (pos > 0) {
+		memmove(str, &str[pos], str_sz - pos);
+		pos = str_sz - pos;
+		str[str_sz - pos] = '\0';
+	}
 }
 
Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -831,4 +831,65 @@
 }
 
+int get_mtab_list(list_t *mtab_list)
+{
+	sysarg_t rc;
+	aid_t req;
+	size_t i;
+	sysarg_t num_mounted_fs;
+	
+	async_exch_t *exch = vfs_exchange_begin();
+
+	req = async_send_0(exch, VFS_IN_MTAB_GET, NULL);
+
+	/* Ask VFS how many filesystems are mounted */
+	rc = async_req_0_1(exch, VFS_IN_PING, &num_mounted_fs);
+	if (rc != EOK)
+		goto exit;
+
+	for (i = 0; i < num_mounted_fs; ++i) {
+		mtab_ent_t *mtab_ent;
+
+		mtab_ent = malloc(sizeof(mtab_ent_t));
+		if (!mtab_ent) {
+			rc = ENOMEM;
+			goto exit;
+		}
+
+		memset(mtab_ent, 0, sizeof(mtab_ent_t));
+
+		rc = async_data_read_start(exch, (void *) mtab_ent->mp,
+		    MAX_PATH_LEN);
+		if (rc != EOK)
+			goto exit;
+
+		rc = async_data_read_start(exch, (void *) mtab_ent->opts,
+			MAX_MNTOPTS_LEN);
+		if (rc != EOK)
+			goto exit;
+
+		rc = async_data_read_start(exch, (void *) mtab_ent->fs_name,
+			FS_NAME_MAXLEN);
+		if (rc != EOK)
+			goto exit;
+
+		sysarg_t p[2];
+
+		rc = async_req_0_2(exch, VFS_IN_PING, &p[0], &p[1]);
+		if (rc != EOK)
+			goto exit;
+
+		mtab_ent->instance = p[0];
+		mtab_ent->service_id = p[1];
+
+		link_initialize(&mtab_ent->link);
+		list_append(&mtab_ent->link, mtab_list);
+	}
+
+exit:
+	async_wait_for(req, &rc);
+	vfs_exchange_end(exch);
+	return rc;
+}
+
 /** @}
  */
Index: uspace/lib/c/include/ipc/vfs.h
===================================================================
--- uspace/lib/c/include/ipc/vfs.h	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/lib/c/include/ipc/vfs.h	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -42,4 +42,5 @@
 #define FS_NAME_MAXLEN  20
 #define MAX_PATH_LEN    (64 * 1024)
+#define MAX_MNTOPTS_LEN 256
 #define PLB_SIZE        (2 * MAX_PATH_LEN)
 
@@ -80,4 +81,5 @@
 	VFS_IN_DUP,
 	VFS_IN_WAIT_HANDLE,
+	VFS_IN_MTAB_GET,
 } vfs_in_request_t;
 
Index: uspace/lib/c/include/str.h
===================================================================
--- uspace/lib/c/include/str.h	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/lib/c/include/str.h	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -91,4 +91,7 @@
 extern char *str_rchr(const char *str, wchar_t ch);
 
+extern void str_rtrim(char *str, wchar_t ch);
+extern void str_ltrim(char *str, wchar_t ch);
+
 extern bool wstr_linsert(wchar_t *str, wchar_t ch, size_t pos, size_t max_pos);
 extern bool wstr_remove(wchar_t *str, size_t pos);
Index: uspace/lib/c/include/vfs/vfs.h
===================================================================
--- uspace/lib/c/include/vfs/vfs.h	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/lib/c/include/vfs/vfs.h	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -39,6 +39,8 @@
 #include <ipc/vfs.h>
 #include <ipc/loc.h>
+#include <adt/list.h>
 #include <stdio.h>
 #include <async.h>
+#include "vfs_mtab.h"
 
 enum vfs_change_state_type {
@@ -55,4 +57,5 @@
 
 extern int fd_wait(void);
+extern int get_mtab_list(list_t *mtab_list);
 
 extern async_exch_t *vfs_exchange_begin(void);
Index: uspace/lib/c/include/vfs/vfs_mtab.h
===================================================================
--- uspace/lib/c/include/vfs/vfs_mtab.h	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
+++ uspace/lib/c/include/vfs/vfs_mtab.h	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_VFS_MTAB_H_
+#define LIBC_VFS_MTAB_H_
+
+#include <sys/types.h>
+#include <ipc/vfs.h>
+#include <adt/list.h>
+
+typedef struct mtab_ent {
+	link_t link;
+	char mp[MAX_PATH_LEN];
+	char opts[MAX_MNTOPTS_LEN];
+	char fs_name[FS_NAME_MAXLEN];
+	unsigned int instance;
+	service_id_t service_id;
+} mtab_ent_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/lib/drv/generic/driver.c	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -970,5 +970,5 @@
 	
 	match_id->id = str_dup(match_id_str);
-	match_id->score = 90;
+	match_id->score = match_score;
 	
 	add_match_id(&fun->match_ids, match_id);
Index: uspace/srv/fs/mfs/mfs_ops.c
===================================================================
--- uspace/srv/fs/mfs/mfs_ops.c	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/srv/fs/mfs/mfs_ops.c	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -384,9 +384,7 @@
 	if (flags & L_DIRECTORY) {
 		ino_i->i_mode = S_IFDIR;
-		ino_i->i_nlinks = 2; /* This accounts for the '.' dentry */
-	} else {
+		ino_i->i_nlinks = 1; /* This accounts for the '.' dentry */
+	} else
 		ino_i->i_mode = S_IFREG;
-		ino_i->i_nlinks = 1;
-	}
 
 	ino_i->i_uid = 0;
@@ -675,4 +673,7 @@
 	if (r != EOK)
 		goto exit_error;
+
+	child->ino_i->i_nlinks++;
+	child->ino_i->dirty = true;
 
 	if (S_ISDIR(child->ino_i->i_mode)) {
Index: uspace/srv/hw/irc/apic/apic.c
===================================================================
--- uspace/srv/hw/irc/apic/apic.c	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/srv/hw/irc/apic/apic.c	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -133,4 +133,6 @@
 	// FIXME: get the map from the kernel, even though this may work
 	//	  for simple cases
+	if (irq == 0)
+		return 2;
 	return irq;
 }
Index: uspace/srv/vfs/vfs.c
===================================================================
--- uspace/srv/vfs/vfs.c	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/srv/vfs/vfs.c	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -127,4 +127,7 @@
 			vfs_wait_handle(callid, &call);
 			break;
+		case VFS_IN_MTAB_GET:
+			vfs_get_mtab(callid, &call);
+			break;
 		default:
 			async_answer_0(callid, ENOTSUP);
Index: uspace/srv/vfs/vfs.h
===================================================================
--- uspace/srv/vfs/vfs.h	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/srv/vfs/vfs.h	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -150,4 +150,7 @@
 extern list_t fs_list;		/**< List of registered file systems. */
 
+extern fibril_mutex_t fs_mntlist_lock;
+extern list_t fs_mntlist;	/**< List of mounted file systems. */
+
 extern vfs_pair_t rootfs;	/**< Root file system. */
 
@@ -162,6 +165,4 @@
 extern uint8_t *plb;		/**< Path Lookup Buffer */
 extern list_t plb_entries;	/**< List of active PLB entries. */
-
-#define MAX_MNTOPTS_LEN		256
 
 /** Holding this rwlock prevents changes in file system namespace. */ 
@@ -219,4 +220,5 @@
 extern void vfs_rename(ipc_callid_t, ipc_call_t *);
 extern void vfs_wait_handle(ipc_callid_t, ipc_call_t *);
+extern void vfs_get_mtab(ipc_callid_t, ipc_call_t *);
 
 #endif
Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision a0c05e778cae904b5aac957ac135bc7796aab364)
+++ uspace/srv/vfs/vfs_ops.c	(revision 45e78687c8f458584cd1e9a8882ce8b6e7371adc)
@@ -52,4 +52,9 @@
 #include <assert.h>
 #include <vfs/canonify.h>
+#include <vfs/vfs_mtab.h>
+
+FIBRIL_MUTEX_INITIALIZE(mtab_list_lock);
+LIST_INITIALIZE(mtab_list);
+static size_t mtab_size = 0;
 
 /* Forward declarations of static functions. */
@@ -68,5 +73,5 @@
 };
 
-static void vfs_mount_internal(ipc_callid_t rid, service_id_t service_id,
+static int vfs_mount_internal(ipc_callid_t rid, service_id_t service_id,
     fs_handle_t fs_handle, char *mp, char *opts)
 {
@@ -91,5 +96,5 @@
 			fibril_rwlock_write_unlock(&namespace_rwlock);
 			async_answer_0(rid, EBUSY);
-			return;
+			return EBUSY;
 		}
 		
@@ -99,5 +104,5 @@
 			fibril_rwlock_write_unlock(&namespace_rwlock);
 			async_answer_0(rid, rc);
-			return;
+			return rc;
 		}
 		
@@ -106,5 +111,5 @@
 			fibril_rwlock_write_unlock(&namespace_rwlock);
 			async_answer_0(rid, ENOMEM);
-			return;
+			return ENOMEM;
 		}
 		
@@ -135,5 +140,5 @@
 				fibril_rwlock_write_unlock(&namespace_rwlock);
 				async_answer_0(rid, rc);
-				return;
+				return rc;
 			}
 			async_wait_for(msg, &rc);
@@ -142,5 +147,5 @@
 				fibril_rwlock_write_unlock(&namespace_rwlock);
 				async_answer_0(rid, rc);
-				return;
+				return rc;
 			}
 
@@ -166,5 +171,5 @@
 			fibril_rwlock_write_unlock(&namespace_rwlock);
 			async_answer_0(rid, rc);
-			return;
+			return rc;
 		} else {
 			/*
@@ -174,5 +179,5 @@
 			fibril_rwlock_write_unlock(&namespace_rwlock);
 			async_answer_0(rid, ENOENT);
-			return;
+			return ENOENT;
 		}
 	}
@@ -207,5 +212,5 @@
 		async_answer_0(rid, rc);
 		fibril_rwlock_write_unlock(&namespace_rwlock);
-		return;
+		return rc;
 	}
 	
@@ -222,5 +227,5 @@
 		fibril_rwlock_write_unlock(&namespace_rwlock);
 		async_answer_0(rid, rc);
-		return;
+		return rc;
 	}
 	
@@ -258,4 +263,5 @@
 	async_answer_0(rid, rc);
 	fibril_rwlock_write_unlock(&namespace_rwlock);
+	return rc;
 }
 
@@ -352,13 +358,49 @@
 	}
 	fibril_mutex_unlock(&fs_list_lock);
-	
-	/* Acknowledge that we know fs_name. */
-	async_answer_0(callid, EOK);
-	
+
+	/* Add the filesystem info to the list of mounted filesystems */
+	mtab_ent_t *mtab_ent = malloc(sizeof(mtab_ent_t));
+	if (!mtab_ent) {
+		async_answer_0(callid, ENOMEM);
+		async_answer_0(rid, ENOMEM);
+		free(mp);
+		free(fs_name);
+		free(opts);
+		return;
+	}
+
 	/* Do the mount */
-	vfs_mount_internal(rid, service_id, fs_handle, mp, opts);
+	rc = vfs_mount_internal(rid, service_id, fs_handle, mp, opts);
+	if (rc != EOK) {
+		async_answer_0(callid, ENOTSUP);
+		async_answer_0(rid, ENOTSUP);
+		free(mtab_ent);
+		free(mp);
+		free(opts);
+		free(fs_name);
+		return;
+	}
+
+	/* Add the filesystem info to the list of mounted filesystems */
+
+	str_cpy(mtab_ent->mp, MAX_PATH_LEN, mp);
+	str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name);
+	str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts);
+	mtab_ent->instance = instance;
+	mtab_ent->service_id = service_id;
+
+	link_initialize(&mtab_ent->link);
+
+	fibril_mutex_lock(&mtab_list_lock);
+	list_append(&mtab_ent->link, &mtab_list);
+	mtab_size++;
+	fibril_mutex_unlock(&mtab_list_lock);
+
 	free(mp);
 	free(fs_name);
 	free(opts);
+
+	/* Acknowledge that we know fs_name. */
+	async_answer_0(callid, EOK);
 }
 
@@ -433,6 +475,4 @@
 		 */
 		
-		free(mp);
-		
 		exch = vfs_exchange_grab(mr_node->fs_handle);
 		rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
@@ -442,4 +482,5 @@
 		if (rc != EOK) {
 			fibril_rwlock_write_unlock(&namespace_rwlock);
+			free(mp);
 			vfs_node_put(mr_node);
 			async_answer_0(rid, rc);
@@ -459,7 +500,7 @@
 		
 		rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
-		free(mp);
 		if (rc != EOK) {
 			fibril_rwlock_write_unlock(&namespace_rwlock);
+			free(mp);
 			vfs_node_put(mr_node);
 			async_answer_0(rid, rc);
@@ -470,4 +511,5 @@
 		if (!mp_node) {
 			fibril_rwlock_write_unlock(&namespace_rwlock);
+			free(mp);
 			vfs_node_put(mr_node);
 			async_answer_0(rid, ENOMEM);
@@ -482,4 +524,5 @@
 		if (rc != EOK) {
 			fibril_rwlock_write_unlock(&namespace_rwlock);
+			free(mp);
 			vfs_node_put(mp_node);
 			vfs_node_put(mr_node);
@@ -499,6 +542,27 @@
 	 */
 	vfs_node_forget(mr_node);
-	
 	fibril_rwlock_write_unlock(&namespace_rwlock);
+
+	fibril_mutex_lock(&mtab_list_lock);
+
+	int found = 0;
+
+	list_foreach(mtab_list, cur) {
+		mtab_ent_t *mtab_ent = list_get_instance(cur, mtab_ent_t,
+		    link);
+
+		if (str_cmp(mtab_ent->mp, mp) == 0) {
+			list_remove(&mtab_ent->link);
+			mtab_size--;
+			free(mtab_ent);
+			found = 1;
+			break;
+		}
+	}
+	assert(found);
+	fibril_mutex_unlock(&mtab_list_lock);
+
+	free(mp);
+
 	async_answer_0(rid, EOK);
 }
@@ -1289,4 +1353,69 @@
 }
 
+void vfs_get_mtab(ipc_callid_t rid, ipc_call_t *request)
+{
+	ipc_callid_t callid;
+	ipc_call_t data;
+	sysarg_t rc = EOK;
+	size_t len;
+
+	fibril_mutex_lock(&mtab_list_lock);
+
+	/* Send to the caller the number of mounted filesystems */
+	callid = async_get_call(&data);
+	if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
+		rc = ENOTSUP;
+		async_answer_0(callid, rc);
+		goto exit;
+	}
+	async_answer_1(callid, EOK, mtab_size);
+
+	list_foreach(mtab_list, cur) {
+		mtab_ent_t *mtab_ent = list_get_instance(cur, mtab_ent_t,
+		    link);
+
+		rc = ENOTSUP;
+
+		if (!async_data_read_receive(&callid, &len)) {
+			async_answer_0(callid, rc);
+			goto exit;
+		}
+
+		(void) async_data_read_finalize(callid, mtab_ent->mp,
+		    str_size(mtab_ent->mp));
+
+		if (!async_data_read_receive(&callid, &len)) {
+			async_answer_0(callid, rc);
+			goto exit;
+		}
+
+		(void) async_data_read_finalize(callid, mtab_ent->opts,
+		    str_size(mtab_ent->opts));
+
+		if (!async_data_read_receive(&callid, &len)) {
+			async_answer_0(callid, rc);
+			goto exit;
+		}
+
+		(void) async_data_read_finalize(callid, mtab_ent->fs_name,
+		    str_size(mtab_ent->fs_name));
+
+		callid = async_get_call(&data);
+
+		if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
+			async_answer_0(callid, rc);
+			goto exit;
+		}
+
+		rc = EOK;
+		async_answer_2(callid, rc, mtab_ent->instance,
+		    mtab_ent->service_id);
+	}
+
+exit:
+	fibril_mutex_unlock(&mtab_list_lock);
+	async_answer_0(rid, rc);
+}
+
 /**
  * @}
