<commit_before>#include <gio/gio.h>
#include <errno.h>

#include "bootchooser.h"
#include "config_file.h"
#include "context.h"
#include "install.h"

#define BAREBOX_STATE_NAME "barebox-state"
#define UBOOT_FWSETENV_NAME "fw_setenv"

#if 0
static gboolean barebox_state_get_int(const gchar* name, int *value) {
	GSubprocess *sub;
	GError *error = NULL;
	gboolean res = FALSE;
	GInputStream *instream;
	GDataInputStream *datainstream;
	gchar* outline;
	guint64 result = 0;
	GPtrArray *args = g_ptr_array_new_full(10, g_free);
	
	g_ptr_array_add(args, g_strdup(BAREBOX_STATE_NAME));
	g_ptr_array_add(args, g_strdup("-g"));
	g_ptr_array_add(args, g_strdup(name));
	g_ptr_array_add(args, NULL);

	sub = g_subprocess_newv((const gchar * const *)args->pdata,
				  G_SUBPROCESS_FLAGS_NONE, &error);
	if (!sub) {
		g_warning("getting state failed: %s", error->message);
		g_clear_error(&error);
		goto out;
	}

	instream = g_subprocess_get_stdout_pipe(sub);
	datainstream = g_data_input_stream_new(instream);

	outline = g_data_input_stream_read_line(datainstream, NULL, NULL, NULL);
	if (!outline) {
		g_warning("failed reading state");
		goto out;
	}


	result = g_ascii_strtoull(outline, NULL, 10);
	if (errno != 0) {
		g_warning("Invalid return value: '%s'\n", outline);
		goto out;
	}

	res = g_subprocess_wait_check(sub, NULL, &error);
	if (!res) {
		g_warning("getting state failed: %s", error->message);
		g_clear_error(&error);
		goto out;
	}

out:
	g_ptr_array_unref(args);
	*value = result;
	return res;
}
#endif

#define BOOTSTATE_PREFIX "bootstate"

/* names: list of gchar, values: list of gint */
static gboolean barebox_state_set(GPtrArray *pairs) {
	GSubprocess *sub;
	GError *error = NULL;
	gboolean res = FALSE;
	GPtrArray *args = g_ptr_array_new_full(2*pairs->len+2, g_free);

	g_assert_cmpuint(pairs->len, >, 0);
	
	g_ptr_array_add(args, g_strdup(BAREBOX_STATE_NAME));
	for (guint i = 0; i < pairs->len; i++) {
		g_ptr_array_add(args, g_strdup("-s"));
		g_ptr_array_add(args, g_strdup(pairs->pdata[i]));
	}
	g_ptr_array_add(args, NULL);

	sub = g_subprocess_newv((const gchar * const *)args->pdata,
				  G_SUBPROCESS_FLAGS_NONE, &error);
	if (!sub) {
		g_warning("starting " BAREBOX_STATE_NAME " failed: %s", error->message);
		g_clear_error(&error);
		goto out;
	}

	res = g_subprocess_wait_check(sub, NULL, &error);
	if (!res) {
		g_warning("setting state failed: %s", error->message);
		g_clear_error(&error);
		goto out;
	}

out:
	g_ptr_array_unref(args);
	return res;
}

/* Set slot status values */
static gboolean barebox_set_state(RaucSlot *slot, gboolean good) {
	gboolean res = FALSE;
	GPtrArray *pairs = g_ptr_array_new_full(10, g_free);
	int attempts;

	g_assert_nonnull(slot);

	if (good) {
		attempts = 3;
	} else {
		/* for marking bad, also set priority to 0 */
		attempts = 0;
		g_ptr_array_add(pairs, g_strdup_printf("%s.%s.priority=%i",
				BOOTSTATE_PREFIX, slot->bootname, 0));
	}

	g_ptr_array_add(pairs, g_strdup_printf("%s.%s.remaining_attempts=%i",
			BOOTSTATE_PREFIX, slot->bootname, attempts));

	res = barebox_state_set(pairs);
	if (!res) {
		g_warning("failed marking as %s", good ? "good" : "bad");
		goto out;
	}

	res = TRUE;
out:
	g_ptr_array_unref(pairs);
	return res;
}

