7a21d264c7
The installed system can have several devices with the same structure. The automatic 'fuid' option can be used to detach one from the other to find the partition where our stage2 image is stored, launched from stage1 (in this case propagator). This option works automatically with the cdrom method: - automatic=method:cdrom,fuid:PATH_TO_UNIQ_UID_FILENAME
351 lines
8.0 KiB
C
351 lines
8.0 KiB
C
/*
|
|
* Guillaume Cottenceau (gc@mandrakesoft.com)
|
|
*
|
|
* Copyright 2000 MandrakeSoft
|
|
*
|
|
* This software may be freely redistributed under the terms of the GNU
|
|
* public license.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Portions from Erik Troan (ewt@redhat.com)
|
|
*
|
|
* Copyright 1996 Red Hat Software
|
|
*
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <sys/mount.h>
|
|
#include <ctype.h>
|
|
#include <dirent.h>
|
|
|
|
#include "stage1.h"
|
|
#include "frontend.h"
|
|
#include "modules.h"
|
|
#include "probing.h"
|
|
#include "log.h"
|
|
#include "mount.h"
|
|
#include "automatic.h"
|
|
|
|
#include "cdrom.h"
|
|
#include "init.h"
|
|
#include "udev.h"
|
|
|
|
extern char version[];
|
|
|
|
static int mount_iso9660(char * dev_name)
|
|
{
|
|
return my_mount(dev_name, IMAGE_LOCATION, "iso9660", 0);
|
|
}
|
|
|
|
static int mount_that_cd_device(char * dev_name)
|
|
{
|
|
char device_fullname[64] = "/dev/";
|
|
strcat(device_fullname, dev_name);
|
|
|
|
char * p = device_fullname + strlen(device_fullname);
|
|
if (islower(p[-1])) {
|
|
int ret;
|
|
|
|
p[0] = '1';
|
|
p[1] = '\0';
|
|
ret = mount_iso9660(device_fullname);
|
|
if (ret != -1)
|
|
return ret;
|
|
p[0] = '\0';
|
|
}
|
|
|
|
return mount_iso9660(device_fullname);
|
|
}
|
|
|
|
/* test_that_cd() returns 0 on success */
|
|
static int test_that_cd(int no_digest)
|
|
{
|
|
char *ramdisk_path = get_ramdisk_path(NULL);
|
|
int rc;
|
|
|
|
if (IS_VERIFICATION && !no_digest) {
|
|
rc = verify_ramdisk_digest(ramdisk_path,
|
|
get_param_valued("hash")) == RETURN_ERROR;
|
|
goto done;
|
|
}
|
|
|
|
log_message("test file on cd: %s\n", ramdisk_path);
|
|
|
|
rc = access(ramdisk_path, R_OK);
|
|
|
|
done:
|
|
free(ramdisk_path);
|
|
return rc;
|
|
}
|
|
|
|
/* test_that_cd_with_file_uid() returns 0 on success, using in automatic mode */
|
|
static int test_that_cd_with_file_uid(const char * dev_name, const char * dev_model)
|
|
{
|
|
const char *uid_file = get_auto_value("fuid");
|
|
char *uid_file_path = get_uid_file_path(NULL, uid_file);
|
|
int rc;
|
|
|
|
if (uid_file_path != NULL && access(uid_file_path, R_OK)) {
|
|
log_message("skip device /dev/%s %s without uid file %s", dev_name, dev_model, uid_file);
|
|
rc = -1;
|
|
goto done;
|
|
}
|
|
|
|
rc = test_that_cd(1);
|
|
|
|
done:
|
|
if (uid_file_path != NULL)
|
|
free(uid_file_path);
|
|
return rc;
|
|
}
|
|
|
|
static enum return_type try_with_device(char * dev_name, char * dev_model);
|
|
|
|
static enum return_type do_with_device(char * dev_name, char * dev_model)
|
|
{
|
|
struct stat st;
|
|
char msg[256];
|
|
char * ramdisk_path;
|
|
if (test_that_cd(0)) {
|
|
enum return_type results;
|
|
umount(IMAGE_LOCATION);
|
|
if (IS_VERIFICATION)
|
|
snprintf(msg, sizeof(msg), "ISO on /dev/%s does not seem to contain proper %s"
|
|
" media:\nhash verification failed.\nTry another media in that drive?", dev_name, version);
|
|
else
|
|
snprintf(msg, sizeof(msg), "That ISO does not seem like proper %s"
|
|
" media.\nTry another media in that drive?", version);
|
|
results = ask_yes_no(msg);
|
|
if (results == RETURN_OK)
|
|
return try_with_device(dev_name, dev_model);
|
|
return results;
|
|
}
|
|
|
|
log_message("found %s ISO9660 media, good news!", version);
|
|
|
|
if (IS_RESCUE) {
|
|
load_ramdisk(NULL, 0);
|
|
umount(IMAGE_LOCATION);
|
|
}
|
|
|
|
ramdisk_path = get_ramdisk_path(NULL);
|
|
stat(ramdisk_path, &st);
|
|
if (S_ISDIR(st.st_mode)) {
|
|
mount(ramdisk_path, STAGE2_LOCATION, NULL, MS_BIND, NULL);
|
|
} else {
|
|
do_losetup(LIVE_DEVICE,ramdisk_path);
|
|
my_mount(LIVE_DEVICE, STAGE2_LOCATION, (IS_LIVE) ? LIVEFS : STAGE2FS, 0);
|
|
}
|
|
|
|
free(ramdisk_path);
|
|
|
|
method_name = strdup("cdrom");
|
|
add_to_env("METHOD", method_name);
|
|
add_to_env("PREFIX", "/");
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
static enum return_type try_with_device(char * dev_name, char * dev_model)
|
|
{
|
|
wait_message("Trying to access media in drive %s", dev_model);
|
|
|
|
if (mount_that_cd_device(dev_name) == -1) {
|
|
enum return_type results;
|
|
char msg[500];
|
|
unset_param(MODE_AUTOMATIC); /* we are in a fallback mode */
|
|
remove_wait_message();
|
|
|
|
snprintf(msg, sizeof(msg), "I can't access %s media in drive %s.\nRetry?", version, dev_model);
|
|
results = ask_yes_no(msg);
|
|
if (results == RETURN_OK)
|
|
return try_with_device(dev_name, dev_model);
|
|
return results;
|
|
}
|
|
remove_wait_message();
|
|
|
|
return do_with_device(dev_name, dev_model);
|
|
}
|
|
|
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
|
|
|
int try_automatic(char ** medias, char ** medias_models)
|
|
{
|
|
static char * already_tried[50] = { NULL };
|
|
char ** model = medias_models;
|
|
char ** ptr = medias;
|
|
int i = 0;
|
|
|
|
if (!medias) {
|
|
for (; i < ARRAY_SIZE(already_tried); ++i) {
|
|
if (!already_tried[i])
|
|
break;
|
|
free(already_tried[i]);
|
|
already_tried[i] = NULL;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
while (ptr && *ptr) {
|
|
char ** p;
|
|
for (p = already_tried; p && *p; p++)
|
|
if (streq(*p, *ptr))
|
|
goto try_automatic_already_tried;
|
|
*p = strdup(*ptr);
|
|
*(p+1) = NULL;
|
|
|
|
wait_message("Trying to access media in drive %s", *model);
|
|
if (mount_that_cd_device(*ptr) != -1) {
|
|
if (!test_that_cd_with_file_uid(*ptr, *model)) {
|
|
remove_wait_message();
|
|
return i;
|
|
}
|
|
else
|
|
umount(IMAGE_LOCATION);
|
|
}
|
|
remove_wait_message();
|
|
|
|
try_automatic_already_tried:
|
|
ptr++;
|
|
model++;
|
|
i++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
enum return_type cdrom_prepare(void)
|
|
{
|
|
char ** medias, ** ptr, ** medias_models;
|
|
char * choice;
|
|
int i, count = 0;
|
|
enum return_type results;
|
|
int timeout=32;
|
|
DIR * diskdir;
|
|
|
|
update_splash("prepare");
|
|
fprintf(stderr,"%c[1A",27);
|
|
for(i=0; i<timeout; i++) {
|
|
if ((diskdir = opendir("/dev/disk/")) != NULL) {
|
|
closedir(diskdir);
|
|
break;
|
|
}
|
|
fprintf(stderr,"\rwaiting for /dev/disk/ %d...", i);
|
|
udev_settle();
|
|
sleep(1);
|
|
}
|
|
update_splash("wait_media");
|
|
get_medias(CDROM, &medias, &medias_models);
|
|
|
|
if (IS_AUTOMATIC) {
|
|
unsigned int j;
|
|
enum return_type automatic_result = RETURN_OK;
|
|
|
|
for (j = 0; j < 15; ++j) {
|
|
udev_settle();
|
|
if (j) {
|
|
wait_message("Waiting %d second%s for CD/DVD/Pendrive media to appear",
|
|
j, j > 1 ? "s" : "");
|
|
sleep(1);
|
|
|
|
/* drop medias */
|
|
for (ptr = medias; *ptr; ++ptr)
|
|
free(*ptr);
|
|
free(medias);
|
|
|
|
/* drop medias_models */
|
|
for (ptr = medias_models; *ptr; ++ptr)
|
|
free(*ptr);
|
|
free(medias_models);
|
|
|
|
/* drop already_tried */
|
|
try_automatic(NULL, NULL);
|
|
|
|
/* refill medias and medias_models;
|
|
note that get_medias() leaks memory */
|
|
get_medias(CDROM, &medias, &medias_models);
|
|
remove_wait_message();
|
|
}
|
|
while ((i = try_automatic(medias, medias_models)) != -1) {
|
|
if (j && automatic_result == RETURN_OK) {
|
|
log_message("found /dev/%s %s after %d seconds of waiting",
|
|
medias[i], medias_models[i], j);
|
|
remove_wait_message();
|
|
}
|
|
if (automatic_result != RETURN_OK) {
|
|
log_message("try next found device /dev/%s %s",
|
|
medias[i], medias_models[i]);
|
|
}
|
|
automatic_result = do_with_device(medias[i], medias_models[i]);
|
|
if (automatic_result == RETURN_OK)
|
|
return RETURN_OK;
|
|
log_message("mount device /dev/%s %s failed", medias[i], medias_models[i]);
|
|
}
|
|
if (automatic_result != RETURN_OK)
|
|
break;
|
|
}
|
|
|
|
ptr = medias;
|
|
while (ptr && *ptr) {
|
|
count++;
|
|
ptr++;
|
|
}
|
|
if (count == 0) {
|
|
stg1_error_message("No CD/DVD/Pendrive found.");
|
|
|
|
i = ask_insmod();
|
|
if (i == RETURN_BACK)
|
|
return RETURN_BACK;
|
|
return cdrom_prepare();
|
|
}
|
|
|
|
if (count == 1) {
|
|
results = try_with_device(*medias, *medias_models);
|
|
if (results == RETURN_OK)
|
|
return RETURN_OK;
|
|
i = ask_insmod();
|
|
if (i == RETURN_BACK)
|
|
return RETURN_BACK;
|
|
return cdrom_prepare();
|
|
}
|
|
|
|
unset_param(MODE_AUTOMATIC);
|
|
}
|
|
|
|
results = ask_from_list_comments("Please choose the drive to boot from.", medias, medias_models, &choice);
|
|
if (results == RETURN_OK) {
|
|
char ** model = medias_models;
|
|
ptr = medias;
|
|
while (ptr && *ptr && model && *model) {
|
|
if (!strcmp(*ptr, choice))
|
|
break;
|
|
ptr++;
|
|
model++;
|
|
}
|
|
results = try_with_device(choice, *model);
|
|
} else
|
|
return results;
|
|
if (results == RETURN_OK)
|
|
{
|
|
update_splash("found_media");
|
|
return RETURN_OK;
|
|
}
|
|
if (results == RETURN_BACK)
|
|
return cdrom_prepare();
|
|
|
|
i = ask_insmod();
|
|
if (i == RETURN_BACK)
|
|
return RETURN_BACK;
|
|
return cdrom_prepare();
|
|
}
|