Home | History | Annotate | Download | only in elflink
      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <unistd.h>
      4 #include <string.h>
      5 #include <console.h>
      6 #include <dprintf.h>
      7 #include <com32.h>
      8 #include <syslinux/adv.h>
      9 #include <syslinux/config.h>
     10 #include <setjmp.h>
     11 #include <linux/list.h>
     12 #include <netinet/in.h>
     13 #include <sys/cpu.h>
     14 #include <core.h>
     15 #include <fcntl.h>
     16 #include <sys/file.h>
     17 #include <fs.h>
     18 #include <ctype.h>
     19 #include <alloca.h>
     20 
     21 #include <sys/exec.h>
     22 #include <sys/module.h>
     23 #include "common.h"
     24 
     25 extern char __dynstr_start[];
     26 extern char __dynstr_end[], __dynsym_end[];
     27 extern char __dynsym_start[];
     28 extern char __got_start[];
     29 extern Elf_Dyn __dynamic_start[];
     30 extern Elf_Word __gnu_hash_start[];
     31 extern char __module_start[];
     32 
     33 struct elf_module core_module = {
     34     .name		= "(core)",
     35     .shallow		= true,
     36     .required		= LIST_HEAD_INIT((core_module.required)),
     37     .dependants		= LIST_HEAD_INIT((core_module.dependants)),
     38     .list		= LIST_HEAD_INIT((core_module.list)),
     39     .module_addr	= (void *)0x0,
     40     .ghash_table	= __gnu_hash_start,
     41     .str_table		= __dynstr_start,
     42     .sym_table		= __dynsym_start,
     43     .got		= __got_start,
     44     .dyn_table		= __dynamic_start,
     45     .syment_size	= sizeof(Elf_Sym),
     46 };
     47 
     48 /*
     49  * Initializes the module subsystem by taking the core module
     50  * (preinitialized shallow module) and placing it on top of the
     51  * modules_head_list.
     52  */
     53 void init_module_subsystem(struct elf_module *module)
     54 {
     55     list_add(&module->list, &modules_head);
     56 }
     57 
     58 __export int start_ldlinux(int argc, char **argv)
     59 {
     60 	int rv;
     61 
     62 again:
     63 	rv = spawn_load(LDLINUX, argc, argv);
     64 	if (rv == EEXIST) {
     65 		/*
     66 		 * If a COM32 module calls execute() we may need to
     67 		 * unload all the modules loaded since ldlinux.*,
     68 		 * and restart initialisation. This is especially
     69 		 * important for config files.
     70 		 *
     71 		 * But before we do that, try our best to make sure
     72 		 * that spawn_load() is gonna succeed, e.g. that we
     73 		 * can find LDLINUX it in PATH.
     74 		 */
     75 		struct elf_module *ldlinux;
     76 		FILE *f;
     77 
     78 		f = findpath(LDLINUX);
     79 		if (!f)
     80 			return ENOENT;
     81 
     82 		fclose(f);
     83 		ldlinux = unload_modules_since(LDLINUX);
     84 
     85 		/*
     86 		 * Finally unload LDLINUX.
     87 		 *
     88 		 * We'll reload it when we jump to 'again' which will
     89 		 * cause all the initialsation steps to be executed
     90 		 * again.
     91 		 */
     92 		module_unload(ldlinux);
     93 		goto again;
     94 	}
     95 
     96 	return rv;
     97 }
     98 
     99 /* note to self: do _*NOT*_ use static key word on this function */
    100 void load_env32(com32sys_t * regs __unused)
    101 {
    102 	struct file_info *fp;
    103 	int fd;
    104 	char *argv[] = { LDLINUX, NULL };
    105 	char realname[FILENAME_MAX];
    106 	size_t size;
    107 
    108 	static const char *search_directories[] = {
    109 		"/boot/isolinux",
    110 		"/isolinux",
    111 		"/boot/syslinux",
    112 		"/syslinux",
    113 		"/",
    114 		NULL
    115 	};
    116 
    117 	static const char *filenames[] = {
    118 		LDLINUX,
    119 		NULL
    120 	};
    121 
    122 	dprintf("Starting %s elf module subsystem...\n", ELF_MOD_SYS);
    123 
    124 	if (strlen(CurrentDirName) && !path_add(CurrentDirName)) {
    125 		printf("Couldn't allocate memory for PATH\n");
    126 		goto out;
    127 	}
    128 
    129 	size = (size_t)__dynstr_end - (size_t)__dynstr_start;
    130 	core_module.strtable_size = size;
    131 	size = (size_t)__dynsym_end - (size_t)__dynsym_start;
    132 	core_module.symtable_size = size;
    133 	core_module.base_addr = (Elf_Addr)__module_start;
    134 
    135 	init_module_subsystem(&core_module);
    136 
    137 	start_ldlinux(1, argv);
    138 
    139 	/*
    140 	 * If we failed to load LDLINUX it could be because our
    141 	 * current working directory isn't the install directory. Try
    142 	 * a bit harder to find LDLINUX. If search_dirs() succeeds
    143 	 * in finding LDLINUX it will set the cwd.
    144 	 */
    145 	fd = opendev(&__file_dev, NULL, O_RDONLY);
    146 	if (fd < 0)
    147 		goto out;
    148 
    149 	fp = &__file_info[fd];
    150 
    151 	if (!search_dirs(&fp->i.fd, search_directories, filenames, realname)) {
    152 		char path[FILENAME_MAX];
    153 
    154 		/*
    155 		 * search_dirs() sets the current working directory if
    156 		 * it successfully opens the file. Add the directory
    157 		 * in which we found ldlinux.* to PATH.
    158 		 */
    159 		if (!core_getcwd(path, sizeof(path)))
    160 			goto out;
    161 
    162 		if (!path_add(path)) {
    163 			printf("Couldn't allocate memory for PATH\n");
    164 			goto out;
    165 		}
    166 
    167 		start_ldlinux(1, argv);
    168 	}
    169 
    170 out:
    171 	writestr("\nFailed to load ");
    172 	writestr(LDLINUX);
    173 }
    174 
    175 static const char *__cmdline;
    176 __export const char *com32_cmdline(void)
    177 {
    178 	return __cmdline;
    179 }
    180 
    181 __export int create_args_and_load(char *cmdline)
    182 {
    183 	char *p, **argv;
    184 	int argc;
    185 	int i;
    186 
    187 	if (!cmdline)
    188 		return -1;
    189 
    190 	for (argc = 0, p = cmdline; *p; argc++) {
    191 		/* Find the end of this arg */
    192 		while(*p && !isspace(*p))
    193 			p++;
    194 
    195 		/*
    196 		 * Now skip all whitespace between arguments.
    197 		 */
    198 		while (*p && isspace(*p))
    199 			p++;
    200 	}
    201 
    202 	/*
    203 	 * Generate a copy of argv on the stack as this is
    204 	 * traditionally where process arguments go.
    205 	 *
    206 	 * argv[0] must be the command name. Remember to allocate
    207 	 * space for the sentinel NULL.
    208 	 */
    209 	argv = alloca((argc + 1) * sizeof(char *));
    210 
    211 	for (i = 0, p = cmdline; i < argc; i++) {
    212 		char *start;
    213 		int len = 0;
    214 
    215 		start = p;
    216 
    217 		/* Find the end of this arg */
    218 		while(*p && !isspace(*p)) {
    219 			p++;
    220 			len++;
    221 		}
    222 
    223 		argv[i] = malloc(len + 1);
    224 		strncpy(argv[i], start, len);
    225 		argv[i][len] = '\0';
    226 
    227 		/*
    228 		 * Now skip all whitespace between arguments.
    229 		 */
    230 		while (*p && isspace(*p))
    231 			p++;
    232 
    233 		/*
    234 		 * Point __cmdline at "argv[1] ... argv[argc-1]"
    235 		 */
    236 		if (i == 0)
    237 			__cmdline = p;
    238 	}
    239 
    240 	/* NUL-terminate */
    241 	argv[argc] = NULL;
    242 
    243 	return spawn_load(argv[0], argc, argv);
    244 }
    245 
    246 void pm_env32_run(com32sys_t *regs)
    247 {
    248 	char *cmdline;
    249 
    250 	cmdline = MK_PTR(regs->es, regs->ebx.w[0]);
    251 	if (create_args_and_load(cmdline) < 0)
    252 		printf("Failed to run com32 module\n");
    253 }
    254