dmi: check both the AC and ID flags at the same time
[syslinux.git] / com32 / elflink / ldlinux / ldlinux.c
blob0172117b195be252e7c8cf4cd284af991363d7e4
1 #include <linux/list.h>
2 #include <sys/times.h>
3 #include <fcntl.h>
4 #include <stdbool.h>
5 #include <string.h>
6 #include <core.h>
7 #include <fs.h>
8 #include "cli.h"
9 #include "console.h"
10 #include "com32.h"
11 #include "menu.h"
12 #include "config.h"
13 #include "syslinux/adv.h"
14 #include "syslinux/boot.h"
15 #include "syslinux/config.h"
17 #include <sys/module.h>
19 struct file_ext {
20 const char *name;
21 enum kernel_type type;
24 static const struct file_ext file_extensions[] = {
25 { ".c32", IMAGE_TYPE_COM32 },
26 { ".img", IMAGE_TYPE_FDIMAGE },
27 { ".bss", IMAGE_TYPE_BSS },
28 { ".bin", IMAGE_TYPE_BOOT },
29 { ".bs", IMAGE_TYPE_BOOT },
30 { ".0", IMAGE_TYPE_PXE },
31 { NULL, 0 },
34 jmp_buf __return_to_command_prompt;
37 * Return a pointer to one byte after the last character of the
38 * command.
40 static inline const char *find_command(const char *str)
42 const char *p;
44 p = str;
45 while (*p && !my_isspace(*p))
46 p++;
47 return p;
50 __export uint32_t parse_image_type(const char *kernel)
52 const struct file_ext *ext;
53 const char *p;
54 int len;
56 /* Find the end of the command */
57 p = find_command(kernel);
58 len = p - kernel;
60 for (ext = file_extensions; ext->name; ext++) {
61 int elen = strlen(ext->name);
63 if (!strncmp(kernel + len - elen, ext->name, elen))
64 return ext->type;
67 /* use IMAGE_TYPE_KERNEL as default */
68 return IMAGE_TYPE_KERNEL;
72 * Returns the kernel name with file extension if one wasn't present.
74 static const char *get_extension(const char *kernel)
76 const struct file_ext *ext;
77 const char *p;
78 int len;
80 /* Find the end of the command */
81 p = find_command(kernel);
82 len = p - kernel;
84 for (ext = file_extensions; ext->name; ext++) {
85 char *str;
86 int elen = strlen(ext->name);
87 FILE *f;
89 str = malloc(len + elen + 1);
91 strncpy(str, kernel, len);
92 strncpy(str + len, ext->name, elen);
93 str[len + elen] = '\0';
94 f = findpath(str);
95 free(str);
97 if (f) {
98 fclose(f);
99 return ext->name;
103 return NULL;
106 const char *apply_extension(const char *kernel, const char *ext)
108 const char *p;
109 char *k;
110 int len = strlen(kernel);
111 int elen = strlen(ext);
113 k = malloc(len + elen + 1);
114 if (!k)
115 return NULL;
117 p = find_command(kernel);
119 len = p - kernel;
121 /* Copy just the kernel name */
122 memcpy(k, kernel, len);
124 /* Append the extension */
125 if (strncmp(p - elen, ext, elen)) {
126 memcpy(k + len, ext, elen);
127 len += elen;
130 /* Copy the rest of the command line */
131 strcpy(k + len, p);
133 k[len + strlen(p)] = '\0';
135 return k;
139 * Attempt to load a kernel after deciding what type of image it is.
141 * We only return from this function if something went wrong loading
142 * the the kernel. If we return the caller should call enter_cmdline()
143 * so that the user can help us out.
145 __export void load_kernel(const char *command_line)
147 struct menu_entry *me;
148 const char *cmdline;
149 const char *kernel;
150 uint32_t type;
152 kernel = strdup(command_line);
153 if (!kernel)
154 goto bad_kernel;
156 /* Virtual kernel? */
157 me = find_label(kernel);
158 if (me) {
159 const char *args;
160 char *cmd;
161 size_t len = strlen(me->cmdline) + 1;
163 /* Find the end of the command */
164 args = find_command(kernel);
165 while(*args && my_isspace(*args))
166 args++;
168 if (strlen(args))
169 len += strlen(args) + 1; /* +1 for space (' ') */
171 cmd = malloc(len);
172 if (!cmd)
173 goto bad_kernel;
175 if (strlen(args))
176 snprintf(cmd, len, "%s %s", me->cmdline, args);
177 else
178 strncpy(cmd, me->cmdline, len);
180 type = parse_image_type(cmd);
181 execute(cmd, type, false);
182 /* We shouldn't return */
183 goto bad_kernel;
186 if (!allowimplicit)
187 goto bad_implicit;
189 /* Insert a null character to ignore any user-specified options */
190 if (!allowoptions) {
191 char *p = (char *)find_command(kernel);
192 *p = '\0';
195 type = parse_image_type(kernel);
196 if (type == IMAGE_TYPE_KERNEL) {
197 const char *ext;
200 * Automatically lookup the extension if one wasn't
201 * supplied by the user.
203 ext = get_extension(kernel);
204 if (ext) {
205 const char *k;
207 k = apply_extension(kernel, ext);
208 if (!k)
209 goto bad_kernel;
211 free((void *)kernel);
212 kernel = k;
214 type = parse_image_type(kernel);
218 execute(kernel, type, true);
219 free((void *)kernel);
221 bad_implicit:
222 bad_kernel:
224 * If we fail to boot the kernel execute the "onerror" command
225 * line.
227 if (onerrorlen) {
228 me = find_label(onerror);
229 if (me)
230 rsprintf(&cmdline, "%s %s", me->cmdline, default_cmd);
231 else
232 rsprintf(&cmdline, "%s %s", onerror, default_cmd);
234 type = parse_image_type(cmdline);
235 execute(cmdline, type, true);
240 * If this function returns you must call ldinux_enter_command() to
241 * preserve the 4.0x behaviour.
243 void ldlinux_auto_boot(void)
245 if (!defaultlevel) {
246 if (strlen(ConfigName))
247 printf("No DEFAULT or UI configuration directive found!\n");
248 if (noescape)
249 kaboom();
250 } else
251 load_kernel(default_cmd);
254 static void enter_cmdline(void)
256 const char *cmdline;
258 /* Enter endless command line prompt, should support "exit" */
259 while (1) {
260 bool to = false;
262 if (noescape) {
263 ldlinux_auto_boot();
264 continue;
267 cmdline = edit_cmdline("boot:", 1, NULL, cat_help_file, &to);
268 printf("\n");
270 /* return if user only press enter or we timed out */
271 if (!cmdline || cmdline[0] == '\0') {
272 if (to && ontimeoutlen)
273 load_kernel(ontimeout);
274 else
275 ldlinux_auto_boot();
276 } else
277 load_kernel(cmdline);
281 void ldlinux_enter_command(void)
283 enter_cmdline();
287 * Undo the work we did in openconsole().
289 static void __destructor close_console(void)
291 int i;
293 for (i = 0; i <= 2; i++)
294 close(i);
297 void ldlinux_console_init(void)
299 openconsole(&dev_stdcon_r, &dev_ansiserial_w);
302 __export int main(int argc __unused, char **argv)
304 const void *adv;
305 const char *cmdline;
306 size_t count = 0;
307 int retval;
309 ldlinux_console_init();
311 parse_configs(&argv[1]);
313 __syslinux_set_serial_console_info();
315 adv = syslinux_getadv(ADV_BOOTONCE, &count);
316 if (adv && count) {
318 * We apparently have a boot-once set; clear it and
319 * then execute the boot-once.
321 char *src, *dst;
322 size_t i;
324 src = (char *)adv;
325 cmdline = dst = malloc(count + 1);
326 if (!dst) {
327 printf("Failed to allocate memory for ADV\n");
328 ldlinux_enter_command();
331 for (i = 0; i < count; i++)
332 *dst++ = *src++;
333 *dst = '\0'; /* Null-terminate */
335 /* Clear the boot-once data from the ADV */
336 if (!syslinux_setadv(ADV_BOOTONCE, 0, NULL))
337 syslinux_adv_write();
340 * The corresponding longjmp is located in the execute function
341 * after a COM32 module has returned.
343 retval = setjmp(__return_to_command_prompt);
344 if (retval == 0)
345 load_kernel(cmdline); /* Shouldn't return */
346 } else {
347 retval = setjmp(__return_to_command_prompt);
348 if (retval == 0) {
349 if (!forceprompt && !shift_is_held())
350 ldlinux_auto_boot();
352 if (defaultlevel > 1)
353 ldlinux_auto_boot();
357 retval = setjmp(__return_to_command_prompt);
358 ldlinux_enter_command();
359 return 0;