Forked from 终究还是我们队 / proj235-Linux的OTA升级系统
Source project has a limited visibility.
grub.c 5.63 KiB
#include "bootloader.h"
#include "grub.h"
static int grubenv_open(struct grubenv_t *grubenv)
	FILE *fp = NULL;
	size_t size;
	int ret = 0;
	char *buf = NULL, *key = NULL, *value = NULL;
	fp = fopen(GRUBENV_PATH, "rb");
	if (!fp) {
		ERROR("Failed to open grubenv file: %s", GRUBENV_PATH);
		ret = -1;
		goto cleanup;
	if (fseek(fp, 0, SEEK_END)) {
		ERROR("Failed to seek end grubenv file: %s", GRUBENV_PATH);
		ret = -1;
		goto cleanup;
	size = (size_t)ftell(fp);
	if (size != GRUBENV_SIZE) {
		ERROR("Invalid grubenv file size: %d", (int)size);
		ret = -1;
		goto cleanup;
	if (fseek(fp, 0, SEEK_SET)) {
		ERROR("Failed to seek set grubenv file: %s", GRUBENV_PATH);
		ret = -1;
		goto cleanup;
	buf = calloc(1, size + 1);
	if (!buf) {
		ERROR("Not enough memory for environment");
		ret = -ENOMEM;
		goto cleanup;
	if (fread(buf, 1, size, fp) != size) {
		ERROR("Failed to read file %s", GRUBENV_PATH);
		ret = 1;
		goto cleanup;
	if (memcmp(buf, GRUBENV_HEADER, strlen(GRUBENV_HEADER) -1)) {
		ERROR("Invalid grubenv header");
		ret = -1;
		goto cleanup;
	char *entry = buf;
	char *p_char = buf;
	while(*p_char != '\0') {
		if (*p_char != '\n') {
			p_char++;
			continue;
		if (*entry == '#') {
			entry = p_char + 1;
			p_char++;
			continue;
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
key = strtok(entry, "="); value = strtok(NULL, "\n"); if (value != NULL && key != NULL) { ret = dict_set_value(&grubenv->vars, key, value); if (ret) { ERROR("Adding pair [%s] = %s into dictionary list" "failed\n", key, value); return ret; } } entry = p_char + 1; p_char++; } cleanup: if (fp) fclose(fp); free(buf); return ret; } static int grubenv_parse_script(struct grubenv_t *grubenv, const char *script) { FILE *fp = NULL; int ret = 0; char *line = NULL, *key = NULL, *value = NULL; size_t len = 0; fp = fopen(script, "rb"); if (!fp) { ERROR("Failed to open grubenv script file: %s", script); ret = -1; goto cleanup; } while ((getline(&line, &len, fp)) != -1) { key = strtok(line, "="); value = strtok(NULL, "\t\n"); if (value != NULL && key != NULL) { ret = dict_set_value(&grubenv->vars, key, value); if (ret) { ERROR("Adding pair [%s] = %s into dictionary" "list failed\n", key, value); goto cleanup; } } } cleanup: if (fp) fclose(fp); free(line); return ret; } static inline void grubenv_update_size(struct grubenv_t *grubenv) { int size = 0; struct dict_entry *grubvar; LIST_FOREACH(grubvar, &grubenv->vars, next) { char *key = dict_entry_get_key(grubvar); char *value = dict_entry_get_value(grubvar); size = size + strlen(key) + strlen(value) + 2; } size += strlen(GRUBENV_HEADER); grubenv->size = size; } static int grubenv_write(struct grubenv_t *grubenv)
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
{ FILE *fp = NULL; char *buf = NULL, *ptr; struct dict_entry *grubvar; int ret = 0, llen = 0; grubenv_update_size(grubenv); if (grubenv->size > GRUBENV_SIZE) { ERROR("Not enough free space in envblk file, %ld", grubenv->size); ret = -1; goto cleanup; } fp = fopen(GRUBENV_PATH_NEW, "wb"); if (!fp) { ERROR("Failed to open file: %s", GRUBENV_PATH_NEW); ret = -1; goto cleanup; } buf = malloc(GRUBENV_SIZE); if (!buf) { ERROR("Not enough memory for environment"); ret = -ENOMEM; goto cleanup; } strncpy(buf, GRUBENV_HEADER, strlen(GRUBENV_HEADER) + 1); LIST_FOREACH(grubvar, &grubenv->vars, next) { char *key = dict_entry_get_key(grubvar); char *value = dict_entry_get_value(grubvar); char *tmp; llen = strlen(key) + strlen(value) + 2; ret = asprintf(&tmp, "%s=%s\n", key, value); if (ret == ENOMEM_ASPRINTF) { ERROR("OOM when copying Grub Env"); goto cleanup; } strncat(buf, tmp, llen); free(tmp); } ptr = buf + grubenv->size; memset(ptr, '#', buf + GRUBENV_SIZE - ptr); ret = fwrite(buf , 1, GRUBENV_SIZE, fp); if (ret != GRUBENV_SIZE) { ERROR("Failed to write file: %s. Bytes written: %d", GRUBENV_PATH_NEW, ret); ret = -1; goto cleanup; } cleanup: if (fp) fclose(fp); free(buf); return ret; } static inline void grubenv_close(struct grubenv_t *grubenv) { dict_drop_db(&grubenv->vars); } static int do_env_set(const char *name, const char *value)