Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision ee9c70363c6e7323102757dbe583add594ffef53)
+++ uspace/app/init/init.c	(revision 63c1dd5baed77410998be60405abb3b36a7a56b3)
@@ -47,4 +47,5 @@
 #include <config.h>
 #include <io/logctl.h>
+#include <vol.h>
 #include "untar.h"
 #include "init.h"
@@ -70,4 +71,9 @@
 #define srv_start(path, ...) \
 	srv_startl(path, path, ##__VA_ARGS__, NULL)
+
+static const char *sys_dirs[] = {
+	"/w/cfg",
+	"/w/data"
+};
 
 /** Print banner */
@@ -320,4 +326,78 @@
 }
 
+/** Init system volume.
+ *
+ * See if system volume is configured. If so, try to wait for it to become
+ * available. If not, create basic directories for live image omde.
+ */
+static errno_t init_sysvol(void)
+{
+	vol_t *vol = NULL;
+	vol_info_t vinfo;
+	volume_id_t *volume_ids = NULL;
+	size_t nvols;
+	size_t i;
+	errno_t rc;
+	bool found_cfg;
+	const char **cp;
+
+	rc = vol_create(&vol);
+	if (rc != EOK) {
+		printf("Error contacting volume service.\n");
+		goto error;
+	}
+
+	rc = vol_get_volumes(vol, &volume_ids, &nvols);
+	if (rc != EOK) {
+		printf("Error getting list of volumes.\n");
+		goto error;
+	}
+
+	/* XXX This could be handled more efficiently by volsrv itself */
+	found_cfg = false;
+	for (i = 0; i < nvols; i++) {
+		rc = vol_info(vol, volume_ids[i], &vinfo);
+		if (rc != EOK) {
+			printf("Error getting volume information.\n");
+			rc = EIO;
+			goto error;
+		}
+
+		if (str_cmp(vinfo.path, "/w") == 0) {
+			found_cfg = true;
+			break;
+		}
+	}
+
+	vol_destroy(vol);
+	free(volume_ids);
+
+	if (!found_cfg) {
+		/* Prepare directory structure for live image mode */
+		printf("%s: Creating live image directory structure.\n", NAME);
+		cp = sys_dirs;
+		while (*cp != NULL) {
+			rc = vfs_link_path(*cp, KIND_DIRECTORY, NULL);
+			if (rc != EOK) {
+				printf("%s: Error creating directory '%s'.\n",
+				    NAME, *cp);
+				return rc;
+			}
+
+			++cp;
+		}
+	} else {
+		printf("%s: System volume is configured.\n", NAME);
+	}
+
+	return EOK;
+error:
+	vol_destroy(vol);
+	if (volume_ids != NULL)
+		free(volume_ids);
+
+	return rc;
+}
+
 int main(int argc, char *argv[])
 {
@@ -375,4 +455,6 @@
 	srv_start("/srv/hound");
 
+	init_sysvol();
+
 	if (!config_key_exists("console")) {
 		rc = compositor(HID_INPUT, HID_COMPOSITOR_SERVER);
Index: uspace/app/sysinst/sysinst.c
===================================================================
--- uspace/app/sysinst/sysinst.c	(revision ee9c70363c6e7323102757dbe583add594ffef53)
+++ uspace/app/sysinst/sysinst.c	(revision 63c1dd5baed77410998be60405abb3b36a7a56b3)
@@ -79,4 +79,9 @@
 #define BOOT_BLOCK_IDX 0 /* MBR */
 
+static const char *sys_dirs[] = {
+	"/cfg",
+	"/data"
+};
+
 /** Label the destination device.
  *
@@ -160,4 +165,44 @@
 	*psvc_id = pinfo.svc_id;
 	return EOK;
+}
+
+/** Set up system volume structure.
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t sysinst_setup_sysvol(void)
+{
+	errno_t rc;
+	char *path = NULL;
+	const char **cp;
+	int rv;
+
+	cp = sys_dirs;
+	while (*cp != NULL) {
+		rv = asprintf(&path, "%s%s", MOUNT_POINT, *cp);
+		if (rv < 0) {
+			rc = ENOMEM;
+			goto error;
+		}
+
+		rc = vfs_link_path(path, KIND_DIRECTORY, NULL);
+		if (rc != EOK) {
+			printf("Error creating directory '%s'.\n", path);
+			goto error;
+		}
+
+		free(path);
+		path = NULL;
+		++cp;
+	}
+
+	free(path);
+	path = NULL;
+
+	return EOK;
+error:
+	if (path != NULL)
+		free(path);
+	return rc;
 }
 
@@ -415,5 +460,10 @@
 		return rc;
 
-	printf("FS created and mounted. Copying boot files.\n");
+	printf("FS created and mounted. Creating system directory structure.\n");
+	rc = sysinst_setup_sysvol();
+	if (rc != EOK)
+		return rc;
+
+	printf("Directories created. Copying boot files.\n");
 	rc = sysinst_copy_boot_files();
 	if (rc != EOK)
Index: uspace/app/tetris/scores.c
===================================================================
--- uspace/app/tetris/scores.c	(revision ee9c70363c6e7323102757dbe583add594ffef53)
+++ uspace/app/tetris/scores.c	(revision 63c1dd5baed77410998be60405abb3b36a7a56b3)
@@ -212,5 +212,5 @@
 	int rc;
 
-	f = fopen("/data/tetris.sco", "rb");
+	f = fopen("/w/data/tetris.sco", "rb");
 	if (f == NULL)
 		return ENOENT;
@@ -231,5 +231,5 @@
 	int rc;
 
-	f = fopen("/data/tetris.sco", "wb");
+	f = fopen("/w/data/tetris.sco", "wb");
 	if (f == NULL) {
 		printf("Error creating table\n");
Index: uspace/app/vol/vol.c
===================================================================
--- uspace/app/vol/vol.c	(revision ee9c70363c6e7323102757dbe583add594ffef53)
+++ uspace/app/vol/vol.c	(revision 63c1dd5baed77410998be60405abb3b36a7a56b3)
@@ -49,4 +49,5 @@
 	vcmd_help,
 	vcmd_list,
+	vcmd_cfglist,
 } vol_cmd_t;
 
@@ -239,8 +240,65 @@
 }
 
+/** List volume configuration entries.
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t vol_cmd_cfglist(void)
+{
+	vol_t *vol = NULL;
+	vol_info_t vinfo;
+	volume_id_t *volume_ids = NULL;
+	size_t nvols;
+	size_t i;
+	table_t *table = NULL;
+	errno_t rc;
+
+	rc = vol_create(&vol);
+	if (rc != EOK) {
+		printf("Error contacting volume service.\n");
+		goto out;
+	}
+
+	rc = vol_get_volumes(vol, &volume_ids, &nvols);
+	if (rc != EOK) {
+		printf("Error getting list of volumes.\n");
+		goto out;
+	}
+
+	rc = table_create(&table);
+	if (rc != EOK) {
+		printf("Out of memory.\n");
+		goto out;
+	}
+
+	table_header_row(table);
+	table_printf(table, "Volume Name\t" "Path\n");
+
+	for (i = 0; i < nvols; i++) {
+		rc = vol_info(vol, volume_ids[i], &vinfo);
+		if (rc != EOK) {
+			printf("Error getting volume information.\n");
+			return EIO;
+		}
+
+		table_printf(table, "%s\t" "%s\n", vinfo.label, vinfo.path);
+	}
+
+	rc = table_print_out(table, stdout);
+	if (rc != EOK)
+		printf("Error printing table.\n");
+out:
+	table_destroy(table);
+	vol_destroy(vol);
+	free(volume_ids);
+
+	return rc;
+}
+
 static void print_syntax(void)
 {
 	printf("Syntax:\n");
-	printf("  %s                List volumes\n", NAME);
+	printf("  %s                List present volumes\n", NAME);
+	printf("  %s -c             List volume configuration entries\n", NAME);
 	printf("  %s -h             Print help\n", NAME);
 	printf("  %s eject <mp>     Eject volume mounted in a directory\n", NAME);
@@ -264,4 +322,6 @@
 		if (str_cmp(cmd, "-h") == 0) {
 			vcmd = vcmd_help;
+		} else if (str_cmp(cmd, "-c") == 0) {
+			vcmd = vcmd_cfglist;
 		} else if (str_cmp(cmd, "eject") == 0) {
 			vcmd = vcmd_eject;
@@ -303,4 +363,7 @@
 		rc = vol_cmd_list();
 		break;
+	case vcmd_cfglist:
+		rc = vol_cmd_cfglist();
+		break;
 	}
 
Index: uspace/lib/c/generic/vol.c
===================================================================
--- uspace/lib/c/generic/vol.c	(revision ee9c70363c6e7323102757dbe583add594ffef53)
+++ uspace/lib/c/generic/vol.c	(revision 63c1dd5baed77410998be60405abb3b36a7a56b3)
@@ -528,4 +528,48 @@
 }
 
+/** Get list of volumes as array of volume IDs.
+ *
+ * @param vol Volume service
+ * @param data Place to store pointer to array
+ * @param count Place to store length of array (number of entries)
+ *
+ * @return EOK on success or an error code
+ */
+errno_t vol_get_volumes(vol_t *vol, volume_id_t **data, size_t *count)
+{
+	return vol_get_ids_internal(vol, VOL_GET_VOLUMES, 0,
+	    (sysarg_t **) data, count);
+}
+
+/** Get volume configuration information.
+ *
+ * @param vol Volume service
+ * @param vid Volume ID
+ * @param vinfo Place to sore volume configuration information
+ * @return EOK on success or an error code
+ */
+errno_t vol_info(vol_t *vol, volume_id_t vid, vol_info_t *vinfo)
+{
+	async_exch_t *exch;
+	errno_t retval;
+	ipc_call_t answer;
+
+	exch = async_exchange_begin(vol->sess);
+	aid_t req = async_send_1(exch, VOL_INFO, vid.id, &answer);
+
+	errno_t rc = async_data_read_start(exch, vinfo, sizeof(vol_info_t));
+	async_exchange_end(exch);
+	if (rc != EOK) {
+		async_forget(req);
+		return EIO;
+	}
+
+	async_wait_for(req, &retval);
+	if (retval != EOK)
+		return EIO;
+
+	return EOK;
+}
+
 /** @}
  */
Index: uspace/lib/c/include/ipc/vol.h
===================================================================
--- uspace/lib/c/include/ipc/vol.h	(revision ee9c70363c6e7323102757dbe583add594ffef53)
+++ uspace/lib/c/include/ipc/vol.h	(revision 63c1dd5baed77410998be60405abb3b36a7a56b3)
@@ -48,5 +48,7 @@
 	VOL_PART_LSUPP,
 	VOL_PART_MKFS,
-	VOL_PART_SET_MOUNTP
+	VOL_PART_SET_MOUNTP,
+	VOL_GET_VOLUMES,
+	VOL_INFO
 } vol_request_t;
 
Index: uspace/lib/c/include/types/vol.h
===================================================================
--- uspace/lib/c/include/types/vol.h	(revision ee9c70363c6e7323102757dbe583add594ffef53)
+++ uspace/lib/c/include/types/vol.h	(revision 63c1dd5baed77410998be60405abb3b36a7a56b3)
@@ -41,4 +41,8 @@
 #include <stdbool.h>
 
+typedef struct {
+	sysarg_t id;
+} volume_id_t;
+
 typedef enum {
 	/** Partition is empty */
@@ -82,4 +86,14 @@
 } vol_part_info_t;
 
+/** Volume configuration information */
+typedef struct {
+	/** Volume identifier */
+	volume_id_t id;
+	/** Volume label */
+	char label[VOL_LABEL_MAXLEN + 1];
+	/** Mount path */
+	char path[MAX_PATH_LEN + 1]; /* XXX too big */
+} vol_info_t;
+
 /** Volume label support */
 typedef struct {
Index: uspace/lib/c/include/vol.h
===================================================================
--- uspace/lib/c/include/vol.h	(revision ee9c70363c6e7323102757dbe583add594ffef53)
+++ uspace/lib/c/include/vol.h	(revision 63c1dd5baed77410998be60405abb3b36a7a56b3)
@@ -55,5 +55,6 @@
     const char *);
 extern errno_t vol_part_set_mountp(vol_t *, service_id_t, const char *);
-
+extern errno_t vol_get_volumes(vol_t *, volume_id_t **, size_t *);
+extern errno_t vol_info(vol_t *, volume_id_t, vol_info_t *);
 extern errno_t vol_fstype_format(vol_fstype_t, char **);
 extern errno_t vol_pcnt_fs_format(vol_part_cnt_t, vol_fstype_t, char **);
Index: uspace/srv/volsrv/types/volume.h
===================================================================
--- uspace/srv/volsrv/types/volume.h	(revision ee9c70363c6e7323102757dbe583add594ffef53)
+++ uspace/srv/volsrv/types/volume.h	(revision 63c1dd5baed77410998be60405abb3b36a7a56b3)
@@ -49,4 +49,6 @@
 	/** Link to vol_volumes */
 	link_t lvolumes;
+	/** ID used by clients to refer to the volume */
+	volume_id_t id;
 	/** Reference count */
 	atomic_refcount_t refcnt;
@@ -69,4 +71,6 @@
 	/** Volumes SIF node */
 	sif_node_t *nvolumes;
+	/** Next ID */
+	sysarg_t next_id;
 } vol_volumes_t;
 
Index: uspace/srv/volsrv/volsrv.c
===================================================================
--- uspace/srv/volsrv/volsrv.c	(revision ee9c70363c6e7323102757dbe583add594ffef53)
+++ uspace/srv/volsrv/volsrv.c	(revision 63c1dd5baed77410998be60405abb3b36a7a56b3)
@@ -419,4 +419,91 @@
 }
 
+static void vol_get_volumes_srv(vol_parts_t *parts, ipc_call_t *icall)
+{
+	ipc_call_t call;
+	size_t size;
+	size_t act_size;
+	errno_t rc;
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "vol_get_volumes_srv()");
+
+	if (!async_data_read_receive(&call, &size)) {
+		async_answer_0(&call, EREFUSED);
+		async_answer_0(icall, EREFUSED);
+		return;
+	}
+
+	volume_id_t *id_buf = (volume_id_t *) malloc(size);
+	if (id_buf == NULL) {
+		async_answer_0(&call, ENOMEM);
+		async_answer_0(icall, ENOMEM);
+		return;
+	}
+
+	rc = vol_get_ids(parts->volumes, id_buf, size, &act_size);
+	if (rc != EOK) {
+		async_answer_0(&call, rc);
+		async_answer_0(icall, rc);
+		return;
+	}
+
+	errno_t retval = async_data_read_finalize(&call, id_buf, size);
+	free(id_buf);
+
+	async_answer_1(icall, retval, act_size);
+}
+
+static void vol_info_srv(vol_parts_t *parts, ipc_call_t *icall)
+{
+	volume_id_t vid;
+	vol_volume_t *volume;
+	vol_info_t vinfo;
+	errno_t rc;
+
+	vid.id = IPC_GET_ARG1(*icall);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_info_srv(%zu)", vid.id);
+
+	rc = vol_volume_find_by_id_ref(parts->volumes, vid, &volume);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_info_srv: volume %zu not found",
+		    vid.id);
+		async_answer_0(icall, ENOENT);
+		return;
+	}
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_info_srv: vol_volume_get_info");
+	rc = vol_volume_get_info(volume, &vinfo);
+	if (rc != EOK) {
+		async_answer_0(icall, EIO);
+		goto error;
+	}
+
+	ipc_call_t call;
+	size_t size;
+	if (!async_data_read_receive(&call, &size)) {
+		async_answer_0(&call, EREFUSED);
+		async_answer_0(icall, EREFUSED);
+		goto error;
+	}
+
+	if (size != sizeof(vol_info_t)) {
+		async_answer_0(&call, EINVAL);
+		async_answer_0(icall, EINVAL);
+		goto error;
+	}
+
+	rc = async_data_read_finalize(&call, &vinfo,
+	    min(size, sizeof(vinfo)));
+	if (rc != EOK) {
+		async_answer_0(&call, rc);
+		async_answer_0(icall, rc);
+		goto error;
+	}
+
+	async_answer_0(icall, EOK);
+error:
+	vol_volume_del_ref(volume);
+}
+
 static void vol_client_conn(ipc_call_t *icall, void *arg)
 {
@@ -467,4 +554,10 @@
 			vol_part_set_mountp_srv(parts, &call);
 			break;
+		case VOL_GET_VOLUMES:
+			vol_get_volumes_srv(parts, &call);
+			break;
+		case VOL_INFO:
+			vol_info_srv(parts, &call);
+			break;
 		default:
 			async_answer_0(&call, EINVAL);
Index: uspace/srv/volsrv/volume.c
===================================================================
--- uspace/srv/volsrv/volume.c	(revision ee9c70363c6e7323102757dbe583add594ffef53)
+++ uspace/srv/volsrv/volume.c	(revision 63c1dd5baed77410998be60405abb3b36a7a56b3)
@@ -125,4 +125,5 @@
 	fibril_mutex_initialize(&volumes->lock);
 	list_initialize(&volumes->volumes);
+	volumes->next_id = 1;
 
 	/* Try opening existing repository */
@@ -222,4 +223,6 @@
 	volume->volumes = volumes;
 	list_append(&volume->lvolumes, &volumes->volumes);
+	volume->id.id = volumes->next_id;
+	++volumes->next_id;
 }
 
