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