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