379 lines
8.4 KiB
C
379 lines
8.4 KiB
C
/*
|
|
* Guillaume Cottenceau (gc@mandrakesoft.com)
|
|
*
|
|
* Copyright 2000 MandrakeSoft
|
|
*
|
|
* View the homepage: http://us.mandrakesoft.com/~gc/html/stage1.html
|
|
*
|
|
*
|
|
* 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 <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mount.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <signal.h>
|
|
|
|
#include "stage1.h"
|
|
|
|
#include "log.h"
|
|
#include "probing.h"
|
|
#include "frontend.h"
|
|
#include "modules.h"
|
|
#include "tools.h"
|
|
#include "automatic.h"
|
|
#include "mount.h"
|
|
#include "insmod.h"
|
|
|
|
#ifndef DISABLE_CDROM
|
|
#include "cdrom.h"
|
|
#endif
|
|
|
|
#ifndef DISABLE_NETWORK
|
|
#include "network.h"
|
|
#endif
|
|
|
|
#ifndef DISABLE_DISK
|
|
#include "disk.h"
|
|
#endif
|
|
|
|
extern char *env[];
|
|
|
|
/************************************************************
|
|
* globals */
|
|
|
|
char version[128] = DISTRIB_NAME;
|
|
char * method_name;
|
|
|
|
void fatal_error(char *msg)
|
|
{
|
|
printf("FATAL ERROR IN STAGE1: %s\n\nI can't recover from this.\nYou may reboot your system.\n", msg);
|
|
while (1);
|
|
}
|
|
|
|
|
|
/************************************************************
|
|
* special frontend functs
|
|
* (the principle is to not pollute frontend code with stage1-specific stuff) */
|
|
|
|
void stg1_error_message(char *msg, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, msg);
|
|
log_message("unsetting automatic");
|
|
unset_param(MODE_AUTOMATIC);
|
|
verror_message(msg, args);
|
|
va_end(args);
|
|
}
|
|
|
|
void stg1_info_message(char *msg, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, msg);
|
|
if (IS_AUTOMATIC) {
|
|
vlog_message(msg, args);
|
|
return;
|
|
}
|
|
vinfo_message(msg, args);
|
|
va_end(args);
|
|
}
|
|
|
|
|
|
/************************************************************
|
|
* spawns a shell on console #2 */
|
|
static pid_t shell_pid = 0;
|
|
static pid_t splash_pid = 0;
|
|
|
|
static void spawn_shell(void)
|
|
{
|
|
#ifdef SPAWN_SHELL
|
|
int fd;
|
|
char * shell_name[] = { "/bin/sh", NULL };
|
|
|
|
log_message("spawning a shell");
|
|
|
|
if (!IS_TESTING) {
|
|
fd = open("/dev/tty2", O_RDWR);
|
|
if (fd == -1) {
|
|
log_message("cannot open /dev/tty2 -- no shell will be provided");
|
|
return;
|
|
}
|
|
else if (access(shell_name[0], X_OK)) {
|
|
log_message("cannot open shell - %s doesn't exist", shell_name[0]);
|
|
return;
|
|
}
|
|
|
|
if (!(shell_pid = fork())) {
|
|
dup2(fd, 0);
|
|
dup2(fd, 1);
|
|
dup2(fd, 2);
|
|
|
|
close(fd);
|
|
setsid();
|
|
if (ioctl(0, TIOCSCTTY, NULL))
|
|
log_perror("could not set new controlling tty");
|
|
|
|
execve(shell_name[0], shell_name, env);
|
|
log_message("execve of %s failed: %s", shell_name[0], strerror(errno));
|
|
exit(-1);
|
|
}
|
|
|
|
close(fd);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void spawn_splash(void)
|
|
{
|
|
#ifdef SPAWN_SPLASH
|
|
int fd;
|
|
char * splash_name[] = { "/sbin/splash", NULL };
|
|
|
|
log_message("spawning a splash screen");
|
|
fd = open("/dev/null", O_RDWR);
|
|
if (fd == -1) {
|
|
log_message("cannot open /dev/null");
|
|
return;
|
|
}
|
|
else if (access(splash_name[0], X_OK)) {
|
|
log_message("%s doesn't exist", splash_name[0]);
|
|
return;
|
|
}
|
|
|
|
if (!(splash_pid = fork())) {
|
|
dup2(fd, 0);
|
|
dup2(fd, 1);
|
|
dup2(fd, 2);
|
|
close(fd);
|
|
setsid();
|
|
execve(splash_name[0], splash_name, env);
|
|
log_message("execve of %s failed: %s", splash_name[0], strerror(errno));
|
|
exit(-1);
|
|
}
|
|
|
|
close(fd);
|
|
#endif
|
|
}
|
|
|
|
/************************************************************
|
|
*/
|
|
|
|
static void expert_third_party_modules(void)
|
|
{
|
|
enum return_type results;
|
|
char * floppy_mount_location = "/tmp/floppy";
|
|
char ** modules;
|
|
char final_name[500];
|
|
char * choice;
|
|
int rc;
|
|
char * questions[] = { "Options", NULL };
|
|
static char ** answers = NULL;
|
|
|
|
results = ask_yes_no("If you want to insert third-party kernel modules, insert "
|
|
"a Linux (ext2fs) formatted floppy containing the modules and confirm. Otherwise, select \"no\".");;
|
|
if (results != RETURN_OK)
|
|
return;
|
|
|
|
my_insmod("floppy", NULL);
|
|
|
|
if (my_mount("/dev/fd0", floppy_mount_location, "ext2", 0) == -1) {
|
|
stg1_error_message("I can't find a Linux ext2 floppy in first floppy drive.");
|
|
return expert_third_party_modules();
|
|
}
|
|
|
|
modules = list_directory(floppy_mount_location);
|
|
|
|
if (!modules || !*modules) {
|
|
stg1_error_message("No modules found on floppy disk.");
|
|
umount(floppy_mount_location);
|
|
return expert_third_party_modules();
|
|
}
|
|
|
|
results = ask_from_list("Which driver would you like to insmod?", modules, &choice);
|
|
if (results != RETURN_OK) {
|
|
umount(floppy_mount_location);
|
|
return;
|
|
}
|
|
|
|
sprintf(final_name, "%s/%s", floppy_mount_location, choice);
|
|
|
|
results = ask_from_entries("Please enter the options:", questions, &answers, 24, NULL);
|
|
if (results != RETURN_OK) {
|
|
umount(floppy_mount_location);
|
|
return expert_third_party_modules();
|
|
}
|
|
|
|
rc = insmod_call(final_name, answers[0]);
|
|
umount(floppy_mount_location);
|
|
|
|
if (rc) {
|
|
log_message("\tfailed");
|
|
stg1_error_message("Insmod failed.");
|
|
}
|
|
|
|
return expert_third_party_modules();
|
|
}
|
|
|
|
/************************************************************
|
|
*/
|
|
|
|
static enum return_type method_select_and_prepare(void)
|
|
{
|
|
enum return_type results;
|
|
char * choice;
|
|
char * means[10], * means_auto[10];
|
|
int i;
|
|
|
|
#ifndef DISABLE_DISK
|
|
char * disk_install = "Hard disk"; char * disk_install_auto = "disk";
|
|
#endif
|
|
#ifndef DISABLE_CDROM
|
|
char * cdrom_install = "CDROM drive"; char * cdrom_install_auto = "cdrom";
|
|
#endif
|
|
#ifndef DISABLE_NETWORK
|
|
char * network_nfs_install = "NFS server"; char * network_nfs_install_auto = "nfs";
|
|
char * network_ftp_install = "FTP server"; char * network_ftp_install_auto = "ftp";
|
|
char * network_http_install = "HTTP server"; char * network_http_install_auto = "http";
|
|
#endif
|
|
|
|
i = 0;
|
|
#ifndef DISABLE_NETWORK
|
|
means[i] = network_nfs_install; means_auto[i++] = network_nfs_install_auto;
|
|
means[i] = network_ftp_install; means_auto[i++] = network_ftp_install_auto;
|
|
means[i] = network_http_install; means_auto[i++] = network_http_install_auto;
|
|
#endif
|
|
#ifndef DISABLE_CDROM
|
|
means[i] = cdrom_install; means_auto[i++] = cdrom_install_auto;
|
|
#endif
|
|
#ifndef DISABLE_DISK
|
|
means[i] = disk_install; means_auto[i++] = disk_install_auto;
|
|
#endif
|
|
means[i] = NULL;
|
|
update_splash();
|
|
|
|
#ifndef DISABLE_NETWORK
|
|
/* if requested by auto "network" param, bring networking up, regardless of method */
|
|
net_prepare();
|
|
#endif
|
|
|
|
results = ask_from_list_auto("Please choose the installation method.", means, &choice, "method", means_auto);
|
|
|
|
if (results != RETURN_OK)
|
|
return method_select_and_prepare();
|
|
|
|
results = RETURN_ERROR;
|
|
|
|
#ifndef DISABLE_CDROM
|
|
if (!strcmp(choice, cdrom_install))
|
|
results = cdrom_prepare();
|
|
#endif
|
|
|
|
#ifndef DISABLE_DISK
|
|
if (!strcmp(choice, disk_install))
|
|
results = disk_prepare();
|
|
#endif
|
|
|
|
#ifndef DISABLE_NETWORK
|
|
if (!strcmp(choice, network_nfs_install))
|
|
results = nfs_prepare();
|
|
|
|
if (!strcmp(choice, network_ftp_install))
|
|
results = ftp_prepare();
|
|
|
|
if (!strcmp(choice, network_http_install))
|
|
results = http_prepare();
|
|
#endif
|
|
|
|
if (results != RETURN_OK)
|
|
return method_select_and_prepare();
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
void getversion()
|
|
{
|
|
FILE *f;
|
|
char *c;
|
|
|
|
if (!(f = fopen(VERSION_FILE, "r"))) return;
|
|
if (fgets(version, sizeof(version), f)) {
|
|
c = strrchr(version, '\n');
|
|
if (c) *c = 0;
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
void stage1()
|
|
{
|
|
enum return_type ret;
|
|
char buf[128];
|
|
char *init;
|
|
|
|
open_log();
|
|
getversion();
|
|
log_message("welcome to the %s install (alt-stage1, built " __DATE__ " " __TIME__")", version);
|
|
process_cmdline();
|
|
handle_env(env);
|
|
spawn_shell();
|
|
spawn_splash();
|
|
prepare_progress();
|
|
update_splash();
|
|
snprintf(buf, sizeof(buf), "Welcome to %s", version);
|
|
init_frontend(buf);
|
|
update_splash();
|
|
|
|
if (IS_RESCUE && total_memory() < MEM_LIMIT_RESCUE) {
|
|
stg1_error_message("You are starting the rescue with a low memory configuration. "
|
|
"From that point, experience showed us that the program may stop "
|
|
"or crash at any point without immediate proper reason. Continue at "
|
|
"your own risk. Alternatively, you may reboot your system now.");
|
|
}
|
|
|
|
init = get_param_valued("init");
|
|
if (init)
|
|
add_to_env("INIT", init);
|
|
|
|
ret = method_select_and_prepare();
|
|
|
|
finish_frontend();
|
|
update_splash();
|
|
|
|
close_log();
|
|
close_progress();
|
|
if (ret != RETURN_OK)
|
|
fatal_error("could not select an installation method");
|
|
|
|
/* all went good */
|
|
if (shell_pid != 0)
|
|
kill(shell_pid, 9);
|
|
|
|
if (splash_pid != 0)
|
|
kill(splash_pid, 9);
|
|
|
|
pass_env(4);
|
|
|
|
exit(0);
|
|
}
|