1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
4 *
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use,
9 * copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom
11 * the Software is furnished to do so, subject to the following
12 * conditions:
13 *
14 * The above copyright notice and this permission notice shall
15 * be included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
25 *
26 * ----------------------------------------------------------------------- */
27
28 #include <getkey.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <syslinux/boot.h>
33
34 #define lnetlib_c /* Define the library */
35
36 #include "lua.h"
37 #include "lauxlib.h"
38 #include "lualib.h"
39 #include "syslinux/boot.h"
40 #include "syslinux/loadfile.h"
41 #include "syslinux/linux.h"
42 #include "syslinux/config.h"
43 #include "syslinux/reboot.h"
44
45 int __parse_argv(char ***argv, const char *str);
46
47 #define SYSLINUX_FILE "syslinux_file"
48
49 typedef struct syslinux_file {
50 char *data;
51 char *name;
52 size_t size;
53 } syslinux_file;
54
55 /*
56 * Most code taken from:
57 * com32/modules/linux.c
58 */
59
60 /* Find the last instance of a particular command line argument
61 (which should include the final =; do not use for boolean arguments) */
find_argument(char ** argv,const char * argument)62 static char *find_argument(char **argv, const char *argument)
63 {
64 int la = strlen(argument);
65 char **arg;
66 char *ptr = NULL;
67
68 for (arg = argv; *arg; arg++) {
69 if (!memcmp(*arg, argument, la))
70 ptr = *arg + la;
71 }
72
73 return ptr;
74 }
75
76 /* Get a value with a potential suffix (k/m/g/t/p/e) */
suffix_number(const char * str)77 static unsigned long long suffix_number(const char *str)
78 {
79 char *ep;
80 unsigned long long v;
81 int shift;
82
83 v = strtoull(str, &ep, 0);
84 switch (*ep | 0x20) {
85 case 'k':
86 shift = 10;
87 break;
88 case 'm':
89 shift = 20;
90 break;
91 case 'g':
92 shift = 30;
93 break;
94 case 't':
95 shift = 40;
96 break;
97 case 'p':
98 shift = 50;
99 break;
100 case 'e':
101 shift = 60;
102 break;
103 default:
104 shift = 0;
105 break;
106 }
107 v <<= shift;
108
109 return v;
110 }
111
112 /* Truncate to 32 bits, with saturate */
saturate32(unsigned long long v)113 static inline uint32_t saturate32(unsigned long long v)
114 {
115 return (v > 0xffffffff) ? 0xffffffff : (uint32_t) v;
116 }
117
118 /* Stitch together the command line from a set of argv's */
make_cmdline(char ** argv)119 static char *make_cmdline(char **argv)
120 {
121 char **arg;
122 size_t bytes;
123 char *cmdline, *p;
124
125 bytes = 1; /* Just in case we have a zero-entry cmdline */
126 for (arg = argv; *arg; arg++) {
127 bytes += strlen(*arg) + 1;
128 }
129
130 p = cmdline = malloc(bytes);
131 if (!cmdline)
132 return NULL;
133
134 for (arg = argv; *arg; arg++) {
135 int len = strlen(*arg);
136 memcpy(p, *arg, len);
137 p[len] = ' ';
138 p += len + 1;
139 }
140
141 if (p > cmdline)
142 p--; /* Remove the last space */
143 *p = '\0';
144
145 return cmdline;
146 }
147
sl_run_command(lua_State * L)148 static int sl_run_command(lua_State * L)
149 {
150 const char *cmd = luaL_checkstring(L, 1); /* Reads the string parameter */
151 syslinux_run_command(cmd);
152 return 0;
153 }
154
155 /* do default boot */
sl_run_default(lua_State * L)156 static int sl_run_default(lua_State * L)
157 {
158 /* Preventing GCC to complain against unused L */
159 L=L;
160 syslinux_run_default();
161 return 0;
162 }
163
164 /* do local boot */
sl_local_boot(lua_State * L)165 static int sl_local_boot(lua_State * L)
166 {
167 uint16_t flags = luaL_checkint(L, 1);
168 syslinux_local_boot(flags);
169 return 0;
170 }
171
sl_final_cleanup(lua_State * L)172 static int sl_final_cleanup(lua_State * L)
173 {
174 uint16_t flags = luaL_checkint(L, 1);
175 syslinux_local_boot(flags);
176 return 0;
177 }
178
179 /* boot linux kernel and initrd */
sl_boot_linux(lua_State * L)180 static int sl_boot_linux(lua_State * L)
181 {
182 const char *kernel = luaL_checkstring(L, 1);
183 const char *cmdline = luaL_optstring(L, 2, "");
184 char *initrd;
185 void *kernel_data, *file_data;
186 size_t kernel_len, file_len;
187 struct initramfs *initramfs;
188 char *newcmdline;
189 uint32_t mem_limit = luaL_optint(L, 3, 0);
190 uint16_t video_mode = luaL_optint(L, 4, 0);
191 int ret;
192 char **argv, **argp, *arg, *p;
193
194 (void)mem_limit;
195 (void)video_mode;
196
197 ret = __parse_argv(&argv, cmdline);
198
199 newcmdline = malloc(strlen(kernel) + 12);
200 if (!newcmdline)
201 printf("Mem alloc failed: cmdline\n");
202
203 strcpy(newcmdline, "BOOT_IMAGE=");
204 strcpy(newcmdline + strlen(newcmdline), kernel);
205 argv[0] = newcmdline;
206 argp = argv;
207
208 /* DEBUG
209 for (i=0; i<ret; i++)
210 printf("%d: %s\n", i, argv[i]);
211 */
212
213 newcmdline = make_cmdline(argp);
214 if (!newcmdline)
215 printf("Creating command line failed!\n");
216
217 /* DEBUG
218 printf("Command line: %s\n", newcmdline);
219 msleep(1000);
220 */
221
222 printf("Loading kernel %s...\n", kernel);
223 if (loadfile(kernel, &kernel_data, &kernel_len))
224 printf("failed!\n");
225 else
226 printf("ok\n");
227
228 initramfs = initramfs_init();
229 if (!initramfs)
230 printf("Initializing initrd failed!\n");
231
232 if ((arg = find_argument(argp, "initrd="))) {
233 do {
234 p = strchr(arg, ',');
235 if (p)
236 *p = '\0';
237
238 initrd = arg;
239 printf("Loading initrd %s... ", initrd);
240 if (initramfs_load_archive(initramfs, initrd)) {
241 printf("failed!\n");
242 }
243 printf("ok\n");
244
245 if (p)
246 *p++ = ',';
247 } while ((arg = p));
248 }
249
250 ret = syslinux_boot_linux(kernel_data, kernel_len, initramfs, NULL, newcmdline);
251
252 printf("syslinux_boot_linux returned %d\n", ret);
253
254 return 0;
255 }
256
257 /* sleep for sec seconds */
sl_sleep(lua_State * L)258 static int sl_sleep(lua_State * L)
259 {
260 unsigned int sec = luaL_checkint(L, 1);
261 sleep(sec);
262 return 0;
263 }
264
265 /* sleep for msec milliseconds */
sl_msleep(lua_State * L)266 static int sl_msleep(lua_State * L)
267 {
268 unsigned int msec = luaL_checkint(L, 1);
269 msleep(msec);
270 return 0;
271 }
272
sl_run_kernel_image(lua_State * L)273 static int sl_run_kernel_image(lua_State * L)
274 {
275 const char *filename = luaL_checkstring(L, 1);
276 const char *cmdline = luaL_checkstring(L, 2);
277 uint32_t ipappend_flags = luaL_checkint(L, 3);
278 uint32_t type = luaL_checkint(L, 4);
279
280 syslinux_run_kernel_image(filename, cmdline, ipappend_flags, type);
281 return 0;
282 }
283
sl_loadfile(lua_State * L)284 static int sl_loadfile(lua_State * L)
285 {
286 const char *filename = luaL_checkstring(L, 1);
287 syslinux_file *file;
288
289 void *file_data;
290 size_t file_len;
291
292 if (loadfile(filename, &file_data, &file_len)) {
293 lua_pushstring(L, "Could not load file");
294 lua_error(L);
295 }
296
297 file = malloc(sizeof(syslinux_file));
298 strlcpy(file->name,filename,sizeof(syslinux_file));
299 file->size = file_len;
300 file->data = file_data;
301
302 lua_pushlightuserdata(L, file);
303 luaL_getmetatable(L, SYSLINUX_FILE);
304 lua_setmetatable(L, -2);
305
306 return 1;
307 }
308
sl_filesize(lua_State * L)309 static int sl_filesize(lua_State * L)
310 {
311 const syslinux_file *file = luaL_checkudata(L, 1, SYSLINUX_FILE);
312
313 lua_pushinteger(L, file->size);
314
315 return 1;
316 }
317
sl_filename(lua_State * L)318 static int sl_filename(lua_State * L)
319 {
320 const syslinux_file *file = luaL_checkudata(L, 1, SYSLINUX_FILE);
321
322 lua_pushstring(L, file->name);
323
324 return 1;
325 }
326
sl_initramfs_init(lua_State * L)327 static int sl_initramfs_init(lua_State * L)
328 {
329 struct initramfs *initramfs;
330
331 initramfs = initramfs_init();
332 if (!initramfs)
333 printf("Initializing initrd failed!\n");
334
335 lua_pushlightuserdata(L, initramfs);
336 luaL_getmetatable(L, SYSLINUX_FILE);
337 lua_setmetatable(L, -2);
338
339 return 1;
340 }
341
sl_initramfs_load_archive(lua_State * L)342 static int sl_initramfs_load_archive(lua_State * L)
343 {
344 struct initramfs *initramfs = luaL_checkudata(L, 1, SYSLINUX_FILE);
345 const char *filename = luaL_checkstring(L, 2);
346
347 if (initramfs_load_archive(initramfs, filename)) {
348 printf("failed!\n");
349 }
350
351 return 0;
352 }
353
sl_initramfs_add_file(lua_State * L)354 static int sl_initramfs_add_file(lua_State * L)
355 {
356 struct initramfs *initramfs = luaL_checkudata(L, 1, SYSLINUX_FILE);
357 const char *filename = luaL_checkstring(L, 2);
358 void *file_data = NULL;
359 size_t file_len = 0;
360
361 return initramfs_add_file(initramfs, file_data, file_len, file_len,
362 filename, 0, 0755);
363 }
364
sl_boot_it(lua_State * L)365 static int sl_boot_it(lua_State * L)
366 {
367 const syslinux_file *kernel = luaL_checkudata(L, 1, SYSLINUX_FILE);
368 struct initramfs *initramfs = luaL_checkudata(L, 2, SYSLINUX_FILE);
369 const char *cmdline = luaL_optstring(L, 3, "");
370 uint32_t mem_limit = luaL_optint(L, 4, 0);
371 uint16_t video_mode = luaL_optint(L, 5, 0);
372 /* Preventing gcc to complain about unused variables */
373 (void)video_mode;
374 (void)mem_limit;
375
376 return syslinux_boot_linux(kernel->data, kernel->size,
377 initramfs, NULL, (char *)cmdline);
378 }
379
sl_config_file(lua_State * L)380 static int sl_config_file(lua_State * L)
381 {
382 const char *config_file = syslinux_config_file();
383 lua_pushstring(L, config_file);
384 return 1;
385 }
386
sl_reboot(lua_State * L)387 static int sl_reboot(lua_State * L)
388 {
389 int warm_boot = luaL_optint(L, 1, 0);
390 /* explicitly convert it to 1 or 0 */
391 warm_boot = warm_boot? 1 : 0;
392 syslinux_reboot(warm_boot);
393 return 0;
394 }
395
sl_ipappend_strs(lua_State * L)396 static int sl_ipappend_strs(lua_State * L)
397 {
398 int i;
399 const struct syslinux_ipappend_strings *ip_strs = syslinux_ipappend_strings();
400 lua_newtable(L);
401 for (i = 0; i < ip_strs->count; i++) {
402 lua_pushinteger(L, i + 1);
403 lua_pushstring(L, ip_strs->ptr[i]);
404 lua_settable(L,-3);
405 }
406 return 1;
407 }
408
sl_derivative(lua_State * L)409 static int sl_derivative(lua_State * L)
410 {
411 const struct syslinux_version *sv;
412
413 sv = syslinux_version();
414
415 switch (sv->filesystem) {
416 case SYSLINUX_FS_SYSLINUX:
417 lua_pushstring(L, "SYSLINUX");
418 break;
419 case SYSLINUX_FS_PXELINUX:
420 lua_pushstring(L, "PXELINUX");
421 break;
422 case SYSLINUX_FS_ISOLINUX:
423 lua_pushstring(L, "ISOLINUX");
424 break;
425 case SYSLINUX_FS_UNKNOWN:
426 default:
427 lua_pushstring(L, "Unknown Syslinux derivative");
428 break;
429 }
430
431 return 1;
432 }
433
sl_version(lua_State * L)434 static int sl_version(lua_State * L)
435 {
436 const struct syslinux_version *sv;
437
438 sv = syslinux_version();
439 lua_pushstring(L, sv->version_string);
440
441 return 1;
442 }
443
sl_get_key(lua_State * L)444 static int sl_get_key (lua_State * L)
445 {
446 int timeout = luaL_checkint (L, 1);
447 lua_pushinteger (L, get_key (stdin, timeout));
448 return 1;
449 }
450
sl_KEY_CTRL(lua_State * L)451 static int sl_KEY_CTRL (lua_State * L)
452 {
453 lua_pushinteger (L, KEY_CTRL (luaL_checkint (L, 1)));
454 return 1;
455 }
456
457 static const luaL_Reg syslinuxlib[] = {
458 {"run_command", sl_run_command},
459 {"run_default", sl_run_default},
460 {"local_boot", sl_local_boot},
461 {"final_cleanup", sl_final_cleanup},
462 {"boot_linux", sl_boot_linux},
463 {"run_kernel_image", sl_run_kernel_image},
464 {"sleep", sl_sleep},
465 {"msleep", sl_msleep},
466 {"loadfile", sl_loadfile},
467 {"filesize", sl_filesize},
468 {"filename", sl_filename},
469 {"initramfs_init", sl_initramfs_init},
470 {"initramfs_load_archive", sl_initramfs_load_archive},
471 {"initramfs_add_file", sl_initramfs_add_file},
472 {"boot_it", sl_boot_it},
473 {"config_file", sl_config_file},
474 {"ipappend_strs", sl_ipappend_strs},
475 {"reboot", sl_reboot},
476 {"derivative", sl_derivative},
477 {"version", sl_version},
478 {"get_key", sl_get_key},
479 {"KEY_CTRL", sl_KEY_CTRL},
480 {NULL, NULL}
481 };
482
483 /* This defines a function that opens up your library. */
484
luaopen_syslinux(lua_State * L)485 LUALIB_API int luaopen_syslinux(lua_State * L)
486 {
487
488 luaL_newmetatable(L, SYSLINUX_FILE);
489
490 luaL_newlib(L, syslinuxlib);
491
492 lua_newtable (L);
493 #define export_key(x) lua_pushinteger (L, KEY_##x); lua_setfield (L, -2, #x);
494 export_key (NONE);
495 export_key (BACKSPACE);
496 export_key (TAB);
497 export_key (ENTER);
498 export_key (ESC);
499 export_key (DEL);
500 export_key (F1);
501 export_key (F2);
502 export_key (F3);
503 export_key (F4);
504 export_key (F5);
505 export_key (F6);
506 export_key (F7);
507 export_key (F8);
508 export_key (F9);
509 export_key (F10);
510 export_key (F11);
511 export_key (F12);
512 export_key (UP);
513 export_key (DOWN);
514 export_key (LEFT);
515 export_key (RIGHT);
516 export_key (PGUP);
517 export_key (PGDN);
518 export_key (HOME);
519 export_key (END);
520 export_key (INSERT);
521 export_key (DELETE);
522 lua_setfield (L, -2, "KEY");
523
524 return 1;
525 }
526