2b2174e3cbd65b9d1fc8fb659c202470420d150f
[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 <system_info.h>
43 #include <tzplatform_config.h>
44
45 #define SYSTEM_INFO_KEY_MODEL           "http://tizen.org/system/model_name"
46 #define SYSTEM_INFO_KEY_PLATFORM_NAME   "http://tizen.org/system/platform.name"
47
48 typedef struct stinfo stinfo;
49
50 struct stinfo {
51     void (*func)(int fd, void *cookie);
52     int fd;
53     void *cookie;
54 };
55
56
57 void *service_bootstrap_func(void *x)
58 {
59     stinfo *sti = x;
60     sti->func(sti->fd, sti->cookie);
61     free(sti);
62     return 0;
63 }
64
65 #if SDB_HOST
66 SDB_MUTEX_DEFINE( dns_lock );
67
68 static void dns_service(int fd, void *cookie)
69 {
70     char *hostname = cookie;
71     struct hostent *hp;
72     unsigned zero = 0;
73
74     sdb_mutex_lock(&dns_lock);
75     hp = gethostbyname(hostname);
76     free(cookie);
77     if(hp == 0) {
78         writex(fd, &zero, 4);
79     } else {
80         writex(fd, hp->h_addr, 4);
81     }
82     sdb_mutex_unlock(&dns_lock);
83     sdb_close(fd);
84 }
85 #else
86
87 #if 0
88 extern int recovery_mode;
89
90 static void recover_service(int s, void *cookie)
91 {
92     unsigned char buf[4096];
93     unsigned count = (unsigned) cookie;
94     int fd;
95
96     fd = sdb_creat("/tmp/update", 0644);
97     if(fd < 0) {
98         sdb_close(s);
99         return;
100     }
101
102     while(count > 0) {
103         unsigned xfer = (count > 4096) ? 4096 : count;
104         if(readx(s, buf, xfer)) break;
105         if(writex(fd, buf, xfer)) break;
106         count -= xfer;
107     }
108
109     if(count == 0) {
110         writex(s, "OKAY", 4);
111     } else {
112         writex(s, "FAIL", 4);
113     }
114     sdb_close(fd);
115     sdb_close(s);
116
117     fd = sdb_creat("/tmp/update.begin", 0644);
118     sdb_close(fd);
119 }
120
121 void restart_root_service(int fd, void *cookie)
122 {
123     char buf[100];
124     char value[PROPERTY_VALUE_MAX];
125
126     if (getuid() == 0) {
127         snprintf(buf, sizeof(buf), "sdbd is already running as root\n");
128         writex(fd, buf, strlen(buf));
129         sdb_close(fd);
130     } else {
131         property_get("ro.debuggable", value, "");
132         if (strcmp(value, "1") != 0) {
133             snprintf(buf, sizeof(buf), "sdbd cannot run as root in production builds\n");
134             writex(fd, buf, strlen(buf));
135             sdb_close(fd);
136             return;
137         }
138
139         property_set("service.sdb.root", "1");
140         snprintf(buf, sizeof(buf), "restarting sdbd as root\n");
141         writex(fd, buf, strlen(buf));
142         sdb_close(fd);
143     }
144 }
145 #endif
146
147 void restart_tcp_service(int fd, void *cookie)
148 {
149     char buf[100];
150     char value[PROPERTY_VALUE_MAX];
151     int port = (int)cookie;
152
153     if (port <= 0) {
154         snprintf(buf, sizeof(buf), "invalid port\n");
155         writex(fd, buf, strlen(buf));
156         sdb_close(fd);
157         return;
158     }
159
160     snprintf(value, sizeof(value), "%d", port);
161     property_set("service.sdb.tcp.port", value);
162     snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
163     writex(fd, buf, strlen(buf));
164     sdb_close(fd);
165 }
166
167 void rootshell_service(int fd, void *cookie)
168 {
169     char buf[100];
170     char *mode = (char*) cookie;
171
172     if (!strcmp(mode, "on")) {
173         if (rootshell_mode == 1) {
174             //snprintf(buf, sizeof(buf), "Already changed to developer mode\n");
175             // do not show message
176         } else {
177             if (access("/bin/su", F_OK) == 0) {
178                 rootshell_mode = 1;
179                 //allows a permitted user to execute a command as the superuser
180                 snprintf(buf, sizeof(buf), "Switched to 'root' account mode\n");
181             } else {
182                 snprintf(buf, sizeof(buf), "Permission denied\n");
183             }
184             writex(fd, buf, strlen(buf));
185         }
186     } else if (!strcmp(mode, "off")) {
187         if (rootshell_mode == 1) {
188             rootshell_mode = 0;
189             snprintf(buf, sizeof(buf), "Switched to 'developer' account mode\n");
190             writex(fd, buf, strlen(buf));
191         }
192     } else {
193         snprintf(buf, sizeof(buf), "Unknown command option\n");
194         writex(fd, buf, strlen(buf));
195     }
196     D("set rootshell to %s\n", rootshell_mode == 1 ? "root" : "developer");
197     sdb_close(fd);
198 }
199
200 void restart_usb_service(int fd, void *cookie)
201 {
202     char buf[100];
203
204     property_set("service.sdb.tcp.port", "0");
205     snprintf(buf, sizeof(buf), "restarting in USB mode\n");
206     writex(fd, buf, strlen(buf));
207     sdb_close(fd);
208 }
209
210 void reboot_service(int fd, void *arg)
211 {
212 #if 0
213     char buf[100];
214     int pid, ret;
215
216     sync();
217
218     /* Attempt to unmount the SD card first.
219      * No need to bother checking for errors.
220      */
221     pid = fork();
222     if (pid == 0) {
223         /* ask vdc to unmount it */
224         // prevent: Use of untrusted string value (TAINTED_STRING)
225         execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount",
226                 getenv("EXTERNAL_STORAGE"), "force", NULL);
227     } else if (pid > 0) {
228         /* wait until vdc succeeds or fails */
229         waitpid(pid, &ret, 0);
230     }
231
232     ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
233     if (ret < 0) {
234         snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
235         writex(fd, buf, strlen(buf));
236     }
237     free(arg);
238     sdb_close(fd);
239 #endif
240 }
241
242 #if !SDB_HOST
243 #define EVENT_SIZE  ( sizeof (struct inotify_event) )
244 #define BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )
245 #define CS_PATH     tzplatform_mkpath(TZ_USER_SHARE,"crash/report")
246
247 void inoti_service(int fd, void *arg)
248 {
249     int wd;
250     int ifd;
251     char buffer[BUF_LEN];
252
253     D( "inoti_service start\n");
254     ifd = inotify_init();
255
256     if ( ifd < 0 ) {
257         D( "inotify_init failed\n");
258         return;
259     }
260
261     wd = inotify_add_watch( ifd, CS_PATH, IN_CREATE);
262
263     for ( ; ; ) {
264         int length, i = 0;
265         length = sdb_read( ifd, buffer, BUF_LEN );
266
267         if ( length < 0 ) {
268             D( "inoti read failed\n");
269             goto done;
270         }
271
272         while ( i < length ) {
273             struct inotify_event *event = ( struct inotify_event * )&buffer[i];
274             if (event->len) {
275                 if ( event->mask & IN_CREATE) {
276                     if (!(event->mask & IN_ISDIR)) {
277                         char *cspath = NULL;
278                         int len = asprintf(&cspath, "%s/%s", CS_PATH, event->name);
279                         D( "The file %s was created.\n", cspath);
280                         writex(fd, cspath, len);
281                         if (cspath != NULL) {
282                             free(cspath);
283                         }
284                     }
285                 }
286             }
287             i += EVENT_SIZE + event->len;
288         }
289     }
290
291 done:
292     inotify_rm_watch( ifd, wd );
293     sdb_close(ifd);
294     sdb_close(fd);
295     D( "inoti_service end\n");
296 }
297 #endif
298 #endif
299
300 #if 0
301 static void echo_service(int fd, void *cookie)
302 {
303     char buf[4096];
304     int r;
305     char *p;
306     int c;
307
308     for(;;) {
309         r = read(fd, buf, 4096);
310         if(r == 0) goto done;
311         if(r < 0) {
312             if(errno == EINTR) continue;
313             else goto done;
314         }
315
316         c = r;
317         p = buf;
318         while(c > 0) {
319             r = write(fd, p, c);
320             if(r > 0) {
321                 c -= r;
322                 p += r;
323                 continue;
324             }
325             if((r < 0) && (errno == EINTR)) continue;
326             goto done;
327         }
328     }
329 done:
330     close(fd);
331 }
332 #endif
333
334 static int create_service_thread(void (*func)(int, void *), void *cookie)
335 {
336     stinfo *sti;
337     sdb_thread_t t;
338     int s[2];
339
340     if(sdb_socketpair(s)) {
341         D("cannot create service socket pair\n");
342         return -1;
343     }
344
345     sti = malloc(sizeof(stinfo));
346     if(sti == 0) fatal("cannot allocate stinfo");
347     sti->func = func;
348     sti->cookie = cookie;
349     sti->fd = s[1];
350
351     if(sdb_thread_create( &t, service_bootstrap_func, sti)){
352         free(sti);
353         sdb_close(s[0]);
354         sdb_close(s[1]);
355         D("cannot create service thread\n");
356         return -1;
357     }
358
359     D("service thread started, %d:%d\n",s[0], s[1]);
360     return s[0];
361 }
362
363 #if !SDB_HOST
364
365 static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
366 {
367 #ifdef HAVE_WIN32_PROC
368     D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
369     fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
370     return -1;
371 #else /* !HAVE_WIN32_PROC */
372     char *devname;
373     int ptm;
374
375     ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
376     if(ptm < 0){
377         D("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
378         return -1;
379     }
380     if (fcntl(ptm, F_SETFD, FD_CLOEXEC) < 0) {
381         D("[ cannot set cloexec to /dev/ptmx - %s ]\n",strerror(errno));
382     }
383
384     if(grantpt(ptm) || unlockpt(ptm) ||
385        ((devname = (char*) ptsname(ptm)) == 0)){
386         D("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
387         sdb_close(ptm);
388         return -1;
389     }
390
391     *pid = fork();
392     if(*pid < 0) {
393         D("- fork failed: %s -\n", strerror(errno));
394         sdb_close(ptm);
395         return -1;
396     }
397
398     if(*pid == 0){
399         int pts;
400
401         setsid();
402
403         pts = unix_open(devname, O_RDWR);
404         if(pts < 0) {
405             fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
406             exit(-1);
407         }
408
409         dup2(pts, 0);
410         dup2(pts, 1);
411         dup2(pts, 2);
412
413         sdb_close(pts);
414         sdb_close(ptm);
415
416         // set OOM adjustment to zero
417         {
418             char text[64];
419             snprintf(text, sizeof text, "/proc/%d/oom_score_adj", getpid());
420             int fd = sdb_open(text, O_WRONLY);
421             if (fd >= 0) {
422                 sdb_write(fd, "0", 1);
423                 sdb_close(fd);
424             } else {
425                // FIXME: not supposed to be here
426                D("sdb: unable to open %s due to %s\n", text, strerror(errno));
427             }
428         }
429
430         verify_commands(arg1);
431
432         execl(cmd, cmd, arg0, arg1, NULL);
433         fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
434                 cmd, strerror(errno), errno);
435         exit(-1);
436     } else {
437         // Don't set child's OOM adjustment to zero.
438         // Let the child do it itself, as sometimes the parent starts
439         // running before the child has a /proc/pid/oom_adj.
440         // """sdb: unable to open /proc/644/oom_adj""" seen in some logs.
441         return ptm;
442     }
443 #endif /* !HAVE_WIN32_PROC */
444 }
445 #endif  /* !SDB_HOST */
446
447 #if SDB_HOST
448 #define SHELL_COMMAND "/bin/sh"
449 #else
450 #define SHELL_COMMAND "/bin/sh" /* tizen specific */
451 #endif
452
453 #if !SDB_HOST
454 static void subproc_waiter_service(int fd, void *cookie)
455 {
456     pid_t pid = (pid_t)cookie;
457
458     D("entered. fd=%d of pid=%d\n", fd, pid);
459     for (;;) {
460         int status;
461         pid_t p = waitpid(pid, &status, 0);
462         if (p == pid) {
463             D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
464             
465             if (WIFEXITED(status)) {
466                 D("*** Exit code %d\n", WEXITSTATUS(status));
467                 break;
468             } else if (WIFSIGNALED(status)) {
469                 D("*** Killed by signal %d\n", WTERMSIG(status));
470                 break;
471             } else {
472                 D("*** Killed by unknown code %d\n", status);
473                 break;
474             }
475          }
476     }
477     D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
478     if (SHELL_EXIT_NOTIFY_FD >=0) {
479       int res;
480       res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
481       D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
482         SHELL_EXIT_NOTIFY_FD, pid, res, errno);
483     }
484 }
485
486 static int create_subproc_thread(const char *name)
487 {
488     stinfo *sti;
489     sdb_thread_t t;
490     int ret_fd;
491     pid_t pid;
492
493     if(name) {
494         ret_fd = create_subprocess(SHELL_COMMAND, "-c", name, &pid);
495     } else {
496         ret_fd = create_subprocess(SHELL_COMMAND, "-", 0, &pid);
497     }
498     D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
499
500     if (ret_fd < 0) {
501         D("cannot create service thread\n");
502         return -1;
503     }
504     sti = malloc(sizeof(stinfo));
505     if(sti == 0) fatal("cannot allocate stinfo");
506     sti->func = subproc_waiter_service;
507     sti->cookie = (void*)pid;
508     sti->fd = ret_fd;
509
510     if(sdb_thread_create( &t, service_bootstrap_func, sti)){
511         free(sti);
512         sdb_close(ret_fd);
513         D("cannot create service thread\n");
514         return -1;
515     }
516
517     D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
518     return ret_fd;
519 }
520
521 static int create_sync_subprocess(void (*func)(int, void *), void* cookie) {
522     stinfo *sti;
523     sdb_thread_t t;
524     int s[2];
525
526     if(sdb_socketpair(s)) {
527         D("cannot create service socket pair\n");
528         return -1;
529     }
530
531     pid_t pid = fork();
532
533     if (pid == 0) {
534         sdb_close(s[0]);
535         func(s[1], cookie);
536         exit(-1);
537     } else if (pid > 0) {
538         sdb_close(s[1]);
539         // FIXME: do not wait child process hear
540         //waitpid(pid, &ret, 0);
541     }
542     if (pid < 0) {
543         D("- fork failed: %s -\n", strerror(errno));
544         sdb_close(s[0]);
545         sdb_close(s[1]);
546         D("cannot create sync service sub process\n");
547         return -1;
548     }
549
550     sti = malloc(sizeof(stinfo));
551     if(sti == 0) fatal("cannot allocate stinfo");
552     sti->func = subproc_waiter_service;
553     sti->cookie = (void*)pid;
554     sti->fd = s[0];
555
556     if(sdb_thread_create( &t, service_bootstrap_func, sti)){
557         free(sti);
558         sdb_close(s[0]);
559         sdb_close(s[1]);
560         printf("cannot create service monitor thread\n");
561         return -1;
562     }
563
564     D("service process started, fd=%d pid=%d\n",s[0], pid);
565     return s[0];
566 }
567
568 static int create_syncproc_thread()
569 {
570     int ret_fd;
571
572     ret_fd = create_sync_subprocess(file_sync_service, NULL);
573     // FIXME: file missing bug when root on mode
574     /*
575     if (should_drop_privileges()) {
576         ret_fd = create_sync_subprocess(file_sync_service, NULL);
577     } else {
578         ret_fd = create_service_thread(file_sync_service, NULL);
579     }
580     */
581
582     return ret_fd;
583 }
584
585 #endif
586
587 #define UNKNOWN "unknown"
588 #define INFOBUF_MAXLEN 64
589 #define INFO_VERSION "2.2.0"
590 typedef struct platform_info {
591     
592     char platform_info_version[INFOBUF_MAXLEN];
593     char model_name[INFOBUF_MAXLEN]; // Emulator
594     char platform_name[INFOBUF_MAXLEN]; // Tizen
595     char platform_version[INFOBUF_MAXLEN]; // 2.2.1
596     char profile_name[INFOBUF_MAXLEN]; // 2.2.1
597 } pinfo;
598
599 static void get_platforminfo(int fd, void *cookie) {
600     pinfo sysinfo;
601
602     char *value = NULL;
603     s_strncpy(sysinfo.platform_info_version, INFO_VERSION, strlen(INFO_VERSION));
604
605     int r = system_info_get_platform_string(SYSTEM_INFO_KEY_MODEL, &value);
606     if (r != SYSTEM_INFO_ERROR_NONE) {
607         s_strncpy(sysinfo.model_name, UNKNOWN, strlen(UNKNOWN));
608         D("fail to get system model:%d\n", errno);
609     } else {
610         s_strncpy(sysinfo.model_name, value, sizeof(sysinfo.model_name));
611         D("returns model_name:%s\n", value);
612         if (value != NULL) {
613             free(value);
614         }
615     }
616
617     r = system_info_get_platform_string(SYSTEM_INFO_KEY_PLATFORM_NAME, &value);
618     if (r != SYSTEM_INFO_ERROR_NONE) {
619         s_strncpy(sysinfo.platform_name, UNKNOWN, strlen(UNKNOWN));
620         D("fail to get platform name:%d\n", errno);
621     } else {
622         s_strncpy(sysinfo.platform_name, value, sizeof(sysinfo.platform_name));
623         D("returns platform_name:%s\n", value);
624         if (value != NULL) {
625             free(value);
626         }
627
628     }
629
630     // FIXME: the result is different when using SYSTEM_INFO_KEY_TIZEN_VERSION_NAME
631     r = system_info_get_platform_string("tizen.org/feature/platform.version", &value);
632     if (r != SYSTEM_INFO_ERROR_NONE) {
633         s_strncpy(sysinfo.platform_version, UNKNOWN, strlen(UNKNOWN));
634         D("fail to get platform version:%d\n", errno);
635     } else {
636         s_strncpy(sysinfo.platform_version, value, sizeof(sysinfo.platform_version));
637         D("returns platform_version:%s\n", value);
638         if (value != NULL) {
639             free(value);
640         }
641     }
642
643     r = system_info_get_platform_string("tizen.org/feature/profile", &value);
644     if (r != SYSTEM_INFO_ERROR_NONE) {
645         s_strncpy(sysinfo.profile_name, UNKNOWN, strlen(UNKNOWN));
646         D("fail to get profile name:%d\n", errno);
647     } else {
648         s_strncpy(sysinfo.profile_name, value, sizeof(sysinfo.profile_name));
649         D("returns profile name:%s\n", value);
650         if (value != NULL) {
651             free(value);
652         }
653     }
654
655     writex(fd, &sysinfo, sizeof(pinfo));
656
657     sdb_close(fd);
658 }
659
660 int service_to_fd(const char *name)
661 {
662     int ret = -1;
663
664     if(!strncmp(name, "tcp:", 4)) {
665         int port = atoi(name + 4);
666         name = strchr(name + 4, ':');
667         if(name == 0) {
668             ret = socket_loopback_client(port, SOCK_STREAM);
669             if (ret >= 0)
670                 disable_tcp_nagle(ret);
671         } else {
672 #if SDB_HOST
673             sdb_mutex_lock(&dns_lock);
674             ret = socket_network_client(name + 1, port, SOCK_STREAM);
675             sdb_mutex_unlock(&dns_lock);
676 #else
677             return -1;
678 #endif
679         }
680 #ifndef HAVE_WINSOCK   /* winsock doesn't implement unix domain sockets */
681     } else if(!strncmp(name, "local:", 6)) {
682         ret = socket_local_client(name + 6,
683                 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
684     } else if(!strncmp(name, "localreserved:", 14)) {
685         ret = socket_local_client(name + 14,
686                 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
687     } else if(!strncmp(name, "localabstract:", 14)) {
688         ret = socket_local_client(name + 14,
689                 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
690     } else if(!strncmp(name, "localfilesystem:", 16)) {
691         ret = socket_local_client(name + 16,
692                 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
693 #endif
694 #if SDB_HOST
695     } else if(!strncmp("dns:", name, 4)){
696         char *n = strdup(name + 4);
697         if(n == 0) return -1;
698         ret = create_service_thread(dns_service, n);
699 #else /* !SDB_HOST */
700     }/* else if(!strncmp("dev:", name, 4)) {// tizen specific
701         ret = unix_open(name + 4, O_RDWR);
702     } else if(!strncmp(name, "framebuffer:", 12)) {
703         ret = create_service_thread(framebuffer_service, 0);
704     } else if(recovery_mode && !strncmp(name, "recover:", 8)) {
705         ret = create_service_thread(recover_service, (void*) atoi(name + 8));
706     } else if (!strncmp(name, "jdwp:", 5)) {
707         ret = create_jdwp_connection_fd(atoi(name+5));
708     } else if (!strncmp(name, "log:", 4)) {
709         ret = create_service_thread(log_service, get_log_file_path(name + 4));
710     }*/ else if(!HOST && !strncmp(name, "shell:", 6)) {
711         if(name[6]) {
712             ret = create_subproc_thread(name + 6);
713         } else {
714             ret = create_subproc_thread(0);
715         }
716     } else if(!strncmp(name, "sync:", 5)) {
717         //ret = create_service_thread(file_sync_service, NULL);
718         ret = create_syncproc_thread();
719     }/*  else if(!strncmp(name, "remount:", 8)) {
720         ret = create_service_thread(remount_service, NULL);
721     } else if(!strncmp(name, "reboot:", 7)) {
722         void* arg = strdup(name + 7);
723         if(arg == 0) return -1;
724         ret = create_service_thread(reboot_service, arg);
725     } else if(!strncmp(name, "root:", 5)) {
726         ret = create_service_thread(restart_root_service, NULL);
727     } else if(!strncmp(name, "backup:", 7)) {
728         char* arg = strdup(name+7);
729         if (arg == NULL) return -1;
730         ret = backup_service(BACKUP, arg);
731     } else if(!strncmp(name, "restore:", 8)) {
732         ret = backup_service(RESTORE, NULL);
733     }*/ else if(!strncmp(name, "root:", 5)) {
734         ret = create_service_thread(rootshell_service, (void *)(name+5));
735     } else if(!strncmp(name, "tcpip:", 6)) {
736         int port;
737         /*if (sscanf(name + 6, "%d", &port) == 0) {
738             port = 0;
739         }*/
740         port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
741         ret = create_service_thread(restart_tcp_service, (void *)port);
742     } else if(!strncmp(name, "usb:", 4)) {
743         ret = create_service_thread(restart_usb_service, NULL);
744     } else if(!strncmp(name, "cs:", 5)) {
745         ret = create_service_thread(inoti_service, NULL);
746 #endif
747     } else if(!strncmp(name, "sysinfo:", 8)){
748         ret = create_service_thread(get_platforminfo, 0);
749     }
750     if (ret >= 0) {
751         if (close_on_exec(ret) < 0) {
752             D("failed to close fd exec\n");
753         }
754     }
755     return ret;
756 }
757
758 #if SDB_HOST
759 struct state_info {
760     transport_type transport;
761     char* serial;
762     int state;
763 };
764
765 static void wait_for_state(int fd, void* cookie)
766 {
767     struct state_info* sinfo = cookie;
768     char* err = "unknown error";
769
770     D("wait_for_state %d\n", sinfo->state);
771
772     atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
773     if(t != 0) {
774         writex(fd, "OKAY", 4);
775     } else {
776         sendfailmsg(fd, err);
777     }
778
779     if (sinfo->serial)
780         free(sinfo->serial);
781     free(sinfo);
782     sdb_close(fd);
783     D("wait_for_state is done\n");
784 }
785 #endif
786
787 #if SDB_HOST
788 asocket*  host_service_to_socket(const char*  name, const char *serial)
789 {
790     if (!strcmp(name,"track-devices")) {
791         return create_device_tracker();
792     } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
793         struct state_info* sinfo = malloc(sizeof(struct state_info));
794
795         if (serial)
796             sinfo->serial = strdup(serial);
797         else
798             sinfo->serial = NULL;
799
800         name += strlen("wait-for-");
801
802         if (!strncmp(name, "local", strlen("local"))) {
803             sinfo->transport = kTransportLocal;
804             sinfo->state = CS_DEVICE;
805         } else if (!strncmp(name, "usb", strlen("usb"))) {
806             sinfo->transport = kTransportUsb;
807             sinfo->state = CS_DEVICE;
808         } else if (!strncmp(name, "any", strlen("any"))) {
809             sinfo->transport = kTransportAny;
810             sinfo->state = CS_DEVICE;
811         } else {
812             free(sinfo);
813             return NULL;
814         }
815
816         int fd = create_service_thread(wait_for_state, sinfo);
817         return create_local_socket(fd);
818     }
819     return NULL;
820 }
821 #endif /* SDB_HOST */