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) {
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;
}
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;
}
}