Merging upstream version 5.01+dfsg.
[syslinux-debian/hramrach.git] / com32 / elflink / ldlinux / ldlinux.c
bloba8b1b386f0746d000a3fd4f03cd94f5d06368477
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 },
35 * Return a pointer to one byte after the last character of the
36 * command.
38 static inline const char *find_command(const char *str)
40 const char *p;
42 p = str;
43 while (*p && !my_isspace(*p))
44 p++;
45 return p;
48 __export uint32_t parse_image_type(const char *kernel)
50 const struct file_ext *ext;
51 const char *p;
52 int len;
54 /* Find the end of the command */
55 p = find_command(kernel);
56 len = p - kernel;
58 for (ext = file_extensions; ext->name; ext++) {
59 int elen = strlen(ext->name);
61 if (!strncmp(kernel + len - elen, ext->name, elen))
62 return ext->type;
65 /* use IMAGE_TYPE_KERNEL as default */
66 return IMAGE_TYPE_KERNEL;
70 * Returns the kernel name with file extension if one wasn't present.
72 static const char *get_extension(const char *kernel)
74 const struct file_ext *ext;
75 const char *p;
76 int len;
78 /* Find the end of the command */
79 p = find_command(kernel);
80 len = p - kernel;
82 for (ext = file_extensions; ext->name; ext++) {
83 char *str;
84 int elen = strlen(ext->name);
85 FILE *f;
87 str = malloc(len + elen + 1);
89 strncpy(str, kernel, len);
90 strncpy(str + len, ext->name, elen);
91 str[len + elen] = '\0';
92 f = findpath(str);
93 free(str);
95 if (f) {
96 fclose(f);
97 return ext->name;
101 return NULL;
104 const char *apply_extension(const char *kernel, const char *ext)
106 const char *p;
107 char *k;
108 int len = strlen(kernel);
109 int elen = strlen(ext);
111 k = malloc(len + elen + 1);
112 if (!k)
113 return NULL;
115 p = find_command(kernel);
117 len = p - kernel;
119 /* Copy just the kernel name */
120 memcpy(k, kernel, len);
122 /* Append the extension */
123 if (strncmp(p - elen, ext, elen)) {
124 memcpy(k + len, ext, elen);
125 len += elen;
128 /* Copy the rest of the command line */
129 strcpy(k + len, p);
131 k[len + strlen(p)] = '\0';
133 return k;
137 * Attempt to load a kernel after deciding what type of image it is.
139 * We only return from this function if something went wrong loading
140 * the the kernel. If we return the caller should call enter_cmdline()
141 * so that the user can help us out.
143 __export void load_kernel(const char *command_line)
145 struct menu_entry *me;
146 const char *cmdline;
147 const char *kernel;
148 uint32_t type;
150 kernel = strdup(command_line);
151 if (!kernel)
152 goto bad_kernel;
154 /* Virtual kernel? */
155 me = find_label(kernel);
156 if (me) {
157 type = parse_image_type(me->cmdline);
159 execute(me->cmdline, type);
160 /* We shouldn't return */
161 goto bad_kernel;
164 if (!allowimplicit)
165 goto bad_implicit;
167 /* Insert a null character to ignore any user-specified options */
168 if (!allowoptions) {
169 char *p = (char *)find_command(kernel);
170 *p = '\0';
173 type = parse_image_type(kernel);
174 if (type == IMAGE_TYPE_KERNEL) {
175 const char *ext;
178 * Automatically lookup the extension if one wasn't
179 * supplied by the user.
181 ext = get_extension(kernel);
182 if (ext) {
183 const char *k;
185 k = apply_extension(kernel, ext);
186 if (!k)
187 goto bad_kernel;
189 free((void *)kernel);
190 kernel = k;
192 type = parse_image_type(kernel);
196 execute(kernel, type);
197 free((void *)kernel);
199 bad_implicit:
200 bad_kernel:
202 * If we fail to boot the kernel execute the "onerror" command
203 * line.
205 if (onerrorlen) {
206 me = find_label(onerror);
207 if (me)
208 rsprintf(&cmdline, "%s %s", me->cmdline, default_cmd);
209 else
210 rsprintf(&cmdline, "%s %s", onerror, default_cmd);
212 type = parse_image_type(cmdline);
213 execute(cmdline, type);
218 * If this function returns you must call ldinux_enter_command() to
219 * preserve the 4.0x behaviour.
221 void ldlinux_auto_boot(void)
223 if (!defaultlevel) {
224 if (strlen(ConfigName))
225 printf("No DEFAULT or UI configuration directive found!\n");
226 if (noescape)
227 kaboom();
228 } else
229 load_kernel(default_cmd);
232 static void enter_cmdline(void)
234 const char *cmdline;
236 /* Enter endless command line prompt, should support "exit" */
237 while (1) {
238 bool to = false;
240 if (noescape) {
241 ldlinux_auto_boot();
242 continue;
245 cmdline = edit_cmdline("boot:", 1, NULL, cat_help_file, &to);
246 printf("\n");
248 /* return if user only press enter or we timed out */
249 if (!cmdline || cmdline[0] == '\0') {
250 if (to && ontimeoutlen)
251 load_kernel(ontimeout);
252 else
253 ldlinux_auto_boot();
254 } else
255 load_kernel(cmdline);
259 void ldlinux_enter_command(void)
261 enter_cmdline();
265 * Undo the work we did in openconsole().
267 static void __destructor close_console(void)
269 int i;
271 for (i = 0; i <= 2; i++)
272 close(i);
275 void ldlinux_console_init(void)
277 openconsole(&dev_stdcon_r, &dev_ansiserial_w);
280 __export int main(int argc __unused, char **argv __unused)
282 const void *adv;
283 const char *cmdline;
284 size_t count = 0;
285 char *config_argv[2] = { NULL, NULL };
287 ldlinux_console_init();
289 if (ConfigName[0])
290 config_argv[0] = ConfigName;
292 parse_configs(config_argv);
294 __syslinux_set_serial_console_info();
296 adv = syslinux_getadv(ADV_BOOTONCE, &count);
297 if (adv && count) {
299 * We apparently have a boot-once set; clear it and
300 * then execute the boot-once.
302 char *src, *dst;
303 size_t i;
305 src = (char *)adv;
306 cmdline = dst = malloc(count + 1);
307 if (!dst) {
308 printf("Failed to allocate memory for ADV\n");
309 ldlinux_enter_command();
312 for (i = 0; i < count; i++)
313 *dst++ = *src++;
314 *dst = '\0'; /* Null-terminate */
316 /* Clear the boot-once data from the ADV */
317 if (!syslinux_setadv(ADV_BOOTONCE, 0, NULL))
318 syslinux_adv_write();
320 load_kernel(cmdline); /* Shouldn't return */
321 ldlinux_enter_command();
324 /* TODO: Check KbdFlags? */
325 if (!forceprompt)
326 ldlinux_auto_boot();
328 if (defaultlevel > 1)
329 ldlinux_auto_boot();
331 ldlinux_enter_command();
332 return 0;