• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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