Skip to content

Instantly share code, notes, and snippets.

@worr
Created February 20, 2013 01:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save worr/4991859 to your computer and use it in GitHub Desktop.
Save worr/4991859 to your computer and use it in GitHub Desktop.
static void check_if_need_to_close(struct cmd_data* cmd_data) {
if (cmd_data->cmd_exited && cmd_data->in_closed && cmd_data->out_closed && cmd_data->err_closed)
g_main_loop_quit(cmd_data->loop);
}
static void check_exit_status(GPid pid, gint status, gpointer user_data) {
wsh_cmd_res_t* res = ((struct cmd_data*)user_data)->res;
wsh_cmd_req_t* req = ((struct cmd_data*)user_data)->req;
res->exit_status = WEXITSTATUS(status);
log_server_cmd_status(req->cmd_string, req->username, req->host, req->cwd, res->exit_status);
g_spawn_close_pid(pid);
((struct cmd_data*)user_data)->cmd_exited = TRUE;
check_if_need_to_close(user_data);
}
static gboolean check_stdout(GIOChannel* out, GIOCondition cond, gpointer user_data) {
wsh_cmd_res_t* res = ((struct cmd_data*)user_data)->res;
wsh_cmd_req_t* req = ((struct cmd_data*)user_data)->req;
gboolean ret = TRUE;
if (cond & G_IO_HUP) {
((struct cmd_data*)user_data)->out_closed = TRUE;
check_if_need_to_close((struct cmd_data*)user_data);
g_io_channel_unref(out);
return FALSE;
}
gchar* buf = NULL;
gsize buf_len = 0;
g_io_channel_read_line(out, &buf, &buf_len, NULL, &res->err);
if (res->err) {
ret = FALSE;
goto check_stdout_err;
}
if (buf)
add_line_stdout(res, buf);
check_stdout_err:
g_free(buf);
return ret;
}
static gboolean check_stderr(GIOChannel* err, GIOCondition cond, gpointer user_data) {
wsh_cmd_res_t* res = ((struct cmd_data*)user_data)->res;
gboolean ret = TRUE;
if (cond & G_IO_HUP) {
((struct cmd_data*)user_data)->err_closed = TRUE;
check_if_need_to_close(user_data);
g_io_channel_unref(err);
return FALSE;
}
gchar* buf = NULL;
gsize buf_len = 0;
g_io_channel_read_line(err, &buf, &buf_len, NULL, &res->err);
if (buf)
add_line_stderr(res, buf);
if (res->err != NULL) {
ret = FALSE;
}
g_free(buf);
return ret;
}
static gboolean write_stdin(GIOChannel* in, GIOCondition cond, gpointer user_data) {
if (cond & G_IO_HUP) {
((struct cmd_data*)user_data)->in_closed = TRUE;
check_if_need_to_close(user_data);
g_io_channel_unref(in);
return FALSE;
}
return TRUE;
}
gint run_cmd(wsh_cmd_res_t res, wsh_cmd_req_t req) {
g_spawn_async_with_pipes(
req->cwd, // working dir
argcv, // argv
req->env, // env
flags, // flags
NULL, // child setup
NULL, // user_data
&pid, // child_pid
&req->in_fd, // stdin
&res->out_fd, // stdout
&res->err_fd, // stderr
&res->err); // Gerror
if (res->err != NULL) {
ret = EXIT_FAILURE;
goto run_cmd_error;
}
// Main loop initialization
GMainContext* context = g_main_context_new();
loop = g_main_loop_new(context, FALSE);
struct cmd_data user_data = {
.loop = loop,
.req = req,
.res = res,
.sudo_rdy = FALSE,
.cmd_exited = FALSE,
.out_closed = FALSE,
.err_closed = FALSE,
.in_closed = FALSE,
};
// Watch child process
GSource* watch_src = g_child_watch_source_new(pid);
g_source_set_callback(watch_src, (GSourceFunc)check_exit_status, &user_data, NULL);
g_source_attach(watch_src, context);
// Initialize IO Channels
out = g_io_channel_unix_new(res->out_fd);
err = g_io_channel_unix_new(res->err_fd);
in = g_io_channel_unix_new(req->in_fd);
// Add IO channels
GSource* stdout_src = g_io_create_watch(out, G_IO_IN | G_IO_HUP);
g_source_set_callback(stdout_src, (GSourceFunc)check_stdout, &user_data, NULL);
g_source_attach(stdout_src, context);
GSource* stderr_src = g_io_create_watch(err, G_IO_IN | G_IO_HUP);
g_source_set_callback(stderr_src, (GSourceFunc)check_stderr, &user_data, NULL);
g_source_attach(stderr_src, context);
GSource* stdin_src = g_io_create_watch(in, G_IO_OUT | G_IO_HUP);
g_source_set_callback(stdin_src, (GSourceFunc)write_stdin, &user_data, NULL);
g_source_attach(stdin_src, context);
// Start dat loop
g_main_loop_run(loop);
g_main_loop_unref(loop);
g_main_context_unref(context);
g_source_unref(watch_src);
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment