From d7dd283b89e612266099ba95f3f1c2a7a0c867e4 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sun, 20 Jul 2014 16:36:41 +0200 Subject: [PATCH] Allow to select the target disk and allow selecting multiple of them. --- langs/de/install/lang_de.c | 16 ++ langs/en/install/lang_en.c | 18 ++ langs/es/install/lang_es.c | 16 ++ langs/fr/install/lang_fr.c | 16 ++ langs/nl/install/lang_nl.c | 16 ++ langs/pl/install/lang_pl.c | 16 ++ langs/ru/install/lang_ru.c | 16 ++ langs/tr/install/lang_tr.c | 16 ++ lfs/installer | 2 +- src/install+setup/install/Makefile | 2 +- src/install+setup/install/hw.c | 200 +++++++++++++++++ src/install+setup/install/hw.h | 39 ++++ src/install+setup/install/install.h | 11 - src/install+setup/install/main.c | 336 ++++++++++++++++++---------- 14 files changed, 591 insertions(+), 129 deletions(-) diff --git a/langs/de/install/lang_de.c b/langs/de/install/lang_de.c index 8c935865ea..5c7032490f 100644 --- a/langs/de/install/lang_de.c +++ b/langs/de/install/lang_de.c @@ -333,6 +333,22 @@ char *de_tr[] = { "Keine GRÜNE Schnittstelle zugewiesen.", /* TR_NO_HARDDISK */ "Keine Festplatte gefunden.", +/* TR_DISK_SELECTION */ +"Festplattenauswahl", +/* TR_DISK_SELECTION_MSG */ +"Wählen Sie die Festplatte(n), auf die Sie IPFire installieren möchten. Diese wird dann zuerst partitioniert und danach wird ein Dateisystem auf die Partitionen installiert.\n\nALLE DATEN AUF DER FESTPLATTE WERDEN GELÖSCHT.", +/* TR_NO_DISK_SELECTED */ +"Es wurde kein Datenträger ausgewählt.\n\nBitte wählen Sie einen oder mehrere Festplatten aus, um mit der Installation fortzufahren.", +/* TR_DISK_SETUP */ +"Festplatten-Setup", +/* TR_DISK_SETUP_DESC */ +"Das Installationsprogramm wird nun die ausgewählte Festplatte vorbereiten:\n\n %s\n\nMöchten Sie fortfahren?", +/* TR_RAID_SETUP */ +"RAID-Setup", +/* TR_RAID_SETUP_DESC */ +"Das Installationsprogramm wird nun eine RAID-Konfiguration auf den ausgewählten Festplatten anlegen:\n\n %s\n %s\n\nMöchten Sie fortfahren?", +/* TR_DELETE_ALL_DATA */ +"Alle Daten löschen", /* TR_NO_IPCOP_TARBALL_FOUND */ "Auf dem Webserver wurde kein ipcop-Tarball gefunden.", /* TR_NO_ORANGE_INTERFACE */ diff --git a/langs/en/install/lang_en.c b/langs/en/install/lang_en.c index 12ac4b5578..1b60505c9f 100644 --- a/langs/en/install/lang_en.c +++ b/langs/en/install/lang_en.c @@ -329,6 +329,24 @@ char *en_tr[] = { "No GREEN interface assigned.", /* TR_NO_HARDDISK */ "No hard disk found.", +/* TR_DISK_SELECTION */ +"Disk Selection", +/* TR_DISK_SELECTION_MSG */ +"Select the disk(s) you want to install IPFire on. First those will be partitioned, and then the partitions will have a filesystem put on them.\n\nALL DATA ON THE DISK WILL BE DESTROYED.", +/* TR_NO_DISK_SELECTED */ +"No disk has been selected.\n\nPlease select one or more disks you want to install IPFire on.", +/* TR_DISK_SETUP */ +"Disk Setup", +/* TR_DISK_SETUP_DESC */ +"The installation program will now prepare the chosen harddisk:\n\n %s\n\nDo you agree to continue?", +/* TR_RAID_SETUP */ +"RAID Setup", +/* TR_RAID_SETUP_DESC */ +"The installation program will now set up a RAID configuration on the selected harddisks:\n\n %s\n %s\n\nDo you agree to continue?", +/* TR_DELETE_ALL_DATA */ +"Delete all data", +/* TR_DISK_CONFIGURATION_NOT_SUPPORTED */ +"You disk configuration is currently not supported.", /* TR_NO_IPCOP_TARBALL_FOUND */ "No ipcop tarball found on Web Server.", /* TR_NO_ORANGE_INTERFACE */ diff --git a/langs/es/install/lang_es.c b/langs/es/install/lang_es.c index 4a08748ccd..49eaaf8f47 100644 --- a/langs/es/install/lang_es.c +++ b/langs/es/install/lang_es.c @@ -325,6 +325,22 @@ char *es_tr[] = { "No se asignó interfaz GREEN.", /* TR_NO_HARDDISK */ "No se encontró unidad de disco duro.", +/* TR_DISK_SELECTION */ +"Disk Selection", +/* TR_DISK_SELECTION_MSG */ +"Select the disk(s) you want to install IPFire on. First those will be partitioned, and then the partitions will have a filesystem put on them.\n\nALL DATA ON THE DISK WILL BE DESTROYED.", +/* TR_NO_DISK_SELECTED */ +"No disk has been selected.\n\nPlease select one or more disks you want to install IPFire on.", +/* TR_DISK_SETUP */ +"Disk Setup", +/* TR_DISK_SETUP_DESC */ +"The installation program will now prepare the chosen harddisk:\n\n %s\n\nDo you agree to continue?", +/* TR_RAID_SETUP */ +"RAID Setup", +/* TR_RAID_SETUP_DESC */ +"The installation program will now set up a RAID configuration on the selected harddisks:\n\n %s\n %s\n\nDo you agree to continue?", +/* TR_DELETE_ALL_DATA */ +"Delete all data", /* TR_NO_IPCOP_TARBALL_FOUND */ "No se encontró ningun archivo tarball de ipcop en el servidor web", /* TR_NO_ORANGE_INTERFACE */ diff --git a/langs/fr/install/lang_fr.c b/langs/fr/install/lang_fr.c index 188e0fd1a5..62085be9b7 100644 --- a/langs/fr/install/lang_fr.c +++ b/langs/fr/install/lang_fr.c @@ -325,6 +325,22 @@ char *fr_tr[] = { "Interface VERTE non attribuée.", /* TR_NO_HARDDISK */ "Aucun disque dur trouvé.", +/* TR_DISK_SELECTION */ +"Disk Selection", +/* TR_DISK_SELECTION_MSG */ +"Select the disk(s) you want to install IPFire on. First those will be partitioned, and then the partitions will have a filesystem put on them.\n\nALL DATA ON THE DISK WILL BE DESTROYED.", +/* TR_NO_DISK_SELECTED */ +"No disk has been selected.\n\nPlease select one or more disks you want to install IPFire on.", +/* TR_DISK_SETUP */ +"Disk Setup", +/* TR_DISK_SETUP_DESC */ +"The installation program will now prepare the chosen harddisk:\n\n %s\n\nDo you agree to continue?", +/* TR_RAID_SETUP */ +"RAID Setup", +/* TR_RAID_SETUP_DESC */ +"The installation program will now set up a RAID configuration on the selected harddisks:\n\n %s\n %s\n\nDo you agree to continue?", +/* TR_DELETE_ALL_DATA */ +"Delete all data", /* TR_NO_IPCOP_TARBALL_FOUND */ "Aucun tarball ipcop trouvé sur le serveur Web.", /* TR_NO_ORANGE_INTERFACE */ diff --git a/langs/nl/install/lang_nl.c b/langs/nl/install/lang_nl.c index cd43fc554c..cc96f47b91 100644 --- a/langs/nl/install/lang_nl.c +++ b/langs/nl/install/lang_nl.c @@ -329,6 +329,22 @@ char *nl_tr[] = { "Er is geen GROENE interface toegewezen.", /* TR_NO_HARDDISK */ "Geen vaste schijf gevonden.", +/* TR_DISK_SELECTION */ +"Disk Selection", +/* TR_DISK_SELECTION_MSG */ +"Select the disk(s) you want to install IPFire on. First those will be partitioned, and then the partitions will have a filesystem put on them.\n\nALL DATA ON THE DISK WILL BE DESTROYED.", +/* TR_NO_DISK_SELECTED */ +"No disk has been selected.\n\nPlease select one or more disks you want to install IPFire on.", +/* TR_DISK_SETUP */ +"Disk Setup", +/* TR_DISK_SETUP_DESC */ +"The installation program will now prepare the chosen harddisk:\n\n %s\n\nDo you agree to continue?", +/* TR_RAID_SETUP */ +"RAID Setup", +/* TR_RAID_SETUP_DESC */ +"The installation program will now set up a RAID configuration on the selected harddisks:\n\n %s\n %s\n\nDo you agree to continue?", +/* TR_DELETE_ALL_DATA */ +"Delete all data", /* TR_NO_IPCOP_TARBALL_FOUND */ "Er is geen ipcop tarball gevonden op de webserver.", /* TR_NO_ORANGE_INTERFACE */ diff --git a/langs/pl/install/lang_pl.c b/langs/pl/install/lang_pl.c index dddf551a67..2fc672159c 100644 --- a/langs/pl/install/lang_pl.c +++ b/langs/pl/install/lang_pl.c @@ -325,6 +325,22 @@ char *pl_tr[] = { "Nie przypisano interfejsu GREEN.", /* TR_NO_HARDDISK */ "Nie znaleziono dysku twardego.", +/* TR_DISK_SELECTION */ +"Disk Selection", +/* TR_DISK_SELECTION_MSG */ +"Select the disk(s) you want to install IPFire on. First those will be partitioned, and then the partitions will have a filesystem put on them.\n\nALL DATA ON THE DISK WILL BE DESTROYED.", +/* TR_NO_DISK_SELECTED */ +"No disk has been selected.\n\nPlease select one or more disks you want to install IPFire on.", +/* TR_DISK_SETUP */ +"Disk Setup", +/* TR_DISK_SETUP_DESC */ +"The installation program will now prepare the chosen harddisk:\n\n %s\n\nDo you agree to continue?", +/* TR_RAID_SETUP */ +"RAID Setup", +/* TR_RAID_SETUP_DESC */ +"The installation program will now set up a RAID configuration on the selected harddisks:\n\n %s\n %s\n\nDo you agree to continue?", +/* TR_DELETE_ALL_DATA */ +"Delete all data", /* TR_NO_IPCOP_TARBALL_FOUND */ "Nie znaleziono archiwum tar ipcop na serwerze Web.", /* TR_NO_ORANGE_INTERFACE */ diff --git a/langs/ru/install/lang_ru.c b/langs/ru/install/lang_ru.c index 40293a209c..0b50ea1aaa 100644 --- a/langs/ru/install/lang_ru.c +++ b/langs/ru/install/lang_ru.c @@ -323,6 +323,22 @@ char *ru_tr[] = { "Не назначен GREEN интерфейс.", /* TR_NO_HARDDISK */ "Не найден жсткий диск.", +/* TR_DISK_SELECTION */ +"Disk Selection", +/* TR_DISK_SELECTION_MSG */ +"Select the disk(s) you want to install IPFire on. First those will be partitioned, and then the partitions will have a filesystem put on them.\n\nALL DATA ON THE DISK WILL BE DESTROYED.", +/* TR_NO_DISK_SELECTED */ +"No disk has been selected.\n\nPlease select one or more disks you want to install IPFire on.", +/* TR_DISK_SETUP */ +"Disk Setup", +/* TR_DISK_SETUP_DESC */ +"The installation program will now prepare the chosen harddisk:\n\n %s\n\nDo you agree to continue?", +/* TR_RAID_SETUP */ +"RAID Setup", +/* TR_RAID_SETUP_DESC */ +"The installation program will now set up a RAID configuration on the selected harddisks:\n\n %s\n %s\n\nDo you agree to continue?", +/* TR_DELETE_ALL_DATA */ +"Delete all data", /* TR_NO_IPCOP_TARBALL_FOUND */ "На сервере не найден архив ipcop.", /* TR_NO_ORANGE_INTERFACE */ diff --git a/langs/tr/install/lang_tr.c b/langs/tr/install/lang_tr.c index 814949a84e..b02e9fa663 100644 --- a/langs/tr/install/lang_tr.c +++ b/langs/tr/install/lang_tr.c @@ -329,6 +329,22 @@ char *tr_tr[] = { "Hiçbir YEŞİL ara birim atanmamış.", /* TR_NO_HARDDISK */ "Sabit disk bulunamadı.", +/* TR_DISK_SELECTION */ +"Disk Selection", +/* TR_DISK_SELECTION_MSG */ +"Select the disk(s) you want to install IPFire on. First those will be partitioned, and then the partitions will have a filesystem put on them.\n\nALL DATA ON THE DISK WILL BE DESTROYED.", +/* TR_NO_DISK_SELECTED */ +"No disk has been selected.\n\nPlease select one or more disks you want to install IPFire on.", +/* TR_DISK_SETUP */ +"Disk Setup", +/* TR_DISK_SETUP_DESC */ +"The installation program will now prepare the chosen harddisk:\n\n %s\n\nDo you agree to continue?", +/* TR_RAID_SETUP */ +"RAID Setup", +/* TR_RAID_SETUP_DESC */ +"The installation program will now set up a RAID configuration on the selected harddisks:\n\n %s\n %s\n\nDo you agree to continue?", +/* TR_DELETE_ALL_DATA */ +"Delete all data", /* TR_NO_IPCOP_TARBALL_FOUND */ "Web sunucuda hiçbir ipfire arşivi bulunamadı.", /* TR_NO_ORANGE_INTERFACE */ diff --git a/lfs/installer b/lfs/installer index 29095eb69e..1fc2058858 100644 --- a/lfs/installer +++ b/lfs/installer @@ -57,7 +57,7 @@ $(TARGET) : cd $(DIR_APP)/libsmooth && make CFLAGS="-Os -fomit-frame-pointer -Wall \ -DNAME='\"$(NAME)\"' -DSNAME='\"$(SNAME)\"' -DVERSION='\"$(VERSION)\"' \ -DSLOGAN='\"$(SLOGAN)\"' -DCONFIG_ROOT='\"$(CONFIG_ROOT)\"'" - cd $(DIR_APP)/install && make CFLAGS="-Os -fomit-frame-pointer -Wall \ + cd $(DIR_APP)/install && make CFLAGS="-Os -std=gnu99 -fomit-frame-pointer -Wall \ -DNAME='\"$(NAME)\"' -DSNAME='\"$(SNAME)\"' -DVERSION='\"$(VERSION)\"' \ -DSLOGAN='\"$(SLOGAN)\"' -DCONFIG_ROOT='\"$(CONFIG_ROOT)\"' -DKERNEL_VERSION='\"$(KVER)\"'" cd $(DIR_APP)/install && install -v -m 0755 install probenic.sh \ diff --git a/src/install+setup/install/Makefile b/src/install+setup/install/Makefile index c8aa01e5c7..3feb635427 100644 --- a/src/install+setup/install/Makefile +++ b/src/install+setup/install/Makefile @@ -25,7 +25,7 @@ INCLUDE = LD = gcc LDFLAGS = -LIBS = -lnewt -lslang -lpci -ludev +LIBS = -lnewt -lslang -lpci -ludev -lblkid COMPILE = $(CC) -c $(INCLUDE) $(CFLAGS) diff --git a/src/install+setup/install/hw.c b/src/install+setup/install/hw.c index eb52f889d6..1fca9fdfa9 100644 --- a/src/install+setup/install/hw.c +++ b/src/install+setup/install/hw.c @@ -19,13 +19,19 @@ #############################################################################*/ #include +#include +#include #include +#include #include #include #include +#include #include #include +#include + #include "hw.h" struct hw* hw_init() { @@ -115,3 +121,197 @@ char* hw_find_source_medium(struct hw* hw) { return ret; } + +static struct hw_disk** hw_create_disks() { + struct hw_disk** ret = malloc(sizeof(*ret) * (HW_MAX_DISKS + 1)); + + return ret; +} + +static unsigned long long hw_block_device_get_size(const char* dev) { + int fd = open(dev, O_RDONLY); + if (fd < 0) + return 0; + + unsigned long long size = blkid_get_dev_size(fd); + close(fd); + + return size; +} + +struct hw_disk** hw_find_disks(struct hw* hw) { + struct hw_disk** ret = hw_create_disks(); + struct hw_disk** disks = ret; + + struct udev_enumerate* enumerate = udev_enumerate_new(hw->udev); + + udev_enumerate_add_match_subsystem(enumerate, "block"); + udev_enumerate_scan_devices(enumerate); + + struct udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate); + + struct udev_list_entry* dev_list_entry; + unsigned int i = HW_MAX_DISKS; + udev_list_entry_foreach(dev_list_entry, devices) { + const char* path = udev_list_entry_get_name(dev_list_entry); + struct udev_device* dev = udev_device_new_from_syspath(hw->udev, path); + + const char* dev_path = udev_device_get_devnode(dev); + + // 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")) { + udev_device_unref(dev); + continue; + } + + // DEVTYPE must be disk (otherwise we will see all sorts of partitions here) + const char* devtype = udev_device_get_property_value(dev, "DEVTYPE"); + if (devtype && (strcmp(devtype, "disk") != 0)) { + udev_device_unref(dev); + continue; + } + + // Skip all source mediums + if (hw_test_source_medium(dev_path) == 0) { + udev_device_unref(dev); + continue; + } + + // Skip devices with a size of zero + unsigned long long size = hw_block_device_get_size(dev_path); + if (size == 0) { + udev_device_unref(dev); + continue; + } + + struct hw_disk* disk = malloc(sizeof(*disk)); + if (disk == NULL) + return NULL; + + disk->ref = 1; + + strncpy(disk->path, dev_path, sizeof(disk->path)); + + disk->size = size; + + // Vendor + const char* vendor = udev_device_get_property_value(dev, "ID_VENDOR"); + if (!vendor) + vendor = udev_device_get_sysattr_value(dev, "vendor"); + if (!vendor) + vendor = udev_device_get_sysattr_value(dev, "manufacturer"); + if (!vendor) + vendor = "N/A"; + + strncpy(disk->vendor, vendor, sizeof(disk->vendor)); + + // Model + const char* model = udev_device_get_property_value(dev, "ID_MODEL"); + if (!model) + model = udev_device_get_sysattr_value(dev, "model"); + if (!model) + model = udev_device_get_sysattr_value(dev, "product"); + if (!model) + model = "N/A"; + + strncpy(disk->model, model, sizeof(disk->model)); + + snprintf(disk->description, sizeof(disk->description), + "%4.1fGB %s - %s", (double)disk->size / pow(1024, 3), + disk->vendor, disk->model); + + *disks++ = disk; + + if (--i == 0) + break; + + udev_device_unref(dev); + } + + udev_enumerate_unref(enumerate); + + *disks = NULL; + + return ret; +} + +void hw_free_disks(struct hw_disk** disks) { + struct hw_disk** disk = disks; + + while (*disk != NULL) { + if (--(*disk)->ref == 0) + free(*disk); + + disk++; + } + + free(disks); +} + +unsigned int hw_count_disks(struct hw_disk** disks) { + unsigned int ret = 0; + + while (*disks++) + ret++; + + return ret; +} + +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); + + for (unsigned int i = 0; i < num_disks; i++) { + if (selection && selection[i]) { + struct hw_disk *selected_disk = disks[i]; + selected_disk->ref++; + + *selected_disks++ = selected_disk; + } + } + + // Set sentinel + *selected_disks = NULL; + + return ret; +} + +struct hw_destination* hw_make_destination(int part_type, struct hw_disk** disks) { + struct hw_destination* dest = malloc(sizeof(*dest)); + + if (part_type == HW_PART_TYPE_NORMAL) { + dest->disk1 = *disks; + dest->disk2 = NULL; + + strncpy(dest->path, dest->disk1->path, sizeof(dest->path)); + + } else if (part_type == HW_PART_TYPE_RAID1) { + dest->disk1 = *disks++; + dest->disk2 = *disks; + + snprintf(dest->path, sizeof(dest->path), "/dev/md0"); + } + + // 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); + + if (dest->is_raid) { + dest->size = (dest->disk1->size >= dest->disk2->size) ? + dest->disk1->size : dest->disk2->size; + } else { + dest->size = dest->disk1->size; + } + + return dest; +} diff --git a/src/install+setup/install/hw.h b/src/install+setup/install/hw.h index 3ef0d18bfe..d5549a4c7a 100644 --- a/src/install+setup/install/hw.h +++ b/src/install+setup/install/hw.h @@ -26,10 +26,44 @@ #define SOURCE_MOUNT_PATH "/cdrom" #define SOURCE_TEST_FILE SOURCE_MOUNT_PATH "/" VERSION ".media" +#define HW_MAX_DISKS 32 +#define STRING_SIZE 1024 +#define DEV_SIZE 128 + +#define HW_PART_TYPE_NORMAL 0 +#define HW_PART_TYPE_RAID1 1 + struct hw { struct udev *udev; }; +struct hw_disk { + char path[DEV_SIZE]; + unsigned long long size; + + char description[STRING_SIZE]; + char vendor[STRING_SIZE]; + char model[STRING_SIZE]; + + // Reference counter + int ref; +}; + +struct hw_destination { + char path[DEV_SIZE]; + unsigned long long size; + + int is_raid; + + const struct hw_disk* disk1; + const struct hw_disk* disk2; + + char part_boot[DEV_SIZE]; + char part_swap[DEV_SIZE]; + char part_root[DEV_SIZE]; + char part_data[DEV_SIZE]; +}; + struct hw* hw_init(); void hw_free(struct hw* hw); @@ -38,4 +72,9 @@ int hw_umount(const char* target); char* hw_find_source_medium(struct hw* hw); +struct hw_disk** hw_find_disks(struct hw* hw); +void hw_free_disks(struct hw_disk** disks); +unsigned int hw_count_disks(struct hw_disk** disks); +struct hw_disk** hw_select_disks(struct hw_disk** disks, int* selection); + #endif /* HEADER_HW_H */ diff --git a/src/install+setup/install/install.h b/src/install+setup/install/install.h index a6e110f44d..500d435f7f 100644 --- a/src/install+setup/install/install.h +++ b/src/install+setup/install/install.h @@ -15,17 +15,6 @@ #define IDE_HD 2 #define IDE_UNKNOWN 3 -/* CDROMS and harddisks. */ -struct devparams -{ - char devnode_disk[30]; // when single partition is addressed - char devnode_part[30]; // when the RAID partition is addressed - char devnode_disk_run[30]; // the same dev but after installation - char devnode_part_run[30]; - char modulename[STRING_SIZE]; - char options[STRING_SIZE]; -}; - /* config.c */ int write_disk_configs(struct devparams *dp); int write_lang_configs( char *lang); diff --git a/src/install+setup/install/main.c b/src/install+setup/install/main.c index b053978f01..0386cf5cdd 100644 --- a/src/install+setup/install/main.c +++ b/src/install+setup/install/main.c @@ -48,6 +48,107 @@ extern char *pl_tr[]; extern char *ru_tr[]; extern char *tr_tr[]; +static int newtChecklist(const char* title, const char* message, + unsigned int width, unsigned int height, unsigned int num_entries, + const char** entries, int* states) { + int ret; + const int list_height = 4; + + char cbstates[num_entries]; + + for (unsigned int i = 0; i < num_entries; i++) { + cbstates[i] = states[i] ? '*' : ' '; + } + + newtCenteredWindow(width, height, title); + + newtComponent textbox = newtTextbox(1, 1, width - 2, height - 6 - list_height, + NEWT_FLAG_WRAP); + newtTextboxSetText(textbox, message); + + int top = newtTextboxGetNumLines(textbox) + 2; + + newtComponent form = newtForm(NULL, NULL, 0); + + newtComponent sb = NULL; + if (list_height < num_entries) { + sb = newtVerticalScrollbar( + width - 4, top + 1, list_height, + NEWT_COLORSET_CHECKBOX, NEWT_COLORSET_ACTCHECKBOX); + + newtFormAddComponent(form, sb); + } + + newtComponent subform = newtForm(sb, NULL, 0); + newtFormSetBackground(subform, NEWT_COLORSET_CHECKBOX); + + newtFormSetHeight(subform, list_height); + newtFormSetWidth(subform, width - 10); + + for (unsigned int i = 0; i < num_entries; i++) { + newtComponent cb = newtCheckbox(4, top + i, entries[i], cbstates[i], + NULL, &cbstates[i]); + + newtFormAddComponent(subform, cb); + } + + newtFormAddComponents(form, textbox, subform, NULL); + + newtComponent btn_okay = newtButton((width - 18) / 3, height - 4, ctr[TR_OK]); + newtComponent btn_cancel = newtButton((width - 18) / 3 * 2 + 9, height - 4, ctr[TR_CANCEL]); + newtFormAddComponents(form, btn_okay, btn_cancel, NULL); + + newtComponent answer = newtRunForm(form); + + if ((answer == NULL) || (answer == btn_cancel)) { + ret = -1; + } else { + ret = 0; + + for (unsigned int i = 0; i < num_entries; i++) { + states[i] = (cbstates[i] != ' '); + + if (states[i]) + ret++; + } + } + + newtFormDestroy(form); + newtPopWindow(); + + return ret; +} + +static int newtWinOkCancel(const char* title, const char* message, int width, int height, + const char* btn_txt_ok, const char* btn_txt_cancel) { + int ret = 1; + + newtCenteredWindow(width, height, title); + + newtComponent form = newtForm(NULL, NULL, 0); + + newtComponent textbox = newtTextbox(1, 1, width - 2, height - 6, NEWT_FLAG_WRAP); + newtTextboxSetText(textbox, message); + newtFormAddComponent(form, textbox); + + newtComponent btn_ok = newtButton((width - 16) / 3, height - 4, btn_txt_ok); + newtComponent btn_cancel = newtButton((width - 16) / 3 * 2 + 9, height - 4, + btn_txt_cancel); + + newtFormAddComponents(form, btn_ok, btn_cancel, NULL); + + newtComponent answer = newtRunForm(form); + + if (answer == btn_ok) { + ret = 0; + } + + newtFormDestroy(form); + newtPopWindow(); + + return ret; +} + int main(int argc, char *argv[]) { struct hw* hw = hw_init(); @@ -56,46 +157,33 @@ int main(int argc, char *argv[]) { char *langnames[] = { "Deutsch", "English", "Français", "Español", "Nederlands", "Polski", "Русский", "Türkçe", NULL }; char *shortlangnames[] = { "de", "en", "fr", "es", "nl", "pl", "ru", "tr", NULL }; char **langtrs[] = { de_tr, en_tr, fr_tr, es_tr, nl_tr, pl_tr, ru_tr, tr_tr, NULL }; - char hdletter; - char harddrive[30]; /* Device holder. */ char* sourcedrive = NULL; - char harddrive_info[STRING_SIZE]; /* Additional infos about target */ - struct devparams hdparams, cdromparams; /* Params for CDROM and HD */ int rc = 0; char commandstring[STRING_SIZE]; char mkfscommand[STRING_SIZE]; char *fstypes[] = { "ext2", "ext3", "ext4", "ReiserFS", NULL }; int fstype = EXT4; int choice; - int i; - int found = 0; char shortlangname[10]; - char message[1000]; + char message[STRING_SIZE]; char title[STRING_SIZE]; int allok = 0; int allok_fastexit=0; - int raid_disk = 0; struct keyvalue *ethernetkv = initkeyvalues(); FILE *handle, *cmdfile, *copying; char line[STRING_SIZE]; char string[STRING_SIZE]; long memory = 0, disk = 0; long system_partition, boot_partition, root_partition, swap_file; - int scsi_disk = 0; - char *yesnoharddisk[3]; // char *yesnoharddisk = { "NO", "YES", NULL }; int unattended = 0; int serialconsole = 0; struct keyvalue *unattendedkv = initkeyvalues(); - int hardyn = 0; char restore_file[STRING_SIZE] = ""; setlocale (LC_ALL, ""); sethostname( SNAME , 10); - memset(&hdparams, 0, sizeof(struct devparams)); - memset(&cdromparams, 0, sizeof(struct devparams)); - /* Log file/terminal stuff. */ if (argc >= 2) { @@ -185,6 +273,14 @@ int main(int argc, char *argv[]) { exit(1); } + /* load unattended configuration */ + if (unattended) { + fprintf(flog, "unattended: Reading unattended.conf\n"); + + (void) readkeyvalues(unattendedkv, UNATTENDED_CONF); + findkey(unattendedkv, "RESTORE_FILE", restore_file); + } + if (!unattended) { // Read the license file. if (!(copying = fopen(LICENSE_FILE, "r"))) { @@ -201,87 +297,100 @@ int main(int argc, char *argv[]) { } } - i = 0; - while (found == 0) { - i++; - fprintf(flog, "Harddisk scan pass %i\n", i); + int part_type = HW_PART_TYPE_NORMAL; - switch (mysystem("/bin/mountdest.sh") % 255) { - case 0: // Found IDE disk - scsi_disk = 0; - raid_disk = 0; - found = 1; - break; - case 1: // Found SCSI disk - scsi_disk = 1; - raid_disk = 0; - found = 1; + // Scan for disks to install on. + struct hw_disk** disks = hw_find_disks(hw); + + struct hw_disk** selected_disks = NULL; + unsigned int num_selected_disks = 0; + + // Check how many disks have been found and what + // we can do with them. + unsigned int num_disks = hw_count_disks(disks); + + while (1) { + // no harddisks found + if (num_disks == 0) { + errorbox(ctr[TR_NO_HARDDISK]); + goto EXIT; + + // exactly one disk has been found + } else if (num_disks == 1) { + selected_disks = hw_select_disks(disks, NULL); + + // more than one usable disk has been found and + // the user needs to choose what to do with them + } else { + const char* disk_names[num_disks]; + int disk_selection[num_disks]; + + for (unsigned int i = 0; i < num_disks; i++) { + disk_names[i] = &disks[i]->description; + disk_selection[i] = 0; + } + + while (!selected_disks) { + rc = newtChecklist(ctr[TR_DISK_SELECTION], ctr[TR_DISK_SELECTION_MSG], + 50, 20, num_disks, disk_names, disk_selection); + + // Error + if (rc < 0) { + goto EXIT; + + // Nothing has been selected + } else if (rc == 0) { + errorbox(ctr[TR_NO_DISK_SELECTED]); + + } else { + selected_disks = hw_select_disks(disks, disk_selection); + } + } + } + + num_selected_disks = hw_count_disks(selected_disks); + + if (num_selected_disks == 1) { + snprintf(message, sizeof(message), ctr[TR_DISK_SETUP_DESC], (*selected_disks)->description); + rc = newtWinOkCancel(ctr[TR_DISK_SETUP], message, 50, 10, + ctr[TR_DELETE_ALL_DATA], ctr[TR_CANCEL]); + + if (rc == 0) break; - case 2: // Found RAID disk - scsi_disk = 0; - raid_disk= 1; - found = 1; + + } else if (num_selected_disks == 2) { + snprintf(message, sizeof(message), ctr[TR_RAID_SETUP_DESC], + (*selected_disks)->description, (*selected_disks + 1)->description); + rc = newtWinOkCancel(ctr[TR_RAID_SETUP], message, 50, 10, + ctr[TR_DELETE_ALL_DATA], ctr[TR_CANCEL]); + + if (rc == 0) { + part_type = HW_PART_TYPE_RAID1; + break; - case 10: // No harddisk found - errorbox(ctr[TR_NO_HARDDISK]); - goto EXIT; + } + + // Currently not supported + } else { + errorbox(ctr[TR_DISK_CONFIGURATION_NOT_SUPPORTED]); } - } - if ((handle = fopen("/tmp/dest_device", "r")) == NULL) { - errorbox(ctr[TR_NO_HARDDISK]); - goto EXIT; - } - fgets(harddrive, 30, handle); - fclose(handle); - if ((handle = fopen("/tmp/dest_device_info", "r")) == NULL) { - sprintf(harddrive_info, "%s", harddrive); + if (selected_disks) { + hw_free_disks(selected_disks); + selected_disks = NULL; + } } - fgets(harddrive_info, 70, handle); - fclose(handle); - - /* load unattended configuration */ - if (unattended) { - fprintf(flog, "unattended: Reading unattended.conf\n"); + hw_free_disks(disks); - (void) readkeyvalues(unattendedkv, UNATTENDED_CONF); - findkey(unattendedkv, "RESTORE_FILE", restore_file); - } - - /* Make the hdparms struct and print the contents. - With USB-KEY install and SCSI disk, while installing, the disk - is named 'sdb,sdc,...' (following keys) - On reboot, it will become 'sda' - To avoid many test, all names are built in the struct. - */ - sprintf(hdparams.devnode_disk, "/dev/%s", harddrive); - /* Address the partition or raid partition (eg dev/sda or /dev/sdap1 */ - sprintf(hdparams.devnode_part, "/dev/%s%s", harddrive,raid_disk ? "p" : ""); - /* Now the names after the machine is booted. Only scsi is affected - and we only install on the first scsi disk. */ - - fprintf(flog, "Destination drive: %s\n", hdparams.devnode_disk); - - sprintf(message, ctr[TR_PREPARE_HARDDISK], harddrive_info); - if (unattended) { - hardyn = 1; - } else { - yesnoharddisk[0] = ctr[TR_NO]; - yesnoharddisk[1] = ctr[TR_YES]; - yesnoharddisk[2] = NULL; - } + struct hw_destination* destination = hw_make_destination(part_type, selected_disks); + assert(destination); - while (! hardyn) { - rc = newtWinMenu(title, message, - 50, 5, 5, 6, yesnoharddisk, - &hardyn, ctr[TR_OK], - ctr[TR_CANCEL], NULL); - if (rc == 2) - goto EXIT; - } - if (rc == 2) - goto EXIT; + fprintf(flog, "Destination drive: %s\n", destination->path); + fprintf(flog, " boot: %s\n", destination->part_boot); + fprintf(flog, " swap: %s\n", destination->part_swap); + fprintf(flog, " root: %s\n", destination->part_root); + fprintf(flog, " data: %s\n", destination->part_data); fstypes[0]=ctr[TR_EXT2FS_DESCR]; fstypes[1]=ctr[TR_EXT3FS_DESCR]; @@ -317,18 +426,7 @@ int main(int argc, char *argv[]) { * partition. In order to do that we need to know the size of * the disk. */ - /* Don't use mysystem here so we can redirect output */ - sprintf(commandstring, "/sbin/sfdisk -s /dev/%s > /tmp/disksize 2> /dev/null", harddrive); - system(commandstring); - - /* Calculate amount of disk space */ - if ((handle = fopen("/tmp/disksize", "r"))) { - fgets(line, STRING_SIZE-1, handle); - if (sscanf (line, "%s", string)) { - disk = atoi(string) / 1024; - } - fclose(handle); - } + disk = destination->size / 1024 / 1024; fprintf(flog, "Disksize = %ld, memory = %ld", disk, memory); @@ -392,10 +490,10 @@ int main(int argc, char *argv[]) { if (disk < 2097150) { // <2TB use sfdisk and normal mbr - snprintf(commandstring, STRING_SIZE, "/sbin/sfdisk -L -uM %s < /tmp/partitiontable", hdparams.devnode_disk); + snprintf(commandstring, STRING_SIZE, "/sbin/sfdisk -L -uM %s < /tmp/partitiontable", destination->path); } else { // >2TB use parted with gpt - snprintf(commandstring, STRING_SIZE, "/usr/sbin/parted -s %s mklabel gpt mkpart boot ext2 1M 64M mkpart swap linux-swap 64M 1000M mkpart root ext4 1000M 5000M mkpart var ext4 5000M 100%% disk_set pmbr_boot on", hdparams.devnode_disk); + snprintf(commandstring, STRING_SIZE, "/usr/sbin/parted -s %s mklabel gpt mkpart boot ext2 1M 64M mkpart swap linux-swap 64M 1000M mkpart root ext4 1000M 5000M mkpart var ext4 5000M 100%% disk_set pmbr_boot on", destination->path); } if (runcommandwithstatus(commandstring, ctr[TR_PARTITIONING_DISK])) @@ -418,7 +516,7 @@ int main(int argc, char *argv[]) { sprintf(mkfscommand, "/sbin/mke2fs -T ext4"); } - snprintf(commandstring, STRING_SIZE, "/sbin/mke2fs -T ext2 -I 128 %s1", hdparams.devnode_part); + snprintf(commandstring, STRING_SIZE, "/sbin/mke2fs -T ext2 -I 128 %s", destination->part_boot); if (runcommandwithstatus(commandstring, ctr[TR_MAKING_BOOT_FILESYSTEM])) { errorbox(ctr[TR_UNABLE_TO_MAKE_BOOT_FILESYSTEM]); @@ -426,7 +524,7 @@ int main(int argc, char *argv[]) { } if (swap_file) { - snprintf(commandstring, STRING_SIZE, "/sbin/mkswap %s2", hdparams.devnode_part); + snprintf(commandstring, STRING_SIZE, "/sbin/mkswap %s", destination->part_swap); if (runcommandwithstatus(commandstring, ctr[TR_MAKING_SWAPSPACE])) { errorbox(ctr[TR_UNABLE_TO_MAKE_SWAPSPACE]); @@ -434,21 +532,21 @@ int main(int argc, char *argv[]) { } } - snprintf(commandstring, STRING_SIZE, "%s %s3", mkfscommand, hdparams.devnode_part); + snprintf(commandstring, STRING_SIZE, "%s %s", mkfscommand, destination->part_root); if (runcommandwithstatus(commandstring, ctr[TR_MAKING_ROOT_FILESYSTEM])) { errorbox(ctr[TR_UNABLE_TO_MAKE_ROOT_FILESYSTEM]); goto EXIT; } - snprintf(commandstring, STRING_SIZE, "%s %s4", mkfscommand, hdparams.devnode_part); + snprintf(commandstring, STRING_SIZE, "%s %s", mkfscommand, destination->part_data); if (runcommandwithstatus(commandstring, ctr[TR_MAKING_LOG_FILESYSTEM])) { errorbox(ctr[TR_UNABLE_TO_MAKE_LOG_FILESYSTEM]); goto EXIT; } - snprintf(commandstring, STRING_SIZE, "/bin/mount %s3 /harddisk", hdparams.devnode_part); + snprintf(commandstring, STRING_SIZE, "/bin/mount %s /harddisk", destination->part_root); if (runcommandwithstatus(commandstring, ctr[TR_MOUNTING_ROOT_FILESYSTEM])) { errorbox(ctr[TR_UNABLE_TO_MOUNT_ROOT_FILESYSTEM]); @@ -459,21 +557,21 @@ int main(int argc, char *argv[]) { mkdir("/harddisk/var", S_IRWXU|S_IRWXG|S_IRWXO); mkdir("/harddisk/var/log", S_IRWXU|S_IRWXG|S_IRWXO); - snprintf(commandstring, STRING_SIZE, "/bin/mount %s1 /harddisk/boot", hdparams.devnode_part); + snprintf(commandstring, STRING_SIZE, "/bin/mount %s /harddisk/boot", destination->part_boot); if (runcommandwithstatus(commandstring, ctr[TR_MOUNTING_BOOT_FILESYSTEM])) { errorbox(ctr[TR_UNABLE_TO_MOUNT_BOOT_FILESYSTEM]); goto EXIT; } if (swap_file) { - snprintf(commandstring, STRING_SIZE, "/sbin/swapon %s2", hdparams.devnode_part); + snprintf(commandstring, STRING_SIZE, "/sbin/swapon %s", destination->part_swap); if (runcommandwithstatus(commandstring, ctr[TR_MOUNTING_SWAP_PARTITION])) { errorbox(ctr[TR_UNABLE_TO_MOUNT_SWAP_PARTITION]); goto EXIT; } } - snprintf(commandstring, STRING_SIZE, "/bin/mount %s4 /harddisk/var", hdparams.devnode_part); + snprintf(commandstring, STRING_SIZE, "/bin/mount %s /harddisk/var", destination->part_data); if (runcommandwithstatus(commandstring, ctr[TR_MOUNTING_LOG_FILESYSTEM])) { errorbox(ctr[TR_UNABLE_TO_MOUNT_LOG_FILESYSTEM]); @@ -508,13 +606,13 @@ int main(int argc, char *argv[]) { } /* Update /etc/fstab */ - snprintf(commandstring, STRING_SIZE, "/bin/sed -i -e \"s#DEVICE1#UUID=$(/sbin/blkid %s1 -sUUID | /usr/bin/cut -d'\"' -f2)#g\" /harddisk/etc/fstab", hdparams.devnode_part); + snprintf(commandstring, STRING_SIZE, "/bin/sed -i -e \"s#DEVICE1#UUID=$(/sbin/blkid %s -sUUID | /usr/bin/cut -d'\"' -f2)#g\" /harddisk/etc/fstab", destination->part_boot); system(commandstring); - snprintf(commandstring, STRING_SIZE, "/bin/sed -i -e \"s#DEVICE2#UUID=$(/sbin/blkid %s2 -sUUID | /usr/bin/cut -d'\"' -f2)#g\" /harddisk/etc/fstab", hdparams.devnode_part); + snprintf(commandstring, STRING_SIZE, "/bin/sed -i -e \"s#DEVICE2#UUID=$(/sbin/blkid %s -sUUID | /usr/bin/cut -d'\"' -f2)#g\" /harddisk/etc/fstab", destination->part_swap); system(commandstring); - snprintf(commandstring, STRING_SIZE, "/bin/sed -i -e \"s#DEVICE3#UUID=$(/sbin/blkid %s3 -sUUID | /usr/bin/cut -d'\"' -f2)#g\" /harddisk/etc/fstab", hdparams.devnode_part); + snprintf(commandstring, STRING_SIZE, "/bin/sed -i -e \"s#DEVICE3#UUID=$(/sbin/blkid %s -sUUID | /usr/bin/cut -d'\"' -f2)#g\" /harddisk/etc/fstab", destination->part_root); system(commandstring); - snprintf(commandstring, STRING_SIZE, "/bin/sed -i -e \"s#DEVICE4#UUID=$(/sbin/blkid %s4 -sUUID | /usr/bin/cut -d'\"' -f2)#g\" /harddisk/etc/fstab", hdparams.devnode_part); + snprintf(commandstring, STRING_SIZE, "/bin/sed -i -e \"s#DEVICE4#UUID=$(/sbin/blkid %s -sUUID | /usr/bin/cut -d'\"' -f2)#g\" /harddisk/etc/fstab", destination->part_data); system(commandstring); if (fstype == EXT2) { @@ -533,7 +631,7 @@ int main(int argc, char *argv[]) { replace("/harddisk/boot/grub/grub.conf", "KVER", KERNEL_VERSION); - snprintf(commandstring, STRING_SIZE, "/bin/sed -i -e \"s#root=ROOT#root=UUID=$(/sbin/blkid %s3 -sUUID | /usr/bin/cut -d'\"' -f2)#g\" /harddisk/boot/grub/grub.conf", hdparams.devnode_part); + snprintf(commandstring, STRING_SIZE, "/bin/sed -i -e \"s#root=ROOT#root=UUID=$(/sbin/blkid %s -sUUID | /usr/bin/cut -d'\"' -f2)#g\" /harddisk/boot/grub/grub.conf", destination->part_root); system(commandstring); mysystem("ln -s grub.conf /harddisk/boot/grub/menu.lst"); @@ -545,12 +643,12 @@ int main(int argc, char *argv[]) { */ FILE *f = NULL; if (f = fopen("/harddisk/boot/grub/device.map", "w")) { - fprintf(f, "(hd0) %s\n", hdparams.devnode_disk); + fprintf(f, "(hd0) %s\n", destination->path); fclose(f); } snprintf(commandstring, STRING_SIZE, - "/usr/sbin/chroot /harddisk /usr/sbin/grub-install --no-floppy %s", hdparams.devnode_disk); + "/usr/sbin/chroot /harddisk /usr/sbin/grub-install --no-floppy %s", destination->path); if (runcommandwithstatus(commandstring, ctr[TR_INSTALLING_GRUB])) { errorbox(ctr[TR_UNABLE_TO_INSTALL_GRUB]); goto EXIT; @@ -633,7 +731,7 @@ EXIT: fcloseall(); if (swap_file) { - snprintf(commandstring, STRING_SIZE, "/bin/swapoff %s2", hdparams.devnode_part); + snprintf(commandstring, STRING_SIZE, "/bin/swapoff %s", destination->part_swap); } newtFinished(); @@ -651,6 +749,12 @@ EXIT: // Free resources free(sourcedrive); + free(destination); + + if (selected_disks) + hw_free_disks(selected_disks); + + hw_free(hw); return 0; } -- 2.39.2