diff options
Diffstat (limited to 'mdk-stage1/network.c')
-rw-r--r-- | mdk-stage1/network.c | 649 |
1 files changed, 535 insertions, 114 deletions
diff --git a/mdk-stage1/network.c b/mdk-stage1/network.c index ae2c685d2..ab512399a 100644 --- a/mdk-stage1/network.c +++ b/mdk-stage1/network.c @@ -1,7 +1,7 @@ /* - * Guillaume Cottenceau (gc@mandrakesoft.com) + * Guillaume Cottenceau (gc) * - * Copyright 2000 MandrakeSoft + * Copyright 2000 Mandriva * * This software may be freely redistributed under the terms of the GNU * public license. @@ -19,9 +19,11 @@ * */ +#include "stage1.h" + #include <stdlib.h> -#include <unistd.h> #include <string.h> +#include <unistd.h> #include <sys/socket.h> #include <net/if.h> #include <arpa/inet.h> @@ -29,14 +31,17 @@ #include <sys/ioctl.h> #include <sys/mount.h> #include <stdio.h> +#include <fcntl.h> #include <netdb.h> #include <resolv.h> +#include <sys/utsname.h> -#include "stage1.h" #include "frontend.h" #include "modules.h" #include "probing.h" #include "log.h" +#include "tools.h" +#include "utils.h" #include "mount.h" #include "automatic.h" #include "dhcp.h" @@ -45,7 +50,12 @@ #include "dns.h" #include "network.h" +#include "directory.h" +#include "wireless.h" +#ifndef DISABLE_KA +#include "ka.h" +#endif static void error_message_net(void) /* reduce code size */ { @@ -237,7 +247,8 @@ static int add_default_route(void) } -static int write_resolvconf(void) { +static int write_resolvconf(void) +{ char * filename = "/etc/resolv.conf"; FILE * f; @@ -265,7 +276,8 @@ static int write_resolvconf(void) { } -static int save_netinfo(struct interface_info * intf) { +static int save_netinfo(struct interface_info * intf) +{ char * file_network = "/tmp/network"; char file_intf[500]; FILE * f; @@ -279,11 +291,8 @@ static int save_netinfo(struct interface_info * intf) { fprintf(f, "NETWORKING=yes\n"); fprintf(f, "FORWARD_IPV4=false\n"); - if (hostname) + if (hostname && !(intf->boot_proto == BOOTPROTO_DHCP)) fprintf(f, "HOSTNAME=%s\n", hostname); - if (domain) - fprintf(f, "DOMAINNAME=%s\n", domain); - if (gateway.s_addr != 0) fprintf(f, "GATEWAY=%s\n", inet_ntoa(gateway)); @@ -301,18 +310,27 @@ static int save_netinfo(struct interface_info * intf) { fprintf(f, "DEVICE=%s\n", intf->device); - if (intf->boot_proto == BOOTPROTO_DHCP) + if (intf->boot_proto == BOOTPROTO_DHCP) { fprintf(f, "BOOTPROTO=dhcp\n"); - else if (intf->boot_proto == BOOTPROTO_STATIC) { + if (dhcp_hostname && !streq(dhcp_hostname, "")) + fprintf(f, "DHCP_HOSTNAME=%s\n", dhcp_hostname); + } else if (intf->boot_proto == BOOTPROTO_STATIC) { fprintf(f, "BOOTPROTO=static\n"); fprintf(f, "IPADDR=%s\n", inet_ntoa(intf->ip)); fprintf(f, "NETMASK=%s\n", inet_ntoa(intf->netmask)); fprintf(f, "NETWORK=%s\n", inet_ntoa(intf->network)); fprintf(f, "BROADCAST=%s\n", inet_ntoa(intf->broadcast)); + if (domain) + fprintf(f, "DOMAIN=%s\n", domain); + if (dns_server.s_addr != 0) + fprintf(f, "DNS1=%s\n", inet_ntoa(dns_server)); + if (dns_server2.s_addr != 0) + fprintf(f, "DNS2=%s\n", inet_ntoa(dns_server2)); } else if (intf->boot_proto == BOOTPROTO_ADSL_PPPOE) { fprintf(f, "BOOTPROTO=adsl_pppoe\n"); fprintf(f, "USER=%s\n", intf->user); fprintf(f, "PASS=%s\n", intf->pass); + fprintf(f, "ACNAME=%s\n", intf->acname); } fclose(f); @@ -342,12 +360,27 @@ char * guess_netmask(char * ip_addr) } +char * guess_domain_from_hostname(char *hostname) +{ + char *domain = strchr(strdup(hostname), '.'); + if (!domain || domain[1] == '\0') { + log_message("unable to guess domain from hostname: %s", hostname); + return NULL; + } + return domain + 1; /* skip '.' */ +} + + static void static_ip_callback(char ** strings) { struct in_addr addr; - if (!inet_aton(strings[0], &addr)) + static int done = 0; + if (done) + return; + if (streq(strings[0], "") || !inet_aton(strings[0], &addr)) return; + done = 1; if (!strcmp(strings[1], "")) { char * ptr; @@ -368,11 +401,11 @@ static void static_ip_callback(char ** strings) static enum return_type setup_network_interface(struct interface_info * intf) { enum return_type results; - char * bootprotos[] = { "Static", "DHCP", "ADSL", NULL }; - char * bootprotos_auto[] = { "static", "dhcp", "adsl" }; + char * bootprotos[] = { "DHCP", "Static", "ADSL", NULL }; + char * bootprotos_auto[] = { "dhcp", "static", "adsl" }; char * choice; - results = ask_from_list_auto("Please choose the desired IP attribution.", bootprotos, &choice, "network", bootprotos_auto); + results = ask_from_list_auto("Please select your network connection type.", bootprotos, &choice, "network", bootprotos_auto); if (results != RETURN_OK) return results; @@ -382,7 +415,7 @@ static enum return_type setup_network_interface(struct interface_info * intf) static char ** answers = NULL; struct in_addr addr; - results = ask_from_entries_auto("Please enter the network information. (leave netmask void for Internet standard)", + results = ask_from_entries_auto("Please enter the network information. (leave netmask blank for Internet standard)", questions, &answers, 16, questions_auto, static_ip_callback); if (results != RETURN_OK) return setup_network_interface(intf); @@ -398,6 +431,11 @@ static enum return_type setup_network_interface(struct interface_info * intf) dns_server.s_addr = 0; /* keep an understandable state */ } + if (streq(answers[0], answers[1])) { + log_message("IP and DNS are the same, guess you don't want a DNS, disabling it"); + dns_server.s_addr = 0; /* keep an understandable state */ + } + if (!inet_aton(answers[2], &gateway)) { log_message("invalid gateway"); gateway.s_addr = 0; /* keep an understandable state */ @@ -464,25 +502,33 @@ static enum return_type configure_network(struct interface_info * intf) dnshostname = mygethostbyaddr(inet_ntoa(intf->ip)); if (dnshostname) { - hostname = strdup(dnshostname); - domain = strchr(strdup(hostname), '.') + 1; - log_message("got hostname and domain from dns entry, %s and %s", hostname, domain); - return RETURN_OK; - } - - log_message("reverse name lookup on self failed"); + if (intf->boot_proto == BOOTPROTO_STATIC) + hostname = strdup(dnshostname); + domain = guess_domain_from_hostname(dnshostname); + if (domain) { + log_message("got hostname and domain from dns entry, %s and %s", dnshostname, domain); + return RETURN_OK; + } + } else + log_message("reverse name lookup on self failed"); if (domain) return RETURN_OK; + dnshostname = NULL; if (dns_server.s_addr != 0) { wait_message("Trying to resolve dns..."); dnshostname = mygethostbyaddr(inet_ntoa(dns_server)); remove_wait_message(); - } + if (dnshostname) { + log_message("got DNS fullname, %s", dnshostname); + domain = guess_domain_from_hostname(dnshostname); + } else + log_message("reverse name lookup on DNS failed"); + } else + log_message("no DNS, unable to guess domain"); - if (dnshostname) { - domain = strchr(strdup(dnshostname), '.') + 1; + if (domain) { log_message("got domain from DNS fullname, %s", domain); } else { enum return_type results; @@ -490,15 +536,21 @@ static enum return_type configure_network(struct interface_info * intf) char * questions_auto[] = { "hostname", "domain" }; static char ** answers = NULL; char * boulet; - - log_message("reverse name lookup on DNS failed"); - - results = ask_from_entries_auto("I could not guess hostname and domain name; please fill in this information. " - "Valid answers are for example: `mybox' for hostname and `mynetwork.com' for " - "domain name, for a machine called `mybox.mynetwork.com' on the Internet.", - questions, &answers, 32, questions_auto, NULL); - if (results != RETURN_OK) + + if (dhcp_hostname || dhcp_domain) { + answers = (char **) calloc(1, sizeof(questions)); + answers[0] = strdup(dhcp_hostname); + answers[1] = strdup(dhcp_domain); + } + + if (!dhcp_hostname || !dhcp_domain) { + results = ask_from_entries_auto("I could not guess hostname and domain name; please fill in this information. " + "Valid answers are for example: `mybox' for hostname and `mynetwork.com' for " + "domain name, for a machine called `mybox.mynetwork.com' on the Internet.", + questions, &answers, 32, questions_auto, NULL); + if (results != RETURN_OK) return results; + } hostname = answers[0]; if ((boulet = strchr(hostname, '.')) != NULL) @@ -506,6 +558,9 @@ static enum return_type configure_network(struct interface_info * intf) domain = answers[1]; } + log_message("using hostname %s", hostname); + log_message("using domain %s", domain); + return RETURN_OK; } @@ -513,17 +568,34 @@ static enum return_type configure_network(struct interface_info * intf) static enum return_type bringup_networking(struct interface_info * intf) { static struct interface_info loopback; - enum return_type results = RETURN_ERROR; - - my_insmod("af_packet", ANY_DRIVER_TYPE, NULL); + enum return_type results; + int fd; + + /* try to find if module already loaded or built-in to avoid failing */ + /* badly */ + fd = open("/proc/net/packet", O_RDONLY); + if (fd < 0) + my_modprobe("af_packet", ANY_DRIVER_TYPE, NULL); + else + close(fd); + + do { + results = configure_wireless(intf->device); + } while (results == RETURN_ERROR); - while (results != RETURN_OK) { + if (results == RETURN_BACK) + return RETURN_BACK; + + do { results = setup_network_interface(intf); if (results != RETURN_OK) return results; write_resolvconf(); results = configure_network(intf); - } + } while (results == RETURN_ERROR); + + if (results == RETURN_BACK) + return bringup_networking(intf); write_resolvconf(); /* maybe we have now domain to write also */ @@ -545,6 +617,63 @@ static enum return_type bringup_networking(struct interface_info * intf) } +static char * auto_select_up_intf(int detection_mode) +{ +#define SIOCETHTOOL 0x8946 +#define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */ + + struct ethtool_value { + uint32_t cmd; + uint32_t data; + }; + + char ** interfaces, ** ptr; + interfaces = get_net_devices(); + + int s; + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + return NULL; + } + + ptr = interfaces; + while (ptr && *ptr) { + if (detection_mode != AUTO_DETECTION_WIRED || !wireless_is_aware(s, *interfaces)) { + struct ifreq ifr; + struct ethtool_value edata; + strncpy(ifr.ifr_name, *ptr, IFNAMSIZ); + edata.cmd = ETHTOOL_GLINK; + ifr.ifr_data = (caddr_t)&edata; + if (ioctl(s, SIOCETHTOOL, &ifr) == 0 && edata.data) { + close(s); + log_message("NETWORK: choosing interface %s (link beat detected)", *ptr); + return *ptr; + } + } + ptr++; + } + + log_message("NETWORK: no interface has a link beat"); + + if (detection_mode == AUTO_DETECTION_WIRED) { + ptr = interfaces; + while (ptr && *ptr) { + if (!wireless_is_aware(s, *interfaces)) { + close(s); + log_message("NETWORK: choosing interface %s (wired interface)", *ptr); + return *ptr; + } + ptr++; + } + log_message("NETWORK: no interface is wired"); + } + + close(s); + + return NULL; +} + + static char * interface_select(void) { char ** interfaces, ** ptr; @@ -572,6 +701,20 @@ static char * interface_select(void) if (count == 1) return *interfaces; + /* this can't be done in ask_from_list_comments_auto because "auto" and "wired" are not in the interfaces list */ + if (IS_AUTOMATIC) { + enum auto_detection_type auto_detect = AUTO_DETECTION_NONE; + if (streq(get_auto_value("interface"), "auto")) + auto_detect = AUTO_DETECTION_ALL; + else if (streq(get_auto_value("interface"), "wired")) + auto_detect = AUTO_DETECTION_WIRED; + if (auto_detect != AUTO_DETECTION_NONE) { + choice = auto_select_up_intf(auto_detect); + if (choice) + return choice; + } + } + i = 0; while (interfaces[i]) { descriptions[i] = get_net_intf_description(interfaces[i]); @@ -587,12 +730,171 @@ static char * interface_select(void) return choice; } +static enum return_type get_http_proxy(char **http_proxy_host, char **http_proxy_port) +{ + char *questions[] = { "HTTP proxy host", "HTTP proxy port", NULL }; + char *questions_auto[] = { "proxy_host", "proxy_port", NULL }; + static char ** answers = NULL; + enum return_type results; + + results = ask_from_entries_auto("Please enter HTTP proxy host and port if you need it, else leave them blank or cancel.", + questions, &answers, 40, questions_auto, NULL); + if (results == RETURN_OK) { + *http_proxy_host = answers[0]; + *http_proxy_port = answers[1]; + } else { + *http_proxy_host = NULL; + *http_proxy_port = NULL; + } + + return results; +} + + +static int url_split(const char *url, const char *protocol, char **host, char **path) +{ + char *protocol_sep, *host_sep; + + protocol_sep = strstr(url, "://"); + if (!protocol_sep) { + log_message("NETWORK: no protocol in \"%s\"", url); + return -1; + } + + if (strncmp(protocol, url, protocol_sep - url)) + return -1; + + url = protocol_sep + 3; + host_sep = strchr(url, '/'); + if (!host_sep || host_sep == url) { + log_message("NETWORK: no hostname in \"%s\"", url); + return -1; + } + + *host = strndup(url, host_sep - url); + *path = strdup(host_sep); + + return 0; +} + +#define MIRRORLIST_MAX_ITEMS 500 +typedef char *mirrorlist_t[2][MIRRORLIST_MAX_ITEMS+1]; + +static enum return_type get_mirrorlist(mirrorlist_t mirrorlist, int start, char *version, const char *protocol, char *http_proxy_host, char *http_proxy_port) { + int fd, size, line_pos = 0; + char path[1024]; + char line[1024]; + char type[100] = DISTRIB_TYPE; + int mirror_idx = start; + + int use_http_proxy = http_proxy_host && http_proxy_port && !streq(http_proxy_host, "") && !streq(http_proxy_port, ""); + lowercase(type); + snprintf(path, sizeof(path), "%s/%s.%s.%s.list", MIRRORLIST_PATH, type, version, ARCH); + + fd = http_download_file(MIRRORLIST_HOST, path, &size, use_http_proxy ? "http" : NULL, http_proxy_host, http_proxy_port); + if (fd < 0) { + log_message("HTTP: unable to get mirrors list from %s (%s)", MIRRORLIST_HOST, path); + return RETURN_ERROR; + } + + while (read(fd, line + line_pos, 1) > 0) { + if (line[line_pos] == '\n') { + char *url; + line[line_pos] = '\0'; + line_pos = 0; + + /* skip medium if it does not look like a distrib path */ + if (!strstr(line, ",type=distrib,")) + continue; + + url = strstr(line, ",url="); + if (!url) + continue; + url += 5; + + if (url_split(url, protocol, &mirrorlist[0][mirror_idx], &mirrorlist[1][mirror_idx]) < 0) + continue; + + mirror_idx++; + } else { + line_pos++; + } + + if (mirror_idx >= MIRRORLIST_MAX_ITEMS) + break; + } + close(fd); + + mirrorlist[0][mirror_idx] = NULL; + mirrorlist[1][mirror_idx] = NULL; + + return RETURN_OK; +} + +static int choose_mirror_from_host_list(mirrorlist_t mirrorlist, char **selected_host, char **filepath) +{ + enum return_type results; + int mirror_idx = 0; + + do { + results = ask_from_list_index("Please select a mirror from the list below.", + mirrorlist[0], NULL, &mirror_idx); + + if (results == RETURN_BACK) { + return RETURN_ERROR; + } else if (results == RETURN_OK) { + if (mirror_idx == 0) { + /* enter the mirror manually */ + return RETURN_OK; + } + *selected_host = strdup(mirrorlist[0][mirror_idx]); + *filepath = strdup(mirrorlist[1][mirror_idx]); + return RETURN_OK; + } + } while (results == RETURN_ERROR); + + return RETURN_ERROR; +} + + +static int choose_mirror_from_list(char *http_proxy_host, char *http_proxy_port, const char *protocol, char **selected_host, char **filepath) +{ + enum return_type results; + char *versions[] = { "Specify the mirror manually", DISTRIB_NAME " " DISTRIB_VERSION, NULL }; + char *version = DISTRIB_NAME " " DISTRIB_VERSION; + + do { + results = ask_from_list("Please select a medium from the list below.", versions, &version); + + if (results == RETURN_BACK) { + return RETURN_BACK; + } else if (results == RETURN_OK) { + if (!strcmp(version, versions[0])) { + /* enter the mirror manually */ + return RETURN_OK; + } else { + /* a medium has been selected */ + mirrorlist_t mirrorlist; + mirrorlist[0][0] = "Specify the mirror manually"; + mirrorlist[1][0] = NULL; + + results = get_mirrorlist(mirrorlist, 1, DISTRIB_VERSION, protocol, http_proxy_host, http_proxy_port); + if (results == RETURN_ERROR) + return RETURN_ERROR; + + results = choose_mirror_from_host_list(mirrorlist, selected_host, filepath); + } + } + } while (results == RETURN_ERROR); + + return results; +} /* -=-=-- */ -static enum return_type intf_select_and_up(void) +enum return_type intf_select_and_up() { static struct interface_info intf[20]; static int num_interfaces = 0; @@ -619,7 +921,7 @@ static enum return_type intf_select_and_up(void) if (results == RETURN_OK) save_netinfo(sel_intf); - + return results; } @@ -631,7 +933,7 @@ enum return_type nfs_prepare(void) char * questions_auto[] = { "server", "directory", NULL }; static char ** answers = NULL; char * nfsmount_location; - enum return_type results = intf_select_and_up(); + enum return_type results = intf_select_and_up(NULL, NULL); if (results != RETURN_OK) return results; @@ -641,7 +943,7 @@ enum return_type nfs_prepare(void) "and the directory containing the " DISTRIB_NAME " Distribution.", questions, &answers, 40, questions_auto, NULL); if (results != RETURN_OK || streq(answers[0], "")) { - unset_param(MODE_AUTOMATIC); /* we are in a fallback mode */ + unset_automatic(); /* we are in a fallback mode */ return nfs_prepare(); } @@ -650,33 +952,21 @@ enum return_type nfs_prepare(void) strcat(nfsmount_location, ":"); strcat(nfsmount_location, answers[1]); - if (my_mount(nfsmount_location, IMAGE_LOCATION, "nfs", 0) == -1) { + if (my_mount(nfsmount_location, MEDIA_LOCATION, "nfs", 0) == -1) { stg1_error_message("I can't mount the directory from the NFS server."); results = RETURN_BACK; continue; } + free(nfsmount_location); nfsmount_location = NULL; - if (access(IMAGE_LOCATION LIVE_LOCATION, R_OK)) { - stg1_error_message("That NFS volume does not seem to contain the " DISTRIB_NAME " Distribution."); - umount(IMAGE_LOCATION); - results = RETURN_BACK; - } + results = try_with_directory(MEDIA_LOCATION, "nfs", "nfs-iso"); + if (results != RETURN_OK) + umount(MEDIA_LOCATION); + if (results == RETURN_ERROR) + return RETURN_ERROR; } while (results == RETURN_BACK); - log_message("found the " DISTRIB_NAME " Installation, good news!"); - - if (IS_SPECIAL_STAGE2) { - if (load_ramdisk() != RETURN_OK) { - stg1_error_message("Could not load program into memory."); - return nfs_prepare(); - } - } - - if (IS_RESCUE) - umount(IMAGE_LOCATION); - - method_name = strdup("nfs"); return RETURN_OK; } @@ -687,10 +977,13 @@ enum return_type ftp_prepare(void) char * questions_auto[] = { "server", "directory", "user", "pass", NULL }; static char ** answers = NULL; enum return_type results; + struct utsname kernel_uname; + char *http_proxy_host, *http_proxy_port; + int use_http_proxy; if (!ramdisk_possible()) { - stg1_error_message("FTP install needs more than %d Mbytes of memory (detected %d Mbytes).", - MEM_LIMIT_RAMDISK, total_memory()); + stg1_error_message("FTP install needs more than %d Mbytes of memory (detected %d Mbytes). You may want to try an NFS install.", + MEM_LIMIT_DRAKX, total_memory()); return RETURN_ERROR; } @@ -699,68 +992,138 @@ enum return_type ftp_prepare(void) if (results != RETURN_OK) return results; + get_http_proxy(&http_proxy_host, &http_proxy_port); + use_http_proxy = http_proxy_host && http_proxy_port && !streq(http_proxy_host, "") && !streq(http_proxy_port, ""); + + uname(&kernel_uname); + do { char location_full[500]; - int ftp_serv_response; + int ftp_serv_response = -1; int fd, size; + int need_arch = 0; + char ftp_hostname[500]; + + if (!IS_AUTOMATIC) { + if (answers == NULL) + answers = (char **) calloc(1, sizeof(questions)); + + results = choose_mirror_from_list(http_proxy_host, http_proxy_port, "ftp", &answers[0], &answers[1]); + + if (results == RETURN_BACK) + return ftp_prepare(); + + if (use_http_proxy) { + results = ask_yes_no("Do you want to use this HTTP proxy for FTP connections too ?"); + + if (results == RETURN_BACK) + return ftp_prepare(); + + use_http_proxy = results == RETURN_OK; + } + } results = ask_from_entries_auto("Please enter the name or IP address of the FTP server, " "the directory containing the " DISTRIB_NAME " Distribution, " - "and the login/pass if necessary (leave login blank for anonymous).", + "and the login/pass if necessary (leave login blank for anonymous). ", questions, &answers, 40, questions_auto, NULL); if (results != RETURN_OK || streq(answers[0], "")) { - unset_param(MODE_AUTOMATIC); /* we are in a fallback mode */ + unset_automatic(); /* we are in a fallback mode */ return ftp_prepare(); } - log_message("FTP: trying to connect to %s", answers[0]); + strcpy(location_full, answers[1][0] == '/' ? "" : "/"); + strcat(location_full, answers[1]); - ftp_serv_response = ftp_open_connection(answers[0], answers[2], answers[3], ""); - if (ftp_serv_response < 0) { - log_message("FTP: error connect %d", ftp_serv_response); - if (ftp_serv_response == FTPERR_BAD_HOSTNAME) - stg1_error_message("Error: bad hostname."); - else if (ftp_serv_response == FTPERR_FAILED_CONNECT) - stg1_error_message("Error: failed to connect to remote host."); - else - stg1_error_message("Error: couldn't connect."); - results = RETURN_BACK; - continue; - } - strcpy(location_full, answers[1]); - strcat(location_full, get_ramdisk_realname()); + if (use_http_proxy) { + log_message("FTP: don't connect to %s directly, will use proxy", answers[0]); + } else { + log_message("FTP: trying to connect to %s", answers[0]); + ftp_serv_response = ftp_open_connection(answers[0], answers[2], answers[3], ""); + if (ftp_serv_response < 0) { + log_message("FTP: error connect %d", ftp_serv_response); + if (ftp_serv_response == FTPERR_BAD_HOSTNAME) + stg1_error_message("Error: bad hostname."); + else if (ftp_serv_response == FTPERR_FAILED_CONNECT) + stg1_error_message("Error: failed to connect to remote host."); + else + stg1_error_message("Error: couldn't connect."); + results = RETURN_BACK; + continue; + } + } + + strcat(location_full, COMPRESSED_FILE_REL("/")); log_message("FTP: trying to retrieve %s", location_full); - fd = ftp_start_download(ftp_serv_response, location_full, &size); + if (use_http_proxy) { + if (strcmp(answers[2], "")) { + strcpy(ftp_hostname, answers[2]); /* user name */ + strcat(ftp_hostname, ":"); + strcat(ftp_hostname, answers[3]); /* password */ + strcat(ftp_hostname, "@"); + } else { + strcpy(ftp_hostname, ""); + } + strcat(ftp_hostname, answers[0]); + fd = http_download_file(ftp_hostname, location_full, &size, "ftp", http_proxy_host, http_proxy_port); + } else { + fd = ftp_start_download(ftp_serv_response, location_full, &size); + } + + /* Try arched directory */ if (fd < 0) { - log_message("FTP: error get %d", fd); - if (fd == FTPERR_PASSIVE_ERROR) - stg1_error_message("Error: error with passive connection."); - else if (fd == FTPERR_FILE_NOT_FOUND) - stg1_error_message("Error: file not found (%s).", location_full); - else if (fd == FTPERR_BAD_SERVER_RESPONSE) - stg1_error_message("Error: bad server response (server too busy?)."); - else - stg1_error_message("Error: couldn't retrieve Installation program."); + log_message("%s failed.", location_full); + char *with_arch = asprintf_("%s%s/%s/%s", answers[1][0] == '/' ? "" : "/", answers[1], ARCH, COMPRESSED_FILE_REL("/")); + log_message("trying %s...", with_arch); + if (use_http_proxy) + fd = http_download_file(answers[0], with_arch, &size, use_http_proxy ? "http" : NULL, http_proxy_host, http_proxy_port); + else + fd = ftp_start_download(ftp_serv_response, with_arch, &size); + if (0 < fd) { + strcpy(location_full, with_arch); + need_arch = 1; + } + } + + if (fd < 0) { + char *msg = str_ftp_error(fd); + log_message("FTP: error get %d for remote file %s", fd, location_full); + stg1_error_message("Error: %s.", msg ? msg : "couldn't retrieve Installation program"); results = RETURN_BACK; continue; } log_message("FTP: size of download %d bytes", size); - results = load_ramdisk_fd(fd, size); - if (results == RETURN_OK) - ftp_end_data_command(ftp_serv_response); - else + results = load_compressed_fd(fd, size); + if (results == RETURN_OK) { + if (!use_http_proxy) + ftp_end_data_command(ftp_serv_response); + } else { + unset_automatic(); /* we are in a fallback mode */ return results; + } - method_name = strdup("ftp"); - add_to_env("HOST", answers[0]); - add_to_env("PREFIX", answers[1]); - if (strcmp(answers[2], "")) { - add_to_env("LOGIN", answers[2]); - add_to_env("PASSWORD", answers[3]); + if (use_http_proxy) { + add_to_env("METHOD", "http"); + snprintf(location_full, sizeof(location_full), "ftp://%s%s", ftp_hostname, answers[1]); + if (need_arch) + strcat(location_full, "/" ARCH); + add_to_env("URLPREFIX", location_full); + add_to_env("PROXY", http_proxy_host); + add_to_env("PROXYPORT", http_proxy_port); + } else { + add_to_env("METHOD", "ftp"); + add_to_env("HOST", answers[0]); + if (need_arch) + strcat(answers[1], "/" ARCH); + add_to_env("PREFIX", answers[1]); + if (!streq(answers[2], "")) { + add_to_env("LOGIN", answers[2]); + add_to_env("PASSWORD", answers[3]); + } } } while (results == RETURN_BACK); @@ -774,10 +1137,11 @@ enum return_type http_prepare(void) char * questions_auto[] = { "server", "directory", NULL }; static char ** answers = NULL; enum return_type results; + char *http_proxy_host, *http_proxy_port; if (!ramdisk_possible()) { - stg1_error_message("HTTP install needs more than %d Mbytes of memory (detected %d Mbytes).", - MEM_LIMIT_RAMDISK, total_memory()); + stg1_error_message("HTTP install needs more than %d Mbytes of memory (detected %d Mbytes). You may want to try an NFS install.", + MEM_LIMIT_DRAKX, total_memory()); return RETURN_ERROR; } @@ -786,24 +1150,53 @@ enum return_type http_prepare(void) if (results != RETURN_OK) return results; + get_http_proxy(&http_proxy_host, &http_proxy_port); + do { char location_full[500]; - int fd, size; + int fd, size, need_arch = 0; + int use_http_proxy; + + if (!IS_AUTOMATIC) { + if (answers == NULL) + answers = (char **) calloc(1, sizeof(questions)); + + results = choose_mirror_from_list(http_proxy_host, http_proxy_port, "http", &answers[0], &answers[1]); + + if (results == RETURN_BACK) + return http_prepare(); + } results = ask_from_entries_auto("Please enter the name or IP address of the HTTP server, " "and the directory containing the " DISTRIB_NAME " Distribution.", questions, &answers, 40, questions_auto, NULL); if (results != RETURN_OK || streq(answers[0], "")) { - unset_param(MODE_AUTOMATIC); /* we are in a fallback mode */ + unset_automatic(); /* we are in a fallback mode */ return http_prepare(); } - strcpy(location_full, answers[1]); - strcat(location_full, get_ramdisk_realname()); + strcpy(location_full, answers[1][0] == '/' ? "" : "/"); + strcat(location_full, answers[1]); + strcat(location_full, COMPRESSED_FILE_REL("/")); - log_message("HTTP: trying to retrieve %s", location_full); + log_message("HTTP: trying to retrieve %s from %s", location_full, answers[0]); - fd = http_download_file(answers[0], location_full, &size); + use_http_proxy = http_proxy_host && http_proxy_port && !streq(http_proxy_host, "") && !streq(http_proxy_port, ""); + + fd = http_download_file(answers[0], location_full, &size, use_http_proxy ? "http" : NULL, http_proxy_host, http_proxy_port); + + /* Try arched directory */ + if (fd < 0) { + log_message("%s failed.", location_full); + char *with_arch = asprintf_("%s%s/%s/%s", answers[1][0] == '/' ? "" : "/", answers[1], ARCH, COMPRESSED_FILE_REL("/")); + log_message("trying %s...", with_arch); + fd = http_download_file(answers[0], with_arch, &size, use_http_proxy ? "http" : NULL, http_proxy_host, http_proxy_port); + if (0 < fd) { + strcpy(location_full, with_arch); + need_arch = 1; + } + } + if (fd < 0) { log_message("HTTP: error %d", fd); if (fd == FTPERR_FAILED_CONNECT) @@ -816,15 +1209,43 @@ enum return_type http_prepare(void) log_message("HTTP: size of download %d bytes", size); - if (load_ramdisk_fd(fd, size) != RETURN_OK) + if (load_compressed_fd(fd, size) != RETURN_OK) { + unset_automatic(); /* we are in a fallback mode */ return RETURN_ERROR; + } - method_name = strdup("http"); - sprintf(location_full, "http://%s/%s", answers[0], answers[1]); + add_to_env("METHOD", "http"); + sprintf(location_full, "http://%s%s%s", answers[0], answers[1][0] == '/' ? "" : "/", answers[1]); + if (need_arch) + strcat(location_full, "/" ARCH); add_to_env("URLPREFIX", location_full); + if (!streq(http_proxy_host, "")) + add_to_env("PROXY", http_proxy_host); + if (!streq(http_proxy_port, "")) + add_to_env("PROXYPORT", http_proxy_port); } while (results == RETURN_BACK); return RETURN_OK; } + +#ifndef DISABLE_KA +enum return_type ka_prepare(void) +{ + enum return_type results; + + if (!ramdisk_possible()) { + stg1_error_message("KA install needs more than %d Mbytes of memory (detected %d Mbytes).", + MEM_LIMIT_DRAKX, total_memory()); + return RETURN_ERROR; + } + + results = intf_select_and_up(); + + if (results != RETURN_OK) + return results; + + return perform_ka(); +} +#endif |