<commit_before>#include "cmd.h"

#include <glib.h>
#include <stdlib.h>
#include <sys/wait.h>

// retval should be g_free'd
static gchar* construct_sudo_cmd(const struct cmd_req* req) {
	// If not sudo, don't actually construct the command
	if (! req->sudo)
		return g_strdup(req->cmd_string);

	// Construct cmd to escalate privs assuming use of sudo
	// Should probably get away from relying explicitly on sudo, but it's good
	// enough for now

	// Thanks to glib this is basically a single function call
	return g_strconcat(SUDO_CMD, req->username, req->cmd_string, NULL);
}

gint run_cmd(struct cmd_res* res, struct cmd_req* req) {
	gchar* old_path;
	pid_t pid;
	gint stat, argcp;
	gchar** argcv;
	gint ret = EXIT_SUCCESS;

	gint flags = G_SPAWN_DO_NOT_REAP_CHILD;
	gchar* cmd = construct_sudo_cmd(req);

	GError* err = NULL;
	if (res->err != NULL)
		res->err = NULL;

// sorry Russ...
#if GLIB_CHECK_VERSION ( 2, 34, 0 )
	flags |= G_SPAWN_SEARCH_PATH_FROM_ENVP;
#else
	flags |= G_SPAWN_SEARCH_PATH;
#endif

	/* Older versions of glib do not include G_SPAWN_SEARCH_PATH_FROM_ENVP
	 * flag. To get around this, we detect what version of glib we're running,
	 * copy the user-defined path into the current path, run the command and restore the
	 * old path.
	 */
	if (glib_check_version(2, 34, 0)) {
		old_path = g_strdup(g_getenv("PATH"));
		g_setenv(g_environ_getenv(req->env, "PATH"), "PATH", TRUE);
	}

	if (! g_shell_parse_argv(cmd, &argcp, &argcv, &err)) {
		ret = EXIT_FAILURE;
		goto run_cmd_error;
	}

	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
		NULL, // stdin
		&res->out_fd, // stdout
		&res->err_fd, // stderr
		&res->err); // Gerror

	if (res->err != NULL) {
		ret = EXIT_FAILURE;
		goto run_cmd_error;
	}

	// wait()s to get status of called function, so we can report it back to
	// the user and so we don't blow away path or anything
	if (waitpid(pid, &stat, 0) != -1) {
		res->exit_status = WEXITSTATUS(stat);
	} else {
		ret = EXIT_FAILURE;
		goto run_cmd_error;
	}

run_cmd_error:

	// Restoring old path
	if (glib_check_version(2, 34, 0)) {
		g_setenv("PATH", old_path, TRUE);
		g_free(old_path);
	}

	g_free(cmd);
	g_free(res->err);
	g_free(err);

	return ret;
}<commit_msg>No point in free()ing GErrors if they're null for now<commit_after>#include "cmd.h"

#include <glib.h>
#include <stdlib.h>
#include <sys/wait.h>

// retval should be g_free'd
static gchar* construct_sudo_cmd(const struct cmd_req* req) {
	// If not sudo, don't actually construct the command
	if (! req->sudo)
		return g_strdup(req->cmd_string);

	// Construct cmd to escalate privs assuming use of sudo
	// Should probably get away from relying explicitly on sudo, but it's good
	// enough for now

	// Thanks to glib this is basically a single function call
	return g_strconcat(SUDO_CMD, req->username, req->cmd_string, NULL);
}

gint run_cmd(struct cmd_res* res, struct cmd_req* req) {
	gchar* old_path;
	pid_t pid;
	gint stat, argcp;
	gchar** argcv;
	gint ret = EXIT_SUCCESS;

	gint flags = G_SPAWN_DO_NOT_REAP_CHILD;
	gchar* cmd = construct_sudo_cmd(req);

	GError* err = NULL;
	if (res->err != NULL)
		res->err = NULL;

// sorry Russ...
#if GLIB_CHECK_VERSION ( 2, 34, 0 )
	flags |= G_SPAWN_SEARCH_PATH_FROM_ENVP;
#else
	flags |= G_SPAWN_SEARCH_PATH;
#endif

	/* Older versions of glib do not include G_SPAWN_SEARCH_PATH_FROM_ENVP
	 * flag. To get around this, we detect what version of glib we're running,
	 * copy the user-defined path into the current path, run the command and restore the
	 * old path.
	 */
	if (glib_check_version(2, 34, 0)) {
		old_path = g_strdup(g_getenv("PATH"));
		g_setenv(g_environ_getenv(req->env, "PATH"), "PATH", TRUE);
	}

	if (! g_shell_parse_argv(cmd, &argcp, &argcv, &err)) {
		ret = EXIT_FAILURE;
		goto run_cmd_error;
	}

	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
		NULL, // stdin
		&res->out_fd, // stdout
		&res->err_fd, // stderr
		&res->err); // Gerror

	if (res->err != NULL) {
		ret = EXIT_FAILURE;
		goto run_cmd_error;
	}

	// wait()s to get status of called function, so we can report it back to
	// the user and so we don't blow away path or anything
	if (waitpid(pid, &stat, 0) != -1) {
		res->exit_status = WEXITSTATUS(stat);
	} else {
		ret = EXIT_FAILURE;
		goto run_cmd_error;
	}

run_cmd_error:

	// Restoring old path
	if (glib_check_version(2, 34, 0)) {
		g_setenv("PATH", old_path, TRUE);
		g_free(old_path);
	}

	g_free(cmd);

	return ret;
}
{'fraction_non_alphanumeric': 0.12840300107181135, 'fraction_numerical': 0.006002143622722401, 'mean_word_length': 3.6427860696517413, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '758564', 'n_tokens_mistral': 1917, 'n_tokens_neox': 1798, 'n_words': 521}