diff --git a/0017-daemon-New-command_out-and-sh_out-APIs.patch b/0017-daemon-New-command_out-and-sh_out-APIs.patch new file mode 100644 index 0000000..7e94493 --- /dev/null +++ b/0017-daemon-New-command_out-and-sh_out-APIs.patch @@ -0,0 +1,308 @@ +From 42ae34115f1e6bff2b501d8ff3ab9ac26c892a22 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 19 Feb 2025 11:11:24 +0000 +Subject: [PATCH] daemon: New command_out and sh_out APIs + +These APIs allow you to capture output from guest commands that +generate more output than the protocol limit allows. + +Thanks: Nijin Ashok +Fixes: https://issues.redhat.com/browse/RHEL-80159 +(cherry picked from commit 47ac4871b2c1dcde317d116c52b13916ab368ea4) +--- + .gitignore | 1 + + daemon/sh.c | 42 +++++++++++++ + generator/actions_core.ml | 25 ++++++++ + generator/proc_nr.ml | 2 + + lib/MAX_PROC_NR | 2 +- + tests/Makefile.am | 10 ++++ + tests/large-command/test-large-command.c | 46 ++++++++++++++ + tests/large-command/test-large-command.sh | 73 +++++++++++++++++++++++ + 8 files changed, 200 insertions(+), 1 deletion(-) + create mode 100644 tests/large-command/test-large-command.c + create mode 100755 tests/large-command/test-large-command.sh + +diff --git a/.gitignore b/.gitignore +index 2fc52e84..68b27c79 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -423,6 +423,7 @@ Makefile.in + /tests/disks/test-add-disks + /tests/disks/test-qemu-drive-libvirt.xml + /tests/events/test-libvirt-auth-callbacks ++/tests/large-command/test-large-command + /tests/mount-local/test-parallel-mount-local + /tests/mountable/test-internal-parse-mountable + /tests/parallel/test-parallel +diff --git a/daemon/sh.c b/daemon/sh.c +index 21d4deea..f8440c1d 100644 +--- a/daemon/sh.c ++++ b/daemon/sh.c +@@ -294,6 +294,40 @@ do_command_lines (char *const *argv) + return lines; /* Caller frees. */ + } + ++/* Has one FileOut parameter. */ ++int ++do_command_out (char *const *argv) ++{ ++ /* We could in theory spool the command to output as it is running, ++ * but error handling mid-command, and progress bars would not work ++ * if we did that. If we encounter a case where this is a problem, ++ * another approach would be to save the output in a temporary file. ++ */ ++ CLEANUP_FREE char *out = NULL; ++ size_t i, n; ++ ++ out = do_command (argv); ++ if (out == NULL) ++ return -1; ++ ++ /* Send the reply message. We know that we're not going to fail now ++ * (except for client cancellation). ++ */ ++ reply (NULL, NULL); ++ ++ n = strlen (out); ++ for (i = 0; i < n; i += GUESTFS_MAX_CHUNK_SIZE) { ++ if (send_file_write (out+i, MIN (GUESTFS_MAX_CHUNK_SIZE, n-i)) < 0) ++ return -1; ++ notify_progress (i, n); ++ } ++ ++ if (send_file_end (0)) ++ return -1; ++ ++ return 0; ++} ++ + char * + do_sh (const char *cmd) + { +@@ -309,3 +343,11 @@ do_sh_lines (const char *cmd) + + return do_command_lines ((char **) argv); + } ++ ++int ++do_sh_out (const char *cmd) ++{ ++ const char *argv[] = { "/bin/sh", "-c", cmd, NULL }; ++ ++ return do_command_out ((char **) argv); ++} +diff --git a/generator/actions_core.ml b/generator/actions_core.ml +index 768f5843..eb047b6b 100644 +--- a/generator/actions_core.ml ++++ b/generator/actions_core.ml +@@ -2352,6 +2352,19 @@ result into a list of lines. + + See also: C" }; + ++ { defaults with ++ name = "command_out"; added = (1, 55, 6); ++ style = RErr, [StringList (PlainString, "arguments"); String (FileOut, "output")], []; ++ progress = true; cancellable = true; ++ test_excuse = "there is a separate test in the tests directory"; ++ shortdesc = "run a command from the guest filesystem"; ++ longdesc = "\ ++This is the same as C, but streams the output ++back, handling the case where the output from the command is ++larger than the protocol limit. ++ ++See also: C" }; ++ + { defaults with + name = "statvfs"; added = (1, 9, 2); + style = RStruct ("statbuf", "statvfs"), [String (Pathname, "path")], []; +@@ -3461,6 +3474,18 @@ into a list of lines. + + See also: C" }; + ++ { defaults with ++ name = "sh_out"; added = (1, 55, 6); ++ style = RErr, [String (PlainString, "command"); String (FileOut, "output")], []; ++ test_excuse = "there is a separate test in the tests directory"; ++ shortdesc = "run a command via the shell"; ++ longdesc = "\ ++This is the same as C, but streams the output ++back, handling the case where the output from the command is ++larger than the protocol limit. ++ ++See also: C" }; ++ + { defaults with + name = "glob_expand"; added = (1, 0, 50); + (* Use Pathname here, and hence ABS_PATH (pattern,...) in +diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml +index 56cd97a9..0ce12e66 100644 +--- a/generator/proc_nr.ml ++++ b/generator/proc_nr.ml +@@ -518,6 +518,8 @@ let proc_nr = [ + 513, "inspect_get_build_id"; + 514, "findfs_partuuid"; + 515, "findfs_partlabel"; ++516, "command_out"; ++517, "sh_out"; + ] + + (* End of list. If adding a new entry, add it at the end of the list +diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR +index 3cda32fc..ac953cd0 100644 +--- a/lib/MAX_PROC_NR ++++ b/lib/MAX_PROC_NR +@@ -1 +1 @@ +-515 ++517 +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 52155f64..f23fb6e9 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -440,6 +440,16 @@ EXTRA_DIST += http/test-http.py + TESTS += journal/test-journal.pl + EXTRA_DIST += journal/test-journal.pl + ++# This binary must be statically linked. It is used for testing ++# the "guestfs_command_out" function. ++ ++large_command_test_large_command_SOURCES = large-command/test-large-command.c ++large_command_test_large_command_LDFLAGS = -all-static ++ ++check_PROGRAMS += large-command/test-large-command ++TESTS += large-command/test-large-command.sh ++EXTRA_DIST += large-command/test-large-command.sh ++ + TESTS += \ + luks/test-luks.sh \ + luks/test-luks-list.sh \ +diff --git a/tests/large-command/test-large-command.c b/tests/large-command/test-large-command.c +new file mode 100644 +index 00000000..0abf435e +--- /dev/null ++++ b/tests/large-command/test-large-command.c +@@ -0,0 +1,46 @@ ++/* libguestfs ++ * Copyright (C) 2009-2025 Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++/* This program, which must be statically linked, is used to test the ++ * guestfs_command_out and guestfs_sh_out functions. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define STREQ(a,b) (strcmp((a),(b)) == 0) ++ ++int ++main (int argc, char *argv[]) ++{ ++ size_t n, i; ++ ++ if (argc > 1) { ++ if (sscanf (argv[1], "%zu", &n) != 1) ++ error (EXIT_FAILURE, 0, "could not parse parameter: %s", argv[1]); ++ for (i = 0; i < n; ++i) ++ putchar ('x'); ++ } else ++ error (EXIT_FAILURE, 0, "missing parameter"); ++ ++ exit (EXIT_SUCCESS); ++} +diff --git a/tests/large-command/test-large-command.sh b/tests/large-command/test-large-command.sh +new file mode 100755 +index 00000000..abcfa868 +--- /dev/null ++++ b/tests/large-command/test-large-command.sh +@@ -0,0 +1,73 @@ ++#!/bin/bash - ++# libguestfs ++# Copyright (C) 2025 Red Hat Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++# Test command-out. We can't easily test sh-out without having a ++# shell (which requires a full guest), however the code path for both ++# is essentially identical. ++ ++set -e ++ ++$TEST_FUNCTIONS ++ ++skip_if_skipped ++ ++skip_unless stat --version ++ ++# Binary must exist and must be linked statically. ++bin=large-command/test-large-command ++skip_unless test -x $bin ++skip_unless bash -c " ldd $bin |& grep -sq 'not a dynamic executable' " ++ ++disk=large-command/test.img ++rm -f $disk ++ ++out1=large-command/test.out1 ++out2=large-command/test.out2 ++out3=large-command/test.out3 ++out4=large-command/test.out4 ++ ++# Must be larger than protocol size, currently 4MB. ++size=$((10 * 1024 * 1024)) ++ ++guestfish -x -N $disk=fs -m /dev/sda1 < - 1:1.54.0-4 +- Add new APIs to allow command output > 4MB + resolves: RHEL-80159 + * Wed Oct 30 2024 Richard W.M. Jones - 1:1.54.0-3 - Rebase to libguestfs 1.54.0 resolves: RHEL-56809