X-Git-Url: http://git.ipfire.org/?p=ipfire-2.x.git;a=blobdiff_plain;f=src%2Finstaller%2Fhw.c;h=ce9777500d5cbd28ecabdb10082f7fbd04760841;hp=ca3b430958f1080065d0c1735abcf95701561a19;hb=ade96ba8a590df6411f7effec637609494072034;hpb=ee00d203d169709e01c9b53f1782a70ca128cd5e diff --git a/src/installer/hw.c b/src/installer/hw.c index ca3b430958..ce9777500d 100644 --- a/src/installer/hw.c +++ b/src/installer/hw.c @@ -24,15 +24,19 @@ #include #include +#include #include #include +#include #include #include #include #include #include #include +#include #include +#include #include #include @@ -81,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) { @@ -219,6 +277,7 @@ struct hw_disk** hw_find_disks(struct hw* hw, const char* sourcedrive) { disk->ref = 1; strncpy(disk->path, dev_path, sizeof(disk->path)); + const char* p = disk->path + 5; disk->size = size; @@ -252,15 +311,15 @@ struct hw_disk** hw_find_disks(struct hw* hw, const char* sourcedrive) { if (*disk->vendor && *disk->model) { snprintf(disk->description, sizeof(disk->description), - "%s - %s - %s", size_str, disk->vendor, disk->model); + "%s - %s - %s - %s", size_str, p, disk->vendor, disk->model); } else if (*disk->vendor || *disk->model) { snprintf(disk->description, sizeof(disk->description), - "%s - %s", size_str, (*disk->vendor) ? disk->vendor : disk->model); + "%s - %s - %s", size_str, p, (*disk->vendor) ? disk->vendor : disk->model); } else { snprintf(disk->description, sizeof(disk->description), - "%s - N/A", size_str); + "%s - %s", size_str, p); } *disks++ = disk; @@ -291,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++) @@ -304,10 +363,10 @@ 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]) { + if (!selection || selection[i]) { struct hw_disk *selected_disk = disks[i]; selected_disk->ref++; @@ -321,6 +380,27 @@ struct hw_disk** hw_select_disks(struct hw_disk** disks, int* selection) { return ret; } +struct hw_disk** hw_select_first_disk(const struct hw_disk** disks) { + struct hw_disk** ret = hw_create_disks(); + struct hw_disk** selected_disks = ret; + + unsigned int num_disks = hw_count_disks(disks); + assert(num_disks > 0); + + for (unsigned int i = 0; i < num_disks; i++) { + struct hw_disk *disk = disks[i]; + disk->ref++; + + *selected_disks++ = disk; + break; + } + + // Set sentinel + *selected_disks = NULL; + + return ret; +} + static unsigned long long hw_swap_size(struct hw_destination* dest) { unsigned long long memory = hw_memory(); @@ -356,11 +436,26 @@ static unsigned long long hw_boot_size(struct hw_destination* dest) { return MB2BYTES(64); } -static int hw_calculate_partition_table(struct hw_destination* dest) { +static int hw_device_has_p_suffix(const struct hw_destination* dest) { + // All RAID devices have the p suffix. + if (dest->is_raid) + return 1; + + // Devices with a number at the end have the p suffix, too. + // e.g. mmcblk0, cciss0 + unsigned int last_char = strlen(dest->path) - 1; + if ((dest->path[last_char] >= '0') && (dest->path[last_char] <= '9')) + return 1; + + return 0; +} + +static int hw_calculate_partition_table(struct hw_destination* dest, int disable_swap) { char path[DEV_SIZE]; int part_idx = 1; - snprintf(path, sizeof(path), "%s%s", dest->path, (dest->is_raid) ? "p" : ""); + snprintf(path, sizeof(path), "%s%s", dest->path, + hw_device_has_p_suffix(dest) ? "p" : ""); dest->part_boot_idx = 0; // Determine the size of the target block device @@ -408,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; @@ -455,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) { @@ -475,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; @@ -486,23 +586,13 @@ struct hw_destination* hw_make_destination(int part_type, struct hw_disk** disks } unsigned long long hw_memory() { - FILE* handle = NULL; - char line[STRING_SIZE]; - - unsigned long long memory = 0; + struct sysinfo si; - /* 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)) { - memory = 0; - } - } - - fclose(handle); - } + int r = sysinfo(&si); + if (r < 0) + return 0; - return memory * 1024; + return si.totalram; } static int hw_zero_out_device(const char* path, int bytes) { @@ -789,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; } @@ -932,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; } @@ -954,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 @@ -967,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); } } @@ -977,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); } } @@ -985,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); } @@ -994,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); } } @@ -1009,3 +1113,31 @@ void hw_sync() { sync(); sync(); } + +int hw_start_networking(const char* output) { + return mysystem(output, "/usr/bin/start-networking.sh"); +} + +char* hw_find_backup_file(const char* output, const char* search_path) { + char path[STRING_SIZE]; + + snprintf(path, sizeof(path), "%s/backup.ipf", search_path); + int r = access(path, R_OK); + + if (r == 0) + return strdup(path); + + return NULL; +} + +int hw_restore_backup(const char* output, const char* backup_path, const char* destination) { + char command[STRING_SIZE]; + + snprintf(command, sizeof(command), "/bin/tar xzpf %s -C %s", backup_path, destination); + int rc = mysystem(output, command); + + if (rc) + return -1; + + return 0; +}