76c28d1b6e3659dea6babc12d4f623a69a66bc7d
[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 #include "log.h"
28
29 #include "sdb.h"
30 #include "file_sync_service.h"
31
32 #if SDB_HOST
33 #  ifndef HAVE_WINSOCK
34 #    include <netinet/in.h>
35 #    include <netdb.h>
36 #    include <sys/ioctl.h>
37 #  endif
38 #else
39 #   include <sys/inotify.h>
40 #   include "sdktools.h"
41 #endif
42
43 #include "strutils.h"
44 #include "utils.h"
45 #include <system_info.h>
46 #include <tzplatform_config.h>
47 #include <sys/smack.h>
48
49 #include <vconf.h>
50 #include <limits.h>
51
52 #include <termios.h>
53 #include <sys/ioctl.h>
54
55 #include "sdbd_plugin.h"
56 #include "plugin.h"
57
58 #define ENV_BUF_MAX     4096
59
60 typedef struct stinfo stinfo;
61
62 struct stinfo {
63     void (*func)(int fd, void *cookie);
64     int fd;
65     void *cookie;
66 };
67
68 void *service_bootstrap_func(void *x)
69 {
70     stinfo *sti = x;
71     sti->func(sti->fd, sti->cookie);
72     free(sti);
73     return 0;
74 }
75
76 #if SDB_HOST
77 SDB_MUTEX_DEFINE( dns_lock );
78
79 static void dns_service(int fd, void *cookie)
80 {
81     char *hostname = cookie;
82     struct hostent *hp;
83     unsigned zero = 0;
84
85     sdb_mutex_lock(&dns_lock);
86     hp = gethostbyname(hostname);
87     free(cookie);
88     if(hp == 0) {
89         writex(fd, &zero, 4);
90     } else {
91         writex(fd, hp->h_addr, 4);
92     }
93     sdb_mutex_unlock(&dns_lock);
94     sdb_close(fd);
95 }
96 #else
97
98 static int is_support_interactive_shell()
99 {
100     return (!strncmp(g_capabilities.intershell_support, PLUGIN_RET_ENABLED, strlen(PLUGIN_RET_ENABLED)));
101 }
102
103 #if 0
104 extern int recovery_mode;
105
106 static void recover_service(int s, void *cookie)
107 {
108     unsigned char buf[4096];
109     unsigned count = (unsigned) cookie;
110     int fd;
111
112     fd = sdb_creat("/tmp/update", 0644);
113     if(fd < 0) {
114         sdb_close(s);
115         return;
116     }
117
118     while(count > 0) {
119         unsigned xfer = (count > 4096) ? 4096 : count;
120         if(readx(s, buf, xfer)) break;
121         if(writex(fd, buf, xfer)) break;
122         count -= xfer;
123     }
124
125     if(count == 0) {
126         writex(s, "OKAY", 4);
127     } else {
128         writex(s, "FAIL", 4);
129     }
130     sdb_close(fd);
131     sdb_close(s);
132
133     fd = sdb_creat("/tmp/update.begin", 0644);
134     sdb_close(fd);
135 }
136
137 void restart_root_service(int fd, void *cookie)
138 {
139     char buf[100];
140     char value[PROPERTY_VALUE_MAX];
141
142     if (getuid() == 0) {
143         snprintf(buf, sizeof(buf), "sdbd is already running as root\n");
144         writex(fd, buf, strlen(buf));
145         sdb_close(fd);
146     } else {
147         property_get("ro.debuggable", value, "");
148         if (strcmp(value, "1") != 0) {
149             snprintf(buf, sizeof(buf), "sdbd cannot run as root in production builds\n");
150             writex(fd, buf, strlen(buf));
151             sdb_close(fd);
152             return;
153         }
154
155         property_set("service.sdb.root", "1");
156         snprintf(buf, sizeof(buf), "restarting sdbd as root\n");
157         writex(fd, buf, strlen(buf));
158         sdb_close(fd);
159     }
160 }
161 #endif
162
163 void restart_tcp_service(int fd, void *cookie)
164 {
165     char buf[100];
166     char value[PROPERTY_VALUE_MAX];
167     int port = (int)cookie;
168
169     if (port <= 0) {
170         snprintf(buf, sizeof(buf), "invalid port\n");
171         writex(fd, buf, strlen(buf));
172         sdb_close(fd);
173         return;
174     }
175
176     snprintf(value, sizeof(value), "%d", port);
177     property_set("service.sdb.tcp.port", value);
178     snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
179     writex(fd, buf, strlen(buf));
180     sdb_close(fd);
181 }
182
183 static int is_support_rootonoff()
184 {
185     return (!strncmp(g_capabilities.rootonoff_support, PLUGIN_RET_ENABLED, strlen(PLUGIN_RET_ENABLED)));
186 }
187
188 void rootshell_service(int fd, void *cookie)
189 {
190     char buf[100];
191     char *mode = (char*) cookie;
192
193     if (!strcmp(mode, "on")) {
194         if (getuid() == 0) {
195             if (rootshell_mode == 1) {
196                 //snprintf(buf, sizeof(buf), "Already changed to sdk user mode\n");
197                 // do not show message
198             } else {
199                 if (is_support_rootonoff()) {
200                     rootshell_mode = 1;
201                     //allows a permitted user to execute a command as the superuser
202                     snprintf(buf, sizeof(buf), "Switched to 'root' account mode\n");
203                 } else {
204                     snprintf(buf, sizeof(buf), "Permission denied\n");
205                 }
206                 writex(fd, buf, strlen(buf));
207             }
208         } else {
209             D("need root permission for root shell: %d\n", getuid());
210             rootshell_mode = 0;
211             snprintf(buf, sizeof(buf), "Permission denied\n");
212             writex(fd, buf, strlen(buf));
213         }
214     } else if (!strcmp(mode, "off")) {
215         if (rootshell_mode == 1) {
216             rootshell_mode = 0;
217             snprintf(buf, sizeof(buf), "Switched to 'sdk user' account mode\n");
218             writex(fd, buf, strlen(buf));
219         }
220     } else {
221         snprintf(buf, sizeof(buf), "Unknown command option : %s\n", mode);
222         writex(fd, buf, strlen(buf));
223     }
224     D("set rootshell to %s\n", rootshell_mode == 1 ? "root" : SDK_USER_NAME);
225     free(mode);
226     sdb_close(fd);
227 }
228
229 enum tzplatform_get_env_error_status {
230     NO_ERROR_TZPLATFORM_ENV = 0,
231     ERROR_TZPLATFORM_ENV_GENERAL = 1,
232     ERROR_TZPLATFORM_ENV_INVALID_VARIABLES = 2,
233 };
234
235 void get_tzplatform_env(int fd, void *cookie) {
236     char buf[PATH_MAX] = { 0, };
237     char *env_name = (char*) cookie;
238     D("environment variable name: %s\n", env_name);
239     enum tzplatform_variable env_id = tzplatform_getid(env_name);
240     if (env_id != _TZPLATFORM_VARIABLES_INVALID_) {
241         const char *env_value = tzplatform_getenv(env_id);
242         if (env_value) {
243             D("environment value : %s\n", env_value);
244             snprintf(buf, sizeof(buf), "%d%s", NO_ERROR_TZPLATFORM_ENV, env_value);
245         } else {
246             D("failed to get environment value using tzplatform_getenv");
247             snprintf(buf, sizeof(buf), "%d", ERROR_TZPLATFORM_ENV_GENERAL);
248         }
249     } else {
250         D("environment name (%s) is invalid\n", env_name);
251         snprintf(buf, sizeof(buf), "%d", ERROR_TZPLATFORM_ENV_INVALID_VARIABLES);
252     }
253     writex(fd, buf, strlen(buf));
254     free(env_name);
255     sdb_close(fd);
256 }
257
258 void restart_usb_service(int fd, void *cookie)
259 {
260     char buf[100];
261
262     property_set("service.sdb.tcp.port", "0");
263     snprintf(buf, sizeof(buf), "restarting in USB mode\n");
264     writex(fd, buf, strlen(buf));
265     sdb_close(fd);
266 }
267
268 void reboot_service(int fd, void *arg)
269 {
270 #if 0
271     char buf[100];
272     int pid, ret;
273
274     sync();
275
276     /* Attempt to unmount the SD card first.
277      * No need to bother checking for errors.
278      */
279     pid = fork();
280     if (pid == 0) {
281         /* ask vdc to unmount it */
282         // prevent: Use of untrusted string value (TAINTED_STRING)
283         execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount",
284                 getenv("EXTERNAL_STORAGE"), "force", NULL);
285     } else if (pid > 0) {
286         /* wait until vdc succeeds or fails */
287         waitpid(pid, &ret, 0);
288     }
289
290     ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
291     if (ret < 0) {
292         snprintf(buf, sizeof(buf), "reboot failed: %s errno:%d\n", errno);
293         writex(fd, buf, strlen(buf));
294     }
295     free(arg);
296     sdb_close(fd);
297 #endif
298 }
299
300 #if !SDB_HOST
301 #define EVENT_SIZE  ( sizeof (struct inotify_event) )
302 #define BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )
303 #define CS_PATH     tzplatform_getenv(TZ_SYS_CRASH)
304
305 void inoti_service(int fd, void *arg)
306 {
307     int wd;
308     int ifd;
309     char buffer[BUF_LEN];
310
311     D( "inoti_service start\n");
312     ifd = inotify_init();
313
314     if ( ifd < 0 ) {
315         D( "inotify_init failed\n");
316         sdb_close(fd);
317         return;
318     }
319
320     wd = inotify_add_watch( ifd, CS_PATH, IN_CREATE);
321     if ( wd < 0 ) {
322         D("inotify_add_watch failed (errno :%d)\n", errno);
323         sdb_close(ifd);
324         sdb_close(fd);
325         return;
326     }
327
328     for ( ; ; ) {
329         int length, i = 0;
330         length = sdb_read( ifd, buffer, BUF_LEN );
331
332         if ( length < 0 ) {
333             D( "inoti read failed\n");
334             goto done;
335         }
336         while (i >= 0 && i <= (length - EVENT_SIZE)) {
337             struct inotify_event *event = (struct inotify_event *) &buffer[i];
338             if (event->len) {
339                 if (event->mask & IN_CREATE) {
340                     if (!(event->mask & IN_ISDIR)) {
341                         char *cspath = NULL;
342                         int len = asprintf(&cspath, "%s/%s", CS_PATH,
343                                 event->name);
344                         D( "The file %s was created.\n", cspath);
345                         writex(fd, cspath, len);
346                         if (cspath != NULL) {
347                             free(cspath);
348                         }
349                     }
350                 }
351             }
352             if (i + EVENT_SIZE + event->len < event->len) { // in case of integer overflow
353                 break;
354             }
355             i += EVENT_SIZE + event->len;
356         }
357     }
358
359 done:
360     inotify_rm_watch( ifd, wd );
361     sdb_close(ifd);
362     sdb_close(fd);
363     D( "inoti_service end\n");
364 }
365 #endif
366 #endif
367
368 #if 0
369 static void echo_service(int fd, void *cookie)
370 {
371     char buf[4096];
372     int r;
373     char *p;
374     int c;
375
376     for(;;) {
377         r = read(fd, buf, 4096);
378         if(r == 0) goto done;
379         if(r < 0) {
380             if(errno == EINTR) continue;
381             else goto done;
382         }
383
384         c = r;
385         p = buf;
386         while(c > 0) {
387             r = write(fd, p, c);
388             if(r > 0) {
389                 c -= r;
390                 p += r;
391                 continue;
392             }
393             if((r < 0) && (errno == EINTR)) continue;
394             goto done;
395         }
396     }
397 done:
398     close(fd);
399 }
400 #endif
401
402 static int create_service_thread(void (*func)(int, void *), void *cookie)
403 {
404     stinfo *sti;
405     sdb_thread_t t;
406     int s[2];
407
408     if(sdb_socketpair(s)) {
409         D("cannot create service socket pair\n");
410         return -1;
411     }
412
413     sti = malloc(sizeof(stinfo));
414     if(sti == 0) fatal("cannot allocate stinfo");
415     sti->func = func;
416     sti->cookie = cookie;
417     sti->fd = s[1];
418
419     if(sdb_thread_create( &t, service_bootstrap_func, sti)){
420         free(sti);
421         sdb_close(s[0]);
422         sdb_close(s[1]);
423         D("cannot create service thread\n");
424         return -1;
425     }
426
427     D("service thread started, %d:%d\n",s[0], s[1]);
428     return s[0];
429 }
430
431 #if !SDB_HOST
432
433 static void redirect_and_exec(int pts, const char *cmd, char * const argv[], char * const envp[])
434 {
435     dup2(pts, 0);
436     dup2(pts, 1);
437     dup2(pts, 2);
438
439     sdb_close(pts);
440
441     execve(cmd, argv, envp);
442 }
443
444 int create_subprocess(const char *cmd, pid_t *pid, char * const argv[], char * const envp[])
445 {
446     char devname[64];
447     int ptm;
448
449     ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
450     if(ptm < 0){
451         D("[ cannot open /dev/ptmx - errno:%d ]\n",errno);
452         return -1;
453     }
454     if (fcntl(ptm, F_SETFD, FD_CLOEXEC) < 0) {
455         D("[ cannot set cloexec to /dev/ptmx - errno:%d ]\n",errno);
456     }
457
458     if(grantpt(ptm) || unlockpt(ptm) ||
459         ptsname_r(ptm, devname, sizeof(devname)) != 0 ){
460         D("[ trouble with /dev/ptmx - errno:%d ]\n", errno);
461         sdb_close(ptm);
462         return -1;
463     }
464
465     if (smack_setlabel(devname, SDK_SHELL_LABEL_NAME, SMACK_LABEL_ACCESS) == -1) {
466         D("unable to set sdk shell smack label %s due to (errno:%d)\n", SDK_SHELL_LABEL_NAME, errno);
467         sdb_close(ptm);
468         return -1;
469     }
470
471     *pid = fork();
472     if(*pid < 0) {
473         D("- fork failed: errno:%d -\n", errno);
474         sdb_close(ptm);
475         return -1;
476     }
477
478     if(*pid == 0){
479         int pts;
480
481         setsid();
482
483         pts = unix_open(devname, O_RDWR);
484         if(pts < 0) {
485             fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
486             exit(-1);
487         }
488
489         sdb_close(ptm);
490
491         // set OOM adjustment to zero
492         {
493             char text[64];
494             //snprintf(text, sizeof text, "/proc/%d/oom_score_adj", getpid());
495             snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
496             int fd = sdb_open(text, O_WRONLY);
497             if (fd >= 0) {
498                 sdb_write(fd, "0", 1);
499                 sdb_close(fd);
500             } else {
501                // FIXME: not supposed to be here
502                D("sdb: unable to open %s due to errno:%d\n", text, errno);
503             }
504         }
505
506         if (should_drop_privileges()) {
507             if (argv[2] != NULL && getuid() == 0 && request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_ROOTCMD, argv[2])) {
508                 // do nothing
509                 D("sdb: executes root commands!!:%s\n", argv[2]);
510             } else {
511                 if (getuid() != g_sdk_user_id && set_sdk_user_privileges() < 0) {
512                     fprintf(stderr, "failed to set SDK user privileges\n");
513                     exit(-1);
514                 }
515             }
516         }
517         redirect_and_exec(pts, cmd, argv, envp);
518         fprintf(stderr, "- exec '%s' failed: (errno:%d) -\n",
519                 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         return ptm;
527     }
528 }
529 #endif  /* !SDB_HOST */
530
531 #define SHELL_COMMAND "/bin/sh-user"
532 #define LOGIN_COMMAND "/bin/login"
533 #define SUPER_USER    "root"
534 #define LOGIN_CONFIG  "/etc/login.defs"
535
536 #if !SDB_HOST
537 static void subproc_waiter_service(int fd, void *cookie)
538 {
539     pid_t pid = (pid_t)cookie;
540
541     D("entered. fd=%d of pid=%d\n", fd, pid);
542     for (;;) {
543         int status;
544         pid_t p = waitpid(pid, &status, 0);
545         if (p == pid) {
546             D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
547             if (WIFEXITED(status)) {
548                 D("*** Exit code %d\n", WEXITSTATUS(status));
549                 break;
550             } else if (WIFSIGNALED(status)) {
551                 D("*** Killed by signal %d\n", WTERMSIG(status));
552                 break;
553             } else {
554                 D("*** Killed by unknown code %d\n", status);
555                 break;
556             }
557          }
558     }
559     D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
560     if (SHELL_EXIT_NOTIFY_FD >=0) {
561       int res;
562       res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
563       D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
564         SHELL_EXIT_NOTIFY_FD, pid, res, errno);
565     }
566 }
567
568 void get_env(char *key, char **env)
569 {
570     FILE *fp;
571     char buf[1024];
572     char *s, *e, *value;
573
574     fp = fopen (LOGIN_CONFIG, "r");
575     if (NULL == fp) {
576         return;
577     }
578
579     while (fgets(buf, (int) sizeof (buf), fp) != NULL) {
580         s = buf;
581         e = buf + (strlen(buf) - 1);
582
583         // trim string
584         while( (e > s) && (*e == ' ' ||  *e == '\n' || *e == '\t')) {
585             e--;
586         }
587         *(e+1) ='\0';
588
589         while(*s != '\0' && (*s == ' ' || *s == '\t' || *s == '\n')) {
590             s++;
591         }
592
593         // skip comment or null string
594         if (*s == '#' || *s == '\0') {
595             continue;
596         }
597         value = s + strcspn(s, " \t");
598         *value++ = '\0';
599
600         if(!strcmp(buf, key)) {
601             *env = strdup(value);
602             break;
603         }
604     }
605
606     fclose(fp);
607 }
608
609 static int create_subproc_thread(const char *name, int lines, int columns)
610 {
611     stinfo *sti;
612     sdb_thread_t t;
613     int ret_fd;
614     pid_t pid;
615     char *value = NULL;
616     char *trim_value = NULL;
617     char path[PATH_MAX];
618     char *envp[MAX_TOKENS];
619     int envp_cnt = 0;
620
621     memset(path, 0, sizeof(path));
622     memset(envp, 0, sizeof(envp));
623
624     envp[envp_cnt++] = strdup("TERM=linux");
625     envp[envp_cnt++] = strdup("DISPLAY=:0");
626
627     if (should_drop_privileges()) {
628         if (g_sdk_home_dir_env) {
629             envp[envp_cnt++] = strdup(g_sdk_home_dir_env);
630         } else {
631             envp[envp_cnt++] = strdup("HOME=/home/owner");
632         }
633         get_env("ENV_PATH", &value);
634     } else {
635         get_env("ENV_SUPATH", &value);
636         if(value == NULL) {
637             get_env("ENV_ROOTPATH", &value);
638         }
639         envp[envp_cnt++] = strdup("HOME=/root");
640     }
641     if (value != NULL) {
642         trim_value = str_trim(value);
643         if (trim_value != NULL) {
644             // if string is not including 'PATH=', append it.
645             if (strncmp(trim_value, "PATH", 4)) {
646                 snprintf(path, sizeof(path), "PATH=%s", trim_value);
647             } else {
648                 snprintf(path, sizeof(path), "%s", trim_value);
649             }
650             envp[envp_cnt++] = strdup(path);
651         } else {
652             snprintf(path, sizeof(path), "%s", value);
653             envp[envp_cnt++] = strdup(path);
654         }
655         free(value);
656     }
657
658     /* get environment variables from plugin */
659     char *envp_plugin = NULL;
660     envp_plugin = malloc(ENV_BUF_MAX);
661     if (envp_plugin == NULL) {
662         D("Cannot allocate the shell commnad buffer.");
663         return -1;
664     }
665     memset(envp_plugin, 0, ENV_BUF_MAX);
666     if (!request_conversion_to_plugin(PLUGIN_SYNC_CMD_GET_SHELL_ENV, NULL,
667                 envp_plugin, ENV_BUF_MAX)) {
668         D("Failed to convert the shell command. (%s)\n", name);
669         free(envp_plugin);
670         return -1;
671     } else {
672        if(envp_plugin[0] != '\0') {
673             envp_cnt = tokenize_append(envp_plugin, "\n", envp, MAX_TOKENS, envp_cnt);
674         }
675     }
676     free(envp_plugin);
677
678     /* Last element of envp must be the NULL-terminator to prevent execvp fail */
679     envp[envp_cnt] = NULL;
680
681     if(name) { // in case of shell execution directly
682         // Check the shell command validation.
683         if (!request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_SHELLCMD, name)) {
684             D("This shell command is invalid. (%s)\n", name);
685             return -1;
686         }
687
688         // Convert the shell command.
689         char *new_cmd = NULL;
690         new_cmd = malloc(SDBD_SHELL_CMD_MAX);
691         if(new_cmd == NULL) {
692             D("Cannot allocate the shell commnad buffer.");
693             return -1;
694         }
695
696         memset(new_cmd, 0, SDBD_SHELL_CMD_MAX);
697         if(!request_conversion_to_plugin(PLUGIN_SYNC_CMD_CONVERT_SHELLCMD, name, new_cmd, SDBD_SHELL_CMD_MAX)) {
698             D("Failed to convert the shell command. (%s)\n", name);
699             free(new_cmd);
700             return -1;
701         }
702
703         D("converted cmd : %s\n", new_cmd);
704
705         char *args[] = {
706             SHELL_COMMAND,
707             "-c",
708             NULL,
709             NULL,
710         };
711         args[2] = new_cmd;
712
713         ret_fd = create_subprocess(SHELL_COMMAND, &pid, (char * const*)args, (char * const*)envp);
714         free(new_cmd);
715     } else { // in case of shell interactively
716         // Check the capability for interactive shell support.
717         if (!is_support_interactive_shell()) {
718             D("This platform dose NOT support the interactive shell\n");
719             return -1;
720         }
721
722         char * const args[] = {
723                 SHELL_COMMAND,
724                 "-",
725                 NULL,
726         };
727         ret_fd = create_subprocess(SHELL_COMMAND, &pid, (char * const*)args, (char * const*)envp);
728 #if 0   // FIXME: should call login command instead of /bin/sh
729         if (should_drop_privileges()) {
730             char *args[] = {
731                 SHELL_COMMAND,
732                 "-",
733                 NULL,
734             };
735             ret_fd = create_subprocess(SHELL_COMMAND, &pid, args, envp);
736         } else {
737             char *args[] = {
738                 LOGIN_COMMAND,
739                 "-f",
740                 SUPER_USER,
741                 NULL,
742             };
743             ret_fd = create_subprocess(LOGIN_COMMAND, &pid, args, envp);
744         }
745 #endif
746     }
747
748     /* free environment variables */
749     int i = 0;
750     if(envp_cnt > 0) {
751         for(i = 0; i < envp_cnt; i++) {
752             if(envp[i]) {
753                 D("envp[%d] = %s\n", i, envp[i]);
754                 free(envp[i]);
755             }
756         }
757     }
758
759     D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
760
761     if (ret_fd < 0) {
762         D("cannot create service thread\n");
763         return -1;
764     }
765
766     if (lines > 0 && columns > 0) {
767         D("shell size lines=%d, columns=%d\n", lines, columns);
768         struct winsize win_sz;
769         win_sz.ws_row = lines;
770         win_sz.ws_col = columns;
771
772         if (ioctl(ret_fd, TIOCSWINSZ, &win_sz) < 0) {
773             D("failed to sync window size.\n");
774         }
775     }
776
777     sti = malloc(sizeof(stinfo));
778     if(sti == 0) fatal("cannot allocate stinfo");
779     sti->func = subproc_waiter_service;
780     sti->cookie = (void*)pid;
781     sti->fd = ret_fd;
782
783     if(sdb_thread_create( &t, service_bootstrap_func, sti)){
784         free(sti);
785         sdb_close(ret_fd);
786         D("cannot create service thread\n");
787         return -1;
788     }
789
790     D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
791     return ret_fd;
792 }
793
794 static int create_sync_subprocess(void (*func)(int, void *), void* cookie) {
795     stinfo *sti;
796     sdb_thread_t t;
797     int s[2];
798
799     if(sdb_socketpair(s)) {
800         D("cannot create service socket pair\n");
801         return -1;
802     }
803
804     pid_t pid = fork();
805
806     if (pid == 0) {
807         sdb_close(s[0]);
808         func(s[1], cookie);
809         exit(-1);
810     } else if (pid > 0) {
811         sdb_close(s[1]);
812         // FIXME: do not wait child process hear
813         //waitpid(pid, &ret, 0);
814     }
815     if (pid < 0) {
816         D("- fork failed: errno:%d -\n", errno);
817         sdb_close(s[0]);
818         sdb_close(s[1]);
819         D("cannot create sync service sub process\n");
820         return -1;
821     }
822
823     sti = malloc(sizeof(stinfo));
824     if(sti == 0) fatal("cannot allocate stinfo");
825     sti->func = subproc_waiter_service;
826     sti->cookie = (void*)pid;
827     sti->fd = s[0];
828
829     if(sdb_thread_create( &t, service_bootstrap_func, sti)){
830         free(sti);
831         sdb_close(s[0]);
832         printf("cannot create service monitor thread\n");
833         return -1;
834     }
835
836     D("service process started, fd=%d pid=%d\n",s[0], pid);
837     return s[0];
838 }
839
840 static int create_syncproc_thread()
841 {
842     int ret_fd;
843
844     ret_fd = create_sync_subprocess(file_sync_service, NULL);
845     // FIXME: file missing bug when root on mode
846     /*
847     if (should_drop_privileges()) {
848         ret_fd = create_sync_subprocess(file_sync_service, NULL);
849     } else {
850         ret_fd = create_service_thread(file_sync_service, NULL);
851     }
852     */
853
854     return ret_fd;
855 }
856 #endif
857
858 static void get_platforminfo(int fd, void *cookie) {
859     pinfo sysinfo;
860
861     char *value = NULL;
862     s_strncpy(sysinfo.platform_info_version, INFO_VERSION, strlen(INFO_VERSION));
863
864     int r = system_info_get_platform_string("http://tizen.org/system/model_name", &value);
865     if (r != SYSTEM_INFO_ERROR_NONE) {
866         s_strncpy(sysinfo.model_name, UNKNOWN, strlen(UNKNOWN));
867         D("fail to get system model:%d\n", errno);
868     } else {
869         s_strncpy(sysinfo.model_name, value, sizeof(sysinfo.model_name));
870         D("returns model_name:%s\n", value);
871         if (value != NULL) {
872             free(value);
873         }
874     }
875
876     r = system_info_get_platform_string("http://tizen.org/system/platform.name", &value);
877     if (r != SYSTEM_INFO_ERROR_NONE) {
878         s_strncpy(sysinfo.platform_name, UNKNOWN, strlen(UNKNOWN));
879         D("fail to get platform name:%d\n", errno);
880     } else {
881         s_strncpy(sysinfo.platform_name, value, sizeof(sysinfo.platform_name));
882         D("returns platform_name:%s\n", value);
883         if (value != NULL) {
884             free(value);
885         }
886
887     }
888
889     // FIXME: the result is different when using SYSTEM_INFO_KEY_TIZEN_VERSION_NAME
890     r = system_info_get_platform_string("tizen.org/feature/platform.version", &value);
891     if (r != SYSTEM_INFO_ERROR_NONE) {
892         s_strncpy(sysinfo.platform_version, UNKNOWN, strlen(UNKNOWN));
893         D("fail to get platform version:%d\n", errno);
894     } else {
895         s_strncpy(sysinfo.platform_version, value, sizeof(sysinfo.platform_version));
896         D("returns platform_version:%s\n", value);
897         if (value != NULL) {
898             free(value);
899         }
900     }
901
902     r = system_info_get_platform_string("tizen.org/feature/profile", &value);
903     if (r != SYSTEM_INFO_ERROR_NONE) {
904         s_strncpy(sysinfo.profile_name, UNKNOWN, strlen(UNKNOWN));
905         D("fail to get profile name:%d\n", errno);
906     } else {
907         s_strncpy(sysinfo.profile_name, value, sizeof(sysinfo.profile_name));
908         D("returns profile name:%s\n", value);
909         if (value != NULL) {
910             free(value);
911         }
912     }
913
914     writex(fd, &sysinfo, sizeof(pinfo));
915
916     sdb_close(fd);
917 }
918
919 static int put_key_value_string(char* buf, int offset, int buf_size, char* key, char* value) {
920     int len = 0;
921     if ((len = snprintf(buf+offset, buf_size-offset, "%s:%s\n", key, value)) > 0) {
922         return len;
923     }
924     return 0;
925 }
926
927 static void get_capability(int fd, void *cookie) {
928     char cap_buffer[CAPBUF_SIZE] = {0,};
929     uint16_t offset = 0;
930
931     // Secure protocol support
932     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
933                                 "secure_protocol", g_capabilities.secure_protocol);
934
935     // Interactive shell support
936     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
937                                 "intershell_support", g_capabilities.intershell_support);
938
939     // File push/pull support
940     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
941                                 "filesync_support", g_capabilities.filesync_support);
942
943     // USB protocol support
944     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
945                                 "usbproto_support", g_capabilities.usbproto_support);
946
947     // Socket protocol support
948     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
949                                 "sockproto_support", g_capabilities.sockproto_support);
950
951     // Window size synchronization support
952     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
953                                 "syncwinsz_support", g_capabilities.syncwinsz_support);
954
955     // Root command support
956     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
957                                 "rootonoff_support", g_capabilities.rootonoff_support);
958
959     // Encryption support
960     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
961                                 "encryption_support", g_capabilities.encryption_support);
962
963     // Zone support
964     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
965                                 "zone_support", g_capabilities.zone_support);
966
967     // Multi-User support
968     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
969                                 "multiuser_support", g_capabilities.multiuser_support);
970
971     // CPU Architecture of model
972     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
973                                 "cpu_arch", g_capabilities.cpu_arch);
974
975     // SDK Tool path
976     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
977                                 "sdk_toolpath", g_capabilities.sdk_toolpath);
978
979     // Profile name
980     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
981                                 "profile_name", g_capabilities.profile_name);
982
983     // Vendor name
984     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
985                                 "vendor_name", g_capabilities.vendor_name);
986
987     // Target name of the launch possible
988     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
989                                 "can_launch", g_capabilities.can_launch);
990
991     // Platform version
992     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
993                                 "platform_version", g_capabilities.platform_version);
994
995     // Product version
996     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
997                                 "product_version", g_capabilities.product_version);
998
999     // Sdbd version
1000     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1001                                 "sdbd_version", g_capabilities.sdbd_version);
1002
1003     // Sdbd plugin version
1004     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1005                                 "sdbd_plugin_version", g_capabilities.sdbd_plugin_version);
1006
1007     // Capability version
1008     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1009                                 "sdbd_cap_version", g_capabilities.sdbd_cap_version);
1010
1011     // Sdbd log enable
1012     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1013             "log_enable", g_capabilities.log_enable);
1014
1015     // Sdbd log path
1016     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1017             "log_path", g_capabilities.log_path);
1018
1019     // Application command support
1020     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1021             "appcmd_support", g_capabilities.appcmd_support);
1022
1023     // appid2pid support
1024     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1025                                 "appid2pid_support", g_capabilities.appid2pid_support);
1026
1027     // pkgcmd debug mode support
1028     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1029                                 "pkgcmd_debugmode", g_capabilities.pkgcmd_debugmode);
1030
1031     offset++; // for '\0' character
1032
1033     writex(fd, &offset, sizeof(uint16_t));
1034     writex(fd, cap_buffer, offset);
1035
1036     sdb_close(fd);
1037 }
1038
1039 static void sync_windowsize(int fd, void *cookie) {
1040     int id, lines, columns;
1041     char *size_info = cookie;
1042     asocket *s = NULL;
1043
1044     if (sscanf(size_info, "%d:%d:%d", &id, &lines, &columns) == 3) {
1045         D("window size information: id=%d, lines=%d, columns=%d\n", id, lines, columns);
1046     }
1047     if((s = find_local_socket(id))) {
1048         struct winsize win_sz;
1049         win_sz.ws_row = lines;
1050         win_sz.ws_col = columns;
1051
1052         if (ioctl(s->fd, TIOCSWINSZ, &win_sz) < 0) {
1053             D("failed to sync window size.\n");
1054             return;
1055         }
1056         D("success to sync window size.\n");
1057     }
1058 }
1059
1060 const unsigned COMMAND_TIMEOUT = 10000;
1061 void get_boot(int fd, void *cookie) {
1062     char buf[2] = { 0, };
1063     int time = 0;
1064     int interval = 1000;
1065     while (time < COMMAND_TIMEOUT) {
1066         if (booting_done == 1) {
1067             D("get_boot:platform booting is done\n");
1068             snprintf(buf, sizeof(buf), "%s", "1");
1069             break;
1070         }
1071         D("get_boot:platform booting is in progress\n");
1072         sdb_sleep_ms(interval);
1073         time += interval;
1074     }
1075     writex(fd, buf, strlen(buf));
1076     sdb_close(fd);
1077 }
1078
1079 int service_to_fd(const char *name)
1080 {
1081     int ret = -1;
1082
1083     if(!strncmp(name, "tcp:", 4)) {
1084         int port = atoi(name + 4);
1085         name = strchr(name + 4, ':');
1086         if(name == 0) {
1087             if (is_emulator()){
1088                 ret = socket_ifr_client(port , SOCK_STREAM, "eth0");
1089             } else {
1090                 ret = socket_ifr_client(port , SOCK_STREAM, "usb0");
1091                 if (ret < 0) {
1092                     if (ifconfig(SDB_FORWARD_IFNAME, SDB_FORWARD_INTERNAL_IP, SDB_FORWARD_INTERNAL_MASK, 1) == 0) {
1093                         ret = socket_ifr_client(port , SOCK_STREAM, SDB_FORWARD_IFNAME);
1094                     }
1095                 }
1096             }
1097             if (ret < 0) {
1098                 ret = socket_loopback_client(port, SOCK_STREAM);
1099             }
1100             if (ret >= 0) {
1101                 disable_tcp_nagle(ret);
1102             }
1103         } else {
1104 #if SDB_HOST
1105             sdb_mutex_lock(&dns_lock);
1106             ret = socket_network_client(name + 1, port, SOCK_STREAM);
1107             sdb_mutex_unlock(&dns_lock);
1108 #else
1109             return -1;
1110 #endif
1111         }
1112 #ifndef HAVE_WINSOCK   /* winsock doesn't implement unix domain sockets */
1113     } else if(!strncmp(name, "local:", 6)) {
1114         ret = socket_local_client(name + 6,
1115                 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
1116     } else if(!strncmp(name, "localreserved:", 14)) {
1117         ret = socket_local_client(name + 14,
1118                 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
1119     } else if(!strncmp(name, "localabstract:", 14)) {
1120         ret = socket_local_client(name + 14,
1121                 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
1122     } else if(!strncmp(name, "localfilesystem:", 16)) {
1123         ret = socket_local_client(name + 16,
1124                 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
1125 #endif
1126 #if SDB_HOST
1127     } else if(!strncmp("dns:", name, 4)){
1128         char *n = strdup(name + 4);
1129         if(n == 0) return -1;
1130         ret = create_service_thread(dns_service, n);
1131 #else /* !SDB_HOST */
1132     }/* else if(!strncmp("dev:", name, 4)) {// tizen specific
1133         ret = unix_open(name + 4, O_RDWR);
1134     } else if(!strncmp(name, "framebuffer:", 12)) {
1135         ret = create_service_thread(framebuffer_service, 0);
1136     } else if(recovery_mode && !strncmp(name, "recover:", 8)) {
1137         ret = create_service_thread(recover_service, (void*) atoi(name + 8));
1138     } else if (!strncmp(name, "jdwp:", 5)) {
1139         ret = create_jdwp_connection_fd(atoi(name+5));
1140     } else if (!strncmp(name, "log:", 4)) {
1141         ret = create_service_thread(log_service, get_log_file_path(name + 4));
1142     }*/ else if(!HOST && !strncmp(name, "shell:", 6)) {
1143         if(name[6]) {
1144             ret = create_subproc_thread(name + 6, 0, 0);
1145         } else {
1146             ret = create_subproc_thread(NULL, 0, 0);
1147         }
1148     } else if(!strncmp(name, "eshell:", 7)) {
1149         int lines, columns;
1150         if (sscanf(name+7, "%d:%d", &lines, &columns) == 2) {
1151             ret = create_subproc_thread(NULL, lines, columns);
1152         }
1153     } else if(!strncmp(name, "sync:", 5)) {
1154         //ret = create_service_thread(file_sync_service, NULL);
1155         ret = create_syncproc_thread();
1156     }/*  else if(!strncmp(name, "remount:", 8)) {
1157         ret = create_service_thread(remount_service, NULL);
1158     } else if(!strncmp(name, "reboot:", 7)) {
1159         void* arg = strdup(name + 7);
1160         if(arg == 0) return -1;
1161         ret = create_service_thread(reboot_service, arg);
1162     } else if(!strncmp(name, "root:", 5)) {
1163         ret = create_service_thread(restart_root_service, NULL);
1164     } else if(!strncmp(name, "backup:", 7)) {
1165         char* arg = strdup(name+7);
1166         if (arg == NULL) return -1;
1167         ret = backup_service(BACKUP, arg);
1168     } else if(!strncmp(name, "restore:", 8)) {
1169         ret = backup_service(RESTORE, NULL);
1170     }*/ else if(!strncmp(name, "root:", 5)) {
1171         char* service_name = NULL;
1172
1173         service_name = strdup(name+5);
1174         ret = create_service_thread(rootshell_service, (void *)(service_name));
1175     } else if(!strncmp(name, "cs:", 5)) {
1176         ret = create_service_thread(inoti_service, NULL);
1177 #endif
1178     } else if(!strncmp(name, "sysinfo:", 8)){
1179         ret = create_service_thread(get_platforminfo, 0);
1180     } else if(!strncmp(name, "capability:", 11)){
1181         ret = create_service_thread(get_capability, 0);
1182     } else if(!strncmp(name, "boot:", 5)){
1183         if (is_emulator()) {
1184             ret = create_service_thread(get_boot, 0);
1185         }
1186     } else if(!strncmp(name, "shellconf:", 10)){
1187         if(!strncmp(name+10, "syncwinsz:", 10)){
1188             ret = create_service_thread(sync_windowsize, (void *)name+20);
1189         }
1190     } else if(!strncmp(name, "tzplatformenv:", 14)) {
1191        char* env_variable = NULL;
1192        env_variable = strdup(name+14);
1193        ret = create_service_thread(get_tzplatform_env, (void *)(env_variable));
1194     } else if(!strncmp(name, "appcmd:", 7)){
1195         ret = request_appcmd_to_plugin(name+7);
1196     }
1197
1198     if (ret >= 0) {
1199         if (close_on_exec(ret) < 0) {
1200             D("failed to close fd exec\n");
1201         }
1202     }
1203     return ret;
1204 }
1205
1206 #if SDB_HOST
1207 struct state_info {
1208     transport_type transport;
1209     char* serial;
1210     int state;
1211 };
1212
1213 static void wait_for_state(int fd, void* cookie)
1214 {
1215     struct state_info* sinfo = cookie;
1216     char* err = "unknown error";
1217
1218     D("wait_for_state %d\n", sinfo->state);
1219
1220     atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
1221     if(t != 0) {
1222         writex(fd, "OKAY", 4);
1223     } else {
1224         sendfailmsg(fd, err);
1225     }
1226
1227     if (sinfo->serial)
1228         free(sinfo->serial);
1229     free(sinfo);
1230     sdb_close(fd);
1231     D("wait_for_state is done\n");
1232 }
1233 #endif
1234
1235 #if SDB_HOST
1236 asocket*  host_service_to_socket(const char*  name, const char *serial)
1237 {
1238     if (!strcmp(name,"track-devices")) {
1239         return create_device_tracker();
1240     } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
1241         struct state_info* sinfo = malloc(sizeof(struct state_info));
1242
1243         if (serial)
1244             sinfo->serial = strdup(serial);
1245         else
1246             sinfo->serial = NULL;
1247
1248         name += strlen("wait-for-");
1249
1250         if (!strncmp(name, "local", strlen("local"))) {
1251             sinfo->transport = kTransportLocal;
1252             sinfo->state = CS_DEVICE;
1253         } else if (!strncmp(name, "usb", strlen("usb"))) {
1254             sinfo->transport = kTransportUsb;
1255             sinfo->state = CS_DEVICE;
1256         } else if (!strncmp(name, "any", strlen("any"))) {
1257             sinfo->transport = kTransportAny;
1258             sinfo->state = CS_DEVICE;
1259         } else {
1260             free(sinfo);
1261             return NULL;
1262         }
1263
1264         int fd = create_service_thread(wait_for_state, sinfo);
1265         return create_local_socket(fd);
1266     }
1267     return NULL;
1268 }
1269 #endif /* SDB_HOST */