254 lines
5.3 KiB
C
254 lines
5.3 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <console.h>
|
|
#include <dprintf.h>
|
|
#include <com32.h>
|
|
#include <syslinux/adv.h>
|
|
#include <syslinux/config.h>
|
|
#include <setjmp.h>
|
|
#include <linux/list.h>
|
|
#include <netinet/in.h>
|
|
#include <sys/cpu.h>
|
|
#include <core.h>
|
|
#include <fcntl.h>
|
|
#include <sys/file.h>
|
|
#include <fs.h>
|
|
#include <ctype.h>
|
|
#include <alloca.h>
|
|
|
|
#include <sys/exec.h>
|
|
#include <sys/module.h>
|
|
#include "common.h"
|
|
|
|
extern char __dynstr_start[];
|
|
extern char __dynstr_end[], __dynsym_end[];
|
|
extern char __dynsym_start[];
|
|
extern char __got_start[];
|
|
extern Elf_Dyn __dynamic_start[];
|
|
extern Elf_Word __gnu_hash_start[];
|
|
extern char __module_start[];
|
|
|
|
struct elf_module core_module = {
|
|
.name = "(core)",
|
|
.shallow = true,
|
|
.required = LIST_HEAD_INIT((core_module.required)),
|
|
.dependants = LIST_HEAD_INIT((core_module.dependants)),
|
|
.list = LIST_HEAD_INIT((core_module.list)),
|
|
.module_addr = (void *)0x0,
|
|
.ghash_table = __gnu_hash_start,
|
|
.str_table = __dynstr_start,
|
|
.sym_table = __dynsym_start,
|
|
.got = __got_start,
|
|
.dyn_table = __dynamic_start,
|
|
.syment_size = sizeof(Elf_Sym),
|
|
};
|
|
|
|
/*
|
|
* Initializes the module subsystem by taking the core module
|
|
* (preinitialized shallow module) and placing it on top of the
|
|
* modules_head_list.
|
|
*/
|
|
void init_module_subsystem(struct elf_module *module)
|
|
{
|
|
list_add(&module->list, &modules_head);
|
|
}
|
|
|
|
__export int start_ldlinux(int argc, char **argv)
|
|
{
|
|
int rv;
|
|
|
|
again:
|
|
rv = spawn_load(LDLINUX, argc, argv);
|
|
if (rv == EEXIST) {
|
|
/*
|
|
* If a COM32 module calls execute() we may need to
|
|
* unload all the modules loaded since ldlinux.*,
|
|
* and restart initialisation. This is especially
|
|
* important for config files.
|
|
*
|
|
* But before we do that, try our best to make sure
|
|
* that spawn_load() is gonna succeed, e.g. that we
|
|
* can find LDLINUX it in PATH.
|
|
*/
|
|
struct elf_module *ldlinux;
|
|
FILE *f;
|
|
|
|
f = findpath(LDLINUX);
|
|
if (!f)
|
|
return ENOENT;
|
|
|
|
fclose(f);
|
|
ldlinux = unload_modules_since(LDLINUX);
|
|
|
|
/*
|
|
* Finally unload LDLINUX.
|
|
*
|
|
* We'll reload it when we jump to 'again' which will
|
|
* cause all the initialsation steps to be executed
|
|
* again.
|
|
*/
|
|
module_unload(ldlinux);
|
|
goto again;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* note to self: do _*NOT*_ use static key word on this function */
|
|
void load_env32(com32sys_t * regs __unused)
|
|
{
|
|
struct file_info *fp;
|
|
int fd;
|
|
char *argv[] = { LDLINUX, NULL };
|
|
char realname[FILENAME_MAX];
|
|
size_t size;
|
|
|
|
static const char *search_directories[] = {
|
|
"/boot/isolinux",
|
|
"/isolinux",
|
|
"/boot/syslinux",
|
|
"/syslinux",
|
|
"/",
|
|
NULL
|
|
};
|
|
|
|
static const char *filenames[] = {
|
|
LDLINUX,
|
|
NULL
|
|
};
|
|
|
|
dprintf("Starting %s elf module subsystem...\n", ELF_MOD_SYS);
|
|
|
|
if (strlen(CurrentDirName) && !path_add(CurrentDirName)) {
|
|
printf("Couldn't allocate memory for PATH\n");
|
|
goto out;
|
|
}
|
|
|
|
size = (size_t)__dynstr_end - (size_t)__dynstr_start;
|
|
core_module.strtable_size = size;
|
|
size = (size_t)__dynsym_end - (size_t)__dynsym_start;
|
|
core_module.symtable_size = size;
|
|
core_module.base_addr = (Elf_Addr)__module_start;
|
|
|
|
init_module_subsystem(&core_module);
|
|
|
|
start_ldlinux(1, argv);
|
|
|
|
/*
|
|
* If we failed to load LDLINUX it could be because our
|
|
* current working directory isn't the install directory. Try
|
|
* a bit harder to find LDLINUX. If search_dirs() succeeds
|
|
* in finding LDLINUX it will set the cwd.
|
|
*/
|
|
fd = opendev(&__file_dev, NULL, O_RDONLY);
|
|
if (fd < 0)
|
|
goto out;
|
|
|
|
fp = &__file_info[fd];
|
|
|
|
if (!search_dirs(&fp->i.fd, search_directories, filenames, realname)) {
|
|
char path[FILENAME_MAX];
|
|
|
|
/*
|
|
* search_dirs() sets the current working directory if
|
|
* it successfully opens the file. Add the directory
|
|
* in which we found ldlinux.* to PATH.
|
|
*/
|
|
if (!core_getcwd(path, sizeof(path)))
|
|
goto out;
|
|
|
|
if (!path_add(path)) {
|
|
printf("Couldn't allocate memory for PATH\n");
|
|
goto out;
|
|
}
|
|
|
|
start_ldlinux(1, argv);
|
|
}
|
|
|
|
out:
|
|
writestr("\nFailed to load ");
|
|
writestr(LDLINUX);
|
|
}
|
|
|
|
static const char *__cmdline;
|
|
__export const char *com32_cmdline(void)
|
|
{
|
|
return __cmdline;
|
|
}
|
|
|
|
__export int create_args_and_load(char *cmdline)
|
|
{
|
|
char *p, **argv;
|
|
int argc;
|
|
int i;
|
|
|
|
if (!cmdline)
|
|
return -1;
|
|
|
|
for (argc = 0, p = cmdline; *p; argc++) {
|
|
/* Find the end of this arg */
|
|
while(*p && !isspace(*p))
|
|
p++;
|
|
|
|
/*
|
|
* Now skip all whitespace between arguments.
|
|
*/
|
|
while (*p && isspace(*p))
|
|
p++;
|
|
}
|
|
|
|
/*
|
|
* Generate a copy of argv on the stack as this is
|
|
* traditionally where process arguments go.
|
|
*
|
|
* argv[0] must be the command name. Remember to allocate
|
|
* space for the sentinel NULL.
|
|
*/
|
|
argv = alloca((argc + 1) * sizeof(char *));
|
|
|
|
for (i = 0, p = cmdline; i < argc; i++) {
|
|
char *start;
|
|
int len = 0;
|
|
|
|
start = p;
|
|
|
|
/* Find the end of this arg */
|
|
while(*p && !isspace(*p)) {
|
|
p++;
|
|
len++;
|
|
}
|
|
|
|
argv[i] = malloc(len + 1);
|
|
strncpy(argv[i], start, len);
|
|
argv[i][len] = '\0';
|
|
|
|
/*
|
|
* Now skip all whitespace between arguments.
|
|
*/
|
|
while (*p && isspace(*p))
|
|
p++;
|
|
|
|
/*
|
|
* Point __cmdline at "argv[1] ... argv[argc-1]"
|
|
*/
|
|
if (i == 0)
|
|
__cmdline = p;
|
|
}
|
|
|
|
/* NUL-terminate */
|
|
argv[argc] = NULL;
|
|
|
|
return spawn_load(argv[0], argc, argv);
|
|
}
|
|
|
|
void pm_env32_run(com32sys_t *regs)
|
|
{
|
|
char *cmdline;
|
|
|
|
cmdline = MK_PTR(regs->es, regs->ebx.w[0]);
|
|
if (create_args_and_load(cmdline) < 0)
|
|
printf("Failed to run com32 module\n");
|
|
}
|