diff --git a/sysinstall/fileops.c b/sysinstall/fileops.c index b3201d35..d18a266c 100644 --- a/sysinstall/fileops.c +++ b/sysinstall/fileops.c @@ -17,6 +17,7 @@ * File operation utility functions. */ +#include #include #include @@ -129,3 +130,42 @@ void write_random_seed(const char* path) } close(fd); } + +char* read_string_file(const char* path) +{ + FILE* fp = fopen(path, "r"); + if ( !fp ) + return NULL; + struct stat st; + if ( fstat(fileno(fp), &st) < 0 ) + { + fclose(fp); + return NULL; + } + size_t content_length; + if ( __builtin_add_overflow(1, st.st_size, &content_length) ) + { + fclose(fp); + errno = EOVERFLOW; + return NULL; + } + char* content = malloc(content_length); + if ( !content ) + { + fclose(fp); + return NULL; + } + size_t amount = fread(content, 1, content_length - 1, fp); + if ( ferror(fp) ) + { + fclose(fp); + free(content); + return NULL; + } + fclose(fp); + if ( 0 < amount && content[amount - 1] == '\n' ) + content[amount - 1] = '\0'; + else + content[amount] = '\0'; + return content; +} diff --git a/sysinstall/fileops.h b/sysinstall/fileops.h index 0f3991a3..c285f44f 100644 --- a/sysinstall/fileops.h +++ b/sysinstall/fileops.h @@ -25,5 +25,6 @@ int mkdir_p(const char* path, mode_t mode); int access_or_die(const char* path, int mode); void mkdir_or_chmod_or_die(const char* path, mode_t mode); void write_random_seed(const char* path); +char* read_string_file(const char* path); #endif diff --git a/sysinstall/sysmerge.c b/sysinstall/sysmerge.c index baad2c39..49db562e 100644 --- a/sysinstall/sysmerge.c +++ b/sysinstall/sysmerge.c @@ -191,7 +191,23 @@ int main(int argc, char* argv[]) } free(new_release_path); - // TODO: Check if /etc/machine matches the current architecture. + const char* old_machine_path = "/etc/machine"; + char* old_machine = read_string_file(old_machine_path); + if ( !old_machine ) + err(2, "%s", old_machine_path); + char* new_machine_path; + if ( asprintf(&new_machine_path, "%s/etc/machine", source) < 0 ) + err(2, "asprintf"); + char* new_machine = read_string_file(new_machine_path); + if ( !new_machine ) + err(2, "%s", new_machine_path); + if ( strcmp(old_machine, new_machine) != 0 ) + errx(2, "%s (%s) does not match %s (%s)", new_machine_path, + new_machine, old_machine_path, old_machine); + free(old_machine); + free(new_machine_path); + free(new_machine); + // TODO: Check for version (skipping, downgrading). struct conf conf; diff --git a/sysinstall/sysupgrade.c b/sysinstall/sysupgrade.c index 561293c0..9e462f59 100644 --- a/sysinstall/sysupgrade.c +++ b/sysinstall/sysupgrade.c @@ -60,6 +60,7 @@ struct installation struct release release; struct mountpoint* mountpoints; size_t mountpoints_used; + char* machine; }; static struct installation* installations; @@ -74,7 +75,8 @@ static char fs[] = "/tmp/fs.XXXXXX"; static bool add_installation(struct blockdevice* bdev, struct release* release, struct mountpoint* mountpoints, - size_t mountpoints_used) + size_t mountpoints_used, + char* machine) { if ( installations_count == installations_length ) { @@ -93,6 +95,7 @@ static bool add_installation(struct blockdevice* bdev, installation->release = *release; installation->mountpoints = mountpoints; installation->mountpoints_used = mountpoints_used; + installation->machine = machine; return true; } @@ -135,7 +138,23 @@ static void search_installation_path(const char* mnt, struct blockdevice* bdev) release_free(&release); return; } - if ( !add_installation(bdev, &release, mountpoints, mountpoints_used) ) + char* machine_path; + if ( asprintf(&machine_path, "%s/etc/machine", mnt) < 0 ) + { + warn("%s: malloc", path_of_blockdevice(bdev)); + release_free(&release); + return; + } + char* machine = read_string_file(machine_path); + free(machine_path); + if ( !machine ) + { + warn("%s/etc/machine", path_of_blockdevice(bdev)); + release_free(&release); + return; + } + if ( !add_installation(bdev, &release, mountpoints, mountpoints_used, + machine) ) { free_mountpoints(mountpoints, mountpoints_used); release_free(&release); @@ -494,7 +513,7 @@ int main(void) if ( installations_count == 0 ) { - while ( true) + while ( true ) { prompt(input, sizeof(input), "No existing installations found, " "run installer instead? (yes/no)", "yes"); @@ -516,9 +535,10 @@ int main(void) for ( size_t i = 0; i < installations_count; i++ ) { struct installation* installation = &installations[i]; - printf(" %-16s %s\n", - path_of_blockdevice(installation->bdev), - installation->release.pretty_name); + printf(" %-16s %s (%s)\n", + path_of_blockdevice(installation->bdev), + installation->release.pretty_name, + installation->machine); } text("\n"); @@ -549,7 +569,27 @@ int main(void) struct release* target_release = &target->release; - // TODO: Check if /etc/machine matches the current architecture. + char* source_machine = read_string_file("/etc/machine"); + if ( !source_machine ) + err(2, "/etc/machine"); + if ( strcmp(target->machine, source_machine) != 0 ) + { + textf("Warning: You are changing an existing installation to another " + "architecture! (%s -> %s) This is not supported and there is no " + "promise this will work!\n", target->machine, source_machine); + while ( true ) + { + prompt(input, sizeof(input), + "Change the existing installation to another architecture?", + "no"); + if ( !strcasecmp(input, "no") || !strcasecmp(input, "yes") ) + break; + } + if ( !strcasecmp(input, "no") ) + errx(2, "upgrade aborted because of architecture mismatch"); + text("\n"); + } + free(source_machine); if ( downgrading_version(target_release, &new_release) ) { @@ -557,7 +597,7 @@ int main(void) "earlier release. This is not supported and there is no promise " "this will work!\n\n"); - while ( true) + while ( true ) { prompt(input, sizeof(input), "Downgrade to an earlier release?", "no"); @@ -594,7 +634,7 @@ int main(void) "release with an earlier ABI. This is not supported and there is " "no promise this will work!\n\n"); - while ( true) + while ( true ) { prompt(input, sizeof(input), "Downgrade to an earlier ABI?", "no");