Commit 3f86ec65 authored by Jonas Termansen's avatar Jonas Termansen

Default to installing GRUB if an existing installation uses GRUB.

parent 84c0844f
/* /*
* Copyright (c) 2015 Jonas 'Sortie' Termansen. * Copyright (c) 2015, 2016 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
...@@ -69,6 +69,7 @@ static enum filesystem_error biosboot_inspect(struct filesystem** fs_ptr, ...@@ -69,6 +69,7 @@ static enum filesystem_error biosboot_inspect(struct filesystem** fs_ptr,
fs->handler = &biosboot_handler; fs->handler = &biosboot_handler;
fs->handler_private = NULL; fs->handler_private = NULL;
fs->fstype_name = "biosboot"; fs->fstype_name = "biosboot";
fs->flags = FILESYSTEM_FLAG_NOT_FILESYSTEM;
return *fs_ptr = fs, FILESYSTEM_ERROR_NONE; return *fs_ptr = fs, FILESYSTEM_ERROR_NONE;
} }
......
/* /*
* Copyright (c) 2015 Jonas 'Sortie' Termansen. * Copyright (c) 2015, 2016 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
...@@ -67,6 +67,7 @@ static enum filesystem_error extended_inspect(struct filesystem** fs_ptr, ...@@ -67,6 +67,7 @@ static enum filesystem_error extended_inspect(struct filesystem** fs_ptr,
fs->handler = &extended_handler; fs->handler = &extended_handler;
fs->handler_private = NULL; fs->handler_private = NULL;
fs->fstype_name = "extended"; fs->fstype_name = "extended";
fs->flags = FILESYSTEM_FLAG_NOT_FILESYSTEM;
return *fs_ptr = fs, FILESYSTEM_ERROR_NONE; return *fs_ptr = fs, FILESYSTEM_ERROR_NONE;
} }
......
/* /*
* Copyright (c) 2015 Jonas 'Sortie' Termansen. * Copyright (c) 2015, 2016 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
...@@ -35,6 +35,7 @@ struct filesystem_handler; ...@@ -35,6 +35,7 @@ struct filesystem_handler;
#define FILESYSTEM_FLAG_UUID (1 << 0) #define FILESYSTEM_FLAG_UUID (1 << 0)
#define FILESYSTEM_FLAG_FSCK_SHOULD (1 << 1) #define FILESYSTEM_FLAG_FSCK_SHOULD (1 << 1)
#define FILESYSTEM_FLAG_FSCK_MUST (1 << 2) #define FILESYSTEM_FLAG_FSCK_MUST (1 << 2)
#define FILESYSTEM_FLAG_NOT_FILESYSTEM (1 << 3)
struct filesystem struct filesystem
{ {
......
...@@ -148,7 +148,8 @@ bootloader to boot the operating system. You will be offered the choice of ...@@ -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 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 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 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 .Pp
Single-boot configurations should use the offered bootloader. Dual-boot Single-boot configurations should use the offered bootloader. Dual-boot
configurations should refuse it and arrange for bootloading by other means. The configurations should refuse it and arrange for bootloading by other means. The
......
...@@ -27,7 +27,7 @@ release.o \ ...@@ -27,7 +27,7 @@ release.o \
OBJS=$(MAIN_OBJS) $(UTIL_OBJS) 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 SYSMERGE_DEPS=conf fileops execute hooks manifest release
SYSUPGRADE_DEPS=conf devices execute fileops hooks interactive manifest release SYSUPGRADE_DEPS=conf devices execute fileops hooks interactive manifest release
......
...@@ -173,19 +173,6 @@ struct filesystem* search_for_filesystem_by_spec(const char* spec) ...@@ -173,19 +173,6 @@ struct filesystem* search_for_filesystem_by_spec(const char* spec)
return NULL; 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) bool check_lacking_partition_table(void)
{ {
for ( size_t di = 0; di < hds_count; di++ ) for ( size_t di = 0; di < hds_count; di++ )
...@@ -327,7 +314,7 @@ bool load_mountpoints(const char* fstab_path, ...@@ -327,7 +314,7 @@ bool load_mountpoints(const char* fstab_path,
return true; return true;
} }
void mountpoint_mount(struct mountpoint* mountpoint) bool mountpoint_mount(struct mountpoint* mountpoint)
{ {
struct filesystem* fs = mountpoint->fs; struct filesystem* fs = mountpoint->fs;
// TODO: It would be ideal to get an exclusive lock so that no other // TODO: It would be ideal to get an exclusive lock so that no other
...@@ -336,17 +323,29 @@ void mountpoint_mount(struct mountpoint* mountpoint) ...@@ -336,17 +323,29 @@ void mountpoint_mount(struct mountpoint* mountpoint)
const char* bdev_path = bdev->p ? bdev->p->path : bdev->hd->path; const char* bdev_path = bdev->p ? bdev->p->path : bdev->hd->path;
assert(bdev_path); assert(bdev_path);
if ( fs->flags & FILESYSTEM_FLAG_FSCK_MUST && !fsck(fs) ) 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 ) 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* pretend_where = mountpoint->entry.fs_file;
const char* where = mountpoint->absolute; const char* where = mountpoint->absolute;
struct stat st; struct stat st;
if ( stat(where, &st) < 0 ) if ( stat(where, &st) < 0 )
err(2, "stat: %s", where); {
warn("stat: %s", where);
return false;
}
if ( (mountpoint->pid = fork()) < 0 ) 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 // TODO: This design is broken. The filesystem should tell us when it is
// ready instead of having to poll like this. // ready instead of having to poll like this.
if ( mountpoint->pid == 0 ) if ( mountpoint->pid == 0 )
...@@ -369,36 +368,41 @@ void mountpoint_mount(struct mountpoint* mountpoint) ...@@ -369,36 +368,41 @@ void mountpoint_mount(struct mountpoint* mountpoint)
int code; int code;
waitpid(mountpoint->pid, &code, 0); waitpid(mountpoint->pid, &code, 0);
mountpoint->pid = -1; mountpoint->pid = -1;
exit(2); return false;
} }
if ( newst.st_dev != st.st_dev || newst.st_ino != st.st_ino ) if ( newst.st_dev != st.st_dev || newst.st_ino != st.st_ino )
break; break;
int code; int code;
pid_t child = waitpid(mountpoint->pid, &code, WNOHANG); pid_t child = waitpid(mountpoint->pid, &code, WNOHANG);
if ( child < 0 ) if ( child < 0 )
err(2, "waitpid"); {
warn("waitpid");
return false;
}
if ( child != 0 ) if ( child != 0 )
{ {
mountpoint->pid = -1; mountpoint->pid = -1;
if ( WIFSIGNALED(code) ) if ( WIFSIGNALED(code) )
errx(2, "%s: Mount failed: %s: %s", bdev_path, fs->driver, warnx("%s: Mount failed: %s: %s", bdev_path, fs->driver,
strsignal(WTERMSIG(code))); strsignal(WTERMSIG(code)));
else if ( !WIFEXITED(code) ) else if ( !WIFEXITED(code) )
errx(2, "%s: Mount failed: %s: %s", bdev_path, fs->driver, warnx("%s: Mount failed: %s: %s", bdev_path, fs->driver,
"Unexpected unusual termination"); "Unexpected unusual termination");
else if ( WEXITSTATUS(code) == 127 ) else if ( WEXITSTATUS(code) == 127 )
errx(2, "%s: Mount failed: %s: %s", bdev_path, fs->driver, warnx("%s: Mount failed: %s: %s", bdev_path, fs->driver,
"Filesystem driver is absent"); "Filesystem driver is absent");
else if ( WEXITSTATUS(code) == 0 ) else if ( WEXITSTATUS(code) == 0 )
errx(2, "%s: Mount failed: %s: Unexpected successful exit", warnx("%s: Mount failed: %s: Unexpected successful exit",
bdev_path, fs->driver); bdev_path, fs->driver);
else else
errx(2, "%s: Mount failed: %s: Exited with status %i", bdev_path, warnx("%s: Mount failed: %s: Exited with status %i", bdev_path,
fs->driver, WEXITSTATUS(code)); fs->driver, WEXITSTATUS(code));
return false;
} }
struct timespec delay = timespec_make(0, 50L * 1000L * 1000L); struct timespec delay = timespec_make(0, 50L * 1000L * 1000L);
nanosleep(&delay, NULL); nanosleep(&delay, NULL);
} }
return true;
} }
void mountpoint_unmount(struct mountpoint* mountpoint) void mountpoint_unmount(struct mountpoint* mountpoint)
......
...@@ -42,14 +42,13 @@ void unscan_devices(void); ...@@ -42,14 +42,13 @@ void unscan_devices(void);
void scan_devices(void); void scan_devices(void);
struct filesystem* search_for_filesystem_by_uuid(const unsigned char* uuid); struct filesystem* search_for_filesystem_by_uuid(const unsigned char* uuid);
struct filesystem* search_for_filesystem_by_spec(const char* spec); struct filesystem* search_for_filesystem_by_spec(const char* spec);
bool check_existing_systems(void);
bool check_lacking_partition_table(void); bool check_lacking_partition_table(void);
bool fsck(struct filesystem* fs); bool fsck(struct filesystem* fs);
void free_mountpoints(struct mountpoint* mnts, size_t mnts_count); void free_mountpoints(struct mountpoint* mnts, size_t mnts_count);
bool load_mountpoints(const char* fstab_path, bool load_mountpoints(const char* fstab_path,
struct mountpoint** mountpoints_out, struct mountpoint** mountpoints_out,
size_t* mountpoints_used_out); size_t* mountpoints_used_out);
void mountpoint_mount(struct mountpoint* mountpoint); bool mountpoint_mount(struct mountpoint* mountpoint);
void mountpoint_unmount(struct mountpoint* mountpoint); void mountpoint_unmount(struct mountpoint* mountpoint);
#endif #endif
...@@ -51,11 +51,13 @@ ...@@ -51,11 +51,13 @@
#include <mount/partition.h> #include <mount/partition.h>
#include <mount/uuid.h> #include <mount/uuid.h>
#include "conf.h"
#include "devices.h" #include "devices.h"
#include "execute.h" #include "execute.h"
#include "fileops.h" #include "fileops.h"
#include "interactive.h" #include "interactive.h"
#include "manifest.h" #include "manifest.h"
#include "release.h"
const char* prompt_man_section = "7"; const char* prompt_man_section = "7";
const char* prompt_man_page = "installation"; const char* prompt_man_page = "installation";
...@@ -105,6 +107,116 @@ static bool missing_bios_boot_partition(struct filesystem* root_fs) ...@@ -105,6 +107,116 @@ static bool missing_bios_boot_partition(struct filesystem* root_fs)
return !search_bios_boot_search(pt); 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, static bool passwd_check(const char* passwd_path,
bool (*check)(struct passwd*, void*), bool (*check)(struct passwd*, void*),
void* check_ctx) void* check_ctx)
...@@ -460,7 +572,10 @@ int main(void) ...@@ -460,7 +572,10 @@ int main(void)
text("\n"); text("\n");
} }
text("Searching for existing installations...\n");
scan_devices(); scan_devices();
bool bootloader_default = should_install_bootloader();
text("\n");
textf("You need a bootloader to start the operating system. GRUB is the " textf("You need a bootloader to start the operating system. GRUB is the "
"standard %s bootloader and this installer comes with a copy. " "standard %s bootloader and this installer comes with a copy. "
...@@ -476,9 +591,7 @@ int main(void) ...@@ -476,9 +591,7 @@ int main(void)
char grub_password[512]; char grub_password[512];
while ( true ) while ( true )
{ {
const char* def = "yes"; const char* def = bootloader_default ? "yes" : "no";
if ( check_existing_systems() )
def = "no";
prompt(accept_grub, sizeof(accept_grub), prompt(accept_grub, sizeof(accept_grub),
"Install a new GRUB bootloader?", def); "Install a new GRUB bootloader?", def);
if ( strcasecmp(accept_grub, "no") == 0 || if ( strcasecmp(accept_grub, "no") == 0 ||
...@@ -704,7 +817,8 @@ int main(void) ...@@ -704,7 +817,8 @@ int main(void)
mnt->absolute = absolute; mnt->absolute = absolute;
if ( mkdir_p(mnt->absolute, 0755) < 0 ) if ( mkdir_p(mnt->absolute, 0755) < 0 )
err(2, "mkdir: %s", mnt->absolute); err(2, "mkdir: %s", mnt->absolute);
mountpoint_mount(mnt); if ( !mountpoint_mount(mnt) )
exit(2);
} }
if ( chdir(fs) < 0 ) if ( chdir(fs) < 0 )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment