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