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