elflink: Replace __intcall() with direct function calls
[syslinux.git] / com32 / elflink / ldlinux / ldlinux.c
blob073f11166b52805885e079a15c90996f7a622b8d
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"
16 #include <sys/module.h>
18 struct file_ext {
19 const char *name;
20 enum kernel_type type;
23 static const struct file_ext file_extensions[] = {
24 { ".com", IMAGE_TYPE_COMBOOT },
25 { ".cbt", IMAGE_TYPE_COMBOOT },
26 { ".c32", IMAGE_TYPE_COM32 },
27 { ".img", IMAGE_TYPE_FDIMAGE },
28 { ".bss", IMAGE_TYPE_BSS },
29 { ".bin", IMAGE_TYPE_BOOT },
30 { ".bs", IMAGE_TYPE_BOOT },
31 { ".0", IMAGE_TYPE_PXE },
32 { NULL, 0 },
36 * Return a pointer to one byte after the last character of the
37 * command.
39 static inline const char *find_command(const char *str)
41 const char *p;
43 p = str;
44 while (*p && !my_isspace(*p))
45 p++;
46 return p;
49 uint32_t parse_image_type(const char *kernel)
51 const struct file_ext *ext;
52 const char *p;
53 int len;
55 /* Find the end of the command */
56 p = find_command(kernel);
57 len = p - kernel;
59 for (ext = file_extensions; ext->name; ext++) {
60 int elen = strlen(ext->name);
62 if (!strncmp(kernel + len - elen, ext->name, elen))
63 return ext->type;
66 /* use IMAGE_TYPE_KERNEL as default */
67 return IMAGE_TYPE_KERNEL;
71 * Returns the kernel name with file extension if one wasn't present.
73 static const char *get_extension(const char *kernel)
75 const struct file_ext *ext;
76 const char *p;
77 int len;
79 /* Find the end of the command */
80 p = find_command(kernel);
81 len = p - kernel;
83 for (ext = file_extensions; ext->name; ext++) {
84 char *str;
85 int elen = strlen(ext->name);
86 int fd;
88 str = malloc(len + elen + 1);
90 strncpy(str, kernel, len);
91 strncpy(str + len, ext->name, elen);
92 str[len + elen] = '\0';
94 fd = searchdir(str);
95 free(str);
97 if (fd >= 0)
98 return ext->name;
101 return NULL;
104 static 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 memcpy(k + len, ext, elen);
125 /* Copy the rest of the command line */
126 strcpy(k + len + elen, p);
128 k[len + elen + strlen(p)] = '\0';
130 return k;
134 * Attempt to load a kernel after deciding what type of image it is.
136 * We only return from this function if something went wrong loading
137 * the the kernel. If we return the caller should call enter_cmdline()
138 * so that the user can help us out.
140 void load_kernel(const char *command_line)
142 struct menu_entry *me;
143 const char *cmdline;
144 const char *kernel;
145 uint32_t type;
147 kernel = strdup(command_line);
148 if (!kernel)
149 goto bad_kernel;
151 /* Virtual kernel? */
152 me = find_label(kernel);
153 if (me) {
154 type = parse_image_type(me->cmdline);
156 execute(me->cmdline, type);
157 /* We shouldn't return */
158 goto bad_kernel;
161 if (!allowimplicit)
162 goto bad_implicit;
164 /* Insert a null character to ignore any user-specified options */
165 if (!allowoptions) {
166 char *p = (char *)find_command(kernel);
167 *p = '\0';
170 type = parse_image_type(kernel);
171 if (type == IMAGE_TYPE_KERNEL) {
172 const char *ext;
175 * Automatically lookup the extension if one wasn't
176 * supplied by the user.
178 ext = get_extension(kernel);
179 if (ext) {
180 const char *k;
182 k = apply_extension(kernel, ext);
183 if (!k)
184 goto bad_kernel;
186 free((void *)kernel);
187 kernel = k;
189 type = parse_image_type(kernel);
193 execute(kernel, type);
194 free((void *)kernel);
196 bad_implicit:
197 bad_kernel:
199 * If we fail to boot the kernel execute the "onerror" command
200 * line.
202 if (onerrorlen) {
203 rsprintf(&cmdline, "%s %s", onerror, default_cmd);
204 execute(cmdline, IMAGE_TYPE_COM32);
208 static void enter_cmdline(void)
210 const char *cmdline;
212 /* Enter endless command line prompt, should support "exit" */
213 while (1) {
214 cmdline = edit_cmdline("boot:", 1, NULL, cat_help_file);
215 printf("\n");
217 /* return if user only press enter or we timed out */
218 if (!cmdline || cmdline[0] == '\0')
219 return;
221 load_kernel(cmdline);
225 int main(int argc __unused, char **argv __unused)
227 const void *adv;
228 const char *cmdline;
229 size_t count = 0;
230 char *config_argv[2] = { NULL, NULL };
232 openconsole(&dev_rawcon_r, &dev_ansiserial_w);
234 if (ConfigName[0])
235 config_argv[0] = ConfigName;
237 parse_configs(config_argv);
239 adv = syslinux_getadv(ADV_BOOTONCE, &count);
240 if (adv && count) {
242 * We apparently have a boot-once set; clear it and
243 * then execute the boot-once.
245 char *src, *dst;
246 size_t i;
248 src = (char *)adv;
249 cmdline = dst = malloc(count + 1);
250 if (!dst) {
251 printf("Failed to allocate memory for ADV\n");
252 goto cmdline;
255 for (i = 0; i < count; i++)
256 *dst++ = *src++;
257 *dst = '\0'; /* Null-terminate */
259 /* Clear the boot-once data from the ADV */
260 if (!syslinux_setadv(ADV_BOOTONCE, 0, NULL))
261 syslinux_adv_write();
263 load_kernel(cmdline); /* Shouldn't return */
264 goto cmdline;
267 /* TODO: Check KbdFlags? */
269 if (forceprompt)
270 goto cmdline;
272 cmdline = default_cmd;
273 auto_boot:
275 * Auto boot
277 if (defaultlevel || noescape) {
278 if (defaultlevel) {
279 load_kernel(cmdline); /* Shouldn't return */
280 } else {
281 printf("No DEFAULT or UI configuration directive found!\n");
283 if (noescape)
284 kaboom();
288 cmdline:
289 /* Only returns if the user pressed enter or input timed out */
290 enter_cmdline();
292 cmdline = ontimeoutlen ? ontimeout : default_cmd;
294 goto auto_boot;
296 return 0;