/* Set slot as primary boot slot */
static gboolean barebox_set_primary(RaucSlot *slot) {
	GPtrArray *pairs = g_ptr_array_new_full(10, g_free);
	int prio1 = 20, prio2 = 10;
	gboolean res = FALSE;
	GList *slots;

	g_assert_nonnull(slot);

	/* Iterate over class members */
	slots = g_hash_table_get_values(r_context()->config->slots);
	for (GList *l = slots; l != NULL; l = l->next) {
		RaucSlot *s = l->data;
		int prio;

		if (s->sclass != slot->sclass)
			continue;

		if (s == slot) {
			prio = prio1;
		} else {
			prio = prio2;
		}
		g_ptr_array_add(pairs, g_strdup_printf("%s.%s.priority=%i",
				BOOTSTATE_PREFIX, s->bootname, prio));
	}

	g_ptr_array_add(pairs, g_strdup_printf("%s.%s.remaining_attempts=%i",
			BOOTSTATE_PREFIX, slot->bootname, 3));

	res = barebox_state_set(pairs);
	if (!res) {
		g_warning("failed marking as primary");
		goto out;
	}

	res = TRUE;
out:
	return res;
}

static gboolean grub_env_set(GPtrArray *pairs) {
	GSubprocess *sub;
	GError *error = NULL;
	gboolean res = FALSE;

	g_assert_cmpuint(pairs->len, >, 0);
	g_assert_nonnull(r_context()->config->grubenv_path);

	g_ptr_array_insert(pairs, 0, g_strdup("grub-editenv"));
	g_ptr_array_insert(pairs, 1, g_strdup(r_context()->config->grubenv_path));
	g_ptr_array_insert(pairs, 2, g_strdup("set"));
	g_ptr_array_add(pairs, NULL);

	sub = g_subprocess_newv((const gchar * const *)pairs->pdata,
				  G_SUBPROCESS_FLAGS_NONE, &error);
	if (!sub) {
		g_warning("starting grub-editenv failed: %s", error->message);
		g_clear_error(&error);
		goto out;
	}

	res = g_subprocess_wait_check(sub, NULL, &error);<commit_msg>bootchooser: fix memory leak<commit_after>#include <gio/gio.h>
#include <errno.h>

#include "bootchooser.h"
#include "config_file.h"
#include "context.h"
#include "install.h"

#define BAREBOX_STATE_NAME "barebox-state"
#define UBOOT_FWSETENV_NAME "fw_setenv"

#if 0
static gboolean barebox_state_get_int(const gchar* name, int *value) {
	GSubprocess *sub;
	GError *error = NULL;
	gboolean res = FALSE;
	GInputStream *instream;
	GDataInputStream *datainstream;
	gchar* outline;
	guint64 result = 0;
	GPtrArray *args = g_ptr_array_new_full(10, g_free);
	
	g_ptr_array_add(args, g_strdup(BAREBOX_STATE_NAME));
	g_ptr_array_add(args, g_strdup("-g"));
	g_ptr_array_add(args, g_strdup(name));
	g_ptr_array_add(args, NULL);

	sub = g_subprocess_newv((const gchar * const *)args->pdata,
				  G_SUBPROCESS_FLAGS_NONE, &error);
	if (!sub) {
		g_warning("getting state failed: %s", error->message);
		g_clear_error(&error);
		goto out;
	}

	instream = g_subprocess_get_stdout_pipe(sub);
	datainstream = g_data_input_stream_new(instream);

	outline = g_data_input_stream_read_line(datainstream, NULL, NULL, NULL);
	if (!outline) {
		g_warning("failed reading state");
		goto out;
	}


	result = g_ascii_strtoull(outline, NULL, 10);
	if (errno != 0) {
		g_warning("Invalid return value: '%s'\n", outline);
		goto out;
	}

	res = g_subprocess_wait_check(sub, NULL, &error);
	if (!res) {
		g_warning("getting state failed: %s", error->message);
		g_clear_error(&error);
		goto out;
	}

out:
	g_ptr_array_unref(args);
	*value = result;
	return res;
}
#endif

#define BOOTSTATE_PREFIX "bootstate"

/* names: list of gchar, values: list of gint */
static gboolean barebox_state_set(GPtrArray *pairs) {
	GSubprocess *sub;
	GError *error = NULL;
	gboolean res = FALSE;
	GPtrArray *args = g_ptr_array_new_full(2*pairs->len+2, g_free);

	g_assert_cmpuint(pairs->len, >, 0);
	
	g_ptr_array_add(args, g_strdup(BAREBOX_STATE_NAME));
	for (guint i = 0; i < pairs->len; i++) {
		g_ptr_array_add(args, g_strdup("-s"));
		g_ptr_array_add(args, g_strdup(pairs->pdata[i]));
	}
	g_ptr_array_add(args, NULL);

	sub = g_subprocess_newv((const gchar * const *)args->pdata,
				  G_SUBPROCESS_FLAGS_NONE, &error);
	if (!sub) {
		g_warning("starting " BAREBOX_STATE_NAME " failed: %s", error->message);
		g_clear_error(&error);
		goto out;
	}

	res = g_subprocess_wait_check(sub, NULL, &error);
	if (!res) {
		g_warning("setting state failed: %s", error->message);
		g_clear_error(&error);
		goto out;
	}

out:
	g_ptr_array_unref(args);
	return res;
}

/* Set slot status values */
static gboolean barebox_set_state(RaucSlot *slot, gboolean good) {
	gboolean res = FALSE;
	GPtrArray *pairs = g_ptr_array_new_full(10, g_free);
	int attempts;

	g_assert_nonnull(slot);

	if (good) {
		attempts = 3;
	} else {
		/* for marking bad, also set priority to 0 */
		attempts = 0;
		g_ptr_array_add(pairs, g_strdup_printf("%s.%s.priority=%i",
				BOOTSTATE_PREFIX, slot->bootname, 0));
	}

	g_ptr_array_add(pairs, g_strdup_printf("%s.%s.remaining_attempts=%i",
			BOOTSTATE_PREFIX, slot->bootname, attempts));

	res = barebox_state_set(pairs);
	if (!res) {
		g_warning("failed marking as %s", good ? "good" : "bad");
		goto out;
	}

	res = TRUE;
out:
	g_ptr_array_unref(pairs);
	return res;
}

/* Set slot as primary boot slot */
static gboolean barebox_set_primary(RaucSlot *slot) {
	GPtrArray *pairs = g_ptr_array_new_full(10, g_free);
	int prio1 = 20, prio2 = 10;
	gboolean res = FALSE;
	GList *slots;

	g_assert_nonnull(slot);

	/* Iterate over class members */
	slots = g_hash_table_get_values(r_context()->config->slots);
	for (GList *l = slots; l != NULL; l = l->next) {
		RaucSlot *s = l->data;
		int prio;

		if (s->sclass != slot->sclass)
			continue;

		if (s == slot) {
			prio = prio1;
		} else {
			prio = prio2;
		}
		g_ptr_array_add(pairs, g_strdup_printf("%s.%s.priority=%i",
				BOOTSTATE_PREFIX, s->bootname, prio));
	}

	g_ptr_array_add(pairs, g_strdup_printf("%s.%s.remaining_attempts=%i",
			BOOTSTATE_PREFIX, slot->bootname, 3));

	res = barebox_state_set(pairs);
	if (!res) {
		g_warning("failed marking as primary");
		goto out;
	}

	res = TRUE;
out:
	g_ptr_array_unref(pairs);
	return res;
}

static gboolean grub_env_set(GPtrArray *pairs) {
	GSubprocess *sub;
	GError *error = NULL;
	gboolean res = FALSE;

	g_assert_cmpuint(pairs->len, >, 0);
	g_assert_nonnull(r_context()->config->grubenv_path);

	g_ptr_array_insert(pairs, 0, g_strdup("grub-editenv"));
	g_ptr_array_insert(pairs, 1, g_strdup(r_context()->config->grubenv_path));
	g_ptr_array_insert(pairs, 2, g_strdup("set"));
	g_ptr_array_add(pairs, NULL);

	sub = g_subprocess_newv((const gchar * const *)pairs->pdata,
				  G_SUBPROCESS_FLAGS_NONE, &error);
	if (!sub) {
		g_warning("starting grub-editenv failed: %s", error->message);
		g_clear_error(&error);
		goto out;
	}

	res = g_subprocess_wait_check(sub, NULL, &error);
{'fraction_non_alphanumeric': 0.14557092711129466, 'fraction_numerical': 0.007020441874870948, 'mean_word_length': 5.077164366373903, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 65, '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': '7345736', 'n_tokens_mistral': 4189, 'n_tokens_neox': 3928, 'n_words': 793}