Improve error handling in upgrade.conf(5) parsing.

This commit is contained in:
Jonas 'Sortie' Termansen 2021-01-17 22:54:35 +01:00
parent 84b008e455
commit ba8800df2c
5 changed files with 77 additions and 50 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, 2016 Jonas 'Sortie' Termansen. * Copyright (c) 2015, 2016, 2017, 2021 Jonas 'Sortie' Termansen.
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -28,54 +28,67 @@
#include "conf.h" #include "conf.h"
static bool conf_boolean(const char* name, const char* value, const char* path) void conf_init(struct conf* conf)
{
memset(conf, 0, sizeof(*conf));
conf->ports = true;
conf->system = true;
}
void conf_free(struct conf* conf)
{
conf_init(conf);
}
static bool conf_boolean(const char* name,
const char* value,
const char* path,
off_t line_number)
{ {
if ( !strcmp(value, "yes") ) if ( !strcmp(value, "yes") )
return true; return true;
if ( !strcmp(value, "no") ) if ( !strcmp(value, "no") )
return false; return false;
printf("%s: %s: Expected yes or no instead of unsupported value\n", printf("%s:%ji: %s: Expected yes or no instead of unsupported value\n",
path, name); path, (intmax_t) line_number, name);
return false; return false;
} }
static void conf_assign(struct conf* conf, static bool conf_assign(struct conf* conf,
const char* name, const char* name,
const char* value, const char* value,
const char* path) const char* path,
off_t line_number)
{ {
if ( !strcmp(name, "grub") ) if ( !strcmp(name, "grub") )
conf->grub = conf_boolean(name, value, path); conf->grub = conf_boolean(name, value, path, line_number);
else if ( !strcmp(name, "newsrc") ) else if ( !strcmp(name, "newsrc") )
conf->newsrc = conf_boolean(name, value, path); conf->newsrc = conf_boolean(name, value, path, line_number);
else if ( !strcmp(name, "ports") ) else if ( !strcmp(name, "ports") )
conf->ports = conf_boolean(name, value, path); conf->ports = conf_boolean(name, value, path, line_number);
else if ( !strcmp(name, "src") ) else if ( !strcmp(name, "src") )
conf->src = conf_boolean(name, value, path); conf->src = conf_boolean(name, value, path, line_number);
else if ( !strcmp(name, "system") ) else if ( !strcmp(name, "system") )
conf->system = conf_boolean(name, value, path); conf->system = conf_boolean(name, value, path, line_number);
else else
printf("%s: %s: Unsupported variable\n", path, name); printf("%s:%ji: Unsupported variable: %s\n", path,
(intmax_t) line_number, name);
return true;
} }
void load_upgrade_conf(struct conf* conf, const char* path) bool conf_load(struct conf* conf, const char* path)
{ {
memset(conf, 0, sizeof(*conf));
conf->ports = true;
conf->system = true;
FILE* fp = fopen(path, "r"); FILE* fp = fopen(path, "r");
if ( !fp ) if ( !fp )
{ return false;
if ( errno == ENOENT )
return;
err(2, "%s", path);
}
char* line = NULL; char* line = NULL;
size_t line_size = 0; size_t line_size = 0;
ssize_t line_length; ssize_t line_length;
intmax_t line_number = 0;
bool success = true;
while ( 0 < (line_length = getline(&line, &line_size, fp)) ) while ( 0 < (line_length = getline(&line, &line_size, fp)) )
{ {
line_number++;
if ( line[line_length - 1] == '\n' ) if ( line[line_length - 1] == '\n' )
line[--line_length] = '\0'; line[--line_length] = '\0';
line_length = 0; line_length = 0;
@ -87,8 +100,13 @@ void load_upgrade_conf(struct conf* conf, const char* path)
char* name = line; char* name = line;
while ( *name && isblank((unsigned char) *name) ) while ( *name && isblank((unsigned char) *name) )
name++; name++;
if ( !*name || *name == '=' ) if ( !*name )
continue; continue;
if ( *name == '=' )
{
printf("%s:%ji: Ignoring malformed line\n", path, line_number);
continue;
}
size_t name_length = 1; size_t name_length = 1;
while ( name[name_length] && while ( name[name_length] &&
!isblank((unsigned char) name[name_length]) && !isblank((unsigned char) name[name_length]) &&
@ -98,15 +116,23 @@ void load_upgrade_conf(struct conf* conf, const char* path)
while ( *value && isblank((unsigned char) *value) ) while ( *value && isblank((unsigned char) *value) )
value++; value++;
if ( *value != '=' ) if ( *value != '=' )
{
printf("%s:%ji: Ignoring malformed line\n", path, line_number);
continue; continue;
}
value++; value++;
while ( *value && isblank((unsigned char) *value) ) while ( *value && isblank((unsigned char) *value) )
value++; value++;
name[name_length] = '\0'; name[name_length] = '\0';
conf_assign(conf, name, value, path); if ( !conf_assign(conf, name, value, path, line_number) )
{
success = false;
break;
}
} }
if ( ferror(fp) ) if ( ferror(fp) )
err(2, "%s", path); success = false;
free(line); free(line);
fclose(fp); fclose(fp);
return success;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, 2016 Jonas 'Sortie' Termansen. * Copyright (c) 2015, 2016, 2017 Jonas 'Sortie' Termansen.
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -29,6 +29,8 @@ struct conf
bool system; bool system;
}; };
void load_upgrade_conf(struct conf* conf, const char* path); void conf_init(struct conf* conf);
void conf_free(struct conf* conf);
bool conf_load(struct conf* conf, const char* path);
#endif #endif

View File

@ -142,27 +142,16 @@ static bool should_install_bootloader_path(const char* mnt,
warn("malloc"); warn("malloc");
return false; return false;
} }
// TODO: The load_upgrade_conf function might exit the process on failure, struct conf conf;
// but we don't want that. Redesign the mountpoint code so the caller conf_init(&conf);
// controls this. bool result = false;
pid_t pid = fork(); if ( conf_load(&conf, conf_path) )
if ( pid < 0 ) result = conf.grub;
{ else if ( errno != ENOENT )
warn("fork"); warn("%s: /etc/upgrade.conf", path_of_blockdevice(bdev));
free(conf_path); conf_free(&conf);
return false; free(conf_path);
} return result;
if ( !pid )
{
struct conf conf;
load_upgrade_conf(&conf, conf_path);
bool should = conf.grub;
_exit(should ? 0 : 1);
}
int status;
if ( waitpid(pid, &status, 0) < 0 )
return false;
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
} }
static bool should_install_bootloader_bdev(struct blockdevice* bdev) static bool should_install_bootloader_bdev(struct blockdevice* bdev)
@ -412,6 +401,11 @@ int main(void)
struct utsname uts; struct utsname uts;
uname(&uts); uname(&uts);
struct conf conf;
conf_init(&conf);
if ( !conf_load(&conf, "/etc/upgrade.conf") && errno != ENOENT )
warn("/etc/upgrade.conf");
static char input[256]; static char input[256];
textf("Hello and welcome to the " BRAND_DISTRIBUTION_NAME " " VERSIONSTR "" textf("Hello and welcome to the " BRAND_DISTRIBUTION_NAME " " VERSIONSTR ""

View File

@ -241,7 +241,9 @@ int main(int argc, char* argv[])
// TODO: Check for version (skipping, downgrading). // TODO: Check for version (skipping, downgrading).
struct conf conf; struct conf conf;
load_upgrade_conf(&conf, "/etc/upgrade.conf"); conf_init(&conf);
if ( !conf_load(&conf, "/etc/upgrade.conf") && errno == ENOENT )
err(2, "/etc/upgrade.conf");
bool can_run_new_abi = bool can_run_new_abi =
abi_compatible(new_release.abi_major, new_release.abi_minor, abi_compatible(new_release.abi_major, new_release.abi_minor,

View File

@ -721,9 +721,12 @@ int main(void)
bool do_upgrade_bootloader; bool do_upgrade_bootloader;
struct conf conf; struct conf conf;
conf_init(&conf);
while ( true ) while ( true )
{ {
load_upgrade_conf(&conf, "etc/upgrade.conf"); conf_free(&conf);
if ( !conf_load(&conf, "etc/upgrade.conf") && errno != ENOENT )
err(2, "etc/upgrade.conf");
do_upgrade_bootloader = do_upgrade_bootloader =
conf.grub && (conf.ports || (conf.system && can_run_old_abi)); conf.grub && (conf.ports || (conf.system && can_run_old_abi));