emulator: new emulator options are introduced 89/22989/3
authorSeokYeon Hwang <syeon.hwang@samsung.com>
Sun, 15 Jun 2014 10:01:58 +0000 (19:01 +0900)
committerSeokYeon Hwang <syeon.hwang@samsung.com>
Mon, 16 Jun 2014 06:36:36 +0000 (15:36 +0900)
It is experimental feature for now.
This feature need [profile].profile configuration file. That file may be provided another way.

Change-Id: I2bf663eb604b62d7de0e5c603571a7239e0ff235
Signed-off-by: SeokYeon Hwang <syeon.hwang@samsung.com>
tizen/src/Makefile.tizen
tizen/src/emul_state.h
tizen/src/emulator.c
tizen/src/emulator_options.c [new file with mode: 0644]
tizen/src/emulator_options.h [new file with mode: 0644]

index 61cb45d7ea8d8a8669cbb56552b978c518a6cb97..63559d253755a02417108226c024c57f0d3c835e 100644 (file)
@@ -31,7 +31,7 @@ GL_CFLAGS := -Wall -g -O2 -fno-strict-aliasing
 endif
 
 # maru loader
-obj-y += emulator.o emul_state.o maru_err_table.o
+obj-y += emulator.o emulator_options.o emul_state.o maru_err_table.o
 
 # osutil
 obj-y += osutil.o
index 62fe4eb77ddbba60c6bafc739f46c1d84ca9acc6..c2755221984888fb3f2ef078e9f754998984c737 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
  *
- * Contact: 
+ * Contact:
  * SeokYeon Hwang <syeon.hwang@samsung.com>
  * MunKyu Im <munkyu.im@samsung.com>
  * GiWoong Kim <giwoong.kim@samsung.com>
index 76be5fa51fbb45c3a6b90b1a96503a593d3dd106..856b0857ad81193ca294869a6172bbf5911c68da 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <getopt.h>
 
 #include "qemu/config-file.h"
 #include "qemu/sockets.h"
@@ -41,6 +42,7 @@
 #include "emul_state.h"
 #include "guest_debug.h"
 #include "guest_server.h"
+#include "emulator_options.h"
 #include "hw/maru_camera_common.h"
 #include "hw/maru_virtio_touchscreen.h"
 #include "check_gl.h"
@@ -95,6 +97,8 @@ gchar maru_kernel_cmdline[LEN_MARU_KERNEL_CMDLINE];
 gchar bin_path[PATH_MAX] = { 0, };
 gchar log_path[PATH_MAX] = { 0, };
 
+gchar *vm_path;
+
 char tizen_target_path[PATH_MAX];
 char tizen_target_img_path[PATH_MAX];
 
@@ -175,65 +179,6 @@ static void make_vm_lock(void)
     make_vm_lock_os();
 }
 
