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