installer: Rework downloading ISO and allow using a custom URL
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 25 Oct 2014 12:56:23 +0000 (14:56 +0200)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 25 Oct 2014 12:56:23 +0000 (14:56 +0200)
lfs/installer
src/installer/configure.ac
src/installer/downloadsource.sh
src/installer/dracut-module/70-dhcpcd.exe
src/installer/dracut-module/module-setup.sh
src/installer/hw.c
src/installer/main.c
src/installer/start-networking.sh

index 7f73222..3364a4d 100644 (file)
@@ -31,6 +31,7 @@ DIR_APP    = $(DIR_SRC)/$(THISAPP)
 TARGET     = $(DIR_INFO)/$(THISAPP)
 
 SLOGAN     = An Open Source Firewall Solution
+DOWNLOAD_URL = http://downloads.ipfire.org/releases/ipfire-2.x/$(VERSION)-core$(CORE)/$(SNAME)-$(VERSION).$(MACHINE)-full-core$(CORE).iso
 
 ###############################################################################
 # Top-level Rules
@@ -58,12 +59,11 @@ $(TARGET) :
                --with-distro-name="$(NAME)" \
                --with-distro-sname="$(SNAME)" \
                --with-distro-slogan="$(SLOGAN)" \
-               --with-config-root="$(CONFIG_ROOT)"
+               --with-config-root="$(CONFIG_ROOT)" \
+               --with-download-url="$(DOWNLOAD_URL)"
+
        cd $(DIR_APP) && make $(MAKETUNING)
        cd $(DIR_APP) && make install
 
-       #Patch ISO Name for download ...
-       #sed -i -e "s|ipfire.iso|download.ipfire.org/releases/ipfire-2.x/$(VERSION)-core$(CORE)/$(SNAME)-$(VERSION).$(MACHINE)-full-core$(CORE).iso|g" \
-       #                       /usr/bin/downloadsource.sh
        @rm -rf $(DIR_APP)
        @$(POSTBUILD)
index da968f6..e93e0af 100644 (file)
@@ -84,6 +84,11 @@ AC_ARG_WITH([config-root],
        AC_DEFINE_UNQUOTED([CONFIG_ROOT], "$withval", [The config-root]),
        AC_MSG_ERROR([*** you need to set CONFIG_ROOT with --with-config-root=]))
 
+AC_ARG_WITH([download-url],
+       AS_HELP_STRING([--with-download-url] [The default download URL]),
+       AC_DEFINE_UNQUOTED([DOWNLOAD_URL], "$withval", [The default download URL]),
+       AC_MSG_ERROR([*** you need to set DOWNLOAD_URL with --with-download-url=]))
+
 AC_CONFIG_FILES([
        Makefile
        po/Makefile.in
index 7504c19..4a48686 100644 (file)
 #                                                                             #
 ###############################################################################
 
-#lfs change the url while build!
-IPFireISO=ipfire.iso
-#
-
-#Get user defined download from boot cmdline
-grep "netinstall=" /proc/cmdline > /dev/null && CMDLINE=1
-if ( [ "$CMDLINE" == "1" ]); then
-       read CMDLINE < /proc/cmdline
-       POS=${CMDLINE%%netinstall*}
-       POS=${#POS}
-       IPFireISO=`echo ${CMDLINE:POS} | cut -d"=" -f2 | cut -d" " -f1`
+function download() {
+       wget -U "IPFire-NetInstall/2.x" "$@"
+}
+
+if [ $# -lt 2 ]; then
+       echo "$0: Insufficient number of arguments" >&2
+       exit 2
+fi
+
+OUTPUT="${1}"
+URL="${2}"
+
+echo "Downloading ${URL}..."
+if ! download -O "${OUTPUT}" "${URL}"; then
+       echo "Download failed" >&2
+
+       rm -f "${OUTPUT}"
+       exit 1
 fi
 
-echo "Download with wget..."
-wget $IPFireISO -O /tmp/download.iso -t3 -U IPFire_NetInstall/2.x
-wget $IPFireISO.md5 -O /tmp/download.iso.md5 -t3 -U IPFire_NetInstall/2.x
-echo
-echo "Checking download..."
-md5_file=`md5sum /tmp/download.iso | cut -d" " -f1`
-md5_down=`cat /tmp/download.iso.md5 | cut -d" " -f1`
-if [ "$md5_file" == "$md5_down" ]; then
-       echo -n "/tmp/download.iso" > /tmp/source_device
-       exit 0
+# Download went well. Checking for MD5 sum
+if download -O "${OUTPUT}.md5" "${URL}.md5" &>/dev/null; then
+       # Read downloaded checksum
+       read -r md5sum rest < "${OUTPUT}.md5"
+       rm -f "${OUTPUT}.md5"
+
+       # Compute checkum of downloaded image file
+       read -r md5sum_image rest <<< "$(md5sum "${OUTPUT}")"
+
+       if [ "${md5sum}" != "${md5sum_image}" ]; then
+               echo "MD5 sum mismatch: ${md5sum} != ${md5sum_image}" >&2
+               exit 2
+       fi
 fi
-echo "Error - SKIP"
-exit 10
+
+exit 0
index 4100fc9..660f269 100755 (executable)
 #
 ########################################################################
 
-dhcpcd_up()
-{
-       set | grep "^new_" | sed "s|^new_||g" | \
-       sed "s|'||g" | \
-       sort > /var/ipfire/dhcpc/dhcpcd-$interface.info
+LEASE_FILE="/var/ipfire/dhcpc/dhcpcd-${interface}.info"
 
-       DNS=`grep "domain_name_servers" /var/ipfire/dhcpc/dhcpcd-$interface.info | cut -d"=" -f2`
-       DNS1=`echo $DNS | cut -d" " -f1`
-       DNS2=`echo $DNS | cut -d" " -f2`
+export_lease() {
+       set | grep "^new_" | sed "s|^new_||g" | \
+       sed "s|'||g" | sort > ${LEASE_FILE}
+}
 
-       echo "nameserver $DNS1" > /etc/resolv.conf
-       echo "nameserver $DNS2" >> /etc/resolv.conf
+make_resolvconf() {
+       local DNS="$(grep 'domain_name_servers' ${LEASE_FILE} | cut -d'=' -f2)"
+       local DNS1="$(echo ${DNS} | cut -d' ' -f1)"
+       local DNS2="$(echo ${DNS} | cut -d' ' -f2)"
 
+       (
+               echo "nameserver ${DNS1}"
+               echo "nameserver ${DNS2}"
+       ) > /etc/resolv.conf
 }
 
-case "$reason" in
-BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC)       dhcpcd_up;;
+case "${reason}" in
+       PREINIT)
+               # Configure MTU
+               if [ -n "${new_interface_mtu}" ] && [ ${new_interface_mtu} -gt 576 ]; then
+                       echo "Setting MTU to ${new_interface_mtu}"
+                       ip link set "${interface}" mtu "${new_interface_mtu}"
+               fi
+               ;;
+
+       BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC)
+               # Export all information about the newly received lease
+               # to file
+               export_lease
+
+               # Create system configuration files
+               make_resolvconf
+               ;;
+
+       EXPIRE|FAIL|IPV4LL|NAK|NOCARRIER|RELEASE|STOP)
+               rm -f "${LEASE_FILE}"
+               ;;
 esac
+
+exit 0
index 31caa54..992fcec 100755 (executable)
@@ -35,17 +35,18 @@ install() {
     inst_multiple tar gzip lzma xz
 
     # Networking
-    inst_multiple dhcpcd ethtool hostname ip ping wget
+    inst_multiple dhcpcd ethtool hostname ip ping sort wget
     inst /usr/bin/start-networking.sh
-    inst /var/ipfire/dhcpc/dhcpcd-run-hooks
     inst /var/ipfire/dhcpc/dhcpcd.conf
-    for file in /var/ipfire/dhcpc/dhcpcd-hooks/*; do
-        inst "${file}"
-    done
+    inst /var/ipfire/dhcpc/dhcpcd-run-hooks
     inst "$moddir/70-dhcpcd.exe" "/var/ipfire/dhcpc/dhcpcd-hooks/70-dhcpcd.exe"
 
+    inst /etc/host.conf /etc/hosts /etc/protocols
+    inst /etc/nsswitch.conf /etc/resolv.conf
+    inst_libdir_file "libnss_dns.so.*"
+
     # Misc. tools
-    inst_multiple cut grep eject killall md5sum touch
+    inst_multiple cut grep eject id killall md5sum touch
     inst_multiple -o fdisk cfdisk df ps top
 
     # Hardware IDs
index 9b9a2d0..651ffdf 100644 (file)
 #include <blkid/blkid.h>
 #include <fcntl.h>
 #include <libudev.h>
+#include <linux/loop.h>
 #include <math.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/mount.h>
+#include <sys/stat.h>
 #include <sys/swap.h>
 #include <sys/sysinfo.h>
 #include <unistd.h>
@@ -82,11 +84,56 @@ 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);
 }
 
index c1a61b3..5a2e0c4 100644 (file)
@@ -229,13 +229,18 @@ static struct config {
        int unattended;
        int serial_console;
        int require_networking;
+       int perform_download;
+       char download_url[STRING_SIZE];
 } config = {
        .unattended = 0,
        .serial_console = 0,
        .require_networking = 0,
+       .perform_download = 0,
+       .download_url = DOWNLOAD_URL,
 };
 
 static void parse_command_line(struct config* c) {
+       char buffer[STRING_SIZE];
        char cmdline[STRING_SIZE];
 
        FILE* f = fopen("/proc/cmdline", "r");
@@ -244,9 +249,13 @@ static void parse_command_line(struct config* c) {
 
        int r = fread(&cmdline, 1, sizeof(cmdline) - 1, f);
        if (r > 0) {
-               char* token = strtok(&cmdline, " ");
+               char* token = strtok(cmdline, " ");
 
                while (token) {
+                       strncpy(buffer, token, sizeof(buffer));
+                       char* val = &buffer;
+                       char* key = strsep(&val, "=");
+
                        // serial console
                        if (strcmp(token, "console=ttyS0") == 0)
                                c->serial_console = 1;
@@ -259,6 +268,15 @@ static void parse_command_line(struct config* c) {
                        else if (strcmp(token, "installer.unattended") == 0)
                                c->unattended = 1;
 
+                       // download url
+                       else if (strcmp(key, "installer.download-url") == 0) {
+                               strncpy(&c->download_url, val, sizeof(c->download_url));
+                               c->perform_download = 1;
+
+                               // Require networking for the download
+                               c->require_networking = 1;
+                       }
+
                        token = strtok(NULL, " ");
                }
        }
@@ -364,16 +382,21 @@ int main(int argc, char *argv[]) {
 
        /* Search for a source drive that holds the right
         * version of the image we are going to install. */
-       sourcedrive = hw_find_source_medium(hw);
-       fprintf(flog, "Source drive: %s\n", sourcedrive);
+       if (!config.perform_download) {
+               sourcedrive = hw_find_source_medium(hw);
+               fprintf(flog, "Source drive: %s\n", sourcedrive);
+       }
 
        /* If we could not find a source drive, we will try
         * downloading the install image */
-       if (!sourcedrive) {
+       if (!sourcedrive)
+               config.perform_download = 1;
+
+       if (config.perform_download) {
                if (!config.unattended) {
                        // Show the right message to the user
                        char reason[STRING_SIZE];
-                       if (config.require_networking) {
+                       if (config.perform_download) {
                                snprintf(reason, sizeof(reason),
                                        _("The installer will now try downloading the installation image."));
                        } else {
@@ -392,6 +415,7 @@ int main(int argc, char *argv[]) {
                                goto EXIT;
                }
 
+               // Make sure that we enable networking before download
                config.require_networking = 1;
        }
 
@@ -420,20 +444,31 @@ int main(int argc, char *argv[]) {
                }
 
                // Download the image if required
-               while (!sourcedrive) {
-                       snprintf(commandstring, sizeof(commandstring), "/usr/bin/downloadsource.sh %s", SOURCE_TEMPFILE);
-                       runcommandwithstatus(commandstring, title, _("Downloading installation image..."), logfile);
-
-                       FILE* f = fopen(SOURCE_TEMPFILE, "r");
-                       if (f) {
-                               sourcedrive = SOURCE_TEMPFILE;
-                               fclose(f);
-                       } else {
-                               rc = newtWinOkCancel(title, _("The installation image could not be downloaded."),
-                                       60, 8, _("Retry"), _("Cancel"));
+               if (config.perform_download) {
+                       fprintf(flog, "Download URL: %s\n", config.download_url);
+                       snprintf(commandstring, sizeof(commandstring), "/usr/bin/downloadsource.sh %s %s",
+                               SOURCE_TEMPFILE, config.download_url);
+
+                       while (!sourcedrive) {
+                               rc = runcommandwithstatus(commandstring, title, _("Downloading installation image..."), logfile);
+
+                               FILE* f = fopen(SOURCE_TEMPFILE, "r");
+                               if (f) {
+                                       sourcedrive = SOURCE_TEMPFILE;
+                                       fclose(f);
+                               } else {
+                                       char reason[STRING_SIZE] = "-";
+                                       if (rc == 2)
+                                               snprintf(reason, sizeof(STRING_SIZE), _("MD5 checksum mismatch"));
 
-                               if (rc)
-                                       goto EXIT;
+                                       snprintf(message, sizeof(message),
+                                               _("The installation image could not be downloaded.\n  Reason: %s\n\n%s"),
+                                               reason, config.download_url);
+
+                                       rc = newtWinOkCancel(title, message, 75, 12, _("Retry"), _("Cancel"));
+                                       if (rc)
+                                               goto EXIT;
+                               }
                        }
                }
        }
@@ -442,9 +477,10 @@ int main(int argc, char *argv[]) {
 
        int r = hw_mount(sourcedrive, SOURCE_MOUNT_PATH, "iso9660", MS_RDONLY);
        if (r) {
-               fprintf(flog, "Could not mount %s to %s\n", sourcedrive, SOURCE_MOUNT_PATH);
-               fprintf(flog, strerror(errno));
-               exit(1);
+               snprintf(message, sizeof(message), _("Could not mount %s to %s:\n  %s\n"),
+                       sourcedrive, SOURCE_MOUNT_PATH, strerror(errno));
+               errorbox(message);
+               goto EXIT;
        }
 
        if (!config.unattended) {
index faeeb17..3cb7a21 100644 (file)
@@ -56,6 +56,10 @@ function main() {
                fi
 
                echo "Successfully started on ${interface}"
+
+               # Wait until everything is settled
+               sleep 15
+
                return 0
        done