propagator/stage1.c
2009-07-06 19:22:03 +04:00

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);
}