-static void set_image_and_log_path(char *qemu_argv)
-{
-    int i, j = 0;
-    int name_len = 0;
-    int prefix_len = 0;
-    int suffix_len = 0;
-    int max = 0;
-    char *path = malloc(PATH_MAX);
-    name_len = strlen(qemu_argv);
-    prefix_len = strlen(IMAGE_PATH_PREFIX);
-    suffix_len = strlen(IMAGE_PATH_SUFFIX);
-    max = name_len - suffix_len;
-    for (i = prefix_len , j = 0; i < max; i++) {
-        path[j++] = qemu_argv[i];
-    }
-    path[j] = '\0';
-    if (!g_path_is_absolute(path)) {
-        strcpy(tizen_target_path, g_get_current_dir());
-    } else {
-        strcpy(tizen_target_path, g_path_get_dirname(path));
-    }
-
-    set_emul_vm_name(g_path_get_basename(tizen_target_path));
-    strcpy(tizen_target_img_path, path);
-    free(path);
-
-    strcpy(log_path, tizen_target_path);
-    strcat(log_path, LOGS_SUFFIX);
-#ifdef CONFIG_WIN32
-    if (access(g_win32_locale_filename_from_utf8(log_path), R_OK) != 0) {
-        g_mkdir(g_win32_locale_filename_from_utf8(log_path), 0755);
-    }
-#else
-    if (access(log_path, R_OK) != 0) {
-        if (g_mkdir(log_path, 0755) < 0) {
-            fprintf(stderr, "failed to create log directory %s\n", log_path);
-        }
-    }
-#endif
-    strcat(log_path, LOGFILE);
-}
-
-static void redir_output(void)
-{
-    FILE *fp;
-
-    fp = freopen(log_path, "a+", stdout);
-    if (fp == NULL) {
-        fprintf(stderr, "log file open error\n");
-    }
-
-    fp = freopen(log_path, "a+", stderr);
-    if (fp == NULL) {
-        fprintf(stderr, "log file open error\n");
-    }
-    setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
-    setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
-}
-
 static void print_system_info(void)
 {
 #define DIV 1024
@@ -359,6 +304,65 @@ void start_skin(void)
 int qemu_main(int argc, char **argv, char **envp);
 
 #ifdef SUPPORT_LEGACY_ARGS
+static void set_image_and_log_path(char *qemu_argv)
+{
+    int i, j = 0;
+    int name_len = 0;
+    int prefix_len = 0;
+    int suffix_len = 0;
+    int max = 0;
+    char *path = malloc(PATH_MAX);
+    name_len = strlen(qemu_argv);
+    prefix_len = strlen(IMAGE_PATH_PREFIX);
+    suffix_len = strlen(IMAGE_PATH_SUFFIX);
+    max = name_len - suffix_len;
+    for (i = prefix_len , j = 0; i < max; i++) {
+        path[j++] = qemu_argv[i];
+    }
+    path[j] = '\0';
+    if (!g_path_is_absolute(path)) {
+        strcpy(tizen_target_path, g_get_current_dir());
+    } else {
+        strcpy(tizen_target_path, g_path_get_dirname(path));
+    }
+
+    set_emul_vm_name(g_path_get_basename(tizen_target_path));
+    strcpy(tizen_target_img_path, path);
+    free(path);
+
+    strcpy(log_path, tizen_target_path);
+    strcat(log_path, LOGS_SUFFIX);
+#ifdef CONFIG_WIN32
+    if (access(g_win32_locale_filename_from_utf8(log_path), R_OK) != 0) {
+        g_mkdir(g_win32_locale_filename_from_utf8(log_path), 0755);
+    }
+#else
+    if (access(log_path, R_OK) != 0) {
+        if (g_mkdir(log_path, 0755) < 0) {
+            fprintf(stderr, "failed to create log directory %s\n", log_path);
+        }
+    }
+#endif
+    strcat(log_path, LOGFILE);
+}
+
+static void redir_output(void)
+{
+    FILE *fp;
+
+    fp = freopen(log_path, "a+", stdout);
+    if (fp == NULL) {
+        fprintf(stderr, "log file open error\n");
+    }
+
+    fp = freopen(log_path, "a+", stderr);
+    if (fp == NULL) {
+        fprintf(stderr, "log file open error\n");
+    }
+    setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
+    setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
+}
+
 // deprecated
 static void extract_qemu_info(int qemu_argc, char **qemu_argv)
 {
@@ -498,6 +502,122 @@ static int emulator_main(int argc, char *argv[], char **envp)
     }
 #endif
 
+    gchar *profile = NULL;
+    int c = 0;
+
+    _qemu_argv = g_malloc(sizeof(char*) * 256);
+    _skin_argv = g_malloc(sizeof(char*) * 256);
+
+    // parse arguments
+    // prevent the error message for undefined options
+    opterr = 0;
+
+    while (c != -1) {
+        static struct option long_options[] = {
+            {"profile",     required_argument,  0,  'p' },
+            {"additional",  required_argument,  0,  'a' },
+            {0,             0,                  0,  0   }
+        };
+
+        c = getopt_long(argc, argv, "p:v:", long_options, NULL);
+
+        if (c == -1)
+            break;
+
+        switch (c) {
+        case '?':
+            set_variable(argv[optind - 1], argv[optind], true);
+            break;
+        case 'p':
+            set_variable("profile", optarg, true);
+            profile = g_strdup(optarg);
+            break;
+        case 'a':
+            // TODO: additional options should be accepted
+            set_variable("additional", optarg, true);
+            c = -1;
+            break;
+        default:
+            break;
+        }
+    }
+
+    if (!profile) {
+        fprintf(stderr, "Usage: %s {-p|--profile} profile\n", argv[0]);
+
+        return -1;
+    }
+
+    // load profile configurations
+    _qemu_argc = 0;
+    _qemu_argv[_qemu_argc++] = g_strdup(argv[0]);
+
+    set_bin_path(_qemu_argv[0]);
+
+    if (!load_profile_default(profile)) {
+        return -1;
+    }
+
+    // set emulator resolution
+    {
+        char *resolution = get_variable("resolution");
+        if (!resolution) {
+            fprintf(stderr, "[resolution] is required.\n");
+        }
+        char **splitted = g_strsplit(resolution, "x", 2);
+        if (!splitted[0] || !splitted[1]) {
+            fprintf(stderr, "resolution value [%s] is weird. Please use format \"WIDTHxHEIGHT\"\n", resolution);
+        }
+        set_emul_resolution(g_ascii_strtoull(splitted[0], NULL, 0),
+                            g_ascii_strtoull(splitted[1], NULL, 0));
+        g_strfreev(splitted);
+    }
+
+    // assemble arguments for qemu and skin
+    if (!assemble_profile_args(&_qemu_argc, _qemu_argv,
+                        &_skin_argc, _skin_argv)) {
+        return -1;
+    }
+
+
+    INFO("Emulator start !!!\n");
+    atexit(maru_atexit);
+
+    print_system_info();
+
+    INFO("Prepare running...\n");
+    INFO("tizen_target_img_path: %s\n", tizen_target_img_path);
+
+    int i;
+
+    fprintf(stdout, "qemu args: =========================================\n");
+    for (i = 0; i < _qemu_argc; ++i) {
+        fprintf(stdout, "%s ", _qemu_argv[i]);
+    }
+    fprintf(stdout, "\nqemu args: =========================================\n");
+
+    fprintf(stdout, "skin args: =========================================\n");
+    for (i = 0; i < _skin_argc; ++i) {
+        fprintf(stdout, "%s ", _skin_argv[i]);
+    }
+    fprintf(stdout, "\nskin args: =========================================\n");
+
+    INFO("socket initialize\n");
+    socket_init();
+
+    INFO("qemu main start!\n");
+    qemu_main(_qemu_argc, _qemu_argv, envp);
+
+    for (i = 0; i < _qemu_argc; ++i) {
+        g_free(_qemu_argv[i]);
+    }
+    for (i = 0; i < _skin_argc; ++i) {
+        g_free(_skin_argv[i]);
+    }
+    reset_variables();
+
+    exit_emulator();
+
     return 0;
 }
 
