Default to installing GRUB if an existing installation uses GRUB.

This commit is contained in:
Jonas 'Sortie' Termansen 2016-08-24 14:45:15 +02:00
parent 84c0844f56
commit 3f86ec6544
8 changed files with 163 additions and 42 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015 Jonas 'Sortie' Termansen.
* Copyright (c) 2015, 2016 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -69,6 +69,7 @@ static enum filesystem_error biosboot_inspect(struct filesystem** fs_ptr,
fs->handler = &biosboot_handler;
fs->handler_private = NULL;
fs->fstype_name = "biosboot";
fs->flags = FILESYSTEM_FLAG_NOT_FILESYSTEM;
return *fs_ptr = fs, FILESYSTEM_ERROR_NONE;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015 Jonas 'Sortie' Termansen.
* Copyright (c) 2015, 2016 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -67,6 +67,7 @@ static enum filesystem_error extended_inspect(struct filesystem** fs_ptr,
fs->handler = &extended_handler;
fs->handler_private = NULL;
fs->fstype_name = "extended";
fs->flags = FILESYSTEM_FLAG_NOT_FILESYSTEM;
return *fs_ptr = fs, FILESYSTEM_ERROR_NONE;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015 Jonas 'Sortie' Termansen.
* Copyright (c) 2015, 2016 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -35,6 +35,7 @@ struct filesystem_handler;
#define FILESYSTEM_FLAG_UUID (1 << 0)
#define FILESYSTEM_FLAG_FSCK_SHOULD (1 << 1)
#define FILESYSTEM_FLAG_FSCK_MUST (1 << 2)
#define FILESYSTEM_FLAG_NOT_FILESYSTEM (1 << 3)
struct filesystem
{

View File

@ -148,7 +148,8 @@ bootloader to boot the operating system. You will be offered the choice of
installing GRUB as the bootloader. Note however that this GRUB is not able to
detect other operating systems and you will have to configure it manually if you
wish to use it in a dual boot scheme. The answer will default to yes if no
existing partitions are found, and will default to no if some are found.
existing partitions are found, or if an existing Sortix installation is found
that uses the provided bootloader; and will otherwise default to no.
.Pp
Single-boot configurations should use the offered bootloader. Dual-boot
configurations should refuse it and arrange for bootloading by other means. The

View File

@ -27,7 +27,7 @@ release.o \
OBJS=$(MAIN_OBJS) $(UTIL_OBJS)
SYSINSTALL_DEPS=devices execute fileops interactive manifest
SYSINSTALL_DEPS=conf devices execute fileops interactive manifest release
SYSMERGE_DEPS=conf fileops execute hooks manifest release
SYSUPGRADE_DEPS=conf devices execute fileops hooks interactive manifest release

View File

@ -173,19 +173,6 @@ struct filesystem* search_for_filesystem_by_spec(const char* spec)
return NULL;
}
bool check_existing_systems(void)
{
for ( size_t di = 0; di < hds_count; di++ )
{
struct blockdevice* dbdev = &hds[di]->bdev;
if ( dbdev->fs )
return true;
else if ( dbdev->pt )
return 1 <= dbdev->pt->partitions_count;
}
return false;
}
bool check_lacking_partition_table(void)
{
for ( size_t di = 0; di < hds_count; di++ )
@ -327,7 +314,7 @@ bool load_mountpoints(const char* fstab_path,
return true;
}
void mountpoint_mount(struct mountpoint* mountpoint)
bool mountpoint_mount(struct mountpoint* mountpoint)
{
struct filesystem* fs = mountpoint->fs;
// TODO: It would be ideal to get an exclusive lock so that no other
@ -336,17 +323,29 @@ void mountpoint_mount(struct mountpoint* mountpoint)
const char* bdev_path = bdev->p ? bdev->p->path : bdev->hd->path;
assert(bdev_path);
if ( fs->flags & FILESYSTEM_FLAG_FSCK_MUST && !fsck(fs) )
errx(2, "Failed to fsck %s", bdev_path);
{
warnx("Failed to fsck %s", bdev_path);
return false;
}
if ( !fs->driver )
errx(2, "%s: Don't know how to mount a %s filesystem",
bdev_path, fs->fstype_name);
{
warnx("%s: Don't know how to mount a %s filesystem",
bdev_path, fs->fstype_name);
return false;
}
const char* pretend_where = mountpoint->entry.fs_file;
const char* where = mountpoint->absolute;
struct stat st;
if ( stat(where, &st) < 0 )
err(2, "stat: %s", where);
{
warn("stat: %s", where);
return false;
}
if ( (mountpoint->pid = fork()) < 0 )
err(2, "%s: Unable to mount: fork", bdev_path);
{
warn("%s: Unable to mount: fork", bdev_path);
return false;
}
// TODO: This design is broken. The filesystem should tell us when it is
// ready instead of having to poll like this.
if ( mountpoint->pid == 0 )
@ -369,36 +368,41 @@ void mountpoint_mount(struct mountpoint* mountpoint)
int code;
waitpid(mountpoint->pid, &code, 0);
mountpoint->pid = -1;
exit(2);
return false;
}
if ( newst.st_dev != st.st_dev || newst.st_ino != st.st_ino )
break;
int code;
pid_t child = waitpid(mountpoint->pid, &code, WNOHANG);
if ( child < 0 )
err(2, "waitpid");
{
warn("waitpid");
return false;
}
if ( child != 0 )
{
mountpoint->pid = -1;
if ( WIFSIGNALED(code) )
errx(2, "%s: Mount failed: %s: %s", bdev_path, fs->driver,
strsignal(WTERMSIG(code)));
warnx("%s: Mount failed: %s: %s", bdev_path, fs->driver,
strsignal(WTERMSIG(code)));
else if ( !WIFEXITED(code) )
errx(2, "%s: Mount failed: %s: %s", bdev_path, fs->driver,
"Unexpected unusual termination");
warnx("%s: Mount failed: %s: %s", bdev_path, fs->driver,
"Unexpected unusual termination");
else if ( WEXITSTATUS(code) == 127 )
errx(2, "%s: Mount failed: %s: %s", bdev_path, fs->driver,
"Filesystem driver is absent");
warnx("%s: Mount failed: %s: %s", bdev_path, fs->driver,
"Filesystem driver is absent");
else if ( WEXITSTATUS(code) == 0 )
errx(2, "%s: Mount failed: %s: Unexpected successful exit",
bdev_path, fs->driver);
warnx("%s: Mount failed: %s: Unexpected successful exit",
bdev_path, fs->driver);
else
errx(2, "%s: Mount failed: %s: Exited with status %i", bdev_path,
fs->driver, WEXITSTATUS(code));
warnx("%s: Mount failed: %s: Exited with status %i", bdev_path,
fs->driver, WEXITSTATUS(code));
return false;
}
struct timespec delay = timespec_make(0, 50L * 1000L * 1000L);
nanosleep(&delay, NULL);
}
return true;
}
void mountpoint_unmount(struct mountpoint* mountpoint)

View File

@ -42,14 +42,13 @@ void unscan_devices(void);
void scan_devices(void);
struct filesystem* search_for_filesystem_by_uuid(const unsigned char* uuid);
struct filesystem* search_for_filesystem_by_spec(const char* spec);
bool check_existing_systems(void);
bool check_lacking_partition_table(void);
bool fsck(struct filesystem* fs);
void free_mountpoints(struct mountpoint* mnts, size_t mnts_count);
bool load_mountpoints(const char* fstab_path,
struct mountpoint** mountpoints_out,
size_t* mountpoints_used_out);
void mountpoint_mount(struct mountpoint* mountpoint);
bool mountpoint_mount(struct mountpoint* mountpoint);
void mountpoint_unmount(struct mountpoint* mountpoint);
#endif

View File

@ -51,11 +51,13 @@
#include <mount/partition.h>
#include <mount/uuid.h>
#include "conf.h"
#include "devices.h"
#include "execute.h"
#include "fileops.h"
#include "interactive.h"
#include "manifest.h"
#include "release.h"
const char* prompt_man_section = "7";
const char* prompt_man_page = "installation";
@ -105,6 +107,116 @@ static bool missing_bios_boot_partition(struct filesystem* root_fs)
return !search_bios_boot_search(pt);
}
static bool should_install_bootloader_path(const char* mnt,
struct blockdevice* bdev)
{
char* release_errpath;
if ( asprintf(&release_errpath, "%s: /etc/sortix-release",
path_of_blockdevice(bdev)) < 0 )
{
warn("malloc");
return false;
}
char* release_path;
if ( asprintf(&release_path, "%s/etc/sortix-release", mnt) < 0 )
{
warn("malloc");
free(release_errpath);
return false;
}
struct release release;
if ( !os_release_load(&release, release_path, release_errpath) )
{
free(release_path);
free(release_errpath);
return false;
}
free(release_path);
free(release_errpath);
char* conf_path;
if ( asprintf(&conf_path, "%s/etc/upgrade.conf", mnt) < 0 )
{
warn("malloc");
return false;
}
// TODO: The load_upgrade_conf function might exit the process on failure,
// but we don't want that. Redesign the mountpoint code so the caller
// controls this.
pid_t pid = fork();
if ( pid < 0 )
{
warn("fork");
free(conf_path);
return false;
}
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)
{
if ( !bdev->fs )
return false;
if ( bdev->fs->flags & FILESYSTEM_FLAG_NOT_FILESYSTEM )
return false;
if ( !bdev->fs->driver )
return false;
char mnt[] = "/tmp/fs.XXXXXX";
if ( !mkdtemp(mnt) )
{
warn("mkdtemp: %s", "/tmp/fs.XXXXXX");
return false;
}
struct mountpoint mp = { 0 };
mp.absolute = mnt;
mp.fs = bdev->fs;
mp.entry.fs_file = mnt;
if ( !mountpoint_mount(&mp) )
{
rmdir(mnt);
return false;
}
bool should = should_install_bootloader_path(mnt, bdev);
mountpoint_unmount(&mp);
rmdir(mnt);
return should;
}
static bool should_install_bootloader(void)
{
bool any_systems = false;
for ( size_t i = 0; i < hds_count; i++ )
{
struct harddisk* hd = hds[i];
if ( hd->bdev.pt )
{
for ( size_t n = 0; n < hd->bdev.pt->partitions_count; n++ )
{
any_systems = true;
struct partition* p = hd->bdev.pt->partitions[n];
if ( should_install_bootloader_bdev(&p->bdev) )
return true;
}
}
else if ( hd->bdev.fs )
{
any_systems = true;
if ( should_install_bootloader_bdev(&hd->bdev) )
return true;
}
}
return !any_systems;
}
static bool passwd_check(const char* passwd_path,
bool (*check)(struct passwd*, void*),
void* check_ctx)
@ -460,7 +572,10 @@ int main(void)
text("\n");
}
text("Searching for existing installations...\n");
scan_devices();
bool bootloader_default = should_install_bootloader();
text("\n");
textf("You need a bootloader to start the operating system. GRUB is the "
"standard %s bootloader and this installer comes with a copy. "
@ -476,9 +591,7 @@ int main(void)
char grub_password[512];
while ( true )
{
const char* def = "yes";
if ( check_existing_systems() )
def = "no";
const char* def = bootloader_default ? "yes" : "no";
prompt(accept_grub, sizeof(accept_grub),
"Install a new GRUB bootloader?", def);
if ( strcasecmp(accept_grub, "no") == 0 ||
@ -704,7 +817,8 @@ int main(void)
mnt->absolute = absolute;
if ( mkdir_p(mnt->absolute, 0755) < 0 )
err(2, "mkdir: %s", mnt->absolute);
mountpoint_mount(mnt);
if ( !mountpoint_mount(mnt) )
exit(2);
}
if ( chdir(fs) < 0 )