2 * GINGE - GINGE Is Not Gp2x Emulator
5 * This work is licensed under the MAME license, see COPYING file for details.
16 #include "../common/host_fb.h"
17 #include "../common/cmn.h"
19 #define PFX "ging_prep: "
20 #define LOADER_STATIC "ginge_sloader"
21 #define LOADER_DYNAMIC "ginge_dyn.sh"
22 #define LAUNCHER "gp2xmenu"
25 #define WRAP_APP "op_runfbapp "
34 static int fb_x, fb_y;
37 static char *sskip(char *p)
39 while (p && *p && isspace(*p))
44 static char *cskip(char *p)
46 while (p && *p && !isspace(*p))
51 static void fb_text_exit(void)
60 static void fb_text_init(void)
62 int ret = host_video_init(&fb_stride, 1);
64 fb_mem = host_video_flip();
71 static void fb_syms_out(void *fbi, int x, int y, int dotsz, int stride, const char *text, int count)
73 int v = -1, n = 0, *p;
77 fb = (char *)fbi + x * dotsz + y * stride;
79 for (i = 0; i < count; i++)
81 for (l = 0; l < 8; l++)
83 #define pix(fdmask,add) \
84 p = (fontdata8x8[((text[i])*8)+l] & fdmask) ? &v : &n; \
85 memcpy(fb + l*stride + add*dotsz, p, dotsz)
101 static void fb_text_out(char *text)
103 int dotsz = 2, w = 320; // hardcoded for now
115 for (; *p && isspace(*p); p++) {
116 if (*p == '\n' || fb_x + dotsz * 8 > w) {
126 if (fb_x + 8 * l > w) {
130 fb_syms_out(fb_mem, fb_x, fb_y, dotsz, fb_stride, p, l);
136 static void fbprintf(int is_err, const char *format, ...)
141 va_start(ap, format);
142 vsnprintf(buff, sizeof(buff), format, ap);
144 fputs(buff, is_err ? stderr : stdout);
149 #define msg(fmt, ...) fbprintf(0, fmt, ##__VA_ARGS__)
150 #define err(fmt, ...) fbprintf(1, fmt, ##__VA_ARGS__)
152 static int id_elf(const char *fname)
155 Elf32_Phdr *phdr = NULL;
159 fi = fopen(fname, "rb");
161 err("open %s: ", fname);
166 if (fread(&hdr, 1, sizeof(hdr), fi) != sizeof(hdr))
169 if (memcmp(hdr.e_ident, ELFMAG "\x01\x01", SELFMAG + 2) != 0)
172 if (hdr.e_phentsize != sizeof(Elf32_Phdr) || hdr.e_phnum == 0)
175 phdr = malloc(hdr.e_phnum * hdr.e_phentsize);
179 if (fread(phdr, hdr.e_phentsize, hdr.e_phnum, fi) != hdr.e_phnum)
184 // do what 'file' does - check for PT_INTERP in program headers
185 for (i = 0; i < hdr.e_phnum; i++) {
186 if (phdr[i].p_type == PT_INTERP) {
198 static void dump_args(FILE *fout, char * const argv[])
203 for (i = 0; argv[i] != NULL; i++) {
208 for (p = argv[i]; *p != 0; p++) {
218 static char *get_arg(char *d, size_t size, char *p)
227 if (len > size - 1) {
228 err(PFX "get_arg: buff to small: %d/%d\n", len, size);
237 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
239 #define CB_ENTRY(x) { x, sizeof(x) - 1 }
243 } conv_blacklist[] = {
245 CB_ENTRY("modprobe"),
247 CB_ENTRY("./cpuctrl_tiny"),
250 static int cmd_in_blacklist(char *cmd)
255 for (i = 0; i < ARRAY_SIZE(conv_blacklist); i++)
256 if (strncmp(cmd, conv_blacklist[i].name, conv_blacklist[i].len) == 0)
262 int main(int argc, char *argv[])
264 static const char out_script[] = "/tmp/ginge_conv.sh";
265 char root_path[512], cwd[512];
266 char **argv_app = NULL;
268 int rerun_gp2xmenu = 1;
269 int quit_if_no_app = 0;
273 for (i = 1; i < argc && argv[i][0] == '-' && argv[i][1] == '-'; i++) {
274 if (strcmp(argv[i], "--cleanup") == 0) {
275 // as loader may crash eny time, restore screen for the menu
276 host_video_init(NULL, 1);
281 if (strcmp(argv[i], "--nomenu") == 0) {
285 if (strcmp(argv[i], "--") == 0) {
290 fprintf(stderr, PFX "ignoring unknown option \"%s\"\n", argv[i]);
296 err("usage: %s [opts] <script|program> [args]\n", argv[0]);
297 err(" --cleanup - restore framebuffer state\n");
298 err(" --nomenu - don't run menu on exit\n");
303 if (getcwd(cwd, sizeof(cwd)) == NULL) {
304 err(PFX "failed to get cwd\n");
308 ret = make_local_path(root_path, sizeof(root_path), "");
310 err(PFX "failed to generate root path\n");
314 fout = fopen(out_script, "w");
316 perror("can't open output script");
320 fprintf(fout, "#!/bin/sh\n");
322 ret = id_elf(argv_app[0]);
323 if (ret == 1 || ret == 2) {
324 if (cmd_in_blacklist(argv_app[0])) {
325 fprintf(stderr, "blacklisted: %s\n", argv_app[0]);
335 fprintf(fout, WRAP_APP "%s%s ", root_path, LOADER_STATIC);
336 dump_args(fout, argv_app);
341 fprintf(fout, WRAP_APP "%s%s \"%s\" ", root_path, LOADER_DYNAMIC, root_path);
342 dump_args(fout, argv_app);
351 fin = fopen(argv_app[0], "r");
356 char buff[512], fname[512], *p, *p2;
358 p = fgets(buff, sizeof(buff), fin);
363 if (p[0] == '#' && p[1] == '!')
371 // things we are sure we want to pass
372 if (*p == '#' || strncmp(p, "export ", 7) == 0)
376 if (strncmp(p, "exec ", 5) == 0)
379 // blacklist some stuff
380 if (strncmp(p, "/sbin/", 6) == 0)
382 else if (strncmp(p, "/bin/", 5) == 0)
386 if (strncmp(p2, "mount ", 6) == 0) {
389 if (strstr(p2, "cramfs")) {
392 p2 = sskip(cskip(p2));
393 p2 = sskip(cskip(p2));
396 err(PFX "cramfs: missing mount file in \"%s\"?\n", p);
399 p2 = get_arg(fname, sizeof(fname), p2);
401 err(PFX "cramfs: missing mount point in \"%s\"?\n", p);
404 get_arg(buff, sizeof(buff), p2);
405 fprintf(fout, "if [ `ls %s | wc -l` -eq 0 ]; then\n", buff);
406 fprintf(fout, " rmdir \"%s\"\n", buff); // cramfsck doesn't want it
407 fprintf(fout, " %stools/cramfsck -x \"%s\" \"%s\"\n", root_path, buff, fname);
408 fprintf(fout, "fi\n");
413 if (cmd_in_blacklist(p2))
417 if (strncmp(p, "cd ", 3) == 0) {
418 get_arg(fname, sizeof(fname), p + 3);
419 if (strncmp(fname, "/usr/gp2x", 9) == 0)
428 // trying to run something from cwd?
429 if ((p[0] == '.' && p[1] == '/') || *p == '/') {
430 get_arg(fname, sizeof(fname), p);
431 p2 = strrchr(fname, '/');
432 if (p2 != NULL && strcmp(p2 + 1, "gp2xmenu") == 0)
438 printf(PFX "prefixing as static: %s", p);
439 fprintf(fout, WRAP_APP "%s%s ", root_path, LOADER_STATIC);
443 printf(PFX "prefixing as dynamic: %s", p);
444 fprintf(fout, WRAP_APP "%s%s \"%s\" ", root_path, LOADER_DYNAMIC, root_path);
460 fprintf(fout, "sync\n");
461 // since we don't know if loader manages to do proper cleanup,
462 // need to wait for it's threads to die
463 fprintf(fout, "sleep 1\n");
464 fprintf(fout, "%sginge_prep --cleanup\n", root_path);
466 if (rerun_gp2xmenu) {
467 fprintf(fout, "cd %s\n", root_path);
468 fprintf(fout, "exec %s%s\n", root_path, LAUNCHER);
473 //msg("starting script..\n");
475 msg("\nsome files need to be unpacked, this may tike a few minutes.\n");
477 msg("Please wait at least while SD LED is active.\n");
480 system("echo ---; cat /tmp/ginge_conv.sh; echo ---");
481 chmod(out_script, S_IRWXU|S_IRWXG|S_IRWXO);
484 execlp(out_script, out_script, NULL);
485 perror("run out_script");
490 // vim:shiftwidth=2:expandtab