X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Finstall%2Bsetup%2Finstall%2Fhw.c;h=e7d60acd32f032fff31f5ef58928b8c0fbe0383d;hb=4a0d9bef07434e0fc789195074581bf749be3d3e;hp=f26c63836f62dcc564b7d54e741a25479de25c70;hpb=c4e966746ecb172767186c094a67b68907831da5;p=people%2Fpmueller%2Fipfire-2.x.git diff --git a/src/install+setup/install/hw.c b/src/install+setup/install/hw.c index f26c63836f..e7d60acd32 100644 --- a/src/install+setup/install/hw.c +++ b/src/install+setup/install/hw.c @@ -18,6 +18,10 @@ # # #############################################################################*/ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + #include #include #include @@ -28,11 +32,20 @@ #include #include #include +#include #include #include #include "hw.h" +#include "../libsmooth/libsmooth.h" + +const char* other_filesystems[] = { + "/dev", + "/proc", + "/sys", + NULL +}; struct hw* hw_init() { struct hw* hw = malloc(sizeof(*hw)); @@ -59,8 +72,8 @@ static int strstartswith(const char* a, const char* b) { return (strncmp(a, b, strlen(b)) == 0); } -int hw_mount(const char* source, const char* target, int flags) { - return mount(source, target, "iso9660", flags, NULL); +int hw_mount(const char* source, const char* target, const char* fs, int flags) { + return mount(source, target, fs, flags, NULL); } int hw_umount(const char* target) { @@ -68,7 +81,7 @@ int hw_umount(const char* target) { } static int hw_test_source_medium(const char* path) { - int ret = hw_mount(path, SOURCE_MOUNT_PATH, MS_RDONLY); + int ret = hw_mount(path, SOURCE_MOUNT_PATH, "iso9660", MS_RDONLY); // If the source could not be mounted we // cannot proceed. @@ -103,7 +116,7 @@ char* hw_find_source_medium(struct hw* hw) { // Skip everything what we cannot work with if (strstartswith(dev_path, "/dev/loop") || strstartswith(dev_path, "/dev/fd") || - strstartswith(dev_path, "/dev/ram")) + strstartswith(dev_path, "/dev/ram") || strstartswith(dev_path, "/dev/md")) continue; if (hw_test_source_medium(dev_path)) { @@ -160,7 +173,8 @@ struct hw_disk** hw_find_disks(struct hw* hw) { // Skip everything what we cannot work with if (strstartswith(dev_path, "/dev/loop") || strstartswith(dev_path, "/dev/fd") || - strstartswith(dev_path, "/dev/ram") || strstartswith(dev_path, "/dev/sr")) { + strstartswith(dev_path, "/dev/ram") || strstartswith(dev_path, "/dev/sr") || + strstartswith(dev_path, "/dev/md")) { udev_device_unref(dev); continue; } @@ -279,6 +293,112 @@ struct hw_disk** hw_select_disks(struct hw_disk** disks, int* selection) { return ret; } +static unsigned long long hw_swap_size(struct hw_destination* dest) { + unsigned long long memory = hw_memory(); + + unsigned long long swap_size = memory / 4; + + // Min. swap size is 128MB + if (swap_size < MB2BYTES(128)) + swap_size = MB2BYTES(128); + + // Cap swap size to 1GB + else if (swap_size > MB2BYTES(1024)) + swap_size = MB2BYTES(1024); + + return swap_size; +} + +static unsigned long long hw_root_size(struct hw_destination* dest) { + unsigned long long root_size; + + if (dest->size < MB2BYTES(2048)) + root_size = MB2BYTES(1024); + + else if (dest->size >= MB2BYTES(2048) && dest->size <= MB2BYTES(3072)) + root_size = MB2BYTES(1536); + + else + root_size = MB2BYTES(2048); + + return root_size; +} + +static unsigned long long hw_boot_size(struct hw_destination* dest) { + return MB2BYTES(64); +} + +static int hw_calculate_partition_table(struct hw_destination* dest) { + // Determine the size of the target block device + if (dest->is_raid) { + dest->size = (dest->disk1->size >= dest->disk2->size) ? + dest->disk1->size : dest->disk2->size; + } else { + dest->size = dest->disk1->size; + } + + dest->size_boot = hw_boot_size(dest); + dest->size_swap = hw_swap_size(dest); + dest->size_root = hw_root_size(dest); + + // Determine the size of the data partition. + unsigned long long used_space = dest->size_boot + dest->size_swap + dest->size_root; + + // Disk is way too small + if (used_space >= dest->size) + return -1; + + dest->size_data = dest->size - used_space; + + // If it gets too small, we remove the swap space. + if (dest->size_data <= MB2BYTES(256)) { + dest->size_data += dest->size_swap; + dest->size_swap = 0; + } + + // Set partition names + char path[DEV_SIZE]; + int part_idx = 1; + + snprintf(path, sizeof(path), "%s%s", dest->path, (dest->is_raid) ? "p" : ""); + + if (dest->size_boot > 0) { + dest->part_boot_idx = part_idx; + + snprintf(dest->part_boot, sizeof(dest->part_boot), "%s%d", path, part_idx++); + } else + *dest->part_boot = '\0'; + + if (dest->size_swap > 0) + snprintf(dest->part_swap, sizeof(dest->part_swap), "%s%d", path, part_idx++); + else + *dest->part_swap = '\0'; + + // There is always a root partition + if (!*dest->part_boot) + dest->part_boot_idx = part_idx; + + snprintf(dest->part_root, sizeof(dest->part_root), "%s%d", path, part_idx++); + + if (dest->size_data > 0) + snprintf(dest->part_data, sizeof(dest->part_data), "%s%d", path, part_idx++); + else + *dest->part_data = '\0'; + + // Determine partition table + dest->part_table = HW_PART_TABLE_MSDOS; + + // Disks over 2TB need to use GPT + if (dest->size >= MB2BYTES(2047 * 1024)) + dest->part_table = HW_PART_TABLE_GPT; + + // We also use GPT on raid disks by default + else if (dest->is_raid) + dest->part_table = HW_PART_TABLE_GPT; + + return 0; +} + struct hw_destination* hw_make_destination(int part_type, struct hw_disk** disks) { struct hw_destination* dest = malloc(sizeof(*dest)); @@ -291,6 +411,7 @@ struct hw_destination* hw_make_destination(int part_type, struct hw_disk** disks } else if (part_type == HW_PART_TYPE_RAID1) { dest->disk1 = *disks++; dest->disk2 = *disks; + dest->raid_level = 1; snprintf(dest->path, sizeof(dest->path), "/dev/md0"); } @@ -298,20 +419,12 @@ struct hw_destination* hw_make_destination(int part_type, struct hw_disk** disks // Is this a RAID device? dest->is_raid = (part_type > HW_PART_TYPE_NORMAL); - // Set partition names - char path[DEV_SIZE]; - snprintf(path, sizeof(path), "%s%s", dest->path, (dest->is_raid) ? "p" : ""); - snprintf(dest->part_boot, sizeof(dest->part_boot), "%s1", path); - snprintf(dest->part_swap, sizeof(dest->part_swap), "%s2", path); - snprintf(dest->part_root, sizeof(dest->part_root), "%s3", path); - snprintf(dest->part_data, sizeof(dest->part_data), "%s4", path); + int r = hw_calculate_partition_table(dest); + if (r) + return NULL; - if (dest->is_raid) { - dest->size = (dest->disk1->size >= dest->disk2->size) ? - dest->disk1->size : dest->disk2->size; - } else { - dest->size = dest->disk1->size; - } + // Set default filesystem + dest->filesystem = HW_FS_DEFAULT; return dest; } @@ -325,7 +438,7 @@ unsigned long long hw_memory() { /* Calculate amount of memory in machine */ if ((handle = fopen("/proc/meminfo", "r"))) { while (fgets(line, sizeof(line), handle)) { - if (!sscanf (line, "MemTotal: %llu kB", memory)) { + if (!sscanf (line, "MemTotal: %llu kB", &memory)) { memory = 0; } } @@ -335,3 +448,277 @@ unsigned long long hw_memory() { return memory * 1024; } + +int hw_create_partitions(struct hw_destination* dest) { + char* cmd = NULL; + + asprintf(&cmd, "/usr/sbin/parted -s %s -a optimal", dest->path); + + // Set partition type + if (dest->part_table == HW_PART_TABLE_MSDOS) + asprintf(&cmd, "%s mklabel msdos", cmd); + else if (dest->part_table == HW_PART_TABLE_GPT) + asprintf(&cmd, "%s mklabel gpt", cmd); + + unsigned long long part_start = 0 * 1024 * 1024; // 1MB + + if (*dest->part_boot) { + asprintf(&cmd, "%s mkpart %s ext2 %lluMB %lluMB", cmd, + (dest->part_table == HW_PART_TABLE_GPT) ? "BOOT" : "primary", + BYTES2MB(part_start), BYTES2MB(part_start + dest->size_boot)); + + part_start += dest->size_boot; + } + + if (*dest->part_swap) { + asprintf(&cmd, "%s mkpart %s linux-swap %lluMB %lluMB", cmd, + (dest->part_table == HW_PART_TABLE_GPT) ? "SWAP" : "primary", + BYTES2MB(part_start), BYTES2MB(part_start + dest->size_swap)); + + part_start += dest->size_swap; + } + + if (*dest->part_root) { + asprintf(&cmd, "%s mkpart %s ext2 %lluMB %lluMB", cmd, + (dest->part_table == HW_PART_TABLE_GPT) ? "ROOT" : "primary", + BYTES2MB(part_start), BYTES2MB(part_start + dest->size_root)); + + part_start += dest->size_root; + } + + if (*dest->part_data) { + asprintf(&cmd, "%s mkpart %s ext2 %lluMB %lluMB", cmd, + (dest->part_table == HW_PART_TABLE_GPT) ? "DATA" : "primary", + BYTES2MB(part_start), BYTES2MB(part_start + dest->size_data)); + + part_start += dest->size_data; + } + + if (dest->part_table == HW_PART_TABLE_MSDOS && dest->part_boot_idx > 0) { + asprintf(&cmd, "%s set %d boot on", cmd, dest->part_boot_idx); + + } else if (dest->part_table == HW_PART_TABLE_GPT) { + asprintf(&cmd, "%s disk_set pmbr_boot on", cmd); + } + + int r = mysystem(cmd); + + if (cmd) + free(cmd); + + return r; +} + +static int hw_format_filesystem(const char* path, int fs) { + char cmd[STRING_SIZE] = "\0"; + + // Swap + if (fs == HW_FS_SWAP) { + snprintf(cmd, sizeof(cmd), "/sbin/mkswap -v1 %s &>/dev/null", path); + // ReiserFS + } else if (fs == HW_FS_REISERFS) { + snprintf(cmd, sizeof(cmd), "/sbin/mkreiserfs -f %s ", path); + + // EXT4 + } else if (fs == HW_FS_EXT4) { + snprintf(cmd, sizeof(cmd), "/sbin/mke2fs -T ext4 %s", path); + + // EXT4 w/o journal + } else if (fs == HW_FS_EXT4_WO_JOURNAL) { + snprintf(cmd, sizeof(cmd), "/sbin/mke2fs -T ext4 -O ^has_journal %s", path); + } + + assert(*cmd); + + int r = mysystem(cmd); + + return r; +} + +int hw_create_filesystems(struct hw_destination* dest) { + int r; + + // boot + if (*dest->part_boot) { + r = hw_format_filesystem(dest->part_boot, dest->filesystem); + if (r) + return r; + } + + // swap + if (*dest->part_swap) { + r = hw_format_filesystem(dest->part_swap, HW_FS_SWAP); + if (r) + return r; + } + + // root + r = hw_format_filesystem(dest->part_root, dest->filesystem); + if (r) + return r; + + // data + if (*dest->part_data) { + r = hw_format_filesystem(dest->part_data, dest->filesystem); + if (r) + return r; + } + + return 0; +} + +int hw_mount_filesystems(struct hw_destination* dest, const char* prefix) { + char target[STRING_SIZE]; + + assert(*prefix == '/'); + + const char* filesystem; + switch (dest->filesystem) { + case HW_FS_REISERFS: + filesystem = "reiserfs"; + break; + + case HW_FS_EXT4: + case HW_FS_EXT4_WO_JOURNAL: + filesystem = "ext4"; + break; + + default: + assert(0); + } + + // root + int r = hw_mount(dest->part_root, prefix, filesystem, 0); + if (r) + return r; + + // boot + if (*dest->part_boot) { + snprintf(target, sizeof(target), "%s%s", prefix, HW_PATH_BOOT); + mkdir(target, S_IRWXU|S_IRWXG|S_IRWXO); + + r = hw_mount(dest->part_boot, target, filesystem, 0); + if (r) { + hw_umount_filesystems(dest, prefix); + + return r; + } + } + + // data + if (*dest->part_data) { + snprintf(target, sizeof(target), "%s%s", prefix, HW_PATH_DATA); + mkdir(target, S_IRWXU|S_IRWXG|S_IRWXO); + + r = hw_mount(dest->part_data, target, filesystem, 0); + if (r) { + hw_umount_filesystems(dest, prefix); + + return r; + } + } + + // swap + if (*dest->part_swap) { + r = swapon(dest->part_swap, 0); + if (r) { + hw_umount_filesystems(dest, prefix); + + return r; + } + } + + // bind-mount misc filesystems + char** otherfs = other_filesystems; + while (*otherfs) { + snprintf(target, sizeof(target), "%s%s", prefix, *otherfs); + + mkdir(target, S_IRWXU|S_IRWXG|S_IRWXO); + r = hw_mount(*otherfs, target, NULL, MS_BIND); + if (r) { + hw_umount_filesystems(dest, prefix); + + return r; + } + + otherfs++; + } + + return 0; +} + +int hw_umount_filesystems(struct hw_destination* dest, const char* prefix) { + // boot + if (*dest->part_boot) { + hw_umount(dest->part_boot); + } + + // data + if (*dest->part_data) { + hw_umount(dest->part_data); + } + + // root + hw_umount(dest->part_root); + + // swap + if (*dest->part_swap) { + swapoff(dest->part_swap); + } + + // misc filesystems + char target[STRING_SIZE]; + char** otherfs = other_filesystems; + + while (*otherfs) { + snprintf(target, sizeof(target), "%s%s", prefix, *otherfs++); + hw_umount(target); + } + + return 0; +} + +int hw_setup_raid(struct hw_destination* dest) { + char* cmd = NULL; + + assert(dest->is_raid); + + asprintf(&cmd, "echo \"y\" | /sbin/mdadm --create --verbose --metadata=0.9 %s", dest->path); + + switch (dest->raid_level) { + case 1: + asprintf(&cmd, "%s --level=1 --raid-devices=2", cmd); + break; + + default: + assert(0); + } + + if (dest->disk1) { + asprintf(&cmd, "%s %s", cmd, dest->disk1->path); + } + + if (dest->disk2) { + asprintf(&cmd, "%s %s", cmd, dest->disk2->path); + } + + int r = mysystem(cmd); + free(cmd); + + // Wait a moment until the device has been properly brought up + if (r == 0) { + unsigned int counter = 10; + while (counter-- > 0) { + sleep(1); + + if (access(dest->path, R_OK) == 0) + break; + } + } + + return r; +} + +int hw_stop_all_raid_arrays() { + return mysystem("/sbin/mdadm --stop --scan"); +}