@@ -294,4 +297,56 @@
 }
 
+/** Find volume structure by ID with locked volumes lock.
+ * *
+ * @param volumes List of volumes
+ * @param vid Volume ID
+ * @param rvolume Place to store pointer to volume structure (existing or new)
+ *
+ * @return EOK on success, ENOENT if not found
+ */
+static errno_t vol_volume_find_by_id_ref_locked(vol_volumes_t *volumes,
+    volume_id_t vid, vol_volume_t **rvolume)
+{
+	assert(fibril_mutex_is_locked(&volumes->lock));
+
+	list_foreach(volumes->volumes, lvolumes, vol_volume_t, volume) {
+		log_msg(LOG_DEFAULT, LVL_DEBUG2,
+		    "vol_volume_find_by_id_ref_locked(%zu==%zu)?",
+		    volume->id.id, vid.id);
+		if (volume->id.id == vid.id) {
+			log_msg(LOG_DEFAULT, LVL_DEBUG2,
+			    "vol_volume_find_by_id_ref_locked: found");
+			/* Add reference */
+			refcount_up(&volume->refcnt);
+			*rvolume = volume;
+			return EOK;
+		}
+	}
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG2,
+	    "vol_volume_find_by_id_ref_locked: not found");
+	return ENOENT;
+}
+
+/** Find volume by ID.
+ *
+ * @param volumes Volumes
+ * @param vid Volume ID
+ * @param rvolume Place to store pointer to volume, with reference count
+ *                increased.
+ * @return EOK on success or an error code
+ */
+errno_t vol_volume_find_by_id_ref(vol_volumes_t *volumes, volume_id_t vid,
+    vol_volume_t **rvolume)
+{
+	errno_t rc;
+
+	fibril_mutex_lock(&volumes->lock);
+	rc = vol_volume_find_by_id_ref_locked(volumes, vid, rvolume);
+	fibril_mutex_unlock(&volumes->lock);
+
+	return rc;
+}
+
 /** Determine if volume has non-default settings that need to persist.
  *
@@ -416,4 +471,50 @@
 }
 
+/** Get list of volume IDs.
+ *
+ * Get the list of IDs of all persistent volumes (volume configuration
+ * entries).
+ *
+ * @param volumes Volumes
+ * @param id_buf Buffer to hold the IDs
+ * @param buf_size Buffer size in bytes
+ * @param act_size Place to store actual number bytes needed
+ * @return EOK on success or an error code
+ */
+errno_t vol_get_ids(vol_volumes_t *volumes, volume_id_t *id_buf,
+    size_t buf_size, size_t *act_size)
+{
+	size_t act_cnt;
+	size_t buf_cnt;
+
+	fibril_mutex_lock(&volumes->lock);
+
+	buf_cnt = buf_size / sizeof(volume_id_t);
+
+	act_cnt = 0;
+	list_foreach(volumes->volumes, lvolumes, vol_volume_t, volume) {
+		if (vol_volume_is_persist(volume))
+			++act_cnt;
+	}
+	*act_size = act_cnt * sizeof(volume_id_t);
+
+	if (buf_size % sizeof(volume_id_t) != 0) {
+		fibril_mutex_unlock(&volumes->lock);
+		return EINVAL;
+	}
+
+	size_t pos = 0;
+	list_foreach(volumes->volumes, lvolumes, vol_volume_t, volume) {
+		if (vol_volume_is_persist(volume)) {
+			if (pos < buf_cnt)
+				id_buf[pos].id = volume->id.id;
+			pos++;
+		}
+	}
+
+	fibril_mutex_unlock(&volumes->lock);
+	return EOK;
+}
+
 /** Load volumes from SIF repository.
  *
@@ -474,4 +575,18 @@
 }
 
+/** Get volume information.
+ *
+ * @param volume Volume
+ * @param vinfo Volume information structure to safe info to
+ * @return EOK on success or an error code
+ */
+errno_t vol_volume_get_info(vol_volume_t *volume, vol_info_t *vinfo)
+{
+	vinfo->id = volume->id;
+	str_cpy(vinfo->label, sizeof(vinfo->label), volume->label);
+	str_cpy(vinfo->path, sizeof(vinfo->path), volume->mountp);
+	return EOK;
+}
+
 /** @}
  */
Index: uspace/srv/volsrv/volume.h
===================================================================
--- uspace/srv/volsrv/volume.h	(revision ee9c70363c6e7323102757dbe583add594ffef53)
+++ uspace/srv/volsrv/volume.h	(revision 63c1dd5baed77410998be60405abb3b36a7a56b3)
@@ -38,4 +38,5 @@
 #define VOLUME_H_
 
+#include "types/vol.h"
 #include "types/volume.h"
 
@@ -44,6 +45,11 @@
 extern errno_t vol_volume_lookup_ref(vol_volumes_t *, const char *,
     vol_volume_t **);
+extern errno_t vol_volume_find_by_id_ref(vol_volumes_t *, volume_id_t,
+    vol_volume_t **);
 extern void vol_volume_del_ref(vol_volume_t *);
 extern errno_t vol_volume_set_mountp(vol_volume_t *, const char *);
+extern errno_t vol_get_ids(vol_volumes_t *, volume_id_t *, size_t,
+    size_t *);
+extern errno_t vol_volume_get_info(vol_volume_t *, vol_info_t *);
 
 #endif
