Centralize shift_is_held(), make it work to force the command line
[syslinux.git] / com32 / elflink / ldlinux / ldlinux.c
blob9b01dd3aac8111a9e935cec21a1ad426be4685b3
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 const char *args;
158 char *cmd;
159 size_t len = strlen(me->cmdline) + 1;
161 /* Find the end of the command */
162 args = find_command(kernel);
163 while(*args && my_isspace(*args))
164 args++;
166 if (strlen(args))
167 len += strlen(args) + 1; /* +1 for space (' ') */
169 cmd = malloc(len);
170 if (!cmd)
171 goto bad_kernel;
173 if (strlen(args))
174 snprintf(cmd, len, "%s %s", me->cmdline, args);
175 else
176 strncpy(cmd, me->cmdline, len);
178 type = parse_image_type(cmd);
179 execute(cmd, type, false);
180 /* We shouldn't return */
181 goto bad_kernel;
184 if (!allowimplicit)
185 goto bad_implicit;
187 /* Insert a null character to ignore any user-specified options */
188 if (!allowoptions) {
189 char *p = (char *)find_command(kernel);
190 *p = '\0';
193 type = parse_image_type(kernel);
194 if (type == IMAGE_TYPE_KERNEL) {
195 const char *ext;
198 * Automatically lookup the extension if one wasn't
199 * supplied by the user.
201 ext = get_extension(kernel);
202 if (ext) {
203 const char *k;
205 k = apply_extension(kernel, ext);
206 if (!k)
207 goto bad_kernel;
209 free((void *)kernel);
210 kernel = k;
212 type = parse_image_type(kernel);
216 execute(kernel, type, true);
217 free((void *)kernel);
219 bad_implicit:
220 bad_kernel:
222 * If we fail to boot the kernel execute the "onerror" command
223 * line.
225 if (onerrorlen) {
226 me = find_label(onerror);
227 if (me)
228 rsprintf(&cmdline, "%s %s", me->cmdline, default_cmd);
229 else
230 rsprintf(&cmdline, "%s %s", onerror, default_cmd);
232 type = parse_image_type(cmdline);
233 execute(cmdline, type, true);
238 * If this function returns you must call ldinux_enter_command() to
239 * preserve the 4.0x behaviour.
241 void ldlinux_auto_boot(void)
243 if (!defaultlevel) {
244 if (strlen(ConfigName))
245 printf("No DEFAULT or UI configuration directive found!\n");
246 if (noescape)
247 kaboom();
248 } else
249 load_kernel(default_cmd);
252 static void enter_cmdline(void)
254 const char *cmdline;
256 /* Enter endless command line prompt, should support "exit" */
257 while (1) {
258 bool to = false;
260 if (noescape) {
261 ldlinux_auto_boot();
262 continue;
265 cmdline = edit_cmdline("boot:", 1, NULL, cat_help_file, &to);
266 printf("\n");
268 /* return if user only press enter or we timed out */
269 if (!cmdline || cmdline[0] == '\0') {
270 if (to && ontimeoutlen)
271 load_kernel(ontimeout);
272 else
273 ldlinux_auto_boot();
274 } else
275 load_kernel(cmdline);
279 void ldlinux_enter_command(void)
281 enter_cmdline();
285 * Undo the work we did in openconsole().
287 static void __destructor close_console(void)
289 int i;
291 for (i = 0; i <= 2; i++)
292 close(i);
295 void ldlinux_console_init(void)
297 openconsole(&dev_stdcon_r, &dev_ansiserial_w);
300 __export int main(int argc __unused, char **argv)
302 const void *adv;
303 const char *cmdline;
304 size_t count = 0;
306 ldlinux_console_init();
308 parse_configs(&argv[1]);
310 __syslinux_set_serial_console_info();
312 adv = syslinux_getadv(ADV_BOOTONCE, &count);
313 if (adv && count) {
315 * We apparently have a boot-once set; clear it and
316 * then execute the boot-once.
318 char *src, *dst;
319 size_t i;
321 src = (char *)adv;
322 cmdline = dst = malloc(count + 1);
323 if (!dst) {
324 printf("Failed to allocate memory for ADV\n");
325 ldlinux_enter_command();
328 for (i = 0; i < count; i++)
329 *dst++ = *src++;
330 *dst = '\0'; /* Null-terminate */
332 /* Clear the boot-once data from the ADV */
333 if (!syslinux_setadv(ADV_BOOTONCE, 0, NULL))
334 syslinux_adv_write();
336 load_kernel(cmdline); /* Shouldn't return */
337 ldlinux_enter_command();
340 if (!forceprompt && !shift_is_held())
341 ldlinux_auto_boot();
343 if (defaultlevel > 1)
344 ldlinux_auto_boot();
346 ldlinux_enter_command();
347 return 0;