+/* Note: 'rc_exit_on_error_flag' is the exit_on_error flag that we
+ * pass to the remote server (when issuing --remote commands). It
+ * does not cause issue_command itself to exit on error.
+ */
+int
+issue_command (const char *cmd, char *argv[], const char *pipecmd,
+ int rc_exit_on_error_flag)
+{
+ int argc;
+ int stdout_saved_fd = -1;
+ int pid = 0;
+ int r;
+
+ reset_progress_bar ();
+
+ /* This counts the commands issued, starting at 1. */
+ command_num++;
+
+ /* For | ... commands. Annoyingly we can't use popen(3) here. */
+ if (pipecmd) {
+ int fd[2];
+
+ if (fflush (stdout) == EOF) {
+ perror ("failed to flush standard output");
+ return -1;
+ }
+ if (pipe (fd) < 0) {
+ perror ("pipe failed");
+ return -1;
+ }
+ pid = fork ();
+ if (pid == -1) {
+ perror ("fork");
+ return -1;
+ }
+
+ if (pid == 0) { /* Child process. */
+ close (fd[1]);
+ if (dup2 (fd[0], 0) < 0) {
+ perror ("dup2 of stdin failed");
+ _exit (1);
+ }
+
+ r = system (pipecmd);
+ if (r == -1) {
+ perror (pipecmd);
+ _exit (1);
+ }
+ _exit (WEXITSTATUS (r));
+ }
+
+ if ((stdout_saved_fd = dup (1)) < 0) {
+ perror ("failed to dup stdout");
+ return -1;
+ }
+ close (fd[0]);
+ if (dup2 (fd[1], 1) < 0) {
+ perror ("failed to dup stdout");
+ close (stdout_saved_fd);
+ return -1;
+ }
+ close (fd[1]);
+ }
+
+ for (argc = 0; argv[argc] != NULL; ++argc)
+ ;
+
+ /* If --remote was set, then send this command to a remote process. */
+ if (remote_control)
+ r = rc_remote (remote_control, cmd, argc, argv, rc_exit_on_error_flag);
+
+ /* Otherwise execute it locally. */
+ else if (STRCASEEQ (cmd, "help")) {
+ if (argc == 0) {
+ display_help ();
+ r = 0;
+ } else
+ r = display_command (argv[0]);
+ }
+ else if (STRCASEEQ (cmd, "quit") ||
+ STRCASEEQ (cmd, "exit") ||
+ STRCASEEQ (cmd, "q")) {
+ quit = 1;
+ r = 0;
+ }
+ else
+ r = run_action (cmd, argc, argv);
+
+ /* Always flush stdout after every command, so that messages, results
+ * etc appear immediately.
+ */
+ if (fflush (stdout) == EOF) {
+ perror ("failed to flush standard output");
+ return -1;
+ }
+
+ if (pipecmd) {
+ close (1);
+ if (dup2 (stdout_saved_fd, 1) < 0) {
+ perror ("failed to dup2 standard output");
+ r = -1;
+ }
+ close (stdout_saved_fd);
+ if (waitpid (pid, NULL, 0) < 0) {
+ perror ("waiting for command to complete");
+ r = -1;
+ }
+ }
+
+ return r;
+}
+
+void
+list_builtin_commands (void)
+{
+ /* help and quit should appear at the top */
+ printf ("%-20s %s\n",
+ "help", _("display a list of commands or help on a command"));
+ printf ("%-20s %s\n",
+ "quit", _("quit guestfish"));
+
+ /* actions are printed after this (see list_commands) */
+}
+
+int
+display_builtin_command (const char *cmd)
+{
+ /* help for actions is auto-generated, see display_command */
+
+ if (STRCASEEQ (cmd, "help")) {
+ printf (_("help - display a list of commands or help on a command\n"
+ " help cmd\n"
+ " help\n"));
+ return 0;
+ }
+ else if (STRCASEEQ (cmd, "quit") ||
+ STRCASEEQ (cmd, "exit") ||
+ STRCASEEQ (cmd, "q")) {
+ printf (_("quit - quit guestfish\n"
+ " quit\n"));
+ return 0;
+ }
+ else {
+ fprintf (stderr, _("%s: command not known, use -h to list all commands\n"),
+ cmd);
+ return -1;
+ }
+}
+
+/* This is printed when the user types in an unknown command for the
+ * first command issued. A common case is the user doing:
+ * guestfish disk.img
+ * expecting guestfish to open 'disk.img' (in fact, this tried to
+ * run a command 'disk.img').
+ */
+void
+extended_help_message (void)
+{
+ fprintf (stderr,
+ _("Did you mean to open a disk image? guestfish -a disk.img\n"
+ "For a list of commands: guestfish -h\n"
+ "For complete documentation: man guestfish\n"));
+}
+
+void
+free_strings (char **argv)
+{
+ int argc;
+
+ for (argc = 0; argv[argc] != NULL; ++argc)
+ free (argv[argc]);
+ free (argv);
+}
+
+int
+count_strings (char *const *argv)
+{
+ int c;
+
+ for (c = 0; argv[c]; ++c)
+ ;
+ return c;
+}
+
+void
+print_strings (char *const *argv)
+{
+ int argc;
+
+ for (argc = 0; argv[argc] != NULL; ++argc)
+ printf ("%s\n", argv[argc]);
+}
+
+void
+print_table (char *const *argv)