[PATCH] commands: cat: add support for concatenating into file
Ahmad Fatoum
a.fatoum at pengutronix.de
Mon Jan 26 02:59:52 PST 2026
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 at 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
More information about the barebox
mailing list