/*
* urlinstall.c - code to set up url (ftp/http) installs
*
* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Author(s): Erik Troan
* Matt Wilson
* Michael Fulbright
* Jeremy Katz
*/
#include
#include
#include
#include
#include
#include
#include "../isys/nl.h"
#include "copy.h"
#include "kickstart.h"
#include "loader.h"
#include "loadermisc.h"
#include "lang.h"
#include "log.h"
#include "method.h"
#include "net.h"
#include "method.h"
#include "urlinstall.h"
#include "cdinstall.h"
#include "urls.h"
#include "windows.h"
/* boot flags */
extern uint64_t flags;
static int loadSingleUrlImage(struct iurlinfo * ui, char * file,
char * dest, char * mntpoint, char * device,
int silentErrors) {
int fd;
int rc = 0;
char filepath[1024];
char *ehdrs = NULL;
snprintf(filepath, sizeof(filepath), "%s", file);
if (ui->protocol == URL_METHOD_HTTP) {
char *arch = getProductArch();
char *name = getProductName();
int q;
q = asprintf(&ehdrs, "User-Agent: anaconda/%s\r\n"
"X-Anaconda-Architecture: %s\r\n"
"X-Anaconda-System-Release: %s\r\n",
VERSION, arch, name);
}
fd = urlinstStartTransfer(ui, filepath, ehdrs);
if (fd == -2) {
if (ehdrs) free (ehdrs);
return 2;
}
else if (fd < 0) {
if (!silentErrors) {
newtWinMessage(_("Error"), _("OK"),
_("Unable to retrieve %s://%s/%s/%s."),
(ui->protocol == URL_METHOD_FTP ? "ftp" : "http"),
ui->address, ui->prefix, filepath);
}
if (ehdrs) free (ehdrs);
return 2;
}
if (dest != NULL) {
rc = copyFileAndLoopbackMount(fd, dest, device, mntpoint);
}
urlinstFinishTransfer(ui, fd);
return rc;
}
static void copyWarnFn (char *msg) {
logMessage(WARNING, msg);
}
static void copyErrorFn (char *msg) {
newtWinMessage(_("Error"), _("OK"), _(msg));
}
static int loadUrlImages(struct iurlinfo * ui) {
char *stage2img;
char tmpstr1[1024], tmpstr2[1024];
int rc;
/* setupRamdisk();*/
/* grab the updates.img before netstg1.img so that we minimize our
* ramdisk usage */
if (!loadSingleUrlImage(ui, "images/updates.img",
"/tmp/updates-disk.img", "/tmp/update-disk",
"/dev/loop7", 1)) {
copyDirectory("/tmp/update-disk", "/tmp/updates", copyWarnFn,
copyErrorFn);
umountLoopback("/tmp/update-disk", "/dev/loop7");
unlink("/tmp/updates-disk.img");
unlink("/tmp/update-disk");
}
/* grab the product.img before netstg1.img so that we minimize our
* ramdisk usage */
if (!loadSingleUrlImage(ui, "images/product.img",
"/tmp/product-disk.img", "/tmp/product-disk",
"/dev/loop7", 1)) {
copyDirectory("/tmp/product-disk", "/tmp/product", copyWarnFn,
copyErrorFn);
umountLoopback("/tmp/product-disk", "/dev/loop7");
unlink("/tmp/product-disk.img");
unlink("/tmp/product-disk");
}
/* require 128MB for use of graphical stage 2 due to size of image */
if (FL_TEXT(flags) || totalMemory() < GUI_STAGE2_RAM) {
stage2img = "minstg2.img";
if (totalMemory() < GUI_STAGE2_RAM)
logMessage(WARNING, "URLINSTALL falling back to non-GUI stage2 "
"due to insufficient RAM");
} else {
stage2img = "stage2.img";
}
snprintf(tmpstr1, sizeof(tmpstr1), "images/%s", stage2img);
snprintf(tmpstr2, sizeof(tmpstr2), "/tmp/%s", stage2img);
rc = loadSingleUrlImage(ui, tmpstr1, tmpstr2,
"/mnt/runtime", "/dev/loop0", 0);
if (rc) {
if (rc != 2)
newtWinMessage(_("Error"), _("OK"),
_("Unable to retrieve the install image."));
return 1;
}
/* now verify the stamp... */
if (!verifyStamp("/mnt/runtime")) {
char * buf;
rc = asprintf(&buf, _("The %s installation tree in that directory does "
"not seem to match your boot media."),
getProductName());
newtWinMessage(_("Error"), _("OK"), buf);
umountLoopback("/mnt/runtime", "/dev/loop0");
return 1;
}
return 0;
}
char * mountUrlImage(struct installMethod * method,
char * location, struct loaderData_s * loaderData) {
int rc;
char * url;
struct iurlinfo ui;
char needsSecondary = ' ';
int dir = 1;
char * cdurl;
enum { URL_STAGE_MAIN, URL_STAGE_SECOND, URL_STAGE_FETCH,
URL_STAGE_DONE } stage = URL_STAGE_MAIN;
/* JKFIXME: we used to do another ram check here... keep it? */
memset(&ui, 0, sizeof(ui));
while (stage != URL_STAGE_DONE) {
switch(stage) {
case URL_STAGE_MAIN:
if (loaderData->method == METHOD_URL && loaderData->methodData) {
url = ((struct urlInstallData *)loaderData->methodData)->url;
logMessage(INFO, "URL_STAGE_MAIN - url is %s", url);
if (!url) {
logMessage(ERROR, "missing url specification");
loaderData->method = -1;
break;
}
/* explode url into ui struct */
convertURLToUI(url, &ui);
/* ks info was adequate, lets skip to fetching image */
stage = URL_STAGE_FETCH;
dir = 1;
break;
} else if (urlMainSetupPanel(&ui, &needsSecondary)) {
return NULL;
}
/* got required information from user, proceed */
stage = (needsSecondary != ' ') ? URL_STAGE_SECOND :
URL_STAGE_FETCH;
dir = 1;
break;
case URL_STAGE_SECOND:
rc = urlSecondarySetupPanel(&ui);
if (rc) {
stage = URL_STAGE_MAIN;
dir = -1;
} else {
stage = URL_STAGE_FETCH;
dir = 1;
}
break;
case URL_STAGE_FETCH:
if (FL_TESTING(flags)) {
stage = URL_STAGE_DONE;
dir = 1;
break;
}
/* ok messy - see if we have a stage2 on local CD */
/* before trying to pull one over network */
cdurl = findAnacondaCD(location, 0);
if (cdurl) {
/* verify that our URL is specifying the correct tree */
/* we do this by attempting to pull a .discinfo file */
if (loadSingleUrlImage(&ui, ".discinfo", NULL, NULL, NULL, 1)) {
umountStage2();
umount(location);
unlink("/tmp/cdrom");
stage = URL_STAGE_MAIN;
dir = -1;
if (loaderData->method >= 0)
loaderData->method = -1;
break;
}
logMessage(INFO, "Detected stage 2 image on CD");
winStatus(50, 3, _("Media Detected"),
_("Local installation media detected..."), 0);
sleep(3);
newtPopWindow();
stage = URL_STAGE_DONE;
dir = 1;
} else {
/* need to find stage 2 on remote site */
if (loadUrlImages(&ui)) {
stage = URL_STAGE_MAIN;
dir = -1;
if (loaderData->method >= 0) {
loaderData->method = -1;
}
} else {
stage = URL_STAGE_DONE;
dir = 1;
}
}
break;
case URL_STAGE_DONE:
break;
}
}
url = convertUIToURL(&ui);
return url;
}
int getFileFromUrl(char * url, char * dest,
struct loaderData_s * loaderData) {
int retval = 0;
struct iurlinfo ui;
enum urlprotocol_t proto =
!strncmp(url, "ftp://", 6) ? URL_METHOD_FTP : URL_METHOD_HTTP;
char * host = NULL, * file = NULL, * chptr = NULL, *login = NULL, *password = NULL;
int fd, rc;
struct networkDeviceConfig netCfg;
char *ehdrs = NULL, *ip = NULL;
if (kickstartNetworkUp(loaderData, &netCfg)) {
logMessage(ERROR, "unable to bring up network");
return 1;
}
memset(&ui, 0, sizeof(ui));
ui.protocol = proto;
netlink_init_interfaces_list();
if ((ip = netlink_interfaces_ip2str(loaderData->netDev)) == NULL) {
logMessage(ERROR, "getFileFromUrl: no client IP information");
return 1;
}
getHostPathandLogin((proto == URL_METHOD_FTP ? url + 6 : url + 7),
&host, &file, &login, &password, ip);
logMessage(INFO, "file location: %s://%s%s",
(proto == URL_METHOD_FTP ? "ftp" : "http"), host, file);
chptr = strchr(host, '/');
if (chptr == NULL) {
ui.address = strdup(host);
ui.prefix = strdup("/");
} else {
*chptr = '\0';
ui.address = strdup(host);
host = chptr;
*host = '/';
ui.prefix = strdup(host);
}
if (password[0] != '\0')
ui.password = strdup (password);
if (login[0] != '\0')
ui.login = strdup (login);
if (proto == URL_METHOD_HTTP) {
char *arch = getProductArch();
char *name = getProductName();
int q;
q = asprintf(&ehdrs, "User-Agent: anaconda/%s\r\n"
"X-Anaconda-Architecture: %s\r\n"
"X-Anaconda-System-Release: %s\r\n",
VERSION, arch, name);
}
if (proto == URL_METHOD_HTTP && FL_KICKSTART_SEND_MAC(flags)) {
/* find all ethernet devices and make a header entry for each one */
int i, q;
char *dev, *mac, *tmpstr;
struct device **devices;
devices = getDevices(DEVICE_NETWORK);
for (i = 0; devices && devices[i]; i++) {
dev = devices[i]->device;
mac = netlink_interfaces_mac2str(dev);
if (mac) {
q = asprintf(&tmpstr, "X-RHN-Provisioning-MAC-%d: %s %s\r\n",
i, dev, mac);
if (!ehdrs) {
ehdrs = strdup(tmpstr);
} else {
ehdrs = (char *) realloc(ehdrs, strlen(ehdrs)+strlen(tmpstr)+1);
strcat(ehdrs, tmpstr);
}
free(mac);
free(tmpstr);
}
}
}
fd = urlinstStartTransfer(&ui, file, ehdrs);
if (fd < 0) {
logMessage(ERROR, "failed to retrieve http://%s/%s%s", ui.address, ui.prefix, file);
retval = 1;
goto err;
}
rc = copyFileFd(fd, dest);
if (rc) {
unlink (dest);
logMessage(ERROR, "failed to copy file to %s", dest);
retval = 1;
goto err;
}
urlinstFinishTransfer(&ui, fd);
err:
if (file) free(file);
if (ehdrs) free(ehdrs);
if (host) free(host);
if (login) free(login);
if (password) free(password);
return retval;
}
/* pull kickstart configuration file via http */
int kickstartFromUrl(char * url, struct loaderData_s * loaderData) {
return getFileFromUrl(url, "/tmp/ks.cfg", loaderData);
}
void setKickstartUrl(struct loaderData_s * loaderData, int argc,
char ** argv) {
char *url = NULL;
poptContext optCon;
int rc;
struct poptOption ksUrlOptions[] = {
{ "url", '\0', POPT_ARG_STRING, &url, 0, NULL, NULL },
{ 0, 0, 0, 0, 0, 0, 0 }
};
logMessage(INFO, "kickstartFromUrl");
optCon = poptGetContext(NULL, argc, (const char **) argv, ksUrlOptions, 0);
if ((rc = poptGetNextOpt(optCon)) < -1) {
startNewt();
newtWinMessage(_("Kickstart Error"), _("OK"),
_("Bad argument to Url kickstart method "
"command %s: %s"),
poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
poptStrerror(rc));
return;
}
if (!url) {
newtWinMessage(_("Kickstart Error"), _("OK"),
_("Must supply a --url argument to Url kickstart method."));
return;
}
/* determine install type */
if (strstr(url, "http://") || strstr(url, "ftp://"))
loaderData->method = METHOD_URL;
else {
newtWinMessage(_("Kickstart Error"), _("OK"),
_("Unknown Url method %s"), url);
return;
}
loaderData->methodData = calloc(sizeof(struct urlInstallData *), 1);
((struct urlInstallData *)loaderData->methodData)->url = url;
logMessage(INFO, "results of url ks, url %s", url);
}
/* vim:set shiftwidth=4 softtabstop=4: */