Revert "Revert "Add the appcmd protocol for product extended routine.""
[sdk/target/sdbd.git] / src / services.c
index 2ecaacc..5d40ce9 100644 (file)
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
@@ -24,6 +24,8 @@
 #include "sysdeps.h"
 
 #define  TRACE_TAG  TRACE_SERVICES
+#include "log.h"
+
 #include "sdb.h"
 #include "file_sync_service.h"
 
 #    include <sys/ioctl.h>
 #  endif
 #else
-#   include "android_reboot.h"
 #   include <sys/inotify.h>
 #   include "sdktools.h"
 #endif
 
+#include "strutils.h"
+#include "utils.h"
+#include <system_info.h>
+#include <tzplatform_config.h>
+
+#include <vconf.h>
+#include <limits.h>
+
+#include <termios.h>
+#include <sys/ioctl.h>
+
+#include "sdbd_plugin.h"
+#include "plugin.h"
+
 typedef struct stinfo stinfo;
 
 struct stinfo {
@@ -47,7 +62,6 @@ struct stinfo {
     void *cookie;
 };
 
-
 void *service_bootstrap_func(void *x)
 {
     stinfo *sti = x;
@@ -78,6 +92,11 @@ static void dns_service(int fd, void *cookie)
 }
 #else
 
+static int is_support_interactive_shell()
+{
+    return (!strncmp(g_capabilities.intershell_support, PLUGIN_RET_ENABLED, strlen(PLUGIN_RET_ENABLED)));
+}
+
 #if 0
 extern int recovery_mode;
 
@@ -158,36 +177,78 @@ void restart_tcp_service(int fd, void *cookie)
     sdb_close(fd);
 }
 
+static int is_support_rootonoff()
+{
+    return (!strncmp(g_capabilities.rootonoff_support, PLUGIN_RET_ENABLED, strlen(PLUGIN_RET_ENABLED)));
+}
+
 void rootshell_service(int fd, void *cookie)
 {
     char buf[100];
     char *mode = (char*) cookie;
 
     if (!strcmp(mode, "on")) {
-        if (rootshell_mode == 1) {
-            //snprintf(buf, sizeof(buf), "Already changed to developer mode\n");
-            // do not show message
-        } else {
-            if (access("/bin/su", F_OK) == 0) {
-                rootshell_mode = 1;
-                //allows a permitted user to execute a command as the superuser
-                snprintf(buf, sizeof(buf), "Switched to 'root' account mode\n");
+        if (getuid() == 0) {
+            if (rootshell_mode == 1) {
+                //snprintf(buf, sizeof(buf), "Already changed to sdk user mode\n");
+                // do not show message
             } else {
-                snprintf(buf, sizeof(buf), "Permission denied\n");
+                if (is_support_rootonoff()) {
+                    rootshell_mode = 1;
+                    //allows a permitted user to execute a command as the superuser
+                    snprintf(buf, sizeof(buf), "Switched to 'root' account mode\n");
+                } else {
+                    snprintf(buf, sizeof(buf), "Permission denied\n");
+                }
+                writex(fd, buf, strlen(buf));
             }
+        } else {
+            D("need root permission for root shell: %d\n", getuid());
+            rootshell_mode = 0;
+            snprintf(buf, sizeof(buf), "Permission denied\n");
             writex(fd, buf, strlen(buf));
         }
     } else if (!strcmp(mode, "off")) {
         if (rootshell_mode == 1) {
             rootshell_mode = 0;
-            snprintf(buf, sizeof(buf), "Switched to 'developer' account mode\n");
+            snprintf(buf, sizeof(buf), "Switched to 'sdk user' account mode\n");
             writex(fd, buf, strlen(buf));
         }
     } else {
-        snprintf(buf, sizeof(buf), "Unknown command option\n");
+       snprintf(buf, sizeof(buf), "Unknown command option : %s\n", mode);
         writex(fd, buf, strlen(buf));
     }
-    D("set rootshell to %s\n", rootshell_mode == 1 ? "root" : "developer");
+    D("set rootshell to %s\n", rootshell_mode == 1 ? "root" : SDK_USER_NAME);
+    free(mode);
+    sdb_close(fd);
+}
+
+enum tzplatform_get_env_error_status {
+    NO_ERROR_TZPLATFORM_ENV = 0,
+    ERROR_TZPLATFORM_ENV_GENERAL = 1,
+    ERROR_TZPLATFORM_ENV_INVALID_VARIABLES = 2,
+};
+
+void get_tzplatform_env(int fd, void *cookie) {
+    char buf[PATH_MAX] = { 0, };
+    char *env_name = (char*) cookie;
+    D("environment variable name: %s\n", env_name);
+    enum tzplatform_variable env_id = tzplatform_getid(env_name);
+    if (env_id != _TZPLATFORM_VARIABLES_INVALID_) {
+        const char *env_value = tzplatform_getenv(env_id);
+        if (env_value) {
+            D("environment value : %s\n", env_value);
+            snprintf(buf, sizeof(buf), "%d%s", NO_ERROR_TZPLATFORM_ENV, env_value);
+        } else {
+            D("failed to get environment value using tzplatform_getenv");
+            snprintf(buf, sizeof(buf), "%d", ERROR_TZPLATFORM_ENV_GENERAL);
+        }
+    } else {
+        D("environment name (%s) is invalid\n", env_name);
+        snprintf(buf, sizeof(buf), "%d", ERROR_TZPLATFORM_ENV_INVALID_VARIABLES);
+    }
+    writex(fd, buf, strlen(buf));
+    free(env_name);
     sdb_close(fd);
 }
 
@@ -225,7 +286,7 @@ void reboot_service(int fd, void *arg)
 
     ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
     if (ret < 0) {
-        snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
+        snprintf(buf, sizeof(buf), "reboot failed: %s errno:%d\n", errno);
         writex(fd, buf, strlen(buf));
     }
     free(arg);
@@ -236,7 +297,7 @@ void reboot_service(int fd, void *arg)
 #if !SDB_HOST
 #define EVENT_SIZE  ( sizeof (struct inotify_event) )
 #define BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )
-#define CS_PATH     "/opt/usr/share/crash/report"
+#define CS_PATH     tzplatform_getenv(TZ_SYS_CRASH)
 
 void inoti_service(int fd, void *arg)
 {
@@ -249,10 +310,17 @@ void inoti_service(int fd, void *arg)
 
     if ( ifd < 0 ) {
         D( "inotify_init failed\n");
+        sdb_close(fd);
         return;
     }
 
     wd = inotify_add_watch( ifd, CS_PATH, IN_CREATE);
+    if ( wd < 0 ) {
+        D("inotify_add_watch failed (errno :%d)\n", errno);
+        sdb_close(ifd);
+        sdb_close(fd);
+        return;
+    }
 
     for ( ; ; ) {
         int length, i = 0;
@@ -262,14 +330,14 @@ void inoti_service(int fd, void *arg)
             D( "inoti read failed\n");
             goto done;
         }
-
-        while ( i < length ) {
-            struct inotify_event *event = ( struct inotify_event * )&buffer[i];
+        while (i >= 0 && i <= (length - EVENT_SIZE)) {
+            struct inotify_event *event = (struct inotify_event *) &buffer[i];
             if (event->len) {
-                if ( event->mask & IN_CREATE) {
+                if (event->mask & IN_CREATE) {
                     if (!(event->mask & IN_ISDIR)) {
                         char *cspath = NULL;
-                        int len = asprintf(&cspath, "%s/%s", CS_PATH, event->name);
+                        int len = asprintf(&cspath, "%s/%s", CS_PATH,
+                                event->name);
                         D( "The file %s was created.\n", cspath);
                         writex(fd, cspath, len);
                         if (cspath != NULL) {
@@ -278,6 +346,9 @@ void inoti_service(int fd, void *arg)
                     }
                 }
             }
+            if (i + EVENT_SIZE + event->len < event->len) { // in case of integer overflow
+                break;
+            }
             i += EVENT_SIZE + event->len;
         }
     }
@@ -356,35 +427,41 @@ static int create_service_thread(void (*func)(int, void *), void *cookie)
 
 #if !SDB_HOST
 
-static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+static void redirect_and_exec(int pts, const char *cmd, char * const argv[], char * const envp[])
 {
-#ifdef HAVE_WIN32_PROC
-    D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
-    fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
-    return -1;
-#else /* !HAVE_WIN32_PROC */
-    char *devname;
+    dup2(pts, 0);
+    dup2(pts, 1);
+    dup2(pts, 2);
+
+    sdb_close(pts);
+
+    execve(cmd, argv, envp);
+}
+
+int create_subprocess(const char *cmd, pid_t *pid, char * const argv[], char * const envp[])
+{
+    char devname[64];
     int ptm;
 
     ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
     if(ptm < 0){
-        D("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
+        D("[ cannot open /dev/ptmx - errno:%d ]\n",errno);
         return -1;
     }
     if (fcntl(ptm, F_SETFD, FD_CLOEXEC) < 0) {
-        D("[ cannot set cloexec to /dev/ptmx - %s ]\n",strerror(errno));
+        D("[ cannot set cloexec to /dev/ptmx - errno:%d ]\n",errno);
     }
 
     if(grantpt(ptm) || unlockpt(ptm) ||
-       ((devname = (char*) ptsname(ptm)) == 0)){
-        D("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
+        ptsname_r(ptm, devname, sizeof(devname)) != 0 ){
+        D("[ trouble with /dev/ptmx - errno:%d ]\n", errno);
         sdb_close(ptm);
         return -1;
     }
 
     *pid = fork();
     if(*pid < 0) {
-        D("- fork failed: %s -\n", strerror(errno));
+        D("- fork failed: errno:%d -\n", errno);
         sdb_close(ptm);
         return -1;
     }
@@ -400,16 +477,12 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1
             exit(-1);
         }
 
-        dup2(pts, 0);
-        dup2(pts, 1);
-        dup2(pts, 2);
-
-        sdb_close(pts);
         sdb_close(ptm);
 
         // set OOM adjustment to zero
         {
             char text[64];
+            //snprintf(text, sizeof text, "/proc/%d/oom_score_adj", getpid());
             snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
             int fd = sdb_open(text, O_WRONLY);
             if (fd >= 0) {
@@ -417,15 +490,24 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1
                 sdb_close(fd);
             } else {
                // FIXME: not supposed to be here
-               D("sdb: unable to open %s due to %s\n", text, strerror(errno));
+               D("sdb: unable to open %s due to errno:%d\n", text, errno);
             }
         }
 
-        verify_commands(arg1);
-
-        execl(cmd, cmd, arg0, arg1, NULL);
-        fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
-                cmd, strerror(errno), errno);
+        if (should_drop_privileges()) {
+            if (argv[2] != NULL && getuid() == 0 && request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_ROOTCMD, argv[2])) {
+                // do nothing
+                D("sdb: executes root commands!!:%s\n", argv[2]);
+            } else {
+                if (getuid() != g_sdk_user_id && set_sdk_user_privileges() < 0) {
+                    fprintf(stderr, "failed to set SDK user privileges\n");
+                    exit(-1);
+                }
+            }
+        }
+        redirect_and_exec(pts, cmd, argv, envp);
+        fprintf(stderr, "- exec '%s' failed: (errno:%d) -\n",
+                cmd, errno);
         exit(-1);
     } else {
         // Don't set child's OOM adjustment to zero.
@@ -434,15 +516,12 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1
         // """sdb: unable to open /proc/644/oom_adj""" seen in some logs.
         return ptm;
     }
-#endif /* !HAVE_WIN32_PROC */
 }
 #endif  /* !SDB_HOST */
 
-#if SDB_HOST
-#define SHELL_COMMAND "/bin/sh"
-#else
-#define SHELL_COMMAND "/bin/sh" /* tizen specific */
-#endif
+#define LOGIN_COMMAND "/bin/login"
+#define SUPER_USER    "root"
+#define LOGIN_CONFIG  "/etc/login.defs"
 
 #if !SDB_HOST
 static void subproc_waiter_service(int fd, void *cookie)
@@ -455,7 +534,6 @@ static void subproc_waiter_service(int fd, void *cookie)
         pid_t p = waitpid(pid, &status, 0);
         if (p == pid) {
             D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
-            
             if (WIFEXITED(status)) {
                 D("*** Exit code %d\n", WEXITSTATUS(status));
                 break;
@@ -477,24 +555,214 @@ static void subproc_waiter_service(int fd, void *cookie)
     }
 }
 
-static int create_subproc_thread(const char *name)
+void get_env(char *key, char **env)
+{
+    FILE *fp;
+    char buf[1024];
+    char *s, *e, *value;
+
+    fp = fopen (LOGIN_CONFIG, "r");
+    if (NULL == fp) {
+        return;
+    }
+
+    while (fgets(buf, (int) sizeof (buf), fp) != NULL) {
+        s = buf;
+        e = buf + (strlen(buf) - 1);
+
+        // trim string
+        while( (e > s) && (*e == ' ' ||  *e == '\n' || *e == '\t')) {
+            e--;
+        }
+        *(e+1) ='\0';
+
+        while(*s != '\0' && (*s == ' ' || *s == '\t' || *s == '\n')) {
+            s++;
+        }
+
+        // skip comment or null string
+        if (*s == '#' || *s == '\0') {
+            continue;
+        }
+        value = s + strcspn(s, " \t");
+        *value++ = '\0';
+
+        if(!strcmp(buf, key)) {
+            *env = strdup(value);
+            break;
+        }
+    }
+
+    fclose(fp);
+}
+
+static int create_subproc_thread(const char *name, int lines, int columns)
 {
     stinfo *sti;
     sdb_thread_t t;
     int ret_fd;
     pid_t pid;
+    char *value = NULL;
+    char *trim_value = NULL;
+    char path[PATH_MAX];
+    char *envp[MAX_TOKENS];
+    int envp_cnt = 0;
+
+    memset(path, 0, sizeof(path));
+    memset(envp, 0, sizeof(envp));
+
+    envp[envp_cnt++] = strdup("TERM=linux");
+    envp[envp_cnt++] = strdup("DISPLAY=:0");
+
+    if (should_drop_privileges()) {
+        if (g_sdk_home_dir_env) {
+            envp[envp_cnt++] = strdup(g_sdk_home_dir_env);
+        } else {
+            envp[envp_cnt++] = strdup("HOME=/home/owner");
+        }
+        get_env("ENV_PATH", &value);
+    } else {
+        get_env("ENV_SUPATH", &value);
+        if(value == NULL) {
+            get_env("ENV_ROOTPATH", &value);
+        }
+        envp[envp_cnt++] = strdup("HOME=/root");
+    }
+    if (value != NULL) {
+        trim_value = str_trim(value);
+        if (trim_value != NULL) {
+            // if string is not including 'PATH=', append it.
+            if (strncmp(trim_value, "PATH", 4)) {
+                snprintf(path, sizeof(path), "PATH=%s", trim_value);
+            } else {
+                snprintf(path, sizeof(path), "%s", trim_value);
+            }
+            envp[envp_cnt++] = strdup(path);
+        } else {
+            snprintf(path, sizeof(path), "%s", value);
+            envp[envp_cnt++] = strdup(path);
+        }
+        free(value);
+    }
 
-    if(name) {
-        ret_fd = create_subprocess(SHELL_COMMAND, "-c", name, &pid);
+    /* get environment variables from plugin */
+    char *envp_plugin = NULL;
+    envp_plugin = malloc(SDBD_PLUGIN_OUTBUF_MAX);
+    if (envp_plugin == NULL) {
+        D("Cannot allocate the shell commnad buffer.");
+        return -1;
+    }
+    memset(envp_plugin, 0, SDBD_PLUGIN_OUTBUF_MAX);
+    if (!request_plugin_cmd(SDBD_CMD_SHELL_ENVVAR, "", envp_plugin, SDBD_PLUGIN_OUTBUF_MAX)) {
+        D("Failed to convert the shell command. (%s)\n", name);
+        free(envp_plugin);
+        return -1;
     } else {
-        ret_fd = create_subprocess(SHELL_COMMAND, "-", 0, &pid);
+       if(envp_plugin[0] != '\0') {
+            envp_cnt = tokenize_append(envp_plugin, "\n", envp, MAX_TOKENS, envp_cnt);
+        }
+    }
+    free(envp_plugin);
+
+    /* Last element of envp must be the NULL-terminator to prevent execvp fail */
+    envp[envp_cnt] = NULL;
+
+    if(name) { // in case of shell execution directly
+        // Check the shell command validation.
+        if (!request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_SHELLCMD, name)) {
+            D("This shell command is invalid. (%s)\n", name);
+            return -1;
+        }
+
+        // Convert the shell command.
+        char *new_cmd = NULL;
+        new_cmd = malloc(SDBD_SHELL_CMD_MAX);
+        if(new_cmd == NULL) {
+            D("Cannot allocate the shell commnad buffer.");
+            return -1;
+        }
+
+        memset(new_cmd, 0, SDBD_SHELL_CMD_MAX);
+        if(!request_conversion_to_plugin(PLUGIN_SYNC_CMD_CONVERT_SHELLCMD, name, new_cmd, SDBD_SHELL_CMD_MAX)) {
+            D("Failed to convert the shell command. (%s)\n", name);
+            free(new_cmd);
+            return -1;
+        }
+
+        D("converted cmd : %s\n", new_cmd);
+
+        char *args[] = {
+            SHELL_COMMAND,
+            "-c",
+            NULL,
+            NULL,
+        };
+        args[2] = new_cmd;
+
+        ret_fd = create_subprocess(SHELL_COMMAND, &pid, (char * const*)args, (char * const*)envp);
+        free(new_cmd);
+    } else { // in case of shell interactively
+        // Check the capability for interactive shell support.
+        if (!is_support_interactive_shell()) {
+            D("This platform dose NOT support the interactive shell\n");
+            return -1;
+        }
+
+        char * const args[] = {
+                SHELL_COMMAND,
+                "-",
+                NULL,
+        };
+        ret_fd = create_subprocess(SHELL_COMMAND, &pid, (char * const*)args, (char * const*)envp);
+#if 0   // FIXME: should call login command instead of /bin/sh
+        if (should_drop_privileges()) {
+            char *args[] = {
+                SHELL_COMMAND,
+                "-",
+                NULL,
+            };
+            ret_fd = create_subprocess(SHELL_COMMAND, &pid, args, envp);
+        } else {
+            char *args[] = {
+                LOGIN_COMMAND,
+                "-f",
+                SUPER_USER,
+                NULL,
+            };
+            ret_fd = create_subprocess(LOGIN_COMMAND, &pid, args, envp);
+        }
+#endif
+    }
+
+    /* free environment variables */
+    int i = 0;
+    if(envp_cnt > 0) {
+        for(i = 0; i < envp_cnt; i++) {
+            if(envp[i]) {
+                D("envp[%d] = %s\n", i, envp[i]);
+                free(envp[i]);
+            }
+        }
     }
+
     D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
 
     if (ret_fd < 0) {
-        printf("cannot create service thread\n");
+        D("cannot create service thread\n");
         return -1;
     }
+
+    if (lines > 0 && columns > 0) {
+        D("shell size lines=%d, columns=%d\n", lines, columns);
+        struct winsize win_sz;
+        win_sz.ws_row = lines;
+        win_sz.ws_col = columns;
+
+        if (ioctl(ret_fd, TIOCSWINSZ, &win_sz) < 0) {
+            D("failed to sync window size.\n");
+        }
+    }
+
     sti = malloc(sizeof(stinfo));
     if(sti == 0) fatal("cannot allocate stinfo");
     sti->func = subproc_waiter_service;
@@ -504,15 +772,287 @@ static int create_subproc_thread(const char *name)
     if(sdb_thread_create( &t, service_bootstrap_func, sti)){
         free(sti);
         sdb_close(ret_fd);
-        printf("cannot create service thread\n");
+        D("cannot create service thread\n");
         return -1;
     }
 
     D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
     return ret_fd;
 }
+
+static int create_sync_subprocess(void (*func)(int, void *), void* cookie) {
+    stinfo *sti;
+    sdb_thread_t t;
+    int s[2];
+
+    if(sdb_socketpair(s)) {
+        D("cannot create service socket pair\n");
+        return -1;
+    }
+
+    pid_t pid = fork();
+
+    if (pid == 0) {
+        sdb_close(s[0]);
+        func(s[1], cookie);
+        exit(-1);
+    } else if (pid > 0) {
+        sdb_close(s[1]);
+        // FIXME: do not wait child process hear
+        //waitpid(pid, &ret, 0);
+    }
+    if (pid < 0) {
+        D("- fork failed: errno:%d -\n", errno);
+        sdb_close(s[0]);
+        sdb_close(s[1]);
+        D("cannot create sync service sub process\n");
+        return -1;
+    }
+
+    sti = malloc(sizeof(stinfo));
+    if(sti == 0) fatal("cannot allocate stinfo");
+    sti->func = subproc_waiter_service;
+    sti->cookie = (void*)pid;
+    sti->fd = s[0];
+
+    if(sdb_thread_create( &t, service_bootstrap_func, sti)){
+        free(sti);
+        sdb_close(s[0]);
+        printf("cannot create service monitor thread\n");
+        return -1;
+    }
+
+    D("service process started, fd=%d pid=%d\n",s[0], pid);
+    return s[0];
+}
+
+static int create_syncproc_thread()
+{
+    int ret_fd;
+
+    ret_fd = create_sync_subprocess(file_sync_service, NULL);
+    // FIXME: file missing bug when root on mode
+    /*
+    if (should_drop_privileges()) {
+        ret_fd = create_sync_subprocess(file_sync_service, NULL);
+    } else {
+        ret_fd = create_service_thread(file_sync_service, NULL);
+    }
+    */
+
+    return ret_fd;
+}
 #endif
 
+static void get_platforminfo(int fd, void *cookie) {
+    pinfo sysinfo;
+
+    char *value = NULL;
+    s_strncpy(sysinfo.platform_info_version, INFO_VERSION, strlen(INFO_VERSION));
+
+    int r = system_info_get_platform_string("http://tizen.org/system/model_name", &value);
+    if (r != SYSTEM_INFO_ERROR_NONE) {
+        s_strncpy(sysinfo.model_name, UNKNOWN, strlen(UNKNOWN));
+        D("fail to get system model:%d\n", errno);
+    } else {
+        s_strncpy(sysinfo.model_name, value, sizeof(sysinfo.model_name));
+        D("returns model_name:%s\n", value);
+        if (value != NULL) {
+            free(value);
+        }
+    }
+
+    r = system_info_get_platform_string("http://tizen.org/system/platform.name", &value);
+    if (r != SYSTEM_INFO_ERROR_NONE) {
+        s_strncpy(sysinfo.platform_name, UNKNOWN, strlen(UNKNOWN));
+        D("fail to get platform name:%d\n", errno);
+    } else {
+        s_strncpy(sysinfo.platform_name, value, sizeof(sysinfo.platform_name));
+        D("returns platform_name:%s\n", value);
+        if (value != NULL) {
+            free(value);
+        }
+
+    }
+
+    // FIXME: the result is different when using SYSTEM_INFO_KEY_TIZEN_VERSION_NAME
+    r = system_info_get_platform_string("tizen.org/feature/platform.version", &value);
+    if (r != SYSTEM_INFO_ERROR_NONE) {
+        s_strncpy(sysinfo.platform_version, UNKNOWN, strlen(UNKNOWN));
+        D("fail to get platform version:%d\n", errno);
+    } else {
+        s_strncpy(sysinfo.platform_version, value, sizeof(sysinfo.platform_version));
+        D("returns platform_version:%s\n", value);
+        if (value != NULL) {
+            free(value);
+        }
+    }
+
+    r = system_info_get_platform_string("tizen.org/feature/profile", &value);
+    if (r != SYSTEM_INFO_ERROR_NONE) {
+        s_strncpy(sysinfo.profile_name, UNKNOWN, strlen(UNKNOWN));
+        D("fail to get profile name:%d\n", errno);
+    } else {
+        s_strncpy(sysinfo.profile_name, value, sizeof(sysinfo.profile_name));
+        D("returns profile name:%s\n", value);
+        if (value != NULL) {
+            free(value);
+        }
+    }
+
+    writex(fd, &sysinfo, sizeof(pinfo));
+
+    sdb_close(fd);
+}
+
+static int put_key_value_string(char* buf, int offset, int buf_size, char* key, char* value) {
+    int len = 0;
+    if ((len = snprintf(buf+offset, buf_size-offset, "%s:%s\n", key, value)) > 0) {
+        return len;
+    }
+    return 0;
+}
+
+static void get_capability(int fd, void *cookie) {
+    char cap_buffer[CAPBUF_SIZE] = {0,};
+    uint16_t offset = 0;
+
+    // Secure protocol support
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "secure_protocol", g_capabilities.secure_protocol);
+
+    // Interactive shell support
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "intershell_support", g_capabilities.intershell_support);
+
+    // File push/pull support
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "filesync_support", g_capabilities.filesync_support);
+
+    // USB protocol support
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "usbproto_support", g_capabilities.usbproto_support);
+
+    // Socket protocol support
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "sockproto_support", g_capabilities.sockproto_support);
+
+    // Window size synchronization support
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "syncwinsz_support", g_capabilities.syncwinsz_support);
+
+    // Root command support
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "rootonoff_support", g_capabilities.rootonoff_support);
+
+    // Zone support
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "zone_support", g_capabilities.zone_support);
+
+    // Multi-User support
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "multiuser_support", g_capabilities.multiuser_support);
+
+    // CPU Architecture of model
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "cpu_arch", g_capabilities.cpu_arch);
+
+    // SDK Tool path
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "sdk_toolpath", g_capabilities.sdk_toolpath);
+
+    // Profile name
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "profile_name", g_capabilities.profile_name);
+
+    // Vendor name
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "vendor_name", g_capabilities.vendor_name);
+
+    // Target name of the launch possible
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "can_launch", g_capabilities.can_launch);
+
+    // Platform version
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "platform_version", g_capabilities.platform_version);
+
+    // Product version
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "product_version", g_capabilities.product_version);
+
+    // Sdbd version
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "sdbd_version", g_capabilities.sdbd_version);
+
+    // Sdbd plugin version
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "sdbd_plugin_version", g_capabilities.sdbd_plugin_version);
+
+    // Capability version
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+                                "sdbd_cap_version", g_capabilities.sdbd_cap_version);
+
+    // Sdbd log enable
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+            "log_enable", g_capabilities.log_enable);
+
+    // Sdbd log path
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+            "log_path", g_capabilities.log_path);
+
+    // Application command support
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+            "appcmd_support", g_capabilities.appcmd_support);
+
+    offset++; // for '\0' character
+
+    writex(fd, &offset, sizeof(uint16_t));
+    writex(fd, cap_buffer, offset);
+
+    sdb_close(fd);
+}
+
+static void sync_windowsize(int fd, void *cookie) {
+    int id, lines, columns;
+    char *size_info = cookie;
+    asocket *s = NULL;
+
+    if (sscanf(size_info, "%d:%d:%d", &id, &lines, &columns) == 3) {
+        D("window size information: id=%d, lines=%d, columns=%d\n", id, lines, columns);
+    }
+    if((s = find_local_socket(id))) {
+        struct winsize win_sz;
+        win_sz.ws_row = lines;
+        win_sz.ws_col = columns;
+
+        if (ioctl(s->fd, TIOCSWINSZ, &win_sz) < 0) {
+            D("failed to sync window size.\n");
+            return;
+        }
+        D("success to sync window size.\n");
+    }
+}
+
+const unsigned COMMAND_TIMEOUT = 10000;
+void get_boot(int fd, void *cookie) {
+    char buf[2] = { 0, };
+    int time = 0;
+    int interval = 1000;
+    while (time < COMMAND_TIMEOUT) {
+        if (booting_done == 1) {
+            D("get_boot:platform booting is done\n");
+            snprintf(buf, sizeof(buf), "%s", "1");
+            break;
+        }
+        D("get_boot:platform booting is in progress\n");
+        sdb_sleep_ms(interval);
+        time += interval;
+    }
+    writex(fd, buf, strlen(buf));
+    sdb_close(fd);
+}
+
 int service_to_fd(const char *name)
 {
     int ret = -1;
@@ -521,9 +1061,22 @@ int service_to_fd(const char *name)
         int port = atoi(name + 4);
         name = strchr(name + 4, ':');
         if(name == 0) {
-            ret = socket_loopback_client(port, SOCK_STREAM);
-            if (ret >= 0)
+            if (is_emulator()){
+                ret = socket_ifr_client(port , SOCK_STREAM, "eth0");
+            } else {
+                ret = socket_ifr_client(port , SOCK_STREAM, "usb0");
+                if (ret < 0) {
+                    if (ifconfig(SDB_FORWARD_IFNAME, SDB_FORWARD_INTERNAL_IP, SDB_FORWARD_INTERNAL_MASK, 1) == 0) {
+                        ret = socket_ifr_client(port , SOCK_STREAM, SDB_FORWARD_IFNAME);
+                    }
+                }
+            }
+            if (ret < 0) {
+                ret = socket_loopback_client(port, SOCK_STREAM);
+            }
+            if (ret >= 0) {
                 disable_tcp_nagle(ret);
+            }
         } else {
 #if SDB_HOST
             sdb_mutex_lock(&dns_lock);
@@ -565,12 +1118,18 @@ int service_to_fd(const char *name)
         ret = create_service_thread(log_service, get_log_file_path(name + 4));
     }*/ else if(!HOST && !strncmp(name, "shell:", 6)) {
         if(name[6]) {
-            ret = create_subproc_thread(name + 6);
+            ret = create_subproc_thread(name + 6, 0, 0);
         } else {
-            ret = create_subproc_thread(0);
+            ret = create_subproc_thread(NULL, 0, 0);
+        }
+    } else if(!strncmp(name, "eshell:", 7)) {
+        int lines, columns;
+        if (sscanf(name+7, "%d:%d", &lines, &columns) == 2) {
+            ret = create_subproc_thread(NULL, lines, columns);
         }
     } else if(!strncmp(name, "sync:", 5)) {
-        ret = create_service_thread(file_sync_subproc, NULL);
+        //ret = create_service_thread(file_sync_service, NULL);
+        ret = create_syncproc_thread();
     }/*  else if(!strncmp(name, "remount:", 8)) {
         ret = create_service_thread(remount_service, NULL);
     } else if(!strncmp(name, "reboot:", 7)) {
@@ -586,24 +1145,33 @@ int service_to_fd(const char *name)
     } else if(!strncmp(name, "restore:", 8)) {
         ret = backup_service(RESTORE, NULL);
     }*/ else if(!strncmp(name, "root:", 5)) {
-        ret = create_service_thread(rootshell_service, (void *)(name+5));
-    } else if(!strncmp(name, "tcpip:", 6)) {
-        int port;
-        /*if (sscanf(name + 6, "%d", &port) == 0) {
-            port = 0;
-        }*/
-        port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
-        ret = create_service_thread(restart_tcp_service, (void *)port);
-    } else if(!strncmp(name, "usb:", 4)) {
-        ret = create_service_thread(restart_usb_service, NULL);
+        char* service_name = NULL;
+
+        service_name = strdup(name+5);
+        ret = create_service_thread(rootshell_service, (void *)(service_name));
     } else if(!strncmp(name, "cs:", 5)) {
         ret = create_service_thread(inoti_service, NULL);
 #endif
-#if 0
-    } else if(!strncmp(name, "echo:", 5)){
-        ret = create_service_thread(echo_service, 0);
-#endif
+    } else if(!strncmp(name, "sysinfo:", 8)){
+        ret = create_service_thread(get_platforminfo, 0);
+    } else if(!strncmp(name, "capability:", 11)){
+        ret = create_service_thread(get_capability, 0);
+    } else if(!strncmp(name, "boot:", 5)){
+        if (is_emulator()) {
+            ret = create_service_thread(get_boot, 0);
+        }
+    } else if(!strncmp(name, "shellconf:", 10)){
+        if(!strncmp(name+10, "syncwinsz:", 10)){
+            ret = create_service_thread(sync_windowsize, (void *)name+20);
+        }
+    } else if(!strncmp(name, "tzplatformenv:", 14)) {
+       char* env_variable = NULL;
+       env_variable = strdup(name+14);
+       ret = create_service_thread(get_tzplatform_env, (void *)(env_variable));
+    } else if(!strncmp(name, "appcmd:", 7)){
+        ret = request_appcmd_to_plugin(name+7);
     }
+
     if (ret >= 0) {
         if (close_on_exec(ret) < 0) {
             D("failed to close fd exec\n");