X-Git-Url: http://git.ipfire.org/?p=ipfire-2.x.git;a=blobdiff_plain;f=src%2Finstaller%2Fhw.c;h=ce9777500d5cbd28ecabdb10082f7fbd04760841;hp=9b9a2d00291ae7b6911bd5eb10848e7c31c444a9;hb=ade96ba8a590df6411f7effec637609494072034;hpb=6e0b26ba7db9d1faa5eb564b07d617c78d8ab0ef diff --git a/src/installer/hw.c b/src/installer/hw.c index 9b9a2d0029..ce9777500d 100644 --- a/src/installer/hw.c +++ b/src/installer/hw.c @@ -24,14 +24,17 @@ #include #include +#include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -82,16 +85,70 @@ static int strstartswith(const char* a, const char* b) { return (strncmp(a, b, strlen(b)) == 0); } +static char loop_device[STRING_SIZE]; + +static int setup_loop_device(const char* source, const char* device) { + int file_fd = open(source, O_RDWR); + if (file_fd < 0) + goto ERROR; + + int device_fd = -1; + if ((device_fd = open(device, O_RDWR)) < 0) + goto ERROR; + + if (ioctl(device_fd, LOOP_SET_FD, file_fd) < 0) + goto ERROR; + + close(file_fd); + close(device_fd); + + return 0; + +ERROR: + if (file_fd >= 0) + close(file_fd); + + if (device_fd >= 0) { + ioctl(device_fd, LOOP_CLR_FD, 0); + close(device_fd); + } + + return -1; +} + int hw_mount(const char* source, const char* target, const char* fs, int flags) { + const char* loop_device = "/dev/loop0"; + // Create target if it does not exist if (access(target, X_OK) != 0) mkdir(target, S_IRWXU|S_IRWXG|S_IRWXO); + struct stat st; + stat(source, &st); + + if (S_ISREG(st.st_mode)) { + int r = setup_loop_device(source, loop_device); + if (r == 0) { + source = loop_device; + } else { + return -1; + } + } + return mount(source, target, fs, flags, NULL); } int hw_umount(const char* target) { - return umount2(target, 0); + int r = umount2(target, 0); + + if (r && errno == EBUSY) { + // Give it a moment to settle + sleep(1); + + r = umount2(target, MNT_FORCE); + } + + return r; } static int hw_test_source_medium(const char* path) { @@ -293,7 +350,7 @@ void hw_free_disks(struct hw_disk** disks) { free(disks); } -unsigned int hw_count_disks(struct hw_disk** disks) { +unsigned int hw_count_disks(const struct hw_disk** disks) { unsigned int ret = 0; while (*disks++) @@ -306,7 +363,7 @@ struct hw_disk** hw_select_disks(struct hw_disk** disks, int* selection) { struct hw_disk** ret = hw_create_disks(); struct hw_disk** selected_disks = ret; - unsigned int num_disks = hw_count_disks(disks); + unsigned int num_disks = hw_count_disks((const struct hw_disk**)disks); for (unsigned int i = 0; i < num_disks; i++) { if (!selection || selection[i]) { @@ -393,7 +450,7 @@ static int hw_device_has_p_suffix(const struct hw_destination* dest) { return 0; } -static int hw_calculate_partition_table(struct hw_destination* dest) { +static int hw_calculate_partition_table(struct hw_destination* dest, int disable_swap) { char path[DEV_SIZE]; int part_idx = 1; @@ -446,9 +503,14 @@ static int hw_calculate_partition_table(struct hw_destination* dest) { } dest->size_boot = hw_boot_size(dest); - dest->size_swap = hw_swap_size(dest); dest->size_root = hw_root_size(dest); + // Should we use swap? + if (disable_swap) + dest->size_swap = 0; + else + dest->size_swap = hw_swap_size(dest); + // Determine the size of the data partition. unsigned long long used_space = dest->size_bootldr + dest->size_boot + dest->size_swap + dest->size_root; @@ -493,7 +555,7 @@ static int hw_calculate_partition_table(struct hw_destination* dest) { return 0; } -struct hw_destination* hw_make_destination(int part_type, struct hw_disk** disks) { +struct hw_destination* hw_make_destination(int part_type, struct hw_disk** disks, int disable_swap) { struct hw_destination* dest = malloc(sizeof(*dest)); if (part_type == HW_PART_TYPE_NORMAL) { @@ -513,7 +575,7 @@ 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); - int r = hw_calculate_partition_table(dest); + int r = hw_calculate_partition_table(dest, disable_swap); if (r) return NULL; @@ -817,36 +879,47 @@ int hw_mount_filesystems(struct hw_destination* dest, const char* prefix) { } int hw_umount_filesystems(struct hw_destination* dest, const char* prefix) { + int r; + char target[STRING_SIZE]; + // Write all buffers to disk before umounting hw_sync(); // boot if (*dest->part_boot) { - hw_umount(dest->part_boot); + snprintf(target, sizeof(target), "%s%s", prefix, HW_PATH_BOOT); + r = hw_umount(target); + if (r) + return -1; } // data if (*dest->part_data) { - hw_umount(dest->part_data); + snprintf(target, sizeof(target), "%s%s", prefix, HW_PATH_DATA); + r = hw_umount(target); + if (r) + return -1; } - // 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); + r = hw_umount(target); + if (r) + return -1; } + // root + r = hw_umount(prefix); + if (r) + return -1; + return 0; } @@ -960,6 +1033,8 @@ int hw_install_bootloader(struct hw_destination* dest, const char* output) { r = system_chroot(output, DESTINATION_MOUNT_PATH, cmd); } + hw_sync(); + return r; } @@ -982,12 +1057,13 @@ static char* hw_get_uuid(const char* dev) { return uuid; } +#define FSTAB_FMT "UUID=%s %-8s %-4s %-10s %d %d\n" + int hw_write_fstab(struct hw_destination* dest) { FILE* f = fopen(DESTINATION_MOUNT_PATH "/etc/fstab", "w"); if (!f) return -1; - const char* fmt = "UUID=%s %-8s %-4s %-10s %d %d\n"; char* uuid = NULL; // boot @@ -995,7 +1071,7 @@ int hw_write_fstab(struct hw_destination* dest) { uuid = hw_get_uuid(dest->part_boot); if (uuid) { - fprintf(f, fmt, uuid, "/boot", "auto", "defaults", 1, 2); + fprintf(f, FSTAB_FMT, uuid, "/boot", "auto", "defaults", 1, 2); free(uuid); } } @@ -1005,7 +1081,7 @@ int hw_write_fstab(struct hw_destination* dest) { uuid = hw_get_uuid(dest->part_swap); if (uuid) { - fprintf(f, fmt, uuid, "swap", "swap", "defaults,pri=1", 0, 0); + fprintf(f, FSTAB_FMT, uuid, "swap", "swap", "defaults,pri=1", 0, 0); free(uuid); } } @@ -1013,7 +1089,7 @@ int hw_write_fstab(struct hw_destination* dest) { // root uuid = hw_get_uuid(dest->part_root); if (uuid) { - fprintf(f, fmt, uuid, "/", "auto", "defaults", 1, 1); + fprintf(f, FSTAB_FMT, uuid, "/", "auto", "defaults", 1, 1); free(uuid); } @@ -1022,7 +1098,7 @@ int hw_write_fstab(struct hw_destination* dest) { uuid = hw_get_uuid(dest->part_data); if (uuid) { - fprintf(f, fmt, uuid, "/var", "auto", "defaults", 1, 1); + fprintf(f, FSTAB_FMT, uuid, "/var", "auto", "defaults", 1, 1); free(uuid); } }