Index: uspace/app/bdwrite/bdwrite.c
===================================================================
--- uspace/app/bdwrite/bdwrite.c	(revision ab5a25977843a097fb7c0687f6bab49005fc16f1)
+++ uspace/app/bdwrite/bdwrite.c	(revision ab5a25977843a097fb7c0687f6bab49005fc16f1)
@@ -0,0 +1,129 @@
+/*
+ * 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>
+
+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;
+	}
+
+	uint8_t *buf = calloc(1, bsize);
+	for (size_t i = 0; i < blkcnt; i++) {
+		memset(buf, (i + 1) % 0x100, bsize);
+		rc = block_write_direct(dev, i + off, 1, buf);
+		if (rc != EOK) {
+			printf("bdwrite: error writing to \"%s\"\n", name);
+			free(buf);
+			block_fini(dev);
+			return 1;
+		}
+	}
+
+	free(buf);
+	block_fini(dev);
+	return 0;
+bad:
+	usage();
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/bdwrite/meson.build
===================================================================
--- uspace/app/bdwrite/meson.build	(revision ab5a25977843a097fb7c0687f6bab49005fc16f1)
+++ uspace/app/bdwrite/meson.build	(revision ab5a25977843a097fb7c0687f6bab49005fc16f1)
@@ -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/meson.build
===================================================================
--- uspace/app/meson.build	(revision 24968b54fa9a3fd2c64b003f54e8a75a9145cee7)
+++ uspace/app/meson.build	(revision ab5a25977843a097fb7c0687f6bab49005fc16f1)
@@ -31,4 +31,5 @@
 	'barber',
 	'bdsh',
+	'bdwrite',
 	'bithenge',
 	'blkdump',