diff --git a/tizen/src/emulator_options.c b/tizen/src/emulator_options.c
new file mode 100644 (file)
index 0000000..bbfadf4
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Emulator
+ *
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <string.h>
+#include "qemu/queue.h"
+
+#include "maru_common.h"
+#include "emulator_options.h"
+#include "emulator.h"
+
+#define LINE_LIMIT 1024
+#define TOKEN_LIMIT 128
+#define OPTION_LIMIT 256
+
+struct variable {
+    gchar *name;
+    gchar *value;
+    QTAILQ_ENTRY(variable) entry;
+};
+
+static QTAILQ_HEAD(, variable) variables =
+    QTAILQ_HEAD_INITIALIZER(variables);
+
+struct emulator_opts {
+    int num;
+    char *options[OPTION_LIMIT];
+};
+
+static struct emulator_opts default_qemu_opts;
+static struct emulator_opts default_skin_opts;
+
+void set_variable(const char * const arg1, const char * const arg2,
+                bool override)
+{
+    char *name = NULL;
+    char *value = NULL;
+    struct variable *var = NULL;
+    int i;
+
+    // strip '-'
+    for (i = 0; i < strlen(arg1); ++i) {
+        if (arg1[i] != '-')
+            break;
+    }
+
+    name = g_strdup(arg1 + i);
+    if(!arg2) {
+        value = g_strdup("");
+    } else {
+        value = g_strdup(arg2);
+    }
+
+    QTAILQ_FOREACH(var, &variables, entry) {
+        if (!g_strcmp0(name, var->name)) {
+            if(!override)
+                return;
+
+            g_free(name);
+            g_free(var->value);
+
+            var->value = value;
+
+            return;
+        }
+    }
+
+    var = g_malloc(sizeof(*var));
+
+
+    var->name = name;
+    var->value = value;
+    QTAILQ_INSERT_TAIL(&variables, var, entry);
+}
+
+char *get_variable(const char * const name)
+{
+    struct variable *var = NULL;
+
+    QTAILQ_FOREACH(var, &variables, entry) {
+        if (!g_strcmp0(name, var->name)) {
+            return var->value;
+        }
+    }
+
+    return NULL;
+}
+
+void reset_variables(void)
+{
+    struct variable *var = NULL;
+
+    QTAILQ_FOREACH(var, &variables, entry) {
+        QTAILQ_REMOVE(&variables, var, entry);
+        g_free(var->name);
+        g_free(var->value);
+    }
+}
+
+static void reset_default_opts(void)
+{
+    int i = 0;
+
+    for (i = 0; i < default_qemu_opts.num; ++i) {
+        g_free(default_qemu_opts.options[i]);
+    }
+    for (i = 0; i < default_skin_opts.num; ++i) {
+        g_free(default_skin_opts.options[i]);
+    }
+}
+
+bool load_profile_default(const char * const profile)
+{
+    int classification = 0;
+    char str[LINE_LIMIT];
+    char *filename;
+    FILE *file = NULL;
+
+    filename = g_strdup_printf("%s/%s.profile", get_bin_path(), profile);
+
+    file = fopen(filename, "r");
+    if (!file) {
+        fprintf(stderr,
+            "Profile configuration file [%s] is not found.\n", filename);
+        g_free(filename);
+        return false;
+    }
+    g_free(filename);
+
+    struct emulator_opts *default_opts = NULL;
+
+    while (fgets(str, LINE_LIMIT, file)) {
+        int i = 0;
+
+        while (str[i] && str[i] != '#') {
+            // tokenize
+            char token[TOKEN_LIMIT] = { '\0', };
+            int start_index = -1;
+            bool in_quote = false;
+
+            do {
+                if (!str[i] ||
+                    (!in_quote &&
+                        (str[i] == ' ' || str[i] == '\t' || str[i] == '#'
+                        || str[i] == '\r' || str[i] == '\n')) ||
+                    (in_quote && str[i] == '"')) {
+                    if (start_index != -1) {
+                        g_strlcpy(token, str + start_index,
+                            i - start_index + 1);
+                    }
+                }
+                else {
+                    if (start_index < 0) {
+                        if (str[i] == '"') {
+                            in_quote = true;
+                            ++i;
+                        }
+                        start_index = i;
+                    }
+                }
+            } while(str[i++] && !token[0]);
+
+            if (!token[0]) {
+                break;
+            }
+
+            // detect label
+            if (!g_strcmp0(token, "[[DEFAULT_VARIABLES]]")) {
+                classification = 0;
+                continue;
+            }
+            else if (!g_strcmp0(token, "[[SKIN_OPTIONS]]")) {
+                default_opts = &default_skin_opts;
+                classification = 1;
+                continue;
+            }
+            else if (!g_strcmp0(token, "[[QEMU_OPTIONS]]")) {
+                default_opts = &default_qemu_opts;
+                classification = 2;
+                continue;
+            }
+
+            // process line
+            switch (classification) {
+            case 0: // default variables
+                {
+                    gchar **splitted = g_strsplit(token, "=", 2);
+                    if (splitted[0] && splitted[1]) {
+                        set_variable(g_strdup(splitted[0]), g_strdup(splitted[1]),
+                                false);
+                    }
+                    g_strfreev(splitted);
+
+                    break;
+                }
+            case 1: // skin options
+            case 2: // qemu options
+                default_opts->options[default_opts->num++] = g_strdup(token);
+
+                break;
+            }
+        }
+    }
+
+    return true;
+}
+
+static bool assemble_args(int *argc, char **argv,
+                struct emulator_opts *default_opts) {
+    int i = 0;
+
+    for (i = 0; i < default_opts->num; ++i) {
+        int j = 0;
+        char *str;
+        int start_index = -1;
+        int end_index = -1;
+        void *arg;
+
+        str = default_opts->options[i];
+
+        // conditional arguments
+        for (j = 0; str[j]; ++j) {
+            if(str[j] == '[') {
+                start_index = j;
+            }
+            else if(str[j] == ']') {
+                end_index = j;
+            }
+        }
+        if (start_index != -1 && end_index != -1) {
+            char cond[TOKEN_LIMIT];
+
+            g_strlcpy(cond, str + start_index + 1, end_index - start_index);
+            g_strstrip(cond);
+            if (strlen(cond) > 0) {
+                if ((cond[0] == '!' && get_variable(g_strstrip(cond + 1))) ||
+                    (cond[0] != '!' && !get_variable(cond))) {
+                    continue;
+                }
+            }
+            g_strlcpy(str, str + end_index + 1, strlen(str));
+            g_strstrip(str);
+        }
+
+        // fill variables
+        start_index = -1;
+        end_index = -1;
+
+        for (j = 0; str[j]; ++j) {
+            if(str[j] == '$' && str[j + 1] && str[j + 1] == '{') {
+                start_index = j++;
+            }
+            else if(str[j] == '}') {
+                end_index = j;
+            }
+        }
+
+        if (start_index != -1 && end_index != -1) {
+            char name[TOKEN_LIMIT];
+            char *value = NULL;
+            int length;
+
+            g_strlcpy(name, str + start_index + 2, end_index - start_index - 1);
+
+            // search stored variables
+            value = get_variable(name);
+
+            // if there is no name in stored variables,
+            // try to search environment variables
+            if(!value) {
+                value = getenv(name);
+            }
+
+            if(!value) {
+                fprintf(stderr, "[%s] is not set."
+                    " Please input value using commandline argument"
+                    " \"--%s\" or profile default file or envirionment"
+                    " variable.\n", name, name);
+                value = (char *)"";
+            }
+
+            length = start_index + strlen(value) + (strlen(str) - end_index);
+            arg = g_malloc(length);
+
+            g_strlcpy(arg, str, start_index + 1);
+            g_strlcat(arg, value, length);
+            g_strlcat(arg, str + end_index + 1, length);
+
+            argv[(*argc)++] = arg;
+        }
+        else {
+            argv[(*argc)++] = g_strdup(str);
+        }
+    }
+
+    return true;
+}
+
+bool assemble_profile_args(int *qemu_argc, char **qemu_argv,
+        int *skin_argc, char **skin_argv)
+{
+    if (!assemble_args(qemu_argc, qemu_argv,
+                &default_qemu_opts)) {
+        reset_default_opts();
+        return false;
+    }
+    if (!assemble_args(skin_argc, skin_argv,
+                &default_skin_opts)) {
+        reset_default_opts();
+        return false;
+    }
+
+    reset_default_opts();
+    return true;
+}
diff --git a/tizen/src/emulator_options.h b/tizen/src/emulator_options.h
new file mode 100644 (file)
index 0000000..c4f370c
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Emulator
+ *
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef __EMULATOR_OPTIONS_H__
+#define __EMULATOR_OPTIONS_H__
+
+void set_variable(const char * const arg1, const char * const arg2, bool override);
+char *get_variable(const char * const name);
+void reset_variables(void);
+bool load_profile_default(const char * const profile);
+bool assemble_profile_args(int *qemu_argc, char **qemu_argv,
+        int *skin_argc, char **skin_argv);
+
+#endif /* __EMULATOR_OPTIONS_H__ */