Index: uspace/app/bdwrite/bdwrite.c
===================================================================
--- uspace/app/bdwrite/bdwrite.c	(revision eebecdc084dfdfda62b1c3e66f0fe06188bc639a)
+++ uspace/app/bdwrite/bdwrite.c	(revision eebecdc084dfdfda62b1c3e66f0fe06188bc639a)
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2024 Miroslav Cimerman
+ * 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 bdwrite
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <block.h>
+#include <errno.h>
+#include <getopt.h>
+#include <mem.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <abi/ipc/ipc.h>
+
+static void usage(void);
+
+static const char usage_str[] =
+    "Usage: bdwrite <dev> -o <offset in blocks> -c <block count>\n"
+    "\n"
+    "  Write cyclic blocks to block device.\n";
+
+static struct option const long_options[] = {
+	{ 0, 0, 0, 0 }
+};
+
+static void usage(void)
+{
+	printf("%s", usage_str);
+}
+
+int main(int argc, char **argv)
+{
+	errno_t rc;
+	size_t bsize;
+	int c;
+	char *name = NULL;
+	size_t blkcnt = 0, off = 0;
+	service_id_t dev;
+
+	if (argc != 6) {
+		goto bad;
+	}
+
+	name = argv[1];
+
+	c = 0;
+	optreset = 1;
+	optind = 0;
+
+	while (c != -1) {
+		c = getopt_long(argc, argv, "o:c:", long_options, NULL);
+		switch (c) {
+		case 'o':
+			off = strtol(optarg, NULL, 10);
+			break;
+		case 'c':
+			blkcnt = strtol(optarg, NULL, 10);
+			break;
+		}
+	}
+
+	rc = loc_service_get_id(name, &dev, 0);
+	if (rc != EOK) {
+		printf("bdwrite: error resolving device \"%s\"\n", name);
+		return 1;
+	}
+	rc = block_init(dev);
+	if (rc != EOK) {
+		printf("bdwrite: error initializing block device \"%s\"\n", name);
+		return 1;
+	}
+
+	rc = block_get_bsize(dev, &bsize);
+	if (rc != EOK) {
+		printf("bdwrite: error getting block size of \"%s\"\n", name);
+		block_fini(dev);
+		return 1;
+	}
+
+	uint64_t to_alloc = min(DATA_XFER_LIMIT, bsize * blkcnt);
+	uint8_t *buf = malloc(to_alloc);
+	if (buf == NULL) {
+		rc = ENOMEM;
+		goto end;
+	}
+	uint64_t left = blkcnt;
+	while (left != 0) {
+		uint64_t blks_to_write = min(to_alloc / bsize, left);
+		uint8_t *ptr = buf;
+		for (size_t i = 0; i < blks_to_write; i++) {
+			/* memset(ptr, (i + 1) % 0x100, bsize); */
+			memset(ptr, 'A' + (i % 26), bsize);
+			ptr += bsize;
+		}
+		rc = block_write_direct(dev, off, blks_to_write, buf);
+		if (rc != EOK) {
+			printf("bdwrite: error writing to \"%s\"\n", name);
+			goto end;
+		}
+		left -= blks_to_write;
+		off += blks_to_write;
+	}
+end:
+	free(buf);
+	block_fini(dev);
+	return rc;
+bad:
+	usage();
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/bdwrite/meson.build
===================================================================
--- uspace/app/bdwrite/meson.build	(revision eebecdc084dfdfda62b1c3e66f0fe06188bc639a)
+++ uspace/app/bdwrite/meson.build	(revision eebecdc084dfdfda62b1c3e66f0fe06188bc639a)
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2024 Miroslav Cimerman
+# 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.
+#
+
+deps = [ 'block' ]
+src = files('bdwrite.c')
Index: uspace/app/hrctl/hrctl.c
===================================================================
--- uspace/app/hrctl/hrctl.c	(revision eebecdc084dfdfda62b1c3e66f0fe06188bc639a)
+++ uspace/app/hrctl/hrctl.c	(revision eebecdc084dfdfda62b1c3e66f0fe06188bc639a)
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2024 Miroslav Cimerman
+ * 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 hrctl
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <hr.h>
+#include <sif.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <str.h>
+#include <str_error.h>
+
+#define HRCTL_SAMPLE_CONFIG_PATH "/cfg/sample_hr_config.sif"
+
+static void usage(void);
+static errno_t fill_config_devs(int, char **, int, hr_config_t *);
+static errno_t load_config(const char *, hr_config_t *);
+
+static const char usage_str[] =
+    "Usage: hrctl [OPTION]... -n <dev_no> <devices>...\n"
+    "\n"
+    "Options:\n"
+    "  -h, --help                display this help and exit\n"
+    "  -C, --create-file=PATH    create an array from file,\n"
+    "                            sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n"
+    "  -A, --assemble-file=PATH  create an array from file\n"
+    "  -s, --status              display status of active arrays\n"
+    "  -H, --hotspare=DEV        add hotspare extent\n"
+    "  -D, --destroy             destroy/disassemble an active array\n"
+    "  -F, --fail-extent         fail an extent, use with -D and set it before\n"
+    "  -c, --create=NAME         create new array\n"
+    "  -a, --assemble=NAME       assemble an existing array\n"
+    "  -n                        non-zero number of devices\n"
+    "  -l, --level=LEVEL         set the RAID level,\n"
+    "                            valid values: 0, 1, 4, 5\n"
+    "  -0                        striping\n"
+    "  -1                        mirroring\n"
+    "  -4                        parity on one extent\n"
+    "  -5                        distributed parity\n"
+    "\n"
+    "When specifying name for creation or assembly, the device name\n"
+    "is automatically prepended with \"devices/\" prefix.\n"
+    "\n"
+    "Example usage:\n"
+    "  hrctl --create hr0 -0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n"
+    "    - creates new mirroring RAID device named /hr0 consisting\n"
+    "      of 2 drives\n"
+    "  hrctl --assemble hr0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n"
+    "    - assembles RAID device named /hr0 consisting of 2 drives,\n"
+    "      that were previously in an array\n"
+    "  hrctl devices/hr0 --hotspare=devices/disk10\n"
+    "    - adds \"devices/disk10\" as hotspare extent\n"
+    "  hrctl -F 0 -D devices/hr0\n"
+    "    - marks first extent as FAILED\n"
+    "Limitations:\n"
+    "  - device name must be less than 32 characters in size\n";
+
+static struct option const long_options[] = {
+	{ "help", no_argument, 0, 'h' },
+	{ "status", no_argument, 0, 's' },
+	{ "assemble", required_argument, 0, 'a' },
+	{ "create", required_argument, 0, 'c' },
+	{ "level", required_argument, 0, 'l' },
+	{ "create-file", required_argument, 0, 'C' },
+	{ "assemble-file", required_argument, 0, 'A' },
+	{ "destroy", required_argument, 0, 'D' },
+	{ "fail-extent", required_argument, 0, 'F' },
+	{ "hotspare", required_argument, 0, 'H' },
+	{ 0, 0, 0, 0 }
+};
+
+static void usage(void)
+{
+	printf("%s", usage_str);
+}
+
+static errno_t fill_config_devs(int argc, char **argv, int optind,
+    hr_config_t *cfg)
+{
+	errno_t rc;
+	size_t i;
+
+	for (i = 0; i < cfg->dev_no; i++) {
+		rc = loc_service_get_id(argv[optind], &cfg->devs[i], 0);
+		if (rc == ENOENT) {
+			printf("hrctl: no device \"%s\", marking as missing\n",
+			    argv[optind]);
+			cfg->devs[i] = 0;
+		} else if (rc != EOK) {
+			printf("hrctl: error resolving device \"%s\", aborting\n",
+			    argv[optind]);
+			return EINVAL;
+		}
+
+		optind++;
+	}
+
+	return EOK;
+}
+
+static errno_t load_config(const char *path, hr_config_t *cfg)
+{
+	errno_t rc;
+	size_t i;
+	sif_doc_t *doc = NULL;
+	sif_node_t *narrays;
+	sif_node_t *rnode;
+	sif_node_t *narray;
+	sif_node_t *nextent;
+	const char *ntype;
+	const char *devname;
+	const char *level_str;
+	const char *dev_no_str;
+	const char *extent_devname;
+
+	rc = sif_load(path, &doc);
+	if (rc != EOK)
+		goto error;
+
+	rnode = sif_get_root(doc);
+
+	narrays = sif_node_first_child(rnode);
+	ntype = sif_node_get_type(narrays);
+	if (str_cmp(ntype, "arrays") != 0) {
+		rc = EIO;
+		goto error;
+	}
+
+	narray = sif_node_first_child(narrays);
+	ntype = sif_node_get_type(narray);
+	if (str_cmp(ntype, "array") != 0) {
+		rc = EIO;
+		goto error;
+	}
+
+	devname = sif_node_get_attr(narray, "devname");
+	if (devname == NULL) {
+		rc = EIO;
+		goto error;
+	}
+	str_cpy(cfg->devname, sizeof(cfg->devname), devname);
+
+	level_str = sif_node_get_attr(narray, "level");
+	if (level_str == NULL)
+		cfg->level = HR_LVL_UNKNOWN;
+	else
+		cfg->level = strtol(level_str, NULL, 10);
+
+	dev_no_str = sif_node_get_attr(narray, "n");
+	if (dev_no_str == NULL) {
+		rc = EIO;
+		goto error;
+	}
+	cfg->dev_no = strtol(dev_no_str, NULL, 10);
+
+	nextent = sif_node_first_child(narray);
+	for (i = 0; i < cfg->dev_no; i++) {
+		if (nextent == NULL) {
+			rc = EINVAL;
+			goto error;
+		}
+
+		ntype = sif_node_get_type(nextent);
+		if (str_cmp(ntype, "extent") != 0) {
+			rc = EIO;
+			goto error;
+		}
+
+		extent_devname = sif_node_get_attr(nextent, "devname");
+		if (extent_devname == NULL) {
+			rc = EIO;
+			goto error;
+		}
+
+		rc = loc_service_get_id(extent_devname, &cfg->devs[i], 0);
+		if (rc == ENOENT) {
+			printf("hrctl: no device \"%s\", marking as missing\n",
+			    extent_devname);
+			cfg->devs[i] = 0;
+			rc = EOK;
+		} else if (rc != EOK) {
+			printf("hrctl: error resolving device \"%s\", aborting\n",
+			    extent_devname);
+			return EINVAL;
+		}
+
+		nextent = sif_node_next_child(nextent);
+	}
+
+error:
+	if (doc != NULL)
+		sif_delete(doc);
+	return rc;
+}
+
+int main(int argc, char **argv)
+{
+	errno_t rc;
+	int retval, c;
+	bool create, assemble;
+	long fail_extent = -1;
+	hr_t *hr = NULL;
+	hr_config_t *cfg;
+
+	cfg = calloc(1, sizeof(hr_config_t));
+	if (cfg == NULL)
+		return 1;
+
+	retval = 0;
+	cfg->level = HR_LVL_UNKNOWN;
+	cfg->dev_no = 0;
+	create = assemble = false;
+
+	if (argc < 2) {
+		goto bad;
+	}
+
+	c = 0;
+	optreset = 1;
+	optind = 0;
+
+	while (c != -1) {
+		c = getopt_long(argc, argv, "hsC:c:A:a:l:0145Ln:D:F:H:",
+		    long_options, NULL);
+		switch (c) {
+		case 's':
+			free(cfg);
+			rc = hr_print_status();
+			if (rc != EOK)
+				return 1;
+			return 0;
+		case 'C':
+			/* only support 1 array inside config for now XXX */
+			rc = load_config(optarg, cfg);
+			if (rc != EOK) {
+				printf("hrctl: failed to load config\n");
+				free(cfg);
+				return 1;
+			}
+			create = true;
+			goto skip;
+		case 'c':
+			if (str_size(optarg) > sizeof(cfg->devname) - 1) {
+				printf("hrctl: device name too long\n");
+				free(cfg);
+				return 1;
+			}
+			str_cpy(cfg->devname, sizeof(cfg->devname), optarg);
+			create = true;
+			break;
+		case 'A':
+			rc = load_config(optarg, cfg);
+			if (rc != EOK) {
+				printf("hrctl: failed to load config\n");
+				free(cfg);
+				return 1;
+			}
+			assemble = true;
+			goto skip;
+		case 'a':
+			if (str_size(optarg) > sizeof(cfg->devname) - 1) {
+				printf("hrctl: device name too long\n");
+				free(cfg);
+				return 1;
+			}
+			str_cpy(cfg->devname, sizeof(cfg->devname), optarg);
+			assemble = true;
+			break;
+		case 'D':
+			rc = hr_stop(optarg, fail_extent);
+			free(cfg);
+			if (rc != EOK) {
+				if (rc == ENOENT)
+					printf("hrctl: service named \"%s\" does not exist\n",
+					    optarg);
+				return 1;
+			}
+			return 0;
+		case 'F':
+			fail_extent = strtol(optarg, NULL, 10);
+			break;
+		case 'l':
+			if (cfg->level != HR_LVL_UNKNOWN)
+				goto bad;
+			cfg->level = strtol(optarg, NULL, 10);
+			break;
+		case '0':
+			if (cfg->level != HR_LVL_UNKNOWN)
+				goto bad;
+			cfg->level = HR_LVL_0;
+			break;
+		case '1':
+			if (cfg->level != HR_LVL_UNKNOWN)
+				goto bad;
+			cfg->level = HR_LVL_1;
+			break;
+		case '4':
+			if (cfg->level != HR_LVL_UNKNOWN)
+				goto bad;
+			cfg->level = HR_LVL_4;
+			break;
+		case '5':
+			if (cfg->level != HR_LVL_UNKNOWN)
+				goto bad;
+			cfg->level = HR_LVL_5;
+			break;
+		case 'n':
+			cfg->dev_no = strtol(optarg, NULL, 10);
+			if ((int)cfg->dev_no + optind != argc)
+				goto bad;
+			rc = fill_config_devs(argc, argv, optind, cfg);
+			if (rc != EOK) {
+				free(cfg);
+				return 1;
+			}
+			goto skip;
+		case 'H':
+			if (optind != 3 && argc != 4)
+				goto bad;
+
+			service_id_t hotspare;
+			service_id_t vol_svc_id;
+
+			rc = loc_service_get_id(argv[1], &vol_svc_id, 0);
+			if (rc != EOK) {
+				printf("hrctl: error resolving volume \"%s\", "
+				    "aborting extent addition\n", argv[1]);
+				goto bad;
+			}
+
+			rc = loc_service_get_id(optarg, &hotspare, 0);
+			if (rc != EOK) {
+				printf("hrctl: error resolving device \"%s\", "
+				    "aborting extent addition\n", optarg);
+				goto bad;
+			}
+
+			rc = hr_add_hotspare(vol_svc_id, hotspare);
+			if (rc != EOK)
+				printf("hrctl: hr_add_hotspare() rc: %s\n",
+				    str_error(rc));
+
+			free(cfg);
+			if (rc != EOK)
+				return 1;
+			else
+				return 0;
+		case 'h':
+		default:
+			usage();
+			free(cfg);
+			return 0;
+		}
+	}
+
+skip:
+	if ((create && assemble) || (!create && !assemble))
+		goto bad;
+
+	if (create && cfg->level == HR_LVL_UNKNOWN) {
+		printf("hrctl: invalid level, exiting\n");
+		goto bad;
+	}
+
+	if (cfg->dev_no > HR_MAX_EXTENTS) {
+		printf("hrctl: too many devices, exiting\n");
+		goto bad;
+	}
+
+	if (cfg->dev_no == 0) {
+		printf("hrctl: invalid number of devices, exiting\n");
+		goto bad;
+	}
+
+	rc = hr_sess_init(&hr);
+	if (rc != EOK) {
+		printf("hrctl: hr_sess_init() rc: %s\n", str_error(rc));
+		retval = 1;
+		goto end;
+	}
+
+	if (create) {
+		rc = hr_create(hr, cfg, false);
+		printf("hrctl: hr_create() rc: %s\n", str_error(rc));
+	} else if (assemble) {
+		rc = hr_create(hr, cfg, true);
+		printf("hrctl: hr_assemble() rc: %s\n", str_error(rc));
+	}
+
+end:
+	free(cfg);
+	hr_sess_destroy(hr);
+	return retval;
+bad:
+	free(cfg);
+	printf("hrctl: bad usage, try hrctl --help\n");
+	return 1;
+}
+
+/** @}
+ */
Index: uspace/app/hrctl/meson.build
===================================================================
--- uspace/app/hrctl/meson.build	(revision eebecdc084dfdfda62b1c3e66f0fe06188bc639a)
+++ uspace/app/hrctl/meson.build	(revision eebecdc084dfdfda62b1c3e66f0fe06188bc639a)
@@ -0,0 +1,32 @@
+#
+# Copyright (c) 2024 Miroslav Cimerman
+# 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.
+#
+
+deps = [ 'device', 'sif' ]
+src = files('hrctl.c')
+
+installed_data += { 'name': 'sample_hr_config.sif', 'dir': '/cfg' }
Index: uspace/app/hrctl/sample_hr_config.sif
===================================================================
--- uspace/app/hrctl/sample_hr_config.sif	(revision eebecdc084dfdfda62b1c3e66f0fe06188bc639a)
+++ uspace/app/hrctl/sample_hr_config.sif	(revision eebecdc084dfdfda62b1c3e66f0fe06188bc639a)
@@ -0,0 +1,9 @@
+<sif>
+<arrays>
+<array devname="hr0" level="1" n="3">
+<extent devname="devices/\hw\sys\00:01.1\c0d0"></extent>
+<extent devname="devices/\hw\sys\00:01.1\c0d1"></extent>
+<extent devname="devices/\hw\sys\00:01.1\c1d1"></extent>
+</array>
+</arrays>
+</sif>
Index: uspace/app/meson.build
===================================================================
--- uspace/app/meson.build	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ uspace/app/meson.build	(revision eebecdc084dfdfda62b1c3e66f0fe06188bc639a)
@@ -31,4 +31,5 @@
 	'barber',
 	'bdsh',
+	'bdwrite',
 	'bithenge',
 	'blkdump',
@@ -52,4 +53,5 @@
 	'hbench',
 	'hello',
+	'hrctl',
 	'inet',
 	'init',
