/*
* hdinstall.c - code to set up hard drive 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
#include
#include
#include "driverdisk.h"
#include "hdinstall.h"
#include "getparts.h"
#include "kickstart.h"
#include "loader.h"
#include "loadermisc.h"
#include "log.h"
#include "lang.h"
#include "modules.h"
#include "method.h"
#include "mediacheck.h"
#include "cdinstall.h"
#include "windows.h"
#include "../isys/imount.h"
#include "../isys/isys.h"
#include "../isys/eddsupport.h"
/* boot flags */
extern uint64_t flags;
/* Pull in second stage image for hard drive install. This is only used
* if method= is passed, not if stage2= is pased.
*/
static int loadHDImages(char * prefix, char * dir,
char * device, char * mntpoint,
char * location) {
int fd = 0, rc, idx, tmp;
char *path, *target = NULL, *dest, *cdurl = NULL;
char *stg2list[] = {"stage2.img", "minstg2.img", NULL};
if (totalMemory() < 128000)
idx = 1;
else
idx = 0;
/* Try to see if we're booted off of a CD with stage2. However,
* passing stage2= overrides this check.
*/
if (!FL_STAGE2(flags))
cdurl = findAnacondaCD(location, 0);
if (cdurl) {
logMessage(INFO, "Detected stage 2 image on CD");
winStatus(50, 3, _("Media Detected"),
_("Local installation media detected..."), 0);
sleep(3);
newtPopWindow();
rc = 0;
} else {
target = NULL;
for (; stg2list[idx]; idx++) {
target = stg2list[idx];
if (!dir || (dir && (!strcmp(dir, "/") || strcmp(dir, ""))))
tmp = asprintf(&path, "%s/images/%s", prefix, target);
else
tmp = asprintf(&path, "%s/%s/images/%s", prefix, dir ? dir : "", target);
logMessage(INFO, "Looking for hd stage2 image %s", path);
if (!access(path, F_OK))
break;
logMessage(INFO, "%s does not exist: %s, trying next target", path, strerror(errno));
}
if (!target) {
logMessage(ERROR, "failed to find hd stage 2 image%s: %s", path, strerror(errno));
return 1;
}
logMessage(INFO, "Found hd stage2, copying %s in RAM as stage2", path);
if ((fd = open(path, O_RDONLY)) < 0) {
logMessage(ERROR, "failed to open %s: %s", path, strerror(errno));
return 1;
}
}
free(path);
/* handle updates.img now before we copy stage2 over... this allows
* us to keep our ramdisk size as small as possible */
tmp = asprintf(&path, "%s/%s/images/updates.img", prefix, dir ? dir : "");
copyUpdatesImg(path);
free(path);
/* handle product.img now before we copy stage2 over... this allows
* us to keep our ramdisk size as small as possible */
tmp = asprintf(&path, "%s/%s/images/product.img", prefix, dir ? dir : "");
copyProductImg(path);
free(path);
if (!cdurl) {
dest = alloca(strlen(target) + 50);
sprintf(dest,"/tmp/%s", target);
rc = copyFileAndLoopbackMount(fd, dest, device, mntpoint);
close(fd);
if (!verifyStamp(mntpoint)) {
char * buf;
fd = asprintf(&buf,
_("The %s installation tree in that directory does "
"not seem to match your boot media."),
getProductName());
newtWinMessage(_("Error"), _("OK"), buf);
free(buf);
umountLoopback(mntpoint, device);
return 1;
}
}
return rc;
}
/* given a partition device and directory, tries to mount hd install image */
static char * setupIsoImages(char * device, char * dirName, char * location) {
int rc;
char *url = NULL, *dirspec, *updpath;
char *path;
char *typetry[] = {"ext3", "ext2", "vfat", NULL};
char **type;
logMessage(INFO, "mounting device %s for hard drive install", device);
if (!FL_TESTING(flags)) {
/* XXX try to mount as ext2 and then vfat */
for (type=typetry; *type; type++) {
if (!doPwMount(device, "/mnt/isodir", *type, "ro"))
break;
}
if (!type)
return NULL;
if (FL_STAGE2(flags)) {
rc = asprintf(&dirspec, "/mnt/isodir%.*s", (int) (strrchr(dirName, '/') - dirName), dirName);
rc = asprintf(&path, "/mnt/isodir%s", dirName);
} else {
if (*dirName == '/')
rc = asprintf(&dirspec, "/mnt/isodir%s", dirName);
else
rc = asprintf(&dirspec, "/mnt/isodir/%s", dirName);
path = validIsoImages(dirspec, 0, 1);
}
if (path) {
logMessage(INFO, "Path to valid iso is %s", path);
rc = asprintf(&updpath, "%s/updates.img", dirspec);
logMessage(INFO, "Looking for updates for HD in %s", updpath);
copyUpdatesImg(updpath);
free(updpath);
free(dirspec);
if (FL_STAGE2(flags)) {
if (!copyFile(path, "/tmp/stage2.img")) {
rc = mountStage2("/tmp/stage2.img", dirName);
umount("/mnt/isodir");
free(path);
if (rc) {
umountLoopback("/mnt/runtime", "/dev/loop0");
flags &= ~LOADER_FLAGS_STAGE2;
goto err;
} else {
rc = asprintf(&url, "hd:%s:%s:/%s",
device,
*type, dirName ? dirName : ".");
return url;
}
}
else {
free(path);
umount("/mnt/isodir");
flags &= ~LOADER_FLAGS_STAGE2;
goto err;
}
}
rc = mountLoopback(path, "/mnt/source", "/dev/loop1");
if (!rc) {
/* This code is for copying small stage2 into ram */
/* and mounting */
rc = loadHDImages("/mnt/source", "/", "/dev/loop0",
"/mnt/runtime", location);
umountLoopback("/mnt/source", "/dev/loop0");
if (rc) {
umount("/mnt/isodir");
free(path);
goto err;
} else {
queryIsoMediaCheck(path);
free(path);
rc = asprintf(&url, "hd:%s:%s:/%s", device,
*type, dirName ? dirName : ".");
return url;
}
}
} else {
free(dirspec);
if (rc) {
umount("/mnt/isodir");
return NULL;
}
}
} else {
/* in test mode I dont know what to do - just pretend I guess */
type = typetry;
}
err:
newtWinMessage(_("Error"), _("OK"),
_("An error occured reading the install "
"from the ISO images. Please check your ISO "
"images and try again."));
return NULL;
}
/* setup hard drive based install from a partition with a filesystem and
* ISO images on that filesystem
*/
char * mountHardDrive(struct installMethod * method,
char * location, struct loaderData_s * loaderData) {
int rc;
int i;
newtComponent listbox, label, dirEntry, form, okay, back, text;
struct newtExitStruct es;
newtGrid entryGrid, grid, buttons;
int done = 0;
char * dir = strdup("");
char * tmpDir;
char * url = NULL;
char * buf;
int numPartitions;
char **partition_list;
char *selpart;
char *kspartition, *ksdirectory;
/* handle kickstart data first if available */
if (loaderData->method == METHOD_HD && loaderData->methodData) {
kspartition = ((struct hdInstallData *)loaderData->methodData)->partition;
ksdirectory = ((struct hdInstallData *)loaderData->methodData)->directory;
logMessage(INFO, "partition is %s, dir is %s", kspartition, ksdirectory);
/* if exist, duplicate */
if (kspartition)
kspartition = strdup(kspartition);
if (ksdirectory)
ksdirectory = strdup(ksdirectory);
if (!kspartition || !ksdirectory) {
logMessage(ERROR, "missing partition or directory specification");
loaderData->method = -1;
} else {
/* if we start with /dev, strip it (#121486) */
char *kspart = kspartition;
if (!strncmp(kspart, "/dev/", 5))
kspart = kspart + 5;
url = setupIsoImages(kspart, ksdirectory, location);
if (!url) {
logMessage(ERROR, "unable to find %s installation images on hd",
getProductName());
loaderData->method = -1;
} else {
free(kspartition);
free(ksdirectory);
return url;
}
}
} else {
kspartition = NULL;
ksdirectory = NULL;
}
/* if we're here its either because this is interactive, or the */
/* hd kickstart directive was faulty and we have to prompt for */
/* location of harddrive image */
partition_list = NULL;
while (!done) {
/* if we're doing another pass free this up first */
if (partition_list)
freePartitionsList(partition_list);
partition_list = getPartitionsList(NULL);
numPartitions = lenPartitionsList(partition_list);
/* no partitions found, try to load a device driver disk for storage */
if (!numPartitions) {
rc = newtWinChoice(_("Hard Drives"), _("Yes"), _("Back"),
_("You don't seem to have any hard drives on "
"your system! Would you like to configure "
"additional devices?"));
if (rc == 2)
return NULL;
rc = loadDriverFromMedia(DEVICE_DISK, loaderData, 0, 0);
if (rc == LOADER_BACK)
return NULL;
continue;
}
/* now find out which partition has the hard drive install images */
rc = asprintf(&buf, _("What partition and directory on that "
"partition hold the CD (iso9660) images "
"for %s? If you don't see the disk drive "
"you're using listed here, press F2 "
"to configure additional devices."),
getProductName());
text = newtTextboxReflowed(-1, -1, buf, 62, 5, 5, 0);
free(buf);
listbox = newtListbox(-1, -1, numPartitions > 5 ? 5 : numPartitions,
NEWT_FLAG_RETURNEXIT |
(numPartitions > 5 ? NEWT_FLAG_SCROLL : 0));
for (i = 0; i < numPartitions; i++)
newtListboxAppendEntry(listbox,partition_list[i],partition_list[i]);
/* if we had ks data around use it to prime entry, then get rid of it*/
if (kspartition) {
newtListboxSetCurrentByKey(listbox, kspartition);
free(kspartition);
kspartition = NULL;
}
label = newtLabel(-1, -1, _("Directory holding images:"));
dirEntry = newtEntry(28, 11, dir, 28, (const char **) &tmpDir,
NEWT_ENTRY_SCROLL);
/* if we had ks data around use it to prime entry, then get rid of it*/
if (ksdirectory) {
newtEntrySet(dirEntry, ksdirectory, 1);
free(ksdirectory);
ksdirectory = NULL;
}
entryGrid = newtGridHStacked(NEWT_GRID_COMPONENT, label,
NEWT_GRID_COMPONENT, dirEntry,
NEWT_GRID_EMPTY);
buttons = newtButtonBar(_("OK"), &okay, _("Back"), &back, NULL);
grid = newtCreateGrid(1, 4);
newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
0, 0, 0, 1, 0, 0);
newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, listbox,
0, 0, 0, 1, 0, 0);
newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, entryGrid,
0, 0, 0, 1, 0, 0);
newtGridSetField(grid, 0, 3, NEWT_GRID_SUBGRID, buttons,
0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
newtGridWrappedWindow(grid, _("Select Partition"));
form = newtForm(NULL, NULL, 0);
newtFormAddHotKey(form, NEWT_KEY_F2);
newtFormAddHotKey(form, NEWT_KEY_F12);
newtGridAddComponentsToForm(grid, form, 1);
newtGridFree(grid, 1);
newtFormRun(form, &es);
selpart = newtListboxGetCurrent(listbox);
free(dir);
if (tmpDir && *tmpDir) {
/* Protect from form free. */
dir = strdup(tmpDir);
} else {
dir = strdup("");
}
newtFormDestroy(form);
newtPopWindow();
if (es.reason == NEWT_EXIT_COMPONENT && es.u.co == back) {
return NULL;
} else if (es.reason == NEWT_EXIT_HOTKEY && es.u.key == NEWT_KEY_F2) {
rc = loadDriverFromMedia(DEVICE_DISK, loaderData, 0, 0);
if (rc == LOADER_BACK)
return NULL;
continue;
}
logMessage(INFO, "partition %s selected", selpart);
url = setupIsoImages(selpart, dir, location);
if (!url) {
newtWinMessage(_("Error"), _("OK"),
_("Device %s does not appear to contain "
"%s CDROM images."), selpart, getProductName());
continue;
}
done = 1;
}
free(dir);
return url;
}
void setKickstartHD(struct loaderData_s * loaderData, int argc,
char ** argv) {
char *biospart = NULL, *partition = NULL, *dir = NULL, *p;
poptContext optCon;
int rc;
struct poptOption ksHDOptions[] = {
{ "biospart", '\0', POPT_ARG_STRING, &biospart, 0, NULL, NULL },
{ "partition", '\0', POPT_ARG_STRING, &partition, 0, NULL, NULL },
{ "dir", '\0', POPT_ARG_STRING, &dir, 0, NULL, NULL },
{ 0, 0, 0, 0, 0, 0, 0 }
};
logMessage(INFO, "kickstartFromHD");
optCon = poptGetContext(NULL, argc, (const char **) argv, ksHDOptions, 0);
if ((rc = poptGetNextOpt(optCon)) < -1) {
startNewt();
newtWinMessage(_("Kickstart Error"), _("OK"),
_("Bad argument to HD kickstart method "
"command %s: %s"),
poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
poptStrerror(rc));
return;
}
if (biospart) {
char * dev;
p = strchr(biospart,'p');
if(!p){
logMessage(ERROR, "Bad argument for --biospart");
return;
}
*p = '\0';
dev = getBiosDisk(biospart);
if (dev == NULL) {
logMessage(ERROR, "Unable to location BIOS partition %s", biospart);
return;
}
partition = malloc(strlen(dev) + strlen(p + 1) + 2);
sprintf(partition, "%s%s", dev, p + 1);
}
loaderData->method = METHOD_HD;
loaderData->methodData = calloc(sizeof(struct hdInstallData *), 1);
if (partition)
((struct hdInstallData *)loaderData->methodData)->partition = partition;
if (dir)
((struct hdInstallData *)loaderData->methodData)->directory = dir;
logMessage(INFO, "results of hd ks, partition is %s, dir is %s", partition,
dir);
}
int kickstartFromHD(char *kssrc) {
int rc;
char *p, *np = NULL, *tmpstr, *ksdev, *kspath;
logMessage(INFO, "getting kickstart file from harddrive");
/* format is hd:[device]:/path/to/ks.cfg */
/* split up pieces */
tmpstr = strdup(kssrc);
p = strchr(tmpstr, ':');
if (p)
np = strchr(p+1, ':');
/* no second colon, assume its the old format of */
/* hd:[device]/path/to/ks.cfg */
/* this format is bad however because some devices have '/' in them! */
if (!np)
np = strchr(p+1, '/');
if (!p || !np) {
logMessage(WARNING, "Format of command line is ks=hd:[device]:/path/to/ks.cfg");
free(tmpstr);
return 1;
}
*np = '\0';
ksdev = p+1;
kspath = np+1;
logMessage(INFO, "Loading ks from device %s on path %s", ksdev, kspath);
if ((rc=getKickstartFromBlockDevice(ksdev, kspath))) {
if (rc == 3) {
startNewt();
newtWinMessage(_("Error"), _("OK"),
_("Cannot find kickstart file on hard drive."));
}
return 1;
}
return 0;
}
int kickstartFromBD(char *kssrc) {
int rc;
char *p, *np = NULL, *r = NULL, *tmpstr, *ksdev, *kspath, *biosksdev;
logMessage(INFO, "getting kickstart file from biosdrive");
/* format is bd:[device]:/path/to/ks.cfg */
/* split of pieces */
tmpstr = strdup(kssrc);
p = strchr(tmpstr, ':');
if (p)
np = strchr(p+1, ':');
if (!p || !np) {
logMessage(WARNING, "Format of command line is ks=bd:device:/path/to/ks.cfg");
free(tmpstr);
return 1;
}
*np = '\0';
kspath = np+1;
r = strchr(p+1,'p');
if(!r){
logMessage(INFO, "Format of biosdisk is 80p1");
free(tmpstr);
return 1;
}
*r = '\0';
biosksdev = getBiosDisk((p + 1));
if(!biosksdev){
startNewt();
newtWinMessage(_("Error"), _("OK"),
_("Cannot find hard drive for BIOS disk %s"),
p + 1);
return 1;
}
ksdev = malloc(strlen(biosksdev) + 3);
sprintf(ksdev, "%s%s", biosksdev, r + 1);
logMessage(INFO, "Loading ks from device %s on path %s", ksdev, kspath);
if ((rc=getKickstartFromBlockDevice(ksdev, kspath))) {
if (rc == 3) {
startNewt();
newtWinMessage(_("Error"), _("OK"),
_("Cannot find kickstart file on hard drive."));
}
return 1;
}
return 0;
}
/* vim:set shiftwidth=4 softtabstop=4: */