* the implementations of event command request handlers were moved in to
separate functions
* the request handlers are called through run_event_state callbacks
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/include/run_event.h | 88 +++++++++++++++++++++++++++++++++++++++++++
src/lib/run_event.c | 96 ++++++++++++++++++++++++++++++++---------------
2 files changed, 154 insertions(+), 30 deletions(-)
diff --git a/src/include/run_event.h b/src/include/run_event.h
index 43730ce..4577444 100644
--- a/src/include/run_event.h
+++ b/src/include/run_event.h
@@ -40,6 +40,57 @@ struct run_event_state {
char* (*logging_callback)(char *log_line, void *param);
void *logging_param;
+ /*
+ * An optional argument for the following callbacks
+ */
+ void *interaction_param;
+
+ /*
+ * Called when child command produced an alert.
+ *
+ * The default value is run_event_stdio_alert()
+ *
+ * @param msg An alert message produced byt child command
+ * @param args An interaction param
+ */
+ void (*alert_callback)(const char *msg, void *interaction_param);
+
+ /*
+ * Called when child command ask for some input. A callee
+ * should return a text whithout any new line character.
+ *
+ * The default value is run_event_stdio_ask()
+ *
+ * @param msg An ask message produced by child command
+ * @param args An interaction param
+ * @return Must allways return string without new lines, an empty string
+ * if response was not get.
+ */
+ char *(*ask_callback)(const char *msg, void *interaction_param);
+
+ /*
+ * Called when child command wants to know 'yes/no' decision.
+ *
+ * The default value is run_event_stdio_ask_yes_no()
+ *
+ * @param msg An ask message produced by child command
+ * @param args An implementor args
+ * @return Return 0 if an answer is NO, otherwise return nonzero value.
+ */
+ int (*ask_yes_no_callback)(const char *msg, void *interaction_param);
+
+ /*
+ * Called when child wants to know a password.
+ *
+ * The default value is run_event_stdio_ask_password()
+ *
+ * @param msg An ask message produced by child command
+ * @param args An interaction param
+ * @return Must allways return string without new lines, an empty string
+ * if password was not get.
+ */
+ char *(*ask_password_callback)(const char *msg, void *interaction_param);
+
/* Internal data for async command execution */
GList *rule_list;
pid_t command_pid;
@@ -76,6 +127,43 @@ int run_event_on_problem_data(struct run_event_state *state,
problem_data_t *dat
*/
char *list_possible_events(struct dump_dir *dd, const char *dump_dir_name, const char
*pfx);
+/* Command line run event callback implemenetation */
+
+/*
+ * Prints the msg param on stdout
+ *
+ * @param msg a printed message
+ * @param param UNUSED
+ */
+void run_event_stdio_alert(const char *msg, void *param);
+
+/*
+ * Prints the msg param on stdout and reads a response from stdin
+ *
+ * @param msg a printed message
+ * @param param UNUSED
+ * @return a malloced string with response, an empty string on error or no response
+ */
+char *run_event_stdio_ask(const char *msg, void *param);
+
+/*
+ * Prints the msg param on stdout and reads a response from stdin
+ *
+ * @param msg a printed message
+ * @param param UNUSED
+ * @return 0 if user's answer is 'no', otherwise non 0 value
+ */
+int run_event_stdio_ask_yes_no(const char *msg, void *param);
+
+/*
+ * Prints the msg param on stdout and reads a response from stdin
+ *
+ * @param msg a printed message
+ * @param param UNUSED
+ * @return a malloced string with response, an empty string on error or no response
+ */
+char *run_event_stdio_ask_password(const char *msg, void *param);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/lib/run_event.c b/src/lib/run_event.c
index 105cef5..ab6d79c 100644
--- a/src/lib/run_event.c
+++ b/src/lib/run_event.c
@@ -23,7 +23,14 @@
struct run_event_state *new_run_event_state()
{
- return xzalloc(sizeof(struct run_event_state));
+ struct run_event_state *state = xzalloc(sizeof(struct run_event_state));
+
+ state->alert_callback = run_event_stdio_alert;
+ state->ask_callback = run_event_stdio_ask;
+ state->ask_yes_no_callback = run_event_stdio_ask_yes_no;
+ state->ask_password_callback = run_event_stdio_ask_password;
+
+ return state;
}
void free_run_event_state(struct run_event_state *state)
@@ -451,60 +458,48 @@ static int run_event_command_on_dir_name(struct run_event_state
*state, const ch
{
msg = buf;
+ char *response = NULL;
/* just cut off prefix, no waiting */
if (strncmp(REPORT_PREFIX_ALERT, msg, alert_prefix_len) == 0)
{
msg += alert_prefix_len;
- printf("%s\n", msg);
- fflush(stdout);
+ state->alert_callback(msg, state->interaction_param);
}
/* wait for y/N response on the same line */
else if (strncmp(REPORT_PREFIX_ASK_YES_NO, msg, ask_yes_no_prefix_len) == 0)
{
msg += ask_yes_no_prefix_len;
- printf("%s [%s/%s] ", msg, _("y"), _("N"));
- fflush(stdout);
- char buf[16];
- if (!fgets(buf, sizeof(buf), stdin))
- buf[0] = '\0';
-
- if (write(state->command_in_fd, buf, strlen(buf)) < 0)
- perror_msg_and_die("write");
+ const bool ans = state->ask_yes_no_callback(msg,
state->interaction_param);
+ response = xstrdup(ans ? "yes" : "no");
}
/* wait for the string on the same line */
else if (strncmp(REPORT_PREFIX_ASK, msg, ask_prefix_len) == 0)
{
msg += ask_prefix_len;
- printf("%s ", msg);
- fflush(stdout);
- char buf[256];
- if (!fgets(buf, sizeof(buf), stdin))
- buf[0] = '\0';
-
- if (write(state->command_in_fd, buf, strlen(buf)) < 0)
- perror_msg_and_die("write");
+ response = state->ask_callback(msg, state->interaction_param);
}
/* set echo off and wait for password on the same line */
else if (strncmp(REPORT_PREFIX_ASK_PASSWORD, msg, ask_password_prefix_len) == 0)
{
msg += ask_password_prefix_len;
- printf("%s ", msg);
- fflush(stdout);
- char buf[256];
- bool changed = set_echo(false);
- if (!fgets(buf, sizeof(buf), stdin))
- buf[0] = '\0';
- if (changed)
- set_echo(true);
-
- if (write(state->command_in_fd, buf, strlen(buf)) < 0)
- perror_msg_and_die("write");
+ response = state->ask_password_callback(msg,
state->interaction_param);
}
/* no special prefix -> forward to log if applicable
* note that callback may take ownership of buf by returning NULL */
else if (state->logging_callback)
buf = state->logging_callback(buf, state->logging_param);
+ if (response)
+ {
+ size_t len = strlen(response);
+ response[len++] = '\n';
+
+ if (full_write(state->command_in_fd, response, len) != len)
+ perror_msg_and_die("Can't write %lu bytes to child's
stdin", len);
+
+ free(response);
+ }
+
free(buf);
}
fclose(fp); /* Got EOF, close. This also closes state->command_out_fd */
@@ -612,3 +607,44 @@ char *list_possible_events(struct dump_dir *dd, const char
*dump_dir_name, const
return strbuf_free_nobuf(result);
}
+
+void run_event_stdio_alert(const char *msg, void *param)
+{
+ printf("%s\n", msg);
+ fflush(stdout);
+}
+
+char *run_event_stdio_ask(const char *msg, void *param)
+{
+ printf("%s ", msg);
+ fflush(stdout);
+ char buf[256];
+ if (!safe_read(STDIN_FILENO, buf, sizeof(buf)))
+ buf[0] = '\0';
+ else
+ strtrimch(buf, '\n');
+
+ return xstrdup(buf);
+}
+
+int run_event_stdio_ask_yes_no(const char *msg, void *param)
+{
+ printf("%s [%s/%s] ", msg, _("y"), _("N"));
+ fflush(stdout);
+ char buf[16];
+ if (!safe_read(STDIN_FILENO, buf, sizeof(buf)))
+ return false;
+
+ return buf[0] == 'y' && (buf[1] == '\n' || buf[1] ==
'\0');
+}
+
+char *run_event_stdio_ask_password(const char *msg, void *param)
+{
+ const bool changed = set_echo(false);
+ char *const password = run_event_stdio_ask(msg, param);
+
+ if (changed)
+ set_echo(true);
+
+ return password;
+}
--
1.7.10.4