]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/execute.c
core: add 'j' in confirmation_spawn to list the jobs that are in progress
[thirdparty/systemd.git] / src / core / execute.c
index 43a0a5cafd75f9582a635dade6e709591f85a3a6..6a7ad66a2118ea739f28315168d548dd0b0ee7fd 100644 (file)
@@ -669,21 +669,27 @@ static int setup_confirm_stdio(const char *vc, int *_saved_stdin, int *_saved_st
         return 0;
 }
 
-_printf_(2, 3) static int write_confirm_message(const char *vc, const char *format, ...) {
+static void write_confirm_error_fd(int err, int fd) {
+        assert(err < 0);
+
+        if (err == -ETIMEDOUT)
+                dprintf(fd, "Confirmation question timed out, assuming positive response.\n");
+        else {
+                errno = -err;
+                dprintf(fd, "Couldn't ask confirmation: %m, assuming positive response.\n");
+        }
+}
+
+static void write_confirm_error(int err, const char *vc) {
         _cleanup_close_ int fd = -1;
-        va_list ap;
 
-        assert(format);
+        assert(vc);
 
         fd = open_terminal(vc, O_WRONLY|O_NOCTTY|O_CLOEXEC);
         if (fd < 0)
-                return fd;
-
-        va_start(ap, format);
-        vdprintf(fd, format, ap);
-        va_end(ap);
+                return;
 
-        return 0;
+        write_confirm_error_fd(err, fd);
 }
 
 static int restore_confirm_stdio(int *saved_stdin, int *saved_stdout) {
@@ -708,22 +714,80 @@ static int restore_confirm_stdio(int *saved_stdin, int *saved_stdout) {
         return r;
 }
 
-static int ask_for_confirmation(const char *vc, char *response, char **argv) {
+enum {
+        CONFIRM_PRETEND_FAILURE = -1,
+        CONFIRM_PRETEND_SUCCESS =  0,
+        CONFIRM_EXECUTE = 1,
+};
+
+static int ask_for_confirmation(const char *vc, Unit *u, const char *cmdline) {
         int saved_stdout = -1, saved_stdin = -1, r;
-        _cleanup_free_ char *line = NULL;
+        _cleanup_free_ char *e = NULL;
+        char c;
 
+        /* For any internal errors, assume a positive response. */
         r = setup_confirm_stdio(vc, &saved_stdin, &saved_stdout);
-        if (r < 0)
-                return r;
+        if (r < 0) {
+                write_confirm_error(r, vc);
+                return CONFIRM_EXECUTE;
+        }
 
-        line = exec_command_line(argv);
-        if (!line)
-                return -ENOMEM;
+        e = ellipsize(cmdline, 60, 100);
+        if (!e) {
+                log_oom();
+                r = CONFIRM_EXECUTE;
+                goto restore_stdio;
+        }
 
-        r = ask_char(response, "yns", "Execute %s? [Yes, No, Skip] ", line);
+        for (;;) {
+                r = ask_char(&c, "yfshiDj", "Execute %s? [y, f, s – h for help] ", e);
+                if (r < 0) {
+                        write_confirm_error_fd(r, STDOUT_FILENO);
+                        r = CONFIRM_EXECUTE;
+                        goto restore_stdio;
+                }
 
-        restore_confirm_stdio(&saved_stdin, &saved_stdout);
+                switch (c) {
+                case 'D':
+                        unit_dump(u, stdout, "  ");
+                        continue; /* ask again */
+                case 'f':
+                        printf("Failing execution.\n");
+                        r = CONFIRM_PRETEND_FAILURE;
+                        break;
+                case 'h':
+                        printf("  D - dump, show the state of the unit\n"
+                               "  f - fail, don't execute the command and pretend it failed\n"
+                               "  h - help\n"
+                               "  i - info, show a short summary of the unit\n"
+                               "  j - jobs, show jobs that are in progress\n"
+                               "  s - skip, don't execute the command and pretend it succeeded\n"
+                               "  y - yes, execute the command\n");
+                        continue; /* ask again */
+                case 'i':
+                        printf("  Description: %s\n"
+                               "  Unit:        %s\n"
+                               "  Command:     %s\n",
+                               u->id, u->description, cmdline);
+                        continue; /* ask again */
+                case 'j':
+                        manager_dump_jobs(u->manager, stdout, "  ");
+                        continue; /* ask again */
+                case 's':
+                        printf("Skipping execution.\n");
+                        r = CONFIRM_PRETEND_SUCCESS;
+                        break;
+                case 'y':
+                        r = CONFIRM_EXECUTE;
+                        break;
+                default:
+                        assert_not_reached("Unhandled choice");
+                }
+                break;
+        }
 
+restore_stdio:
+        restore_confirm_stdio(&saved_stdin, &saved_stdout);
         return r;
 }
 
@@ -2311,21 +2375,22 @@ static int exec_child(
 
         if (params->confirm_spawn) {
                 const char *vc = params->confirm_spawn;
-                char response;
-
-                r = ask_for_confirmation(vc, &response, argv);
-                if (r == -ETIMEDOUT)
-                        write_confirm_message(vc, "Confirmation question timed out, assuming positive response.\n");
-                else if (r < 0)
-                        write_confirm_message(vc, "Couldn't ask confirmation question, assuming positive response: %s\n", strerror(-r));
-                else if (response == 's') {
-                        write_confirm_message(vc, "Skipping execution.\n");
+                _cleanup_free_ char *cmdline = NULL;
+
+                cmdline = exec_command_line(argv);
+                if (!cmdline) {
+                        *exit_status = EXIT_CONFIRM;
+                        return -ENOMEM;
+                }
+
+                r = ask_for_confirmation(vc, unit, cmdline);
+                if (r != CONFIRM_EXECUTE) {
+                        if (r == CONFIRM_PRETEND_SUCCESS) {
+                                *exit_status = EXIT_SUCCESS;
+                                return 0;
+                        }
                         *exit_status = EXIT_CONFIRM;
                         return -ECANCELED;
-                } else if (response == 'n') {
-                        write_confirm_message(vc, "Failing execution.\n");
-                        *exit_status = 0;
-                        return 0;
                 }
         }