mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
To: barebox@lists.infradead.org
Cc: Ahmad Fatoum <a.fatoum@pengutronix.de>
Subject: [PATCH] commands: cat: add support for concatenating into file
Date: Mon, 26 Jan 2026 11:59:52 +0100	[thread overview]
Message-ID: <20260126105952.2155950-1-a.fatoum@pengutronix.de> (raw)

For testing initrd concatenation, it would be useful if barebox could
repeat the operation on the shell and then it can compare it against
the result, so add cat -o and -a options, like we already got for
echo.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 commands/cat.c        | 76 ++++++++++++++++++++++++++++++++++---------
 test/py/test_shell.py | 32 ++++++++++++++++++
 2 files changed, 92 insertions(+), 16 deletions(-)

diff --git a/commands/cat.c b/commands/cat.c
index 503520dc64a5..aa77b19907e0 100644
--- a/commands/cat.c
+++ b/commands/cat.c
@@ -14,6 +14,8 @@
 #include <errno.h>
 #include <xfuncs.h>
 #include <malloc.h>
+#include <getopt.h>
+#include <libfile.h>
 
 #define BUFSIZE 1024
 
@@ -23,20 +25,46 @@
  */
 static int do_cat(int argc, char *argv[])
 {
+	const char *outfile = NULL;
 	int ret;
-	int fd, i;
+	int fd, outfd = -1, i;
 	char *buf;
 	int err = 0;
-	int args = 1;
+	int oflags = O_WRONLY | O_CREAT;
+	int opt;
 
-	if (argc < 2) {
-		perror("cat");
-		return 1;
+	while ((opt = getopt(argc, argv, "a:o:")) > 0) {
+		switch(opt) {
+		case 'a':
+			oflags |= O_APPEND;
+			outfile = optarg;
+			break;
+		case 'o':
+			oflags |= O_TRUNC;
+			outfile = optarg;
+			break;
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
+
+	argv += optind;
+	argc -= optind;
+
+	if (argc == 0)
+		return COMMAND_ERROR_USAGE;
+
+	if (outfile) {
+		outfd = open(outfile, oflags);
+		if (outfd < 0) {
+			perror("open");
+			return 1;
+		}
 	}
 
 	buf = xmalloc(BUFSIZE);
 
-	while (args < argc) {
+	for (int args = 0; args < argc; args++) {
 		fd = open(argv[args], O_RDONLY);
 		if (fd < 0) {
 			err = 1;
@@ -44,24 +72,36 @@ static int do_cat(int argc, char *argv[])
 			goto out;
 		}
 
-		while((ret = read(fd, buf, BUFSIZE)) > 0) {
-			for(i = 0; i < ret; i++) {
-				if (isprint(buf[i]) || buf[i] == '\n' || buf[i] == '\t')
-					putchar(buf[i]);
-				else
-					putchar('.');
-			}
-			if(ctrlc()) {
+
+		if (outfd >= 0) {
+			ret = copy_fd(fd, outfd, 0);
+			if (ret < 0) {
+				perror("copy_fd");
 				err = 1;
 				close(fd);
 				goto out;
 			}
+		} else {
+			while((ret = read(fd, buf, BUFSIZE)) > 0) {
+				for (i = 0; i < ret; i++) {
+					if (isprint(buf[i]) || buf[i] == '\n' || buf[i] == '\t')
+						putchar(buf[i]);
+					else
+						putchar('.');
+				}
+				if(ctrlc()) {
+					err = 1;
+					close(fd);
+					goto out;
+				}
+			}
 		}
+
 		close(fd);
-		args++;
 	}
 
 out:
+	close(outfd);
 	free(buf);
 
 	return err;
@@ -69,12 +109,16 @@ static int do_cat(int argc, char *argv[])
 
 BAREBOX_CMD_HELP_START(cat)
 BAREBOX_CMD_HELP_TEXT("Currently only printable characters and NL, TAB are printed.")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-a FILE", "append to FILE instead of using stdout")
+BAREBOX_CMD_HELP_OPT ("-o FILE", "overwrite FILE instead of using stdout")
 BAREBOX_CMD_HELP_END
 
 BAREBOX_CMD_START(cat)
 	.cmd		= do_cat,
 	BAREBOX_CMD_DESC("concatenate file(s) to stdout")
-	BAREBOX_CMD_OPTS("FILE...")
+	BAREBOX_CMD_OPTS("[-ao] FILE...")
 	BAREBOX_CMD_GROUP(CMD_GRP_FILE)
 	BAREBOX_CMD_HELP(cmd_cat_help)
 BAREBOX_CMD_END
diff --git a/test/py/test_shell.py b/test/py/test_shell.py
index 50ae497fc6c3..9010270e0e63 100644
--- a/test/py/test_shell.py
+++ b/test/py/test_shell.py
@@ -32,6 +32,38 @@ def test_shell_quoting(barebox):
     assert barebox.run_check('source /tmp/script && echo "$var"') == "A B"
 
 
+def test_barebox_echo_cat(barebox, barebox_config):
+    skip_disabled(barebox_config, "CONFIG_CMD_ECHO", "CONFIG_CMD_CAT")
+
+    barebox.run_check('rm -f stanza*')
+
+    barebox.run_check('echo -o stanza-1 meow')
+    barebox.run_check('echo -o stanza-1 mau')
+    barebox.run_check('echo -o stanza-2 meow')
+    barebox.run_check('echo -a stanza-2 meow')
+    barebox.run_check('cat  -o stanza-3 /dev/null')
+    barebox.run_check('echo -a stanza-3 mau')
+    barebox.run_check('echo -a stanza-3 ma')
+
+    expected = ["mau", "meow", "meow", "mau", "ma"]
+
+    stdout = barebox.run_check('ls -l stanza-*')
+
+    assert len(stdout) == 3
+
+    assert barebox.run_check('cat stanza-*') == expected
+
+    barebox.run_check('rm -f stanza')
+
+    stdout = barebox.run_check('cat -o stanza stanza-*')
+    assert stdout == []
+    assert barebox.run_check('cat stanza') == expected
+
+    stdout = barebox.run_check('cat -a stanza stanza-*')
+    assert stdout == []
+    assert barebox.run_check('cat stanza') == expected + expected
+
+
 def test_barebox_md5sum(barebox, barebox_config):
     skip_disabled(barebox_config, "CONFIG_CMD_MD5SUM", "CONFIG_CMD_ECHO")
 
-- 
2.47.3




             reply	other threads:[~2026-01-26 11:00 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-26 10:59 Ahmad Fatoum [this message]
2026-01-27  7:33 ` Sascha Hauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260126105952.2155950-1-a.fatoum@pengutronix.de \
    --to=a.fatoum@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox