Implementation of fork-exec
[sdk/target/sdbd.git] / src / services.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <grp.h>
23
24 #include "sysdeps.h"
25
26 //#define  TRACE_TAG  TRACE_SERVICES
27 #define LOG_TAG "SDBD_TRACE_SERVICES"
28 #include "log.h"
29
30 #include "sdb.h"
31 #include "file_sync_service.h"
32
33 #include <sys/inotify.h>
34 #include "sdktools.h"
35 #include <sys/socket.h>
36 #include <sys/un.h>
37
38 #include "strutils.h"
39 #include "utils.h"
40 #include <system_info.h>
41 #include <tzplatform_config.h>
42 #include <sys/smack.h>
43
44 #include <vconf.h>
45 #include <limits.h>
46
47 #include <termios.h>
48 #include <sys/ioctl.h>
49
50 #include "sdbd_plugin.h"
51 #include "plugin.h"
52
53 #define ENV_BUF_MAX     4096
54
55 typedef struct stinfo stinfo;
56
57 struct stinfo {
58     void (*func)(int fd, void *cookie);
59     int fd;
60     void *cookie;
61 };
62
63 extern int create_async_extcmd_proc_thread( int cmd, parameters* in );
64
65 void *service_bootstrap_func(void *x)
66 {
67     stinfo *sti = x;
68     sti->func(sti->fd, sti->cookie);
69     free(sti);
70     return 0;
71 }
72
73 static int is_support_interactive_shell()
74 {
75     return (!strncmp(g_capabilities.intershell_support, PLUGIN_RET_ENABLED, strlen(PLUGIN_RET_ENABLED)));
76 }
77
78 #if 0
79 extern int recovery_mode;
80
81 static void recover_service(int s, void *cookie)
82 {
83     unsigned char buf[4096];
84     unsigned count = (unsigned) cookie;
85     int fd;
86
87     fd = sdb_creat("/tmp/update", 0644);
88     if(fd < 0) {
89         sdb_close(s);
90         return;
91     }
92
93     while(count > 0) {
94         unsigned xfer = (count > 4096) ? 4096 : count;
95         if(readx(s, buf, xfer)) break;
96         if(writex(fd, buf, xfer)) break;
97         count -= xfer;
98     }
99
100     if(count == 0) {
101         writex(s, "OKAY", 4);
102     } else {
103         writex(s, "FAIL", 4);
104     }
105     sdb_close(fd);
106     sdb_close(s);
107
108     fd = sdb_creat("/tmp/update.begin", 0644);
109     sdb_close(fd);
110 }
111
112 #endif
113
114 static int is_support_rootonoff()
115 {
116     return (!strncmp(g_capabilities.rootonoff_support, PLUGIN_RET_ENABLED, strlen(PLUGIN_RET_ENABLED)));
117 }
118
119 void rootshell_service(int fd, void *cookie)
120 {
121     char buf[100];
122     char *mode = (char*) cookie;
123
124     if (!strcmp(mode, "on")) {
125         if (rootshell_mode == 1) {
126             //snprintf(buf, sizeof(buf), "Already changed to sdk user mode\n");
127             // do not show message
128         } else {
129             if (is_support_rootonoff()) {
130                 rootshell_mode = 1;
131                 //allows a permitted user to execute a command as the superuser
132                 snprintf(buf, sizeof(buf), "Switched to 'root' account mode\n");
133             } else {
134                 snprintf(buf, sizeof(buf), "Permission denied\n");
135             }
136             writex(fd, buf, strlen(buf));
137         }
138     } else if (!strcmp(mode, "off")) {
139         if (rootshell_mode == 1) {
140             rootshell_mode = 0;
141             snprintf(buf, sizeof(buf), "Switched to 'sdk user' account mode\n");
142             writex(fd, buf, strlen(buf));
143         }
144     } else {
145         snprintf(buf, sizeof(buf), "Unknown command option : %s\n", mode);
146         writex(fd, buf, strlen(buf));
147     }
148     D("set rootshell to %s\n", rootshell_mode == 1 ? "root" : SDK_USER_NAME);
149     free(mode);
150     sdb_close(fd);
151 }
152
153 enum tzplatform_get_env_error_status {
154     NO_ERROR_TZPLATFORM_ENV = 0,
155     ERROR_TZPLATFORM_ENV_GENERAL = 1,
156     ERROR_TZPLATFORM_ENV_INVALID_VARIABLES = 2,
157 };
158
159 void get_tzplatform_env(int fd, void *cookie) {
160     char buf[PATH_MAX] = { 0, };
161     char *env_name = (char*) cookie;
162     D("environment variable name: %s\n", env_name);
163     enum tzplatform_variable env_id = tzplatform_getid(env_name);
164     if (env_id != _TZPLATFORM_VARIABLES_INVALID_) {
165         const char *env_value = tzplatform_getenv(env_id);
166         if (env_value) {
167             D("environment value : %s\n", env_value);
168             snprintf(buf, sizeof(buf), "%d%s", NO_ERROR_TZPLATFORM_ENV, env_value);
169         } else {
170             E("failed to get environment value using tzplatform_getenv");
171             snprintf(buf, sizeof(buf), "%d", ERROR_TZPLATFORM_ENV_GENERAL);
172         }
173     } else {
174         E("environment name (%s) is invalid\n", env_name);
175         snprintf(buf, sizeof(buf), "%d", ERROR_TZPLATFORM_ENV_INVALID_VARIABLES);
176     }
177     writex(fd, buf, strlen(buf));
178     free(env_name);
179     sdb_close(fd);
180 }
181
182 void reboot_service(int fd, void *arg)
183 {
184 #if 0
185     char buf[100];
186     int pid, ret;
187
188     sync();
189
190     /* Attempt to unmount the SD card first.
191      * No need to bother checking for errors.
192      */
193     pid = fork();
194     if (pid == 0) {
195         /* ask vdc to unmount it */
196         // prevent: Use of untrusted string value (TAINTED_STRING)
197         execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount",
198                 getenv("EXTERNAL_STORAGE"), "force", NULL);
199     } else if (pid > 0) {
200         /* wait until vdc succeeds or fails */
201         waitpid(pid, &ret, 0);
202     }
203
204     ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
205     if (ret < 0) {
206         snprintf(buf, sizeof(buf), "reboot failed: %s errno:%d\n", errno);
207         writex(fd, buf, strlen(buf));
208     }
209     free(arg);
210     sdb_close(fd);
211 #endif
212 }
213
214 #define EVENT_SIZE  ( sizeof (struct inotify_event) )
215 #define BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )
216 #define CS_PATH     tzplatform_getenv(TZ_SYS_CRASH)
217
218 void inoti_service(int fd, void *arg)
219 {
220     int wd;
221     int ifd;
222     char buffer[BUF_LEN];
223
224     I( "inoti_service start\n");
225     ifd = inotify_init();
226
227     if ( ifd < 0 ) {
228         E( "inotify_init failed\n");
229         sdb_close(fd);
230         return;
231     }
232
233     wd = inotify_add_watch(ifd, CS_PATH, IN_CREATE | IN_MOVE);
234     if ( wd < 0 ) {
235         E("inotify_add_watch failed (errno :%d)\n", errno);
236         sdb_close(ifd);
237         sdb_close(fd);
238         return;
239     }
240
241     for ( ; ; ) {
242         int length, i = 0;
243         length = sdb_read( ifd, buffer, BUF_LEN );
244
245         if ( length < 0 ) {
246             E( "inoti read failed\n");
247             goto done;
248         }
249         int payload = length >= EVENT_SIZE ? length - EVENT_SIZE : 0;
250         while (i >= 0 && i <= payload) {
251             struct inotify_event *event = (struct inotify_event *) &buffer[i];
252             if (event->len) {
253                 if (event->mask & IN_CREATE) {
254                     if (!(event->mask & IN_ISDIR)) {
255                         char *cspath = NULL;
256                         int len = asprintf(&cspath, "%s/%s", CS_PATH, event->name);
257                         if (len >= 0) {
258                             D( "The file %s was created.\n", cspath);
259                             writex(fd, cspath, len);
260                             free(cspath);
261                         } else {
262                             E( "asprintf was failed\n" );
263                         }
264                     }
265                 } else if (event->mask & IN_MOVE) {
266                     if (!(event->mask & IN_ISDIR)) {
267                         char *cspath = NULL;
268                         int len = asprintf(&cspath, "%s/%s", CS_PATH, event->name);
269                         if (len >= 0) {
270                             D("The file %s was moved.\n", cspath);
271                             writex(fd, cspath, len);
272                             free(cspath);
273                         } else {
274                             E("asprintf was failed\n");
275                         }
276                     }
277                 }
278             }
279             if (i + EVENT_SIZE + event->len < event->len) { // in case of integer overflow
280                 break;
281             }
282             i += EVENT_SIZE + event->len;
283         }
284     }
285
286 done:
287     inotify_rm_watch( ifd, wd );
288     sdb_close(ifd);
289     sdb_close(fd);
290     I( "inoti_service end\n");
291 }
292
293 #if 0
294 static void echo_service(int fd, void *cookie)
295 {
296     char buf[4096];
297     int r;
298     char *p;
299     int c;
300
301     for(;;) {
302         r = read(fd, buf, 4096);
303         if(r == 0) goto done;
304         if(r < 0) {
305             if(errno == EINTR) continue;
306             else goto done;
307         }
308
309         c = r;
310         p = buf;
311         while(c > 0) {
312             r = write(fd, p, c);
313             if(r > 0) {
314                 c -= r;
315                 p += r;
316                 continue;
317             }
318             if((r < 0) && (errno == EINTR)) continue;
319             goto done;
320         }
321     }
322 done:
323     close(fd);
324 }
325 #endif
326
327 static int create_service_thread(void (*func)(int, void *), void *cookie)
328 {
329     stinfo *sti;
330     sdb_thread_t t;
331     int s[2];
332
333     if(sdb_socketpair(s)) {
334         E("cannot create service socket pair\n");
335         return -1;
336     }
337
338     sti = malloc(sizeof(stinfo));
339     if(sti == 0) fatal("cannot allocate stinfo");
340     sti->func = func;
341     sti->cookie = cookie;
342     sti->fd = s[1];
343
344     if(sdb_thread_create( &t, service_bootstrap_func, sti)){
345         free(sti);
346         sdb_close(s[0]);
347         sdb_close(s[1]);
348         E("cannot create service thread\n");
349         return -1;
350     }
351
352     D("service thread started, %d:%d\n",s[0], s[1]);
353     return s[0];
354 }
355
356 static void redirect_and_exec(int pts, const char *cmd, char * const argv[], char * const envp[])
357 {
358     dup2(pts, 0);
359     dup2(pts, 1);
360     dup2(pts, 2);
361
362     sdb_close(pts);
363
364     execve(cmd, argv, envp);
365 }
366
367 int create_subprocess(const char *cmd, pid_t *pid, char * const argv[], char * const envp[])
368 {
369     char devname[64];
370     int ptm;
371
372     ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
373     if(ptm < 0){
374         E("[ cannot open /dev/ptmx - errno:%d ]\n",errno);
375         return -1;
376     }
377     if (fcntl(ptm, F_SETFD, FD_CLOEXEC) < 0) {
378         E("[ cannot set cloexec to /dev/ptmx - errno:%d ]\n",errno);
379     }
380
381     if(grantpt(ptm) || unlockpt(ptm) ||
382         ptsname_r(ptm, devname, sizeof(devname)) != 0 ){
383         E("[ trouble with /dev/ptmx - errno:%d ]\n", errno);
384         sdb_close(ptm);
385         return -1;
386     }
387
388     *pid = fork();
389     if(*pid < 0) {
390         E("- fork failed: errno:%d -\n", errno);
391         sdb_close(ptm);
392         return -1;
393     }
394
395     if(*pid == 0){
396         int pts;
397
398         setsid();
399
400         pts = unix_open(devname, O_RDWR);
401         if(pts < 0) {
402             fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
403             exit(-1);
404         }
405
406         sdb_close(ptm);
407
408         // set OOM adjustment to zero
409         {
410             char text[64];
411             //snprintf(text, sizeof text, "/proc/%d/oom_score_adj", getpid());
412             snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
413             int fd = sdb_open(text, O_WRONLY);
414             if (fd >= 0) {
415                 sdb_write(fd, "0", 1);
416                 sdb_close(fd);
417             } else {
418                // FIXME: not supposed to be here
419                E("sdb: unable to open %s due to errno:%d\n", text, errno);
420             }
421         }
422
423         if (should_drop_privileges()) {
424             if (argv[2] != NULL && request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_ROOTCMD, argv[2])) {
425                 // do nothing
426                 D("sdb: executes root commands!!:%s\n", argv[2]);
427             } else {
428                 if (getuid() != g_sdk_user_id && set_sdk_user_privileges(RESERVE_CAPABILITIES_AFTER_FORK) < 0) {
429                     fprintf(stderr, "failed to set SDK user privileges\n");
430                     exit(-1);
431                 }
432             }
433         } else {
434             set_root_privileges();
435         }
436         redirect_and_exec(pts, cmd, argv, envp);
437         fprintf(stderr, "- exec '%s' failed: (errno:%d) -\n",
438                 cmd, errno);
439         exit(-1);
440     } else {
441         // Don't set child's OOM adjustment to zero.
442         // Let the child do it itself, as sometimes the parent starts
443         // running before the child has a /proc/pid/oom_adj.
444         // """sdb: unable to open /proc/644/oom_adj""" seen in some logs.
445         return ptm;
446     }
447 }
448
449 /* receive the ptm from child, sdbd-user */
450 static ssize_t recv_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
451 {
452     struct msghdr msg;
453     struct iovec iov[1];
454     struct cmsghdr *pheader;
455     union {
456         struct cmsghdr cmhdr;
457         char control[CMSG_SPACE(sizeof(int))];
458     } control_un;
459     ssize_t ret;
460
461     memset(&msg, 0, sizeof(msg));
462     msg.msg_control = control_un.control;
463     msg.msg_controllen = sizeof(control_un.control);
464
465     msg.msg_name = NULL;
466     msg.msg_namelen = 0;
467
468     iov[0].iov_base = ptr;
469     iov[0].iov_len = nbytes;
470     msg.msg_iov = iov;
471     msg.msg_iovlen = 1;
472
473     if ((ret = recvmsg(fd, &msg, 0)) <= 0) {
474         return ret;
475     }
476
477     if ((pheader = CMSG_FIRSTHDR(&msg)) != NULL &&
478             pheader->cmsg_len == CMSG_LEN(sizeof(int))) {
479         if (pheader->cmsg_level != SOL_SOCKET) {
480             I("sdb: control level != SOL_SOCKET");
481             exit(-1);
482         }
483         if (pheader->cmsg_type != SCM_RIGHTS) {
484             I("sdb: control type != SCM_RIGHTS");
485             exit(-1);
486         }
487         memcpy(recvfd, CMSG_DATA(pheader), sizeof(int));
488     } else {
489         *recvfd = -1;
490     }
491
492     return ret;
493 }
494
495 int create_userprocess(const char *cmd, pid_t *pid, char * const argv[], char * const envp[])
496 {
497     *pid = fork();
498     if(*pid < 0) {
499         E("- fork failed: errno:%d -\n", errno);
500         return -1;
501     }
502
503     if (*pid == 0) {
504         if (should_drop_privileges()) {
505             if (argv[2] != NULL && request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_ROOTCMD, argv[2])) {
506                 set_root_privileges();
507                 D("sdb: executes root commands!!:%s\n", argv[2]);
508             } else {
509                 if (getuid() != g_sdk_user_id && set_sdk_user_privileges(RESERVE_CAPABILITIES_AFTER_FORK) < 0) {
510                     E("failed to set SDK user privileges\n");
511                     exit(-1);
512                 }
513             }
514         } else {
515             set_root_privileges();
516         }
517         /* exec sdbduser */
518         execve(cmd, argv, envp);
519         E("- exec '%s' failed: (errno:%d) -\n", cmd, errno);
520         exit(-1);
521     } else {
522         // Don't set child's OOM adjustment to zero.
523         // Let the child do it itself, as sometimes the parent starts
524         // running before the child has a /proc/pid/oom_adj.
525         // """sdb: unable to open /proc/644/oom_adj""" seen in some logs.
526         char tmptext[32];
527         int ptm = -1;
528         struct sockaddr_un addr;
529         int sock;
530         int trycnt = 1;
531
532         /* The child process will open .sdbduser_pid.sock socket.
533            This socket transfers the ptm fd that was opened by child process.
534            You can see related code on subprocess.c file. */
535         snprintf(tmptext, sizeof tmptext, "/tmp/.sdbduser_%d.sock", (int)(*pid));
536         char *sockpath = strdup(tmptext);
537         if (sockpath == NULL) {
538             E("failed to get socket path, %d\n", errno);
539             return -1;
540         }
541         D("read fd socket is %s\n", sockpath);
542
543         sock = socket(PF_LOCAL, SOCK_STREAM, 0);
544         if (sock == -1) {
545             E("socket error, %d\n", errno);
546             free(sockpath);
547             return -1;
548         }
549         memset(&addr, 0, sizeof(addr));
550         addr.sun_family = AF_LOCAL;
551         s_strncpy(addr.sun_path, sockpath, strlen(sockpath));
552         int slen = offsetof(struct sockaddr_un, sun_path) + strlen(sockpath);
553         while (connect(sock, (struct sockaddr *)&addr, slen) == -1
554                 && trycnt < 300) {
555             D("try to connect socket %s, %d times.\n", sockpath, trycnt++);
556             /* sleep maximum 100 times */
557             usleep(10000);
558         }
559         if (trycnt == 300) {
560             E("failed to connect, errno: %d\n", errno);
561             if (sdb_close(sock) == -1) {
562                 E("close sock error, %d\n", errno);
563             }
564             free(sockpath);
565             return -1;
566         }
567
568         char c;
569         if (recv_fd(sock, &c, 1, &ptm) == -1) {
570             E("recv_fd error, %d\n", errno);
571             if (sdb_close(sock) == -1) {
572                 E("close sock error, %d\n", errno);
573             }
574             free(sockpath);
575             return -1;
576         } else {
577             D("got ptm fd from child, fd: %d\n", ptm);
578         }
579
580         if (sdb_close(sock) == -1) {
581             E("close sock error, %d\n", errno);
582         }
583         free(sockpath);
584
585         I("getting child's ptm successed.\n");
586         return ptm;
587     }
588 }
589
590 #define USER_DAEMON_COMMAND "/usr/sbin/sdbd-user"
591 #define LOGIN_COMMAND "/bin/login"
592 #define SUPER_USER    "root"
593 #define LOGIN_CONFIG  "/etc/login.defs"
594
595 static void subproc_waiter_service(int fd, void *cookie)
596 {
597     pid_t pid = (pid_t)((intptr_t)cookie);
598
599     D("entered. fd=%d of pid=%d\n", fd, pid);
600     for (;;) {
601         int status;
602         pid_t p = waitpid(pid, &status, 0);
603         D("entered fd=%d, post waitpid(pid=%d)\n", fd, p);
604         if (p == pid) {
605             D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
606             if (WIFEXITED(status)) {
607                 D("*** Exit code %d\n", WEXITSTATUS(status));
608                 break;
609             } else if (WIFSIGNALED(status)) {
610                 D("*** Killed by signal %d\n", WTERMSIG(status));
611                 break;
612             } else {
613                 D("*** Killed by unknown code %d\n", status);
614                 break;
615             }
616          }
617     }
618     D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
619     if (SHELL_EXIT_NOTIFY_FD >=0) {
620       int res;
621       res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
622       D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
623         SHELL_EXIT_NOTIFY_FD, pid, res, errno);
624     }
625 }
626
627 void get_env(char *key, char **env)
628 {
629     FILE *fp;
630     char buf[1024];
631     char *s, *e, *value;
632
633     fp = fopen (LOGIN_CONFIG, "r");
634     if (NULL == fp) {
635         return;
636     }
637
638     while (fgets(buf, (int) sizeof (buf), fp) != NULL) {
639         s = buf;
640         e = buf + (strlen(buf) - 1);
641
642         // trim string
643         while( (e > s) && (*e == ' ' ||  *e == '\n' || *e == '\t')) {
644             e--;
645         }
646         *(e+1) ='\0';
647
648         while(*s != '\0' && (*s == ' ' || *s == '\t' || *s == '\n')) {
649             s++;
650         }
651
652         // skip comment or null string
653         if (*s == '#' || *s == '\0') {
654             continue;
655         }
656         value = s + strcspn(s, " \t");
657         *value++ = '\0';
658
659         if(!strcmp(buf, key)) {
660             *env = strdup(value);
661             break;
662         }
663     }
664
665     fclose(fp);
666 }
667
668 static int create_subproc_thread(const char *name, int lines, int columns)
669 {
670     stinfo *sti;
671     sdb_thread_t t;
672     int ret_fd;
673     pid_t pid;
674     char *value = NULL;
675     char *trim_value = NULL;
676     char path[PATH_MAX];
677     char *envp[MAX_TOKENS];
678     int envp_cnt = 0;
679
680     memset(path, 0, sizeof(path));
681     memset(envp, 0, sizeof(envp));
682
683     envp[envp_cnt++] = strdup("TERM=linux");
684     envp[envp_cnt++] = strdup("DISPLAY=:0");
685
686     if (should_drop_privileges()) {
687         if (g_sdk_home_dir_env) {
688             envp[envp_cnt++] = strdup(g_sdk_home_dir_env);
689         } else {
690             envp[envp_cnt++] = strdup("HOME=/home/owner");
691         }
692         get_env("ENV_PATH", &value);
693     } else {
694         get_env("ENV_SUPATH", &value);
695         if(value == NULL) {
696             get_env("ENV_ROOTPATH", &value);
697         }
698         envp[envp_cnt++] = strdup("HOME=/root");
699     }
700     if (value != NULL) {
701         trim_value = str_trim(value);
702         if (trim_value != NULL) {
703             // if string is not including 'PATH=', append it.
704             if (strncmp(trim_value, "PATH", 4)) {
705                 snprintf(path, sizeof(path), "PATH=%s", trim_value);
706             } else {
707                 snprintf(path, sizeof(path), "%s", trim_value);
708             }
709             envp[envp_cnt++] = strdup(path);
710         } else {
711             snprintf(path, sizeof(path), "%s", value);
712             envp[envp_cnt++] = strdup(path);
713         }
714         free(value);
715     }
716
717     /* get environment variables from plugin */
718     char *envp_plugin = NULL;
719     envp_plugin = malloc(ENV_BUF_MAX);
720     if (envp_plugin == NULL) {
721         E("Cannot allocate the shell commnad buffer.");
722         return -1;
723     }
724     memset(envp_plugin, 0, ENV_BUF_MAX);
725     if (!request_conversion_to_plugin(PLUGIN_SYNC_CMD_GET_SHELL_ENV, NULL,
726                 envp_plugin, ENV_BUF_MAX)) {
727         E("Failed to convert the shell command. (%s)\n", name);
728         free(envp_plugin);
729         return -1;
730     } else {
731        if(envp_plugin[0] != '\0') {
732             envp_cnt = tokenize_append(envp_plugin, "\n", envp, MAX_TOKENS, envp_cnt);
733         }
734     }
735     free(envp_plugin);
736
737     /* Last element of envp must be the NULL-terminator to prevent execvp fail */
738     envp[envp_cnt] = NULL;
739
740     if(name) { // in case of shell execution directly
741         // Check the shell command validation.
742         if (!request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_SHELLCMD, name)) {
743             E("This shell command is invalid. (%s)\n", name);
744             return -1;
745         }
746
747         // Convert the shell command.
748         char *new_cmd = NULL;
749         new_cmd = malloc(SDBD_SHELL_CMD_MAX);
750         if(new_cmd == NULL) {
751             E("Cannot allocate the shell commnad buffer.");
752             return -1;
753         }
754
755         memset(new_cmd, 0, SDBD_SHELL_CMD_MAX);
756         if(!request_conversion_to_plugin(PLUGIN_SYNC_CMD_CONVERT_SHELLCMD, name, new_cmd, SDBD_SHELL_CMD_MAX)) {
757             E("Failed to convert the shell command. (%s)\n", name);
758             free(new_cmd);
759             return -1;
760         }
761
762         D("converted cmd : %s\n", new_cmd);
763
764         char *args[] = {
765             USER_DAEMON_COMMAND,
766             "-c",
767             NULL,
768             NULL,
769         };
770         args[2] = new_cmd;
771
772         ret_fd = create_userprocess(USER_DAEMON_COMMAND, &pid, (char * const*)args, (char * const*)envp);
773         free(new_cmd);
774     } else { // in case of shell interactively
775         // Check the capability for interactive shell support.
776         if (!is_support_interactive_shell()) {
777             E("This platform dose NOT support the interactive shell\n");
778             return -1;
779         }
780
781         char * const args[] = {
782                 USER_DAEMON_COMMAND,
783                 "-",
784                 NULL,
785         };
786         ret_fd = create_userprocess(USER_DAEMON_COMMAND, &pid, (char * const*)args, (char * const*)envp);
787 #if 0   // FIXME: should call login command instead of /bin/sh
788         if (should_drop_privileges()) {
789             char *args[] = {
790                 USER_DAEMON_COMMAND,
791                 "-",
792                 NULL,
793             };
794             ret_fd = create_userprocess(USER_DAEMON_COMMAND, &pid, args, envp);
795         } else {
796             char *args[] = {
797                 LOGIN_COMMAND,
798                 "-f",
799                 SUPER_USER,
800                 NULL,
801             };
802             ret_fd = create_subprocess(LOGIN_COMMAND, &pid, args, envp);
803         }
804 #endif
805     }
806
807     /* free environment variables */
808     int i = 0;
809     if(envp_cnt > 0) {
810         for(i = 0; i < envp_cnt; i++) {
811             if(envp[i]) {
812                 D("envp[%d] = %s\n", i, envp[i]);
813                 free(envp[i]);
814             }
815         }
816     }
817
818     D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
819
820     if (ret_fd < 0) {
821         E("cannot create service thread\n");
822         return -1;
823     }
824
825     if (lines > 0 && columns > 0) {
826         D("shell size lines=%d, columns=%d\n", lines, columns);
827         struct winsize win_sz;
828         win_sz.ws_row = lines;
829         win_sz.ws_col = columns;
830
831         if (ioctl(ret_fd, TIOCSWINSZ, &win_sz) < 0) {
832             E("failed to sync window size.\n");
833         }
834     }
835
836     sti = malloc(sizeof(stinfo));
837     if(sti == 0) fatal("cannot allocate stinfo");
838     sti->func = subproc_waiter_service;
839     sti->cookie = (void*)((intptr_t)pid);
840     sti->fd = ret_fd;
841
842     if(sdb_thread_create( &t, service_bootstrap_func, sti)){
843         free(sti);
844         sdb_close(ret_fd);
845         E("cannot create service thread\n");
846         return -1;
847     }
848
849     D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
850     return ret_fd;
851 }
852
853 static int create_sync_subprocess(void (*func)(int, void *), void* cookie) {
854     stinfo *sti;
855     sdb_thread_t t;
856     int s[2];
857
858 #ifdef EXEC_AFTER_FORK
859     if(sdb_socketpair_without_execclose(s)) {
860         E("cannot create service socket pair\n");
861         return -1;
862     }
863 #else
864     if(sdb_socketpair(s)) {
865         E("cannot create service socket pair\n");
866         return -1;
867     }
868 #endif
869
870     D("SERVICE create_sync_subprocess cookie=%s\n",(char*)cookie);
871     pid_t pid = fork();
872
873     if (pid == 0) {
874         sdb_close(s[0]);
875 #ifdef EXEC_AFTER_FORK
876         // exec the new process to do file sync
877         char *fname="/usr/sbin/sdbd-service";
878         char *arg[5];
879         char targ[10];
880         char smarg[10];
881         sprintf(targ,"%d",s[1]);
882         sprintf(smarg, "%d",rootshell_mode);
883         D("SERVICE fd to be used by child process %d",s[1]);
884         D("SERVICE rootmode to be used by child process %s",smarg);
885         arg[0]=fname;
886         arg[1]=targ;
887         arg[2]= strdup((char*)cookie);
888         D("SERVICE cookie to be used by child process %s",arg[2]);
889         arg[3]=smarg;
890         arg[4]=NULL;
891         execvp(fname,arg);
892 #else
893         func(s[1], cookie);
894         exit(-1);
895 #endif
896     } else if (pid > 0) {
897         D("SERVICE fd passed by parent process %d",s[1]);
898         sdb_close(s[1]);
899         // FIXME: do not wait child process hear
900         //waitpid(pid, &ret, 0);
901     } else {
902         E("- fork failed: errno:%d -\n", errno);
903         sdb_close(s[0]);
904         sdb_close(s[1]);
905         E("cannot create sync service sub process\n");
906         return -1;
907     }
908
909     sti = malloc(sizeof(stinfo));
910     if(sti == 0) fatal("cannot allocate stinfo");
911     sti->func = subproc_waiter_service;
912     sti->cookie = (void*)((intptr_t)pid);
913     sti->fd = s[0];
914
915     if(sdb_thread_create( &t, service_bootstrap_func, sti)){
916         free(sti);
917         sdb_close(s[0]);
918         printf("cannot create service monitor thread\n");
919         return -1;
920     }
921
922     D("service process started, fd=%d pid=%d\n",s[0], pid);
923     return s[0];
924 }
925
926 static int create_syncproc_thread(const char *cmd)
927 {
928     int ret_fd;
929
930     ret_fd = create_sync_subprocess(file_sync_service, (void*)cmd);
931     // FIXME: file missing bug when root on mode
932     /*
933     if (should_drop_privileges()) {
934         ret_fd = create_sync_subprocess(file_sync_service, NULL);
935     } else {
936         ret_fd = create_service_thread(file_sync_service, NULL);
937     }
938     */
939
940     return ret_fd;
941 }
942
943 static int create_extcmd_subproc_thread(const char *name, int lines, int columns)
944 {
945     stinfo *sti;
946     sdb_thread_t t;
947     int ret_fd;
948     pid_t pid;
949     char *value = NULL;
950     char *trim_value = NULL;
951     char path[PATH_MAX];
952     char *envp[MAX_TOKENS];
953     int envp_cnt = 0;
954
955     memset(path, 0, sizeof(path));
956     memset(envp, 0, sizeof(envp));
957
958     envp[envp_cnt++] = strdup("TERM=linux");
959     envp[envp_cnt++] = strdup("DISPLAY=:0");
960
961     if (should_drop_privileges()) {
962         if (g_sdk_home_dir_env) {
963             envp[envp_cnt++] = strdup(g_sdk_home_dir_env);
964         } else {
965             envp[envp_cnt++] = strdup("HOME=/home/owner");
966         }
967         get_env("ENV_PATH", &value);
968     } else {
969         get_env("ENV_SUPATH", &value);
970         if(value == NULL) {
971             get_env("ENV_ROOTPATH", &value);
972         }
973         envp[envp_cnt++] = strdup("HOME=/root");
974     }
975     if (value != NULL) {
976         trim_value = str_trim(value);
977         if (trim_value != NULL) {
978             // if string is not including 'PATH=', append it.
979             if (strncmp(trim_value, "PATH", 4)) {
980                 snprintf(path, sizeof(path), "PATH=%s", trim_value);
981             } else {
982                 snprintf(path, sizeof(path), "%s", trim_value);
983             }
984             envp[envp_cnt++] = strdup(path);
985         } else {
986             snprintf(path, sizeof(path), "%s", value);
987             envp[envp_cnt++] = strdup(path);
988         }
989         free(value);
990     }
991
992     /* get environment variables from plugin */
993     char *envp_plugin = NULL;
994     envp_plugin = malloc(ENV_BUF_MAX);
995     if (envp_plugin == NULL) {
996         E("Cannot allocate the shell commnad buffer.");
997         return -1;
998     }
999     memset(envp_plugin, 0, ENV_BUF_MAX);
1000     if (!request_extcmd_conversion_to_plugin(PLUGIN_SYNC_CMD_GET_SHELL_ENV, NULL,
1001                 envp_plugin, ENV_BUF_MAX)) {
1002         E("Failed to convert the shell command. (%s)\n", name);
1003         free(envp_plugin);
1004         return -1;
1005     } else {
1006        if(envp_plugin[0] != '\0') {
1007             envp_cnt = tokenize_append(envp_plugin, "\n", envp, MAX_TOKENS, envp_cnt);
1008         }
1009     }
1010     free(envp_plugin);
1011
1012     /* Last element of envp must be the NULL-terminator to prevent execvp fail */
1013     envp[envp_cnt] = NULL;
1014
1015     if(name) { // in case of shell execution directly
1016         // Check the shell command validation.
1017         if (!request_extcmd_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_SHELLCMD, name)) {
1018             E("This extcmd command is invalid. (%s)\n", name);
1019             return -1;
1020         }
1021
1022         // Convert the shell command.
1023         char *new_cmd = NULL;
1024         new_cmd = malloc(SDBD_SHELL_CMD_MAX);
1025         if(new_cmd == NULL) {
1026             E("Cannot allocate the shell commnad buffer.");
1027             return -1;
1028         }
1029
1030         memset(new_cmd, 0, SDBD_SHELL_CMD_MAX);
1031         if(!request_extcmd_conversion_to_plugin(PLUGIN_SYNC_CMD_CONVERT_SHELLCMD, name, new_cmd, SDBD_SHELL_CMD_MAX)) {
1032             E("Failed to convert the shell command. (%s)\n", name);
1033             free(new_cmd);
1034             return -1;
1035         }
1036
1037         D("converted cmd : %s\n", new_cmd);
1038
1039         char *args[] = {
1040             USER_DAEMON_COMMAND,
1041             "-c",
1042             NULL,
1043             NULL,
1044         };
1045         args[2] = new_cmd;
1046
1047         ret_fd = create_userprocess(USER_DAEMON_COMMAND, &pid, (char * const*)args, (char * const*)envp);
1048         free(new_cmd);
1049     } else { // in case of shell interactively
1050         // Check the capability for interactive shell support.
1051         if (!is_support_interactive_shell()) {
1052             E("This platform dose NOT support the interactive shell\n");
1053             return -1;
1054         }
1055
1056         char * const args[] = {
1057                 USER_DAEMON_COMMAND,
1058                 "-",
1059                 NULL,
1060         };
1061         ret_fd = create_userprocess(USER_DAEMON_COMMAND, &pid, (char * const*)args, (char * const*)envp);
1062 #if 0   // FIXME: should call login command instead of /bin/sh
1063         if (should_drop_privileges()) {
1064             char *args[] = {
1065                 USER_DAEMON_COMMAND,
1066                 "-",
1067                 NULL,
1068             };
1069             ret_fd = create_userprocess(USER_DAEMON_COMMAND, &pid, args, envp);
1070         } else {
1071             char *args[] = {
1072                 LOGIN_COMMAND,
1073                 "-f",
1074                 SUPER_USER,
1075                 NULL,
1076             };
1077             ret_fd = create_subprocess(LOGIN_COMMAND, &pid, args, envp);
1078         }
1079 #endif
1080     }
1081
1082     /* free environment variables */
1083     int i = 0;
1084     if(envp_cnt > 0) {
1085         for(i = 0; i < envp_cnt; i++) {
1086             if(envp[i]) {
1087                 D("envp[%d] = %s\n", i, envp[i]);
1088                 free(envp[i]);
1089             }
1090         }
1091     }
1092
1093     D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
1094
1095     if (ret_fd < 0) {
1096         E("cannot create service thread\n");
1097         return -1;
1098     }
1099
1100     if (lines > 0 && columns > 0) {
1101         D("shell size lines=%d, columns=%d\n", lines, columns);
1102         struct winsize win_sz;
1103         win_sz.ws_row = lines;
1104         win_sz.ws_col = columns;
1105
1106         if (ioctl(ret_fd, TIOCSWINSZ, &win_sz) < 0) {
1107             E("failed to sync window size.\n");
1108         }
1109     }
1110
1111     sti = malloc(sizeof(stinfo));
1112     if(sti == 0) fatal("cannot allocate stinfo");
1113     sti->func = subproc_waiter_service;
1114     sti->cookie = (void*)((intptr_t)pid);
1115     sti->fd = ret_fd;
1116
1117     if(sdb_thread_create( &t, service_bootstrap_func, sti)){
1118         free(sti);
1119         sdb_close(ret_fd);
1120         E("cannot create service thread\n");
1121         return -1;
1122     }
1123
1124     D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
1125     return ret_fd;
1126 }
1127
1128 static void get_platforminfo(int fd, void *cookie) {
1129     pinfo sysinfo;
1130
1131     char *value = NULL;
1132     s_strncpy(sysinfo.platform_info_version, INFO_VERSION, sizeof(sysinfo.platform_info_version));
1133
1134     int r = system_info_get_platform_string("http://tizen.org/system/model_name", &value);
1135     if (r != SYSTEM_INFO_ERROR_NONE) {
1136         s_strncpy(sysinfo.model_name, UNKNOWN, sizeof(sysinfo.model_name));
1137         E("fail to get system model:%d\n", errno);
1138     } else {
1139         s_strncpy(sysinfo.model_name, value, sizeof(sysinfo.model_name));
1140         D("returns model_name:%s\n", value);
1141         if (value != NULL) {
1142             free(value);
1143         }
1144     }
1145
1146     r = system_info_get_platform_string("http://tizen.org/system/platform.name", &value);
1147     if (r != SYSTEM_INFO_ERROR_NONE) {
1148         s_strncpy(sysinfo.platform_name, UNKNOWN, sizeof(sysinfo.platform_name));
1149         E("fail to get platform name:%d\n", errno);
1150     } else {
1151         s_strncpy(sysinfo.platform_name, value, sizeof(sysinfo.platform_name));
1152         D("returns platform_name:%s\n", value);
1153         if (value != NULL) {
1154             free(value);
1155         }
1156
1157     }
1158
1159     // FIXME: the result is different when using SYSTEM_INFO_KEY_TIZEN_VERSION_NAME
1160     r = system_info_get_platform_string("tizen.org/feature/platform.version", &value);
1161     if (r != SYSTEM_INFO_ERROR_NONE) {
1162         s_strncpy(sysinfo.platform_version, UNKNOWN, sizeof(sysinfo.platform_version));
1163         E("fail to get platform version:%d\n", errno);
1164     } else {
1165         s_strncpy(sysinfo.platform_version, value, sizeof(sysinfo.platform_version));
1166         D("returns platform_version:%s\n", value);
1167         if (value != NULL) {
1168             free(value);
1169         }
1170     }
1171
1172     r = system_info_get_platform_string("tizen.org/feature/profile", &value);
1173     if (r != SYSTEM_INFO_ERROR_NONE) {
1174         s_strncpy(sysinfo.profile_name, UNKNOWN, sizeof(sysinfo.profile_name));
1175         E("fail to get profile name:%d\n", errno);
1176     } else {
1177         s_strncpy(sysinfo.profile_name, value, sizeof(sysinfo.profile_name));
1178         D("returns profile name:%s\n", value);
1179         if (value != NULL) {
1180             free(value);
1181         }
1182     }
1183
1184     writex(fd, &sysinfo, sizeof(pinfo));
1185
1186     sdb_close(fd);
1187 }
1188
1189 static int put_key_value_string(char* buf, int offset, int buf_size, char* key, char* value) {
1190     int len = 0;
1191     if ((len = snprintf(buf+offset, buf_size-offset, "%s:%s\n", key, value)) > 0) {
1192         return len;
1193     }
1194     return 0;
1195 }
1196
1197 static void get_capability(int fd, void *cookie) {
1198     char cap_buffer[CAPBUF_SIZE] = {0,};
1199     uint16_t offset = 0;
1200
1201     // Secure protocol support
1202     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1203             "secure_protocol", g_capabilities.secure_protocol);
1204
1205     // Interactive shell support
1206     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1207             "intershell_support", g_capabilities.intershell_support);
1208
1209     // File push/pull support
1210     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1211             "filesync_support", g_capabilities.filesync_support);
1212
1213     // USB protocol support
1214     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1215             "usbproto_support", g_capabilities.usbproto_support);
1216
1217     // Socket protocol support
1218     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1219             "sockproto_support", g_capabilities.sockproto_support);
1220
1221     // Window size synchronization support
1222     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1223             "syncwinsz_support", g_capabilities.syncwinsz_support);
1224
1225     // sdbd root permission
1226     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1227             "sdbd_rootperm", g_capabilities.root_permission);
1228
1229     // Root command support
1230     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1231             "rootonoff_support", g_capabilities.rootonoff_support);
1232
1233     // Encryption support
1234     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1235             "encryption_support", g_capabilities.encryption_support);
1236
1237     // Zone support
1238     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1239             "zone_support", g_capabilities.zone_support);
1240
1241     // Multi-User support
1242     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1243             "multiuser_support", g_capabilities.multiuser_support);
1244
1245     // CPU Architecture of model
1246     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1247             "cpu_arch", g_capabilities.cpu_arch);
1248
1249     // SDK Tool path
1250     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1251             "sdk_toolpath", g_capabilities.sdk_toolpath);
1252
1253     // Profile name
1254     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1255             "profile_name", g_capabilities.profile_name);
1256
1257     // Vendor name
1258     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1259             "vendor_name", g_capabilities.vendor_name);
1260
1261     // Target name of the launch possible
1262     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1263             "can_launch", g_capabilities.can_launch);
1264
1265     // Device name
1266     char* value = NULL;
1267     value = vconf_get_str(VCONFKEY_SETAPPL_DEVICE_NAME_STR);
1268     if(value) {
1269         snprintf(g_capabilities.device_name, sizeof(g_capabilities.device_name),
1270                 "%s", value);
1271         if (value != NULL) {
1272             free(value);
1273         }
1274     } else {
1275         snprintf(g_capabilities.device_name, sizeof(g_capabilities.device_name),
1276                 "%s", UNKNOWN);
1277         D("fail to get the Device name:%d\n", errno);
1278     }
1279     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1280             "device_name", g_capabilities.device_name);
1281
1282     // Platform version
1283     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1284             "platform_version", g_capabilities.platform_version);
1285
1286     // Product version
1287     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1288             "product_version", g_capabilities.product_version);
1289
1290     // Sdbd version
1291     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1292             "sdbd_version", g_capabilities.sdbd_version);
1293
1294     // Sdbd plugin version
1295     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1296             "sdbd_plugin_version", g_capabilities.sdbd_plugin_version);
1297
1298     // Capability version
1299     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1300             "sdbd_cap_version", g_capabilities.sdbd_cap_version);
1301
1302     // Sdbd log enable
1303     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1304             "log_enable", g_capabilities.log_enable);
1305
1306     // Sdbd log path
1307     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1308             "log_path", g_capabilities.log_path);
1309
1310     // Application command support
1311     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1312             "appcmd_support", g_capabilities.appcmd_support);
1313
1314     // appid2pid support
1315     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1316             "appid2pid_support", g_capabilities.appid2pid_support);
1317
1318     // pkgcmd debug mode support
1319     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1320             "pkgcmd_debugmode", g_capabilities.pkgcmd_debugmode);
1321
1322     // pkgcmd debug mode support
1323     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1324             "netcoredbg_support", g_capabilities.netcoredbg_support);
1325
1326     offset++; // for '\0' character
1327
1328     writex(fd, &offset, sizeof(uint16_t));
1329     writex(fd, cap_buffer, offset);
1330
1331     sdb_close(fd);
1332 }
1333
1334 static void sync_windowsize(int fd, void *cookie) {
1335     int id, lines, columns;
1336     char *size_info = (char*)cookie;
1337     asocket *s = NULL;
1338
1339     if (sscanf(size_info, "%d:%d:%d", &id, &lines, &columns) == 3) {
1340         D("window size information: id=%d, lines=%d, columns=%d\n", id, lines, columns);
1341     }
1342     if((s = find_local_socket(id))) {
1343         struct winsize win_sz;
1344         win_sz.ws_row = lines;
1345         win_sz.ws_col = columns;
1346
1347         if (ioctl(s->fd, TIOCSWINSZ, &win_sz) < 0) {
1348             E("failed to sync window size.\n");
1349             return;
1350         }
1351         I("success to sync window size.\n");
1352     }
1353     free(size_info);
1354     sdb_close(fd);
1355 }
1356
1357 const unsigned COMMAND_TIMEOUT = 10000;
1358 void get_boot(int fd, void *cookie) {
1359     char buf[2] = { 0, };
1360     int time = 0;
1361     int interval = 1000;
1362     while (time < COMMAND_TIMEOUT) {
1363         if (booting_done == 1) {
1364             I("get_boot:platform booting is done\n");
1365             snprintf(buf, sizeof(buf), "%s", "1");
1366             break;
1367         }
1368         I("get_boot:platform booting is in progress\n");
1369         sdb_sleep_ms(interval);
1370         time += interval;
1371     }
1372     writex(fd, buf, strlen(buf));
1373     sdb_close(fd);
1374 }
1375
1376 #define GRANT_FILE "/opt/share/askuser_disable"
1377 int grantfile_exist = 0;
1378 // TODO remove debug codes (snprintf buf)
1379 void handle_grantfile(int fd, void *cookie) {
1380     char buf[2] = { 0, };
1381     int opcode = atoi((char*)cookie);
1382     char* tmppath = NULL;
1383
1384     if (opcode == 1) { // create
1385         tmppath = realpath(GRANT_FILE, NULL);
1386         if (tmppath == NULL && errno == ENOENT) {
1387             grantfile_exist = 0;
1388             FILE *f = fopen(GRANT_FILE, "w");
1389
1390             if (f != NULL) {
1391                 fclose(f);
1392                 snprintf(buf, sizeof(buf), "%s", " ");
1393             } else {
1394                 D("sdbd: cannot create %s file, errno %d.\n", GRANT_FILE, errno);
1395                 snprintf(buf, sizeof(buf), "%s", "5");
1396             }
1397         } else {
1398             grantfile_exist = 1;
1399             D("sdbd: %s file is already existed.\n", GRANT_FILE);
1400             snprintf(buf, sizeof(buf), "%s", "3");
1401             free(tmppath);
1402         }
1403     } else if (opcode == 2) { // remove
1404         if (grantfile_exist != 0) {
1405             D("sdbd: %s file is already existed.\n", GRANT_FILE);
1406             snprintf(buf, sizeof(buf), "%s", "4");
1407         } else {
1408             tmppath = realpath(GRANT_FILE, NULL);
1409             if (tmppath == NULL && errno == ENOENT) {
1410                 D("sdbd: cannot find %s file.\n", GRANT_FILE);
1411                 snprintf(buf, sizeof(buf), "%s", "6");
1412             } else if (tmppath != NULL && !strncmp(GRANT_FILE, tmppath, strlen(GRANT_FILE)+1)) {
1413                 sdb_unlink(GRANT_FILE);
1414                 snprintf(buf, sizeof(buf), "%s", " ");
1415                 free(tmppath);
1416             } else {
1417                 D("sdbd: unknown error has occured.\n");
1418                 snprintf(buf, sizeof(buf), "%s", "8");
1419                 if (tmppath != NULL) {
1420                     free(tmppath);
1421                 }
1422             }
1423         }
1424     } else {
1425         // abnormal operation
1426         D("sdbd: abnormal operation.\n");
1427         snprintf(buf, sizeof(buf), "%s", "9");
1428     }
1429     writex(fd, buf, strlen(buf));
1430     sdb_close(fd);
1431 }
1432
1433 int request_extcmd_to_plugin(const char* in_buf) {
1434     char full_cmd[ENV_BUF_MAX] = {0,};
1435     char *tokens[MAX_TOKENS];
1436     int args_cnt = tokenize(in_buf, ":", tokens, MAX_TOKENS);
1437     if (args_cnt < 3) {
1438         E("failed to parse extcmd.\n");
1439         return 0;
1440     }
1441
1442     char* cmd_name = tokens[0];
1443     char* cmd_no = tokens[args_cnt - 2];
1444     int cmd = atoi(cmd_no);
1445     char* exec_type = tokens[args_cnt - 1];
1446
1447     if (strlen(full_cmd) + strlen(cmd_name) + 1  >= ENV_BUF_MAX) {
1448         strncat(full_cmd, cmd_name, ENV_BUF_MAX - 1);
1449         full_cmd[ENV_BUF_MAX - 1] = '\0';
1450     }
1451     else {
1452         strncat(full_cmd, cmd_name, ENV_BUF_MAX - 1);
1453     }
1454
1455     int i = 1;
1456     for(;i < args_cnt - 2;i++) {
1457         if (tokens[i] == NULL){
1458                 continue;
1459         }
1460         if (strlen(full_cmd) + strlen(tokens[i]) + 2 >= ENV_BUF_MAX) {
1461             break;
1462         }
1463         strncat(full_cmd, " ",1);
1464         strncat(full_cmd, tokens[i], ENV_BUF_MAX - 1);
1465     }
1466     D("full extcmd: %s\n", full_cmd);
1467     if (!strcmp(exec_type, "sync")) {
1468         return create_extcmd_subproc_thread(full_cmd, 0, 0);
1469     }
1470
1471     else if (!strcmp(exec_type, "async")) {
1472         parameters* in;
1473         int fd;
1474
1475         in = (parameters*) malloc(sizeof(parameters));
1476         if (in == NULL) {
1477             E("failed to allocate memory for the parameters\n");
1478             return -1;
1479         }
1480
1481         if (strlen(full_cmd) > 0) {
1482             in->number_of_parameter = 1;
1483             in->array_of_parameter = (parameter*) malloc(sizeof(parameter));
1484             if (in->array_of_parameter == NULL) {
1485                 free(in);
1486                 E("failed to allocate memory for the parameter\n");
1487                 return -1;
1488             }
1489             in->array_of_parameter[0].type = type_string;
1490             in->array_of_parameter[0].v_string.length = strlen(full_cmd);
1491             in->array_of_parameter[0].v_string.data = strdup(full_cmd);
1492         } else {
1493             in->number_of_parameter = 0;
1494             in->array_of_parameter = NULL;
1495         }
1496
1497         fd = create_async_extcmd_proc_thread(cmd, in);
1498
1499         return fd;
1500     }
1501
1502     return 0;
1503 }
1504
1505 int service_to_fd(const char *name)
1506 {
1507     int ret = -1;
1508
1509     if(!strncmp(name, "tcp:", 4)) {
1510         int port = atoi(name + 4);
1511         name = strchr(name + 4, ':');
1512         if(name == 0) {
1513             if (is_emulator()){
1514                 ret = socket_ifr_client(port , SOCK_STREAM, "eth0");
1515             } else {
1516                 ret = socket_ifr_client(port , SOCK_STREAM, "usb0");
1517                 if (ret < 0) {
1518                     if (ifconfig(SDB_FORWARD_IFNAME, SDB_FORWARD_INTERNAL_IP, SDB_FORWARD_INTERNAL_MASK, 1) == 0) {
1519                         ret = socket_ifr_client(port , SOCK_STREAM, SDB_FORWARD_IFNAME);
1520                     }
1521                 }
1522             }
1523             if (ret < 0) {
1524                 ret = socket_loopback_client(port, SOCK_STREAM);
1525             }
1526             if (ret >= 0) {
1527                 disable_tcp_nagle(ret);
1528             }
1529         } else {
1530             return -1;
1531         }
1532 #ifndef HAVE_WINSOCK   /* winsock doesn't implement unix domain sockets */
1533     } else if(!strncmp(name, "local:", 6)) {
1534         ret = socket_local_client(name + 6,
1535                 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
1536     } else if(!strncmp(name, "localreserved:", 14)) {
1537         ret = socket_local_client(name + 14,
1538                 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
1539     } else if(!strncmp(name, "localabstract:", 14)) {
1540         ret = socket_local_client(name + 14,
1541                 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
1542     } else if(!strncmp(name, "localfilesystem:", 16)) {
1543         ret = socket_local_client(name + 16,
1544                 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
1545 #endif
1546     }/* else if(!strncmp("dev:", name, 4)) {// tizen specific
1547         ret = unix_open(name + 4, O_RDWR);
1548     } else if(!strncmp(name, "framebuffer:", 12)) {
1549         ret = create_service_thread(framebuffer_service, 0);
1550     } else if(recovery_mode && !strncmp(name, "recover:", 8)) {
1551         ret = create_service_thread(recover_service, (void*) atoi(name + 8));
1552     } else if (!strncmp(name, "jdwp:", 5)) {
1553         ret = create_jdwp_connection_fd(atoi(name+5));
1554     } else if (!strncmp(name, "log:", 4)) {
1555         ret = create_service_thread(log_service, get_log_file_path(name + 4));
1556     }*/ else if(!HOST && !strncmp(name, "shell:", 6)) {
1557         if(name[6]) {
1558                 if (request_handlecmd_to_plugin(PLUGIN_SYNC_CMD_HANDLE_BY_PLUGIN, name+6)) {
1559                         D("This shell command is handled by plugin. (%s)\n", name+6);
1560                         ret = request_shellcmd_to_plugin(name+6);
1561                 }
1562                 else {
1563                         ret = create_subproc_thread(name + 6, 0, 0);
1564                 }
1565         } else {
1566             ret = create_subproc_thread(NULL, 0, 0);
1567         }
1568     } else if(!strncmp(name, "eshell:", 7)) {
1569         int lines, columns;
1570         if (sscanf(name+7, "%d:%d", &lines, &columns) == 2) {
1571             ret = create_subproc_thread(NULL, lines, columns);
1572         }
1573     } else if(!strncmp(name, "sync:", 5)) {
1574         //ret = create_service_thread(file_sync_service, NULL);
1575         ret = create_syncproc_thread(name + 5);
1576     }/*  else if(!strncmp(name, "remount:", 8)) {
1577         ret = create_service_thread(remount_service, NULL);
1578     } else if(!strncmp(name, "reboot:", 7)) {
1579         void* arg = strdup(name + 7);
1580         if(arg == 0) return -1;
1581         ret = create_service_thread(reboot_service, arg);
1582     } else if(!strncmp(name, "root:", 5)) {
1583         ret = create_service_thread(restart_root_service, NULL);
1584     } else if(!strncmp(name, "backup:", 7)) {
1585         char* arg = strdup(name+7);
1586         if (arg == NULL) return -1;
1587         ret = backup_service(BACKUP, arg);
1588     } else if(!strncmp(name, "restore:", 8)) {
1589         ret = backup_service(RESTORE, NULL);
1590     }*/ else if(!strncmp(name, "root:", 5)) {
1591         char* service_name = NULL;
1592
1593         service_name = strdup(name+5);
1594         ret = create_service_thread(rootshell_service, (void *)(service_name));
1595     } else if(!strncmp(name, "cs:", 3)) {
1596         ret = create_service_thread(inoti_service, NULL);
1597     } else if(!strncmp(name, "sysinfo:", 8)){
1598         ret = create_service_thread(get_platforminfo, 0);
1599     } else if(!strncmp(name, "capability:", 11)){
1600         ret = create_service_thread(get_capability, 0);
1601     } else if(!strncmp(name, "boot:", 5)){
1602         if (is_emulator()) {
1603             ret = create_service_thread(get_boot, 0);
1604         }
1605     } else if(!strncmp(name, "shellconf:", 10)){
1606         if(!strncmp(name+10, "syncwinsz:", 10)){
1607             char* size_info = NULL;
1608             size_info = strdup(name+20);
1609             ret = create_service_thread(sync_windowsize, (void *)size_info);
1610         }
1611     } else if(!strncmp(name, "tzplatformenv:", 14)) {
1612        char* env_variable = NULL;
1613        env_variable = strdup(name+14);
1614        ret = create_service_thread(get_tzplatform_env, (void *)(env_variable));
1615     } else if(!strncmp(name, "grantfile:", 10)){
1616         ret = create_service_thread(handle_grantfile, (void*)name+10);
1617     } else if(!strncmp(name, "appcmd:", 7)){
1618         ret = request_appcmd_to_plugin(name+7);
1619     } else if(!strncmp(name, "extcmd:", 7)) {
1620         ret = request_extcmd_to_plugin(name+7);
1621     }
1622
1623     if (ret >= 0) {
1624         if (close_on_exec(ret) < 0) {
1625             E("failed to close fd exec\n");
1626         }
1627     }
1628     return ret;
1629 }