cf0189f91137abed9e06b74b7492d604ebea1ef1
[profile/ivi/syslinux.git] / com32 / lua / src / syslinux.c
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 <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <syslinux/boot.h>
32
33 #define lnetlib_c               /* Define the library */
34
35 #include "lua.h"
36 #include "lauxlib.h"
37 #include "lualib.h"
38 #include "syslinux/boot.h"
39 #include "syslinux/loadfile.h"
40 #include "syslinux/linux.h"
41 #include "../../cmenu/libmenu/com32io.h"
42
43 int __parse_argv(char ***argv, const char *str);
44
45 #define SYSLINUX_FILE "syslinux_file"
46
47 typedef struct syslinux_file {
48     char *data;
49     char *name;
50     size_t size;
51 } syslinux_file;
52
53 /*
54  * Most code taken from:
55  *      com32/modules/linux.c
56  */
57
58 /* Find the last instance of a particular command line argument
59    (which should include the final =; do not use for boolean arguments) */
60 static char *find_argument(char **argv, const char *argument)
61 {
62     int la = strlen(argument);
63     char **arg;
64     char *ptr = NULL;
65
66     for (arg = argv; *arg; arg++) {
67         if (!memcmp(*arg, argument, la))
68             ptr = *arg + la;
69     }
70
71     return ptr;
72 }
73
74 /* Get a value with a potential suffix (k/m/g/t/p/e) */
75 static unsigned long long suffix_number(const char *str)
76 {
77     char *ep;
78     unsigned long long v;
79     int shift;
80
81     v = strtoull(str, &ep, 0);
82     switch (*ep | 0x20) {
83     case 'k':
84         shift = 10;
85         break;
86     case 'm':
87         shift = 20;
88         break;
89     case 'g':
90         shift = 30;
91         break;
92     case 't':
93         shift = 40;
94         break;
95     case 'p':
96         shift = 50;
97         break;
98     case 'e':
99         shift = 60;
100         break;
101     default:
102         shift = 0;
103         break;
104     }
105     v <<= shift;
106
107     return v;
108 }
109
110 /* Truncate to 32 bits, with saturate */
111 static inline uint32_t saturate32(unsigned long long v)
112 {
113     return (v > 0xffffffff) ? 0xffffffff : (uint32_t) v;
114 }
115
116 /* Stitch together the command line from a set of argv's */
117 static char *make_cmdline(char **argv)
118 {
119     char **arg;
120     size_t bytes;
121     char *cmdline, *p;
122
123     bytes = 1;                  /* Just in case we have a zero-entry cmdline */
124     for (arg = argv; *arg; arg++) {
125         bytes += strlen(*arg) + 1;
126     }
127
128     p = cmdline = malloc(bytes);
129     if (!cmdline)
130         return NULL;
131
132     for (arg = argv; *arg; arg++) {
133         int len = strlen(*arg);
134         memcpy(p, *arg, len);
135         p[len] = ' ';
136         p += len + 1;
137     }
138
139     if (p > cmdline)
140         p--;                    /* Remove the last space */
141     *p = '\0';
142
143     return cmdline;
144 }
145
146 static int sl_run_command(lua_State * L)
147 {
148     const char *cmd = luaL_checkstring(L, 1);   /* Reads the string parameter */
149     syslinux_run_command(cmd);
150     return 0;
151 }
152
153 /* do default boot */
154 static int sl_run_default(lua_State * L)
155 {
156     syslinux_run_default();
157     return 0;
158 }
159
160 /* do local boot */
161 static int sl_local_boot(lua_State * L)
162 {
163     uint16_t flags = luaL_checkint(L, 1);
164     syslinux_local_boot(flags);
165     return 0;
166 }
167
168 static int sl_final_cleanup(lua_State * L)
169 {
170     uint16_t flags = luaL_checkint(L, 1);
171     syslinux_local_boot(flags);
172     return 0;
173 }
174
175 /* boot linux kernel and initrd */
176 static int sl_boot_linux(lua_State * L)
177 {
178     const char *kernel = luaL_checkstring(L, 1);
179     const char *cmdline = luaL_optstring(L, 2, "");
180     char *initrd;
181     void *kernel_data, *file_data;
182     size_t kernel_len, file_len;
183     struct initramfs *initramfs;
184     char *newcmdline;
185     uint32_t mem_limit = luaL_optint(L, 3, 0);
186     uint16_t video_mode = luaL_optint(L, 4, 0);
187 //  int ret, i;
188     int ret;
189     char **argv, **argp, *arg, *p;
190
191     ret = __parse_argv(&argv, cmdline);
192
193     newcmdline = malloc(strlen(kernel) + 12);
194     if (!newcmdline)
195         printf("Mem alloc failed: cmdline\n");
196
197     strcpy(newcmdline, "BOOT_IMAGE=");
198     strcpy(newcmdline + strlen(newcmdline), kernel);
199     argv[0] = newcmdline;
200     argp = argv;
201
202     /* DEBUG
203        for (i=0; i<ret; i++)
204        printf("%d: %s\n", i, argv[i]);
205      */
206
207     newcmdline = make_cmdline(argp);
208     if (!newcmdline)
209         printf("Creating command line failed!\n");
210
211     /* DEBUG
212        printf("Command line: %s\n", newcmdline);
213        msleep(1000);
214      */
215
216     /* Look for specific command-line arguments we care about */
217     if ((arg = find_argument(argp, "mem=")))
218         mem_limit = saturate32(suffix_number(arg));
219
220     if ((arg = find_argument(argp, "vga="))) {
221         switch (arg[0] | 0x20) {
222         case 'a':               /* "ask" */
223             video_mode = 0xfffd;
224             break;
225         case 'e':               /* "ext" */
226             video_mode = 0xfffe;
227             break;
228         case 'n':               /* "normal" */
229             video_mode = 0xffff;
230             break;
231         default:
232             video_mode = strtoul(arg, NULL, 0);
233             break;
234         }
235     }
236
237     printf("Loading kernel %s...\n", kernel);
238     if (loadfile(kernel, &kernel_data, &kernel_len))
239         printf("failed!\n");
240     else
241         printf("ok\n");
242
243     initramfs = initramfs_init();
244     if (!initramfs)
245         printf("Initializing initrd failed!\n");
246
247     if ((arg = find_argument(argp, "initrd="))) {
248         do {
249             p = strchr(arg, ',');
250             if (p)
251                 *p = '\0';
252
253             initrd = arg;
254             printf("Loading initrd %s... ", initrd);
255             if (initramfs_load_archive(initramfs, initrd)) {
256                 printf("failed!\n");
257             }
258             printf("ok\n");
259
260             if (p)
261                 *p++ = ',';
262         } while ((arg = p));
263     }
264
265     if (!loadfile("/testfile1", &file_data, &file_len)) {
266         if (initramfs_add_file(initramfs, file_data, file_len, file_len,
267                                "/testfile1", 0, 0755))
268             printf("Adding extra file failed\n");
269     } else
270         printf("Loading extra file failed\n");
271
272     /* DEBUG
273        msleep(10000);
274      */
275
276     ret = syslinux_boot_linux(kernel_data, kernel_len, initramfs, newcmdline);
277
278     printf("syslinux_boot_linux returned %d\n", ret);
279
280     return 0;
281 }
282
283 /* sleep for sec seconds */
284 static int sl_sleep(lua_State * L)
285 {
286     unsigned int sec = luaL_checkint(L, 1);
287     sleep(sec);
288     return 0;
289 }
290
291 /* sleep for msec milliseconds */
292 static int sl_msleep(lua_State * L)
293 {
294     unsigned int msec = luaL_checkint(L, 1);
295     msleep(msec);
296     return 0;
297 }
298
299 static int sl_run_kernel_image(lua_State * L)
300 {
301     const char *filename = luaL_checkstring(L, 1);
302     const char *cmdline = luaL_checkstring(L, 2);
303     uint32_t ipappend_flags = luaL_checkint(L, 3);
304     uint32_t type = luaL_checkint(L, 4);
305
306     syslinux_run_kernel_image(filename, cmdline, ipappend_flags, type);
307     return 0;
308 }
309
310 static int sl_loadfile(lua_State * L)
311 {
312     const char *filename = luaL_checkstring(L, 1);
313     syslinux_file *file;
314
315     void *file_data;
316     size_t file_len;
317
318     if (loadfile(filename, &file_data, &file_len)) {
319         lua_pushstring(L, "Could not load file");
320         lua_error(L);
321     }
322
323     file = malloc(sizeof(syslinux_file));
324     file->name = filename;
325     file->size = file_len;
326     file->data = file_data;
327
328     lua_pushlightuserdata(L, file);
329     luaL_getmetatable(L, SYSLINUX_FILE);
330     lua_setmetatable(L, -2);
331
332     return 1;
333 }
334
335 static int sl_filesize(lua_State * L)
336 {
337     const syslinux_file *file = luaL_checkudata(L, 1, SYSLINUX_FILE);
338
339     lua_pushinteger(L, file->size);
340
341     return 1;
342 }
343
344 static int sl_filename(lua_State * L)
345 {
346     const syslinux_file *file = luaL_checkudata(L, 1, SYSLINUX_FILE);
347
348     lua_pushstring(L, file->name);
349
350     return 1;
351 }
352
353 static int sl_initramfs_init(lua_State * L)
354 {
355     struct initramfs *initramfs;
356
357     initramfs = initramfs_init();
358     if (!initramfs)
359         printf("Initializing initrd failed!\n");
360
361     lua_pushlightuserdata(L, initramfs);
362     luaL_getmetatable(L, SYSLINUX_FILE);
363     lua_setmetatable(L, -2);
364
365     return 1;
366 }
367
368 static int sl_initramfs_load_archive(lua_State * L)
369 {
370     const struct initramfs *initramfs = luaL_checkudata(L, 1, SYSLINUX_FILE);
371     const char *filename = luaL_checkstring(L, 2);
372
373     if (initramfs_load_archive(initramfs, filename)) {
374         printf("failed!\n");
375     }
376
377     return 0;
378 }
379
380 static int sl_initramfs_add_file(lua_State * L)
381 {
382     const struct initramfs *initramfs = luaL_checkudata(L, 1, SYSLINUX_FILE);
383     const char *filename = luaL_checkstring(L, 2);
384     void *file_data;
385     size_t file_len = 0;
386
387     if (initramfs_add_file(initramfs, file_data, file_len, file_len,
388                            "/testfile1", 0, 0755))
389
390         return 0;
391 }
392
393 static int sl_boot_it(lua_State * L)
394 {
395     const syslinux_file *kernel = luaL_checkudata(L, 1, SYSLINUX_FILE);
396     const struct initramfs *initramfs = luaL_checkudata(L, 2, SYSLINUX_FILE);
397     const char *cmdline = luaL_optstring(L, 3, "");
398     uint32_t mem_limit = luaL_optint(L, 4, 0);
399     uint16_t video_mode = luaL_optint(L, 5, 0);
400     int ret;
401
402     ret = syslinux_boot_linux(kernel->data, kernel->size, initramfs, cmdline);
403
404     return 0;
405 }
406
407 static const luaL_reg syslinuxlib[] = {
408     {"run_command", sl_run_command},
409     {"run_default", sl_run_default},
410     {"local_boot", sl_local_boot},
411     {"final_cleanup", sl_final_cleanup},
412     {"boot_linux", sl_boot_linux},
413     {"run_kernel_image", sl_run_kernel_image},
414     {"sleep", sl_sleep},
415     {"msleep", sl_msleep},
416     {"loadfile", sl_loadfile},
417     {"filesize", sl_filesize},
418     {"filename", sl_filename},
419     {"initramfs_init", sl_initramfs_init},
420     {"initramfs_load_archive", sl_initramfs_load_archive},
421     {"initramfs_add_file", sl_initramfs_add_file},
422     {"boot_it", sl_boot_it},
423     {NULL, NULL}
424 };
425
426 /* This defines a function that opens up your library. */
427
428 LUALIB_API int luaopen_syslinux(lua_State * L)
429 {
430
431     luaL_newmetatable(L, SYSLINUX_FILE);
432
433     luaL_openlib(L, LUA_SYSLINUXLIBNAME, syslinuxlib, 0);
434     return 1;
435 }