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