Merge branch 'tizen_2.4_merge' into tizen
[sdk/target/sdbd.git] / src / sdb.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 #define  TRACE_TAG   TRACE_SDB
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <ctype.h>
22 #include <stdarg.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <time.h>
26 #include <sys/time.h>
27 #include <signal.h>
28 #include <grp.h>
29 #include <netdb.h>
30 #include <tzplatform_config.h>
31 #include <pthread.h>
32 #include <dlfcn.h>
33
34 #include "sysdeps.h"
35 #include "sdb.h"
36 #include "strutils.h"
37 #if !SDB_HOST
38 #include "commandline_sdbd.h"
39 #endif
40 #include "utils.h"
41 #include "sdktools.h"
42
43 #if !SDB_HOST
44 #include <linux/prctl.h>
45 #define SDB_PIDPATH "/tmp/.sdbd.pid"
46 #else
47 #include "usb_vendors.h"
48 #endif
49 #include <system_info.h>
50 #include <vconf.h>
51 #include "utils.h"
52 #define PROC_CMDLINE_PATH "/proc/cmdline"
53 #define USB_SERIAL_PATH "/sys/class/usb_mode/usb0/iSerial"
54
55 #include <sys/ioctl.h>
56 #include <net/if.h>
57 #include <netinet/in.h>
58 #include <arpa/inet.h>
59 #define GUEST_IP_INTERFACE "eth0"
60
61 SDB_MUTEX_DEFINE(zone_check_lock);
62 #if SDB_TRACE
63 SDB_MUTEX_DEFINE( D_lock );
64 #endif
65
66 int HOST = 0;
67 #define HOME_DEV_PATH tzplatform_getenv(TZ_SDK_HOME)
68 #define DEV_NAME tzplatform_getenv(TZ_SDK_USER_NAME)
69 #if !SDB_HOST
70 SdbdCommandlineArgs sdbd_commandline_args;
71 #endif
72
73 void (*usb_init)() = NULL;
74 void (*usb_cleanup)() = NULL;
75 int (*usb_write)(usb_handle *h, const void *data, int len) = NULL;
76 int (*usb_read)(usb_handle *h, void *data, int len) = NULL;
77 int (*usb_close)(usb_handle *h) = NULL;
78 void (*usb_kick)(usb_handle *h) = NULL;
79
80 int is_emulator(void) {
81 #if SDB_HOST
82         return 0;
83 #else
84         return sdbd_commandline_args.emulator.host != NULL;
85 #endif
86 }
87
88 int is_container_enabled(void) {
89     bool value;
90     int ret;
91     ret = system_info_get_platform_bool("tizen.org/feature/container", &value);
92     if (ret != SYSTEM_INFO_ERROR_NONE) {
93         D("failed to get container information: %d\n", errno);
94         return 0;
95     } else {
96         D("tizen container: %d\n", value);
97         if (value == true)
98             return 1;
99         else
100             return 0;
101     }
102 }
103
104 void* g_sdbd_plugin_handle = NULL;
105 SDBD_PLUGIN_CMD_PROC_PTR sdbd_plugin_cmd_proc = NULL;
106
107 void handle_sig_term(int sig) {
108 #ifdef SDB_PIDPATH
109     if (access(SDB_PIDPATH, F_OK) == 0)
110         sdb_unlink(SDB_PIDPATH);
111 #endif
112     char *cmd1_args[] = {"/usr/bin/killall", "/usr/bin/debug_launchpad_preloading_preinitializing_daemon", NULL};
113     spawn("/usr/bin/killall", cmd1_args);
114     sdb_sleep_ms(1000);
115 }
116
117 static const char *sdb_device_banner = "device";
118
119 void fatal(const char *fmt, ...)
120 {
121     va_list ap;
122     va_start(ap, fmt);
123     fprintf(stderr, "error: ");
124     vfprintf(stderr, fmt, ap);
125     fprintf(stderr, "\n");
126     va_end(ap);
127     exit(-1);
128 }
129
130 void fatal_errno(const char *fmt, ...)
131 {
132     va_list ap;
133     va_start(ap, fmt);
134     fprintf(stderr, "errno: %d: ", errno);
135     vfprintf(stderr, fmt, ap);
136     fprintf(stderr, "\n");
137     va_end(ap);
138     exit(-1);
139 }
140
141 int   sdb_trace_mask;
142
143 /* read a comma/space/colum/semi-column separated list of tags
144  * from the SDB_TRACE environment variable and build the trace
145  * mask from it. note that '1' and 'all' are special cases to
146  * enable all tracing
147  */
148 void  sdb_trace_init(void)
149 {
150     const char*  p = getenv("SDB_TRACE");
151     const char*  q;
152
153     static const struct {
154         const char*  tag;
155         int           flag;
156     } tags[] = {
157         { "1", 0 },
158         { "all", 0 },
159         { "sdb", TRACE_SDB },
160         { "sockets", TRACE_SOCKETS },
161         { "packets", TRACE_PACKETS },
162         { "rwx", TRACE_RWX },
163         { "usb", TRACE_USB },
164         { "sync", TRACE_SYNC },
165         { "sysdeps", TRACE_SYSDEPS },
166         { "transport", TRACE_TRANSPORT },
167         { "jdwp", TRACE_JDWP },
168         { "services", TRACE_SERVICES },
169         { "properties", TRACE_PROPERTIES },
170         { "sdktools", TRACE_SDKTOOLS },
171         { NULL, 0 }
172     };
173
174     if (p == NULL)
175             return;
176
177     /* use a comma/column/semi-colum/space separated list */
178     while (*p) {
179         int  len, tagn;
180
181         q = strpbrk(p, " ,:;");
182         if (q == NULL) {
183             q = p + strlen(p);
184         }
185         len = q - p;
186
187         for (tagn = 0; tags[tagn].tag != NULL; tagn++)
188         {
189             int  taglen = strlen(tags[tagn].tag);
190
191             if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
192             {
193                 int  flag = tags[tagn].flag;
194                 if (flag == 0) {
195                     sdb_trace_mask = ~0;
196                     return;
197                 }
198                 sdb_trace_mask |= (1 << flag);
199                 break;
200             }
201         }
202         p = q;
203         if (*p)
204             p++;
205     }
206 }
207
208 #if !SDB_HOST
209 /*
210  * Implements SDB tracing inside the emulator.
211  */
212
213 #include <stdarg.h>
214
215 /*
216  * Redefine open and write for qemu_pipe.h that contains inlined references
217  * to those routines. We will redifine them back after qemu_pipe.h inclusion.
218  */
219
220 #undef open
221 #undef write
222 #define open    sdb_open
223 #define write   sdb_write
224 #include "qemu_pipe.h"
225 #undef open
226 #undef write
227 #define open    ___xxx_open
228 #define write   ___xxx_write
229
230 /* A handle to sdb-debug qemud service in the emulator. */
231 int   sdb_debug_qemu = -1;
232
233 /* Initializes connection with the sdb-debug qemud service in the emulator. */
234 #if 0 /* doen't support in Tizen */
235 static int sdb_qemu_trace_init(void)
236 {
237     char con_name[32];
238
239     if (sdb_debug_qemu >= 0) {
240         return 0;
241     }
242
243     /* sdb debugging QEMUD service connection request. */
244     snprintf(con_name, sizeof(con_name), "qemud:sdb-debug");
245     sdb_debug_qemu = qemu_pipe_open(con_name);
246     return (sdb_debug_qemu >= 0) ? 0 : -1;
247 }
248
249 void sdb_qemu_trace(const char* fmt, ...)
250 {
251     va_list args;
252     va_start(args, fmt);
253     char msg[1024];
254
255     if (sdb_debug_qemu >= 0) {
256         vsnprintf(msg, sizeof(msg), fmt, args);
257         sdb_write(sdb_debug_qemu, msg, strlen(msg));
258     }
259 }
260 #endif
261 #endif  /* !SDB_HOST */
262
263 apacket *get_apacket(void)
264 {
265     apacket *p = malloc(sizeof(apacket));
266     if(p == 0) fatal("failed to allocate an apacket");
267     memset(p, 0, sizeof(apacket) - MAX_PAYLOAD);
268     return p;
269 }
270
271 void put_apacket(apacket *p)
272 {
273     if (p != NULL) {
274         free(p);
275         p = NULL;
276     }
277 }
278
279 void handle_online(void)
280 {
281     D("sdb: online\n");
282 }
283
284 void handle_offline(atransport *t)
285 {
286     D("sdb: offline\n");
287     //Close the associated usb
288     run_transport_disconnects(t);
289 }
290
291 #if TRACE_PACKETS
292 #define DUMPMAX 32
293 void print_packet(const char *label, apacket *p)
294 {
295     char *tag;
296     char *x;
297     unsigned count;
298
299     switch(p->msg.command){
300     case A_SYNC: tag = "SYNC"; break;
301     case A_CNXN: tag = "CNXN" ; break;
302     case A_OPEN: tag = "OPEN"; break;
303     case A_OKAY: tag = "OKAY"; break;
304     case A_CLSE: tag = "CLSE"; break;
305     case A_WRTE: tag = "WRTE"; break;
306     default: tag = "????"; break;
307     }
308
309     fprintf(stderr, "%s: %s %08x %08x %04x \"",
310             label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
311     count = p->msg.data_length;
312     x = (char*) p->data;
313     if(count > DUMPMAX) {
314         count = DUMPMAX;
315         tag = "\n";
316     } else {
317         tag = "\"\n";
318     }
319     while(count-- > 0){
320         if((*x >= ' ') && (*x < 127)) {
321             fputc(*x, stderr);
322         } else {
323             fputc('.', stderr);
324         }
325         x++;
326     }
327     fprintf(stderr, tag);
328 }
329 #endif
330
331 static void send_ready(unsigned local, unsigned remote, atransport *t)
332 {
333     D("Calling send_ready \n");
334     apacket *p = get_apacket();
335     p->msg.command = A_OKAY;
336     p->msg.arg0 = local;
337     p->msg.arg1 = remote;
338     send_packet(p, t);
339 }
340
341 static void send_close(unsigned local, unsigned remote, atransport *t)
342 {
343     D("Calling send_close \n");
344     apacket *p = get_apacket();
345     p->msg.command = A_CLSE;
346     p->msg.arg0 = local;
347     p->msg.arg1 = remote;
348     send_packet(p, t);
349 }
350
351 static void send_connect(atransport *t)
352 {
353     D("Calling send_connect \n");
354     apacket *cp = get_apacket();
355     cp->msg.command = A_CNXN;
356     cp->msg.arg0 = A_VERSION;
357     cp->msg.arg1 = MAX_PAYLOAD;
358
359     char device_name[256]={0,};
360     int r = 0;
361     int status = 0;
362     if (is_pwlocked()) {
363         status = 1;
364         t->connection_state = CS_PWLOCK;
365     }
366
367     if (is_emulator()) {
368         r = get_emulator_name(device_name, sizeof device_name);
369     } else {
370         r = get_device_name(device_name, sizeof device_name);
371     }
372     if (r < 0) {
373         snprintf((char*) cp->data, sizeof cp->data, "%s::%s::%d", sdb_device_banner, DEFAULT_DEVICENAME, status);
374     } else {
375         snprintf((char*) cp->data, sizeof cp->data, "%s::%s::%d", sdb_device_banner, device_name, status);
376     }
377
378     D("CNXN data:%s\n", (char*)cp->data);
379     cp->msg.data_length = strlen((char*) cp->data) + 1;
380
381     send_packet(cp, t);
382 #if SDB_HOST
383         /* XXX why sleep here? */
384     // allow the device some time to respond to the connect message
385     sdb_sleep_ms(1000);
386 #endif
387 }
388
389 static void send_device_status()
390 {
391     D("broadcast device status\n");
392     apacket* cp = get_apacket();
393     cp->msg.command = A_STAT;
394     cp->msg.arg0 = is_pwlocked();
395     cp->msg.arg1 = 0;
396
397     broadcast_transport(cp);
398
399     //all broadcasted packets are memory copied
400     //so, we should call put_apacket
401     put_apacket(cp);
402 }
403
404 static char *connection_state_name(atransport *t)
405 {
406     if (t == NULL) {
407         return "unknown";
408     }
409
410     switch(t->connection_state) {
411     case CS_BOOTLOADER:
412         return "bootloader";
413     case CS_DEVICE:
414         return "device";
415     case CS_OFFLINE:
416         return "offline";
417     default:
418         return "unknown";
419     }
420 }
421
422 static int get_str_cmdline(char *src, char *dest, char str[], int str_size) {
423     char *s = strstr(src, dest);
424     if (s == NULL) {
425         return -1;
426     }
427     char *e = strstr(s, " ");
428     if (e == NULL) {
429         return -1;
430     }
431
432     int len = e-s-strlen(dest);
433
434     if (len >= str_size) {
435         D("buffer size(%d) should be bigger than %d\n", str_size, len+1);
436         return -1;
437     }
438
439     strncpy(str, s + strlen(dest), len);
440     str[len]='\0';
441     return len;
442 }
443
444 int get_emulator_forward_port() {
445     SdbdCommandlineArgs *sdbd_args = &sdbd_commandline_args; /* alias */
446
447     if (sdbd_args->emulator.host == NULL) {
448         return -1;
449     }
450
451     return sdbd_args->emulator.port;
452 }
453
454 int get_emulator_name(char str[], int str_size) {
455     SdbdCommandlineArgs *sdbd_args = &sdbd_commandline_args; /* alias */
456
457     if (sdbd_args->emulator.host == NULL) {
458         return -1;
459     }
460
461     s_strncpy(str, sdbd_args->emulator.host, str_size);
462     return 0;
463 }
464
465 int get_device_name(char str[], int str_size) {
466     char *value = NULL;
467     int r = system_info_get_platform_string("http://tizen.org/system/model_name", &value);
468     if (r != SYSTEM_INFO_ERROR_NONE) {
469         D("fail to get system model:%d\n", errno);
470         return -1;
471     } else {
472         s_strncpy(str, value, str_size);
473         D("returns model_name:%s\n", value);
474         if (value != NULL) {
475             free(value);
476         }
477         return 0;
478     }
479     /*
480     int fd = unix_open(USB_SERIAL_PATH, O_RDONLY);
481     if (fd < 0) {
482         D("fail to read:%s (%d)\n", USB_SERIAL_PATH, errno);
483         return -1;
484     }
485
486     if(read_line(fd, str, str_size)) {
487         D("device serial name: %s\n", str);
488         sdb_close(fd);
489         return 0;
490     }
491     sdb_close(fd);
492     */
493     return -1;
494 }
495
496 static int get_cmdline_value(char *split, char str[], int str_size) {
497     char cmdline[512];
498     int fd = unix_open(PROC_CMDLINE_PATH, O_RDONLY);
499
500     if (fd < 0) {
501         D("fail to read /proc/cmdline\n");
502         return -1;
503     }
504     if(read_line(fd, cmdline, sizeof(cmdline))) {
505         D("qemu cmd: %s\n", cmdline);
506         if (get_str_cmdline(cmdline, split, str, str_size) < 1) {
507             D("could not get the (%s) value from cmdline\n", split);
508             sdb_close(fd);
509             return -1;
510         }
511     }
512     sdb_close(fd);
513     return 0;
514 }
515
516 int get_emulator_hostip(char str[], int str_size) {
517     return get_cmdline_value("host_ip=", str, str_size);
518 }
519
520 int get_emulator_guestip(char str[], int str_size) {
521     int           s;
522     struct ifreq ifr;
523     struct sockaddr_in *sin;
524
525     s = socket(AF_INET, SOCK_DGRAM, 0);
526     if(s < 0) {
527         D("socket error\n");
528         return -1;
529     }
530
531     snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", GUEST_IP_INTERFACE);
532     if(ioctl(s, SIOCGIFHWADDR, &ifr) < 0) {
533         D("ioctl hwaddr error\n");
534         sdb_close(s);
535         return -1;
536     }
537
538     if(ioctl(s, SIOCGIFADDR, &ifr) < 0) {
539         D("ioctl addr error\n");
540         sdb_close(s);
541         return -1;
542     }
543     sin = (struct sockaddr_in *)&ifr.ifr_addr;
544     snprintf(str, str_size, "%s", inet_ntoa(sin->sin_addr));
545     sdb_close(s);
546
547     return 0;
548 }
549
550 void parse_banner(char *banner, atransport *t)
551 {
552     char *type, *product, *end;
553
554     D("parse_banner: %s\n", banner);
555     type = banner;
556     product = strchr(type, ':');
557     if(product) {
558         *product++ = 0;
559     } else {
560         product = "";
561     }
562
563         /* remove trailing ':' */
564     end = strchr(product, ':');
565     if(end) *end = 0;
566
567         /* save product name in device structure */
568     if (t->product == NULL) {
569         t->product = strdup(product);
570     } else if (strcmp(product, t->product) != 0) {
571         free(t->product);
572         t->product = strdup(product);
573     }
574
575     if(!strcmp(type, "bootloader")){
576         D("setting connection_state to CS_BOOTLOADER\n");
577         t->connection_state = CS_BOOTLOADER;
578         update_transports();
579         return;
580     }
581
582     if(!strcmp(type, "device")) {
583         D("setting connection_state to CS_DEVICE\n");
584         t->connection_state = CS_DEVICE;
585         update_transports();
586         return;
587     }
588
589     if(!strcmp(type, "recovery")) {
590         D("setting connection_state to CS_RECOVERY\n");
591         t->connection_state = CS_RECOVERY;
592         update_transports();
593         return;
594     }
595
596     if(!strcmp(type, "sideload")) {
597         D("setting connection_state to CS_SIDELOAD\n");
598         t->connection_state = CS_SIDELOAD;
599         update_transports();
600         return;
601     }
602
603     t->connection_state = CS_HOST;
604 }
605
606 void handle_packet(apacket *p, atransport *t)
607 {
608     asocket *s;
609
610     D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
611                 ((char*) (&(p->msg.command)))[1],
612                 ((char*) (&(p->msg.command)))[2],
613                 ((char*) (&(p->msg.command)))[3]);
614
615     print_packet("recv", p);
616
617     switch(p->msg.command){
618     case A_SYNC:
619         if(p->msg.arg0){
620             send_packet(p, t);
621             if(HOST) send_connect(t);
622         } else {
623             t->connection_state = CS_OFFLINE;
624             handle_offline(t);
625             send_packet(p, t);
626         }
627         return;
628
629     case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
630             /* XXX verify version, etc */
631         if(t->connection_state != CS_OFFLINE) {
632             t->connection_state = CS_OFFLINE;
633             handle_offline(t);
634         }
635         parse_banner((char*) p->data, t);
636         handle_online();
637         if(!HOST) send_connect(t);
638         break;
639
640     case A_OPEN: /* OPEN(local-id, 0, "destination") */
641         if (is_pwlocked() && t->connection_state == CS_PWLOCK) { // in case of already locked before get A_CNXN
642             D("open failed due to password locked before get A_CNXN:%d\n", t->connection_state);
643             send_close(0, p->msg.arg0, t);
644         } else {
645             if(t->connection_state != CS_OFFLINE) {
646                 char *name = (char*) p->data;
647                 name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
648                 s = create_local_service_socket(name);
649                 if(s == 0) {
650                     send_close(0, p->msg.arg0, t);
651                 } else {
652                     s->peer = create_remote_socket(p->msg.arg0, t);
653                     s->peer->peer = s;
654                     send_ready(s->id, s->peer->id, t);
655                     s->ready(s);
656                 }
657             }
658         }
659         break;
660
661     case A_OKAY: /* READY(local-id, remote-id, "") */
662         if(t->connection_state != CS_OFFLINE) {
663             if((s = find_local_socket(p->msg.arg1))) {
664                 if(s->peer == 0) {
665                     s->peer = create_remote_socket(p->msg.arg0, t);
666                     s->peer->peer = s;
667                 }
668                 s->ready(s);
669             }
670         }
671         break;
672
673     case A_CLSE: /* CLOSE(local-id, remote-id, "") */
674         if(t->connection_state != CS_OFFLINE) {
675             if((s = find_local_socket(p->msg.arg1))) {
676                 s->close(s);
677             }
678         }
679         break;
680
681     case A_WRTE:
682         if(t->connection_state != CS_OFFLINE) {
683             if((s = find_local_socket(p->msg.arg1))) {
684                 unsigned rid = p->msg.arg0;
685                 p->len = p->msg.data_length;
686
687                 if(s->enqueue(s, p) == 0) {
688                     D("Enqueue the socket\n");
689                     send_ready(s->id, rid, t);
690                 }
691                 return;
692             }
693         }
694         break;
695
696     default:
697         printf("handle_packet: what is %08x?!\n", p->msg.command);
698     }
699
700     put_apacket(p);
701 }
702
703 alistener listener_list = {
704     .next = &listener_list,
705     .prev = &listener_list,
706 };
707
708 static void ss_listener_event_func(int _fd, unsigned ev, void *_l)
709 {
710     asocket *s;
711
712     if(ev & FDE_READ) {
713         struct sockaddr addr;
714         socklen_t alen;
715         int fd;
716
717         alen = sizeof(addr);
718         fd = sdb_socket_accept(_fd, &addr, &alen);
719         if(fd < 0) return;
720
721         sdb_socket_setbufsize(fd, CHUNK_SIZE);
722
723         s = create_local_socket(fd);
724         if(s) {
725             connect_to_smartsocket(s);
726             return;
727         }
728
729         sdb_close(fd);
730     }
731 }
732
733 static void listener_event_func(int _fd, unsigned ev, void *_l)
734 {
735     alistener *l = _l;
736     asocket *s;
737
738     if(ev & FDE_READ) {
739         struct sockaddr addr;
740         socklen_t alen;
741         int fd;
742
743         alen = sizeof(addr);
744         fd = sdb_socket_accept(_fd, &addr, &alen);
745         if(fd < 0) return;
746
747         s = create_local_socket(fd);
748         if(s) {
749             s->transport = l->transport;
750             connect_to_remote(s, l->connect_to);
751             return;
752         }
753
754         sdb_close(fd);
755     }
756 }
757
758 static void  free_listener(alistener*  l)
759 {
760     if (l->next) {
761         l->next->prev = l->prev;
762         l->prev->next = l->next;
763         l->next = l->prev = l;
764     }
765
766     // closes the corresponding fd
767     fdevent_remove(&l->fde);
768
769     if (l->local_name)
770         free((char*)l->local_name);
771
772     if (l->connect_to)
773         free((char*)l->connect_to);
774
775     if (l->transport) {
776         remove_transport_disconnect(l->transport, &l->disconnect);
777     }
778     free(l);
779 }
780
781 static void listener_disconnect(void*  _l, atransport*  t)
782 {
783     alistener*  l = _l;
784
785     free_listener(l);
786 }
787
788 int local_name_to_fd(const char *name)
789 {
790     int port;
791
792     if(!strncmp("tcp:", name, 4)){
793         int  ret;
794         port = atoi(name + 4);
795         ret = socket_loopback_server(port, SOCK_STREAM);
796         return ret;
797     }
798 #ifndef HAVE_WIN32_IPC  /* no Unix-domain sockets on Win32 */
799     // It's non-sensical to support the "reserved" space on the sdb host side
800     if(!strncmp(name, "local:", 6)) {
801         return socket_local_server(name + 6,
802                 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
803     } else if(!strncmp(name, "localabstract:", 14)) {
804         return socket_local_server(name + 14,
805                 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
806     } else if(!strncmp(name, "localfilesystem:", 16)) {
807         return socket_local_server(name + 16,
808                 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
809     }
810
811 #endif
812     printf("unknown local portname '%s'\n", name);
813     return -1;
814 }
815
816 static int remove_listener(const char *local_name, const char *connect_to, atransport* transport)
817 {
818     alistener *l;
819
820     for (l = listener_list.next; l != &listener_list; l = l->next) {
821         if (!strcmp(local_name, l->local_name) &&
822             !strcmp(connect_to, l->connect_to) &&
823             l->transport && l->transport == transport) {
824
825             listener_disconnect(l, transport);
826             return 0;
827         }
828     }
829
830     return -1;
831 }
832
833 static int install_listener(const char *local_name, const char *connect_to, atransport* transport)
834 {
835     alistener *l;
836
837     //printf("install_listener('%s','%s')\n", local_name, connect_to);
838
839     for(l = listener_list.next; l != &listener_list; l = l->next){
840         if(strcmp(local_name, l->local_name) == 0) {
841             char *cto;
842
843                 /* can't repurpose a smartsocket */
844             if(l->connect_to[0] == '*') {
845                 return -1;
846             }
847
848             cto = strdup(connect_to);
849             if(cto == 0) {
850                 return -1;
851             }
852
853             //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
854             free((void*) l->connect_to);
855             l->connect_to = cto;
856             if (l->transport != transport) {
857                 remove_transport_disconnect(l->transport, &l->disconnect);
858                 l->transport = transport;
859                 add_transport_disconnect(l->transport, &l->disconnect);
860             }
861             return 0;
862         }
863     }
864
865     if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
866     if((l->local_name = strdup(local_name)) == 0) goto nomem;
867     if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
868
869
870     l->fd = local_name_to_fd(local_name);
871     if(l->fd < 0) {
872         free((void*) l->local_name);
873         free((void*) l->connect_to);
874         free(l);
875         printf("cannot bind '%s'\n", local_name);
876         return -2;
877     }
878
879     if (close_on_exec(l->fd) < 0) {
880         D("fail to close fd exec:%d\n",l->fd);
881     }
882     if(!strcmp(l->connect_to, "*smartsocket*")) {
883         fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
884     } else {
885         fdevent_install(&l->fde, l->fd, listener_event_func, l);
886     }
887     fdevent_set(&l->fde, FDE_READ);
888
889     l->next = &listener_list;
890     l->prev = listener_list.prev;
891     l->next->prev = l;
892     l->prev->next = l;
893     l->transport = transport;
894
895     if (transport) {
896         l->disconnect.opaque = l;
897         l->disconnect.func   = listener_disconnect;
898         add_transport_disconnect(transport, &l->disconnect);
899     }
900     return 0;
901
902 nomem:
903     fatal("cannot allocate listener");
904     return 0;
905 }
906
907 #ifdef HAVE_WIN32_PROC
908 static BOOL WINAPI ctrlc_handler(DWORD type)
909 {
910     exit(STATUS_CONTROL_C_EXIT);
911     return TRUE;
912 }
913 #endif
914
915 static void sdb_cleanup(void)
916 {
917     clear_sdbd_commandline_args(&sdbd_commandline_args);
918     usb_cleanup();
919 //    if(required_pid > 0) {
920 //        kill(required_pid, SIGKILL);
921 //    }
922     if (g_sdbd_plugin_handle) {
923         dlclose(g_sdbd_plugin_handle);
924         g_sdbd_plugin_handle = NULL;
925     }
926 }
927
928 void start_logging(void)
929 {
930 #ifdef HAVE_WIN32_PROC
931     char    temp[ MAX_PATH ];
932     FILE*   fnul;
933     FILE*   flog;
934
935     GetTempPath( sizeof(temp) - 8, temp );
936     strcat( temp, "sdb.log" );
937
938     /* Win32 specific redirections */
939     fnul = fopen( "NUL", "rt" );
940     if (fnul != NULL)
941         stdin[0] = fnul[0];
942
943     flog = fopen( temp, "at" );
944     if (flog == NULL)
945         flog = fnul;
946
947     setvbuf( flog, NULL, _IONBF, 0 );
948
949     stdout[0] = flog[0];
950     stderr[0] = flog[0];
951     fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid());
952 #else
953     int fd;
954
955     fd = unix_open("/dev/null", O_RDONLY);
956     if (fd < 0) {
957         // hopefully not gonna happen
958         return;
959     }
960     dup2(fd, 0);
961     sdb_close(fd);
962
963     fd = unix_open("/tmp/sdb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
964     if(fd < 0) {
965         fd = unix_open("/dev/null", O_WRONLY);
966         if (fd < 0) {
967             // hopefully not gonna happen
968             return;
969         }
970     }
971     dup2(fd, 1);
972     dup2(fd, 2);
973     sdb_close(fd);
974     fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid());
975 #endif
976 }
977
978 #if !SDB_HOST
979 void start_device_log(void)
980 {
981     int fd;
982     char    path[PATH_MAX];
983     struct tm now;
984     time_t t;
985 //    char value[PROPERTY_VALUE_MAX];
986     const char* p = getenv("SDB_TRACE");
987     // read the trace mask from persistent property persist.sdb.trace_mask
988     // give up if the property is not set or cannot be parsed
989 #if 0 /* tizen specific */
990     property_get("persist.sdb.trace_mask", value, "");
991     if (sscanf(value, "%x", &sdb_trace_mask) != 1)
992         return;
993 #endif
994
995     if (p == NULL) {
996         return;
997     }
998     tzset();
999     time(&t);
1000     localtime_r(&t, &now);
1001     strftime(path, sizeof(path),
1002                 "/tmp/sdbd-%Y-%m-%d-%H-%M-%S.txt",
1003                 &now);
1004     fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
1005     if (fd < 0) {
1006         return;
1007     }
1008
1009     // redirect stdout and stderr to the log file
1010     dup2(fd, 1);
1011     dup2(fd, 2);
1012     fprintf(stderr,"--- sdbd starting (pid %d) ---\n", getpid());
1013     sdb_close(fd);
1014
1015     fd = unix_open("/dev/null", O_RDONLY);
1016     if (fd < 0) {
1017         // hopefully not gonna happen
1018         return;
1019     }
1020     dup2(fd, 0);
1021     sdb_close(fd);
1022 }
1023
1024 int daemonize(void) {
1025
1026     // set file creation mask to 0
1027     umask(0);
1028
1029     switch (fork()) {
1030     case -1:
1031         return -1;
1032     case 0:
1033         break;
1034     default:
1035         _exit(0);
1036     }
1037 #ifdef SDB_PIDPATH
1038     FILE *f = fopen(SDB_PIDPATH, "w");
1039
1040     if (f != NULL) {
1041         fprintf(f, "%d\n", getpid());
1042         fclose(f);
1043     }
1044 #endif
1045     if (setsid() == -1)
1046         return -1;
1047
1048     if (chdir("/") < 0)
1049         D("sdbd: unable to change working directory to /\n");
1050
1051     return 0;
1052 }
1053 #endif
1054
1055 #if SDB_HOST
1056 int launch_server(int server_port)
1057 {
1058 #ifdef HAVE_WIN32_PROC
1059     /* we need to start the server in the background                    */
1060     /* we create a PIPE that will be used to wait for the server's "OK" */
1061     /* message since the pipe handles must be inheritable, we use a     */
1062     /* security attribute                                               */
1063     HANDLE                pipe_read, pipe_write;
1064     SECURITY_ATTRIBUTES   sa;
1065     STARTUPINFO           startup;
1066     PROCESS_INFORMATION   pinfo;
1067     char                  program_path[ MAX_PATH ];
1068     int                   ret;
1069
1070     sa.nLength = sizeof(sa);
1071     sa.lpSecurityDescriptor = NULL;
1072     sa.bInheritHandle = TRUE;
1073
1074     /* create pipe, and ensure its read handle isn't inheritable */
1075     ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
1076     if (!ret) {
1077         fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
1078         return -1;
1079     }
1080
1081     SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
1082
1083     ZeroMemory( &startup, sizeof(startup) );
1084     startup.cb = sizeof(startup);
1085     startup.hStdInput  = GetStdHandle( STD_INPUT_HANDLE );
1086     startup.hStdOutput = pipe_write;
1087     startup.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
1088     startup.dwFlags    = STARTF_USESTDHANDLES;
1089
1090     ZeroMemory( &pinfo, sizeof(pinfo) );
1091
1092     /* get path of current program */
1093     GetModuleFileName( NULL, program_path, sizeof(program_path) );
1094
1095     ret = CreateProcess(
1096             program_path,                              /* program path  */
1097             "sdb fork-server server",
1098                                     /* the fork-server argument will set the
1099                                        debug = 2 in the child           */
1100             NULL,                   /* process handle is not inheritable */
1101             NULL,                    /* thread handle is not inheritable */
1102             TRUE,                          /* yes, inherit some handles */
1103             DETACHED_PROCESS, /* the new process doesn't have a console */
1104             NULL,                     /* use parent's environment block */
1105             NULL,                    /* use parent's starting directory */
1106             &startup,                 /* startup info, i.e. std handles */
1107             &pinfo );
1108
1109     CloseHandle( pipe_write );
1110
1111     if (!ret) {
1112         fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
1113         CloseHandle( pipe_read );
1114         return -1;
1115     }
1116
1117     CloseHandle( pinfo.hProcess );
1118     CloseHandle( pinfo.hThread );
1119
1120     /* wait for the "OK\n" message */
1121     {
1122         char  temp[3];
1123         DWORD  count;
1124
1125         ret = ReadFile( pipe_read, temp, 3, &count, NULL );
1126         CloseHandle( pipe_read );
1127         if ( !ret ) {
1128             fprintf(stderr, "could not read ok from SDB Server, error = %ld\n", GetLastError() );
1129             return -1;
1130         }
1131         if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
1132             fprintf(stderr, "SDB server didn't ACK\n" );
1133             return -1;
1134         }
1135     }
1136 #elif defined(HAVE_FORKEXEC)
1137     char    path[PATH_MAX];
1138     int     fd[2];
1139
1140     // set up a pipe so the child can tell us when it is ready.
1141     // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
1142     if (pipe(fd)) {
1143         fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
1144         return -1;
1145     }
1146     get_my_path(path, PATH_MAX);
1147     pid_t pid = fork();
1148     if(pid < 0) return -1;
1149
1150     if (pid == 0) {
1151         // child side of the fork
1152
1153         // redirect stderr to the pipe
1154         // we use stderr instead of stdout due to stdout's buffering behavior.
1155         sdb_close(fd[0]);
1156         dup2(fd[1], STDERR_FILENO);
1157         sdb_close(fd[1]);
1158
1159         // child process
1160         int result = execl(path, "sdb", "fork-server", "server", NULL);
1161         // this should not return
1162         fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
1163     } else  {
1164         // parent side of the fork
1165
1166         char  temp[3];
1167
1168         temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
1169         // wait for the "OK\n" message
1170         sdb_close(fd[1]);
1171         int ret = sdb_read(fd[0], temp, 3);
1172         int saved_errno = errno;
1173         sdb_close(fd[0]);
1174         if (ret < 0) {
1175             fprintf(stderr, "could not read ok from SDB Server, errno = %d\n", saved_errno);
1176             return -1;
1177         }
1178         if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
1179             fprintf(stderr, "SDB server didn't ACK\n" );
1180             return -1;
1181         }
1182
1183         setsid();
1184     }
1185 #else
1186 #error "cannot implement background server start on this platform"
1187 #endif
1188     return 0;
1189 }
1190 #endif
1191
1192 /* Constructs a local name of form tcp:port.
1193  * target_str points to the target string, it's content will be overwritten.
1194  * target_size is the capacity of the target string.
1195  * server_port is the port number to use for the local name.
1196  */
1197 void build_local_name(char* target_str, size_t target_size, int server_port)
1198 {
1199   snprintf(target_str, target_size, "tcp:%d", server_port);
1200 }
1201
1202 #if !SDB_HOST
1203 static void init_drop_privileges() {
1204 #ifdef _DROP_PRIVILEGE
1205     rootshell_mode = 0;
1206 #else
1207     rootshell_mode = 1;
1208 #endif
1209 }
1210
1211 int is_pwlocked(void) {
1212     int pwlock_status = 0;
1213     int pwlock_type = 0;
1214
1215     if (vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &pwlock_status)) {
1216         pwlock_status = 0;
1217         D("failed to get pw lock status\n");
1218     }
1219 #ifdef _WEARABLE
1220     D("wearable lock applied\n");
1221     // for wearable which uses different VCONF key (lock type)
1222         if (vconf_get_int(VCONFKEY_SETAPPL_PRIVACY_LOCK_TYPE_INT, &pwlock_type)) {
1223                 pwlock_type = 0;
1224                 D("failed to get pw lock type\n");
1225         }
1226           if ((pwlock_status == VCONFKEY_IDLE_LOCK) && (pwlock_type != SETTING_PRIVACY_LOCK_TYPE_NONE)) {
1227                    D("device has been locked\n");
1228                    return 1; // locked!
1229           }
1230 #else
1231         D("mobile lock applied\n");
1232     // for mobile
1233     if (vconf_get_int(VCONFKEY_SETAPPL_SCREEN_LOCK_TYPE_INT, &pwlock_type)) {
1234         pwlock_type = 0;
1235         D("failed to get pw lock type\n");
1236     }
1237     if (pwlock_status == VCONFKEY_IDLE_LOCK && ((pwlock_type != SETTING_SCREEN_LOCK_TYPE_NONE) && (pwlock_type != SETTING_SCREEN_LOCK_TYPE_SWIPE))) {
1238         D("device has been locked\n");
1239         return 1; // locked!
1240     }
1241 #endif
1242     return 0; // unlocked!
1243 }
1244
1245 int should_drop_privileges() {
1246     if (rootshell_mode == 1) { // if root, then don't drop
1247         return 0;
1248     }
1249     return 1;
1250 }
1251
1252 static void *pwlock_tmp_cb(void *x)
1253 {
1254     int status = is_pwlocked();
1255     /**
1256      * FIXME: make it callback using vconf_notify_key_changed
1257      */
1258
1259     while(1) {
1260         if (status != is_pwlocked()) {
1261             send_device_status();
1262             status = is_pwlocked();
1263         }
1264         sdb_sleep_ms(3000);
1265     }
1266     return 0;
1267 }
1268
1269 void register_pwlock_cb() {
1270     D("registerd vconf callback\n");
1271
1272     sdb_thread_t t;
1273     if(sdb_thread_create( &t, pwlock_tmp_cb, NULL)){
1274         D("cannot create service thread\n");
1275         return;
1276     }
1277 }
1278
1279 #include <dbus/dbus.h>
1280 #include <dbus/dbus-glib.h>
1281 #include <dbus/dbus-glib-lowlevel.h>
1282
1283 #define BOOTING_DONE_SIGNAL    "BootingDone"
1284 #define DEVICED_CORE_INTERFACE "org.tizen.system.deviced.core"
1285 #define SDBD_BOOT_INFO_FILE "/tmp/sdbd_boot_info"
1286
1287 static DBusHandlerResult __sdbd_dbus_signal_filter(DBusConnection *conn,
1288                 DBusMessage *message, void *user_data) {
1289         D("got dbus message\n");
1290         const char *interface;
1291
1292         DBusError error;
1293         dbus_error_init(&error);
1294
1295         interface = dbus_message_get_interface(message);
1296         if (interface == NULL) {
1297                 D("reject by security issue - no interface\n");
1298                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1299         }
1300
1301         if (dbus_message_is_signal(message, DEVICED_CORE_INTERFACE,
1302                         BOOTING_DONE_SIGNAL)) {
1303                 booting_done = 1;
1304                 if (access(SDBD_BOOT_INFO_FILE, F_OK) == 0) {
1305                         D("booting is done before\n");
1306                 } else {
1307                         FILE *f = fopen(SDBD_BOOT_INFO_FILE, "w");
1308                         if (f != NULL) {
1309                                 fprintf(f, "%d", 1);
1310                                 fclose(f);
1311                         }
1312                 }
1313                 D("booting is done\n");
1314         }
1315
1316         D("handled dbus message\n");
1317         return DBUS_HANDLER_RESULT_HANDLED;
1318 }
1319
1320 static void *bootdone_cb(void *x) {
1321         int MAX_LOCAL_BUFSZ = 128;
1322         DBusError error;
1323         DBusConnection *bus;
1324         char rule[MAX_LOCAL_BUFSZ];
1325         GMainLoop *mainloop;
1326
1327         g_type_init();
1328
1329         dbus_error_init(&error);
1330         bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
1331         if (!bus) {
1332                 D("Failed to connect to the D-BUS daemon: %s", error.message);
1333                 dbus_error_free(&error);
1334                 return -1;
1335         }
1336         dbus_connection_setup_with_g_main(bus, NULL);
1337
1338         snprintf(rule, MAX_LOCAL_BUFSZ, "type='signal',interface='%s'",
1339                         DEVICED_CORE_INTERFACE);
1340         /* listening to messages */
1341         dbus_bus_add_match(bus, rule, &error);
1342         if (dbus_error_is_set(&error)) {
1343                 D("Fail to rule set: %s", error.message);
1344                 dbus_error_free(&error);
1345                 return -1;
1346         }
1347
1348         if (dbus_connection_add_filter(bus, __sdbd_dbus_signal_filter, NULL, NULL)
1349                         == FALSE)
1350                 return -1;
1351
1352         D("booting signal initialized\n");
1353         mainloop = g_main_loop_new(NULL, FALSE);
1354         g_main_loop_run(mainloop);
1355
1356         D("dbus loop exited");
1357
1358         return 0;
1359 }
1360
1361 void register_bootdone_cb() {
1362         D("registerd bootdone callback\n");
1363
1364         sdb_thread_t t;
1365         if (sdb_thread_create(&t, bootdone_cb, NULL)) {
1366                 D("cannot create service thread\n");
1367                 return;
1368         }
1369 }
1370
1371 int set_developer_privileges() {
1372     gid_t groups[] = { SID_DEVELOPER, SID_APP_LOGGING, SID_SYS_LOGGING, SID_INPUT };
1373     if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) {
1374         D("set groups failed (errno: %d)\n", errno);
1375     }
1376
1377     // then switch user and group to developer
1378     if (setgid(SID_DEVELOPER) != 0) {
1379         D("set group id failed (errno: %d)\n", errno);
1380         return -1;
1381     }
1382
1383     if (setuid(SID_DEVELOPER) != 0) {
1384         D("set user id failed (errno: %d)\n", errno);
1385         return -1;
1386     }
1387
1388     if (chdir(HOME_DEV_PATH) < 0) {
1389         D("sdbd: unable to change working directory to %s\n", HOME_DEV_PATH);
1390     } else {
1391         if (chdir("/") < 0) {
1392             D("sdbd: unable to change working directory to /\n");
1393         }
1394     }
1395     // TODO: use pam later
1396     char * env = malloc(strlen("HOME=") + strlen(HOME_DEV_PATH) + 1);
1397     if(env == 0) fatal("failed to allocate for env string");
1398     strcpy(env, "HOME=");
1399     strcat(env, HOME_DEV_PATH);
1400     putenv(env);
1401     free(env);
1402
1403     return 1;
1404 }
1405 #define ONDEMAND_ROOT_PATH tzplatform_getenv(TZ_SDK_HOME)
1406
1407 static void execute_required_process() {
1408     char *cmd_args[] = {"/usr/bin/debug_launchpad_preloading_preinitializing_daemon",NULL};
1409
1410     spawn("/usr/bin/debug_launchpad_preloading_preinitializing_daemon", cmd_args);
1411 }
1412
1413 /* default plugin proc */
1414 static int get_plugin_capability(const char* in_buf, sdbd_plugin_param out) {
1415     int ret = SDBD_PLUGIN_RET_NOT_SUPPORT;
1416
1417     if (in_buf == NULL) {
1418         D("Invalid argument\n");
1419         return SDBD_PLUGIN_RET_FAIL;
1420     }
1421
1422     if (SDBD_CMP_CAP(in_buf, SECURE)) {
1423         snprintf(out.data, out.len, "%s", SDBD_CAP_RET_DISABLED);
1424         ret = SDBD_PLUGIN_RET_SUCCESS;
1425     } else if (SDBD_CMP_CAP(in_buf, INTER_SHELL)) {
1426         snprintf(out.data, out.len, "%s", SDBD_CAP_RET_ENABLED);
1427         ret = SDBD_PLUGIN_RET_SUCCESS;
1428     } else if (SDBD_CMP_CAP(in_buf, FILESYNC)) {
1429         // - push : SDBD_CAP_RET_PUSH
1430         // - pull : SDBD_CAP_RET_PULL
1431         // - both : SDBD_CAP_RET_PUSHPULL
1432         // - disabled : SDBD_CAP_RET_DISABLED
1433         snprintf(out.data, out.len, "%s", SDBD_CAP_RET_PUSHPULL);
1434         ret = SDBD_PLUGIN_RET_SUCCESS;
1435     } else if (SDBD_CMP_CAP(in_buf, USBPROTO)) {
1436         if (is_emulator()) {
1437             snprintf(out.data, out.len, "%s", SDBD_CAP_RET_DISABLED);
1438         } else {
1439             snprintf(out.data, out.len, "%s", SDBD_CAP_RET_ENABLED);
1440         }
1441         ret = SDBD_PLUGIN_RET_SUCCESS;
1442     } else if (SDBD_CMP_CAP(in_buf, SOCKPROTO)) {
1443         if (is_emulator()) {
1444             snprintf(out.data, out.len, "%s", SDBD_CAP_RET_ENABLED);
1445         } else {
1446             snprintf(out.data, out.len, "%s", SDBD_CAP_RET_ENABLED);
1447         }
1448         ret = SDBD_PLUGIN_RET_SUCCESS;
1449     } else if (SDBD_CMP_CAP(in_buf, ROOTONOFF)) {
1450         if (access("/bin/su", F_OK) == 0) {
1451             snprintf(out.data, out.len, "%s", SDBD_CAP_RET_ENABLED);
1452         } else {
1453             snprintf(out.data, out.len, "%s", SDBD_CAP_RET_DISABLED);
1454         }
1455     } else if (SDBD_CMP_CAP(in_buf, PLUGIN_VER)) {
1456         snprintf(out.data, out.len, "%s", UNKNOWN);
1457         ret = SDBD_PLUGIN_RET_SUCCESS;
1458     } else if (SDBD_CMP_CAP(in_buf, PRODUCT_VER)) {
1459         snprintf(out.data, out.len, "%s", UNKNOWN);
1460         ret = SDBD_PLUGIN_RET_SUCCESS;
1461     }
1462
1463     return ret;
1464 }
1465
1466 static int verify_shell_cmd(const char* in_buf, sdbd_plugin_param out) {
1467     int ret = SDBD_PLUGIN_RET_FAIL;
1468
1469     if (in_buf == NULL) {
1470         D("Invalid argument\n");
1471         return SDBD_PLUGIN_RET_FAIL;
1472     }
1473
1474     D("shell command : %s\n", in_buf);
1475
1476     snprintf(out.data, out.len, "%s", SDBD_RET_VALID);
1477     ret = SDBD_PLUGIN_RET_SUCCESS;
1478
1479     return ret;
1480 }
1481
1482 static int convert_shell_cmd(const char* in_buf, sdbd_plugin_param out) {
1483     int ret = SDBD_PLUGIN_RET_FAIL;
1484
1485     if (in_buf == NULL) {
1486         D("Invalid argument\n");
1487         return SDBD_PLUGIN_RET_FAIL;
1488     }
1489
1490     snprintf(out.data, out.len, "%s", in_buf);
1491     ret = SDBD_PLUGIN_RET_SUCCESS;
1492
1493     return ret;
1494 }
1495
1496 static int verify_peer_ip(const char* in_buf, sdbd_plugin_param out) {
1497     int ret = SDBD_PLUGIN_RET_FAIL;
1498
1499     if (in_buf == NULL) {
1500         D("Invalid argument\n");
1501         return SDBD_PLUGIN_RET_FAIL;
1502     }
1503
1504     D("peer ip : %s\n", in_buf);
1505
1506     snprintf(out.data, out.len, "%s", SDBD_RET_VALID);
1507     ret = SDBD_PLUGIN_RET_SUCCESS;
1508
1509     return ret;
1510 }
1511
1512 static int verify_sdbd_launch(const char* in_buf, sdbd_plugin_param out) {
1513     snprintf(out.data, out.len, "%s", SDBD_RET_VALID);
1514     return SDBD_PLUGIN_RET_SUCCESS;
1515 }
1516
1517 static int verify_root_cmd(const char* in_buf, sdbd_plugin_param out) {
1518     int ret = SDBD_PLUGIN_RET_FAIL;
1519
1520     if (in_buf == NULL) {
1521         D("Invalid argument\n");
1522         return SDBD_PLUGIN_RET_FAIL;
1523     }
1524
1525     D("shell command : %s\n", in_buf);
1526
1527     if (verify_root_commands(in_buf)) {
1528         snprintf(out.data, out.len, "%s", SDBD_RET_VALID);
1529     } else {
1530         snprintf(out.data, out.len, "%s", SDBD_RET_INVALID);
1531     }
1532     ret = SDBD_PLUGIN_RET_SUCCESS;
1533
1534     return ret;
1535 }
1536
1537 int default_cmd_proc(const char* cmd,
1538                     const char* in_buf, sdbd_plugin_param out) {
1539     int ret = SDBD_PLUGIN_RET_NOT_SUPPORT;
1540
1541     /* Check the arguments */
1542     if (cmd == NULL || out.data == NULL) {
1543         D("Invalid argument\n");
1544         return SDBD_PLUGIN_RET_FAIL;
1545     }
1546
1547     D("handle the command : %s\n", cmd);
1548
1549     /* Handle the request from sdbd */
1550     if (SDBD_CMP_CMD(cmd, PLUGIN_CAP)) {
1551         ret = get_plugin_capability(in_buf, out);
1552     } else if (SDBD_CMP_CMD(cmd, VERIFY_SHELLCMD)) {
1553         ret = verify_shell_cmd(in_buf, out);
1554     } else if (SDBD_CMP_CMD(cmd, CONV_SHELLCMD)) {
1555         ret = convert_shell_cmd(in_buf, out);
1556     } else if (SDBD_CMP_CMD(cmd, VERIFY_PEERIP)) {
1557         ret = verify_peer_ip(in_buf, out);
1558     } else if (SDBD_CMP_CMD(cmd, VERIFY_LAUNCH)) {
1559         ret = verify_sdbd_launch(in_buf, out);
1560     } else if (SDBD_CMP_CMD(cmd, VERIFY_ROOTCMD)) {
1561         ret = verify_root_cmd(in_buf, out);
1562     } else {
1563         D("Not supported command : %s\n", cmd);
1564         ret = SDBD_PLUGIN_RET_NOT_SUPPORT;
1565     }
1566
1567     return ret;
1568 }
1569
1570 int request_plugin_cmd(const char* cmd, const char* in_buf,
1571                         char *out_buf, unsigned int out_len)
1572 {
1573     int ret = SDBD_PLUGIN_RET_FAIL;
1574     sdbd_plugin_param out;
1575
1576     if (out_len > SDBD_PLUGIN_OUTBUF_MAX) {
1577         D("invalid parameter : %s\n", cmd);
1578         return 0;
1579     }
1580
1581     out.data = out_buf;
1582     out.len = out_len;
1583
1584     ret = sdbd_plugin_cmd_proc(cmd, in_buf, out);
1585     if (ret == SDBD_PLUGIN_RET_FAIL) {
1586         D("failed to request : %s\n", cmd);
1587         return 0;
1588     }
1589     if (ret == SDBD_PLUGIN_RET_NOT_SUPPORT) {
1590         // retry in default handler
1591         ret = default_cmd_proc(cmd, in_buf, out);
1592         if (ret == SDBD_PLUGIN_RET_FAIL) {
1593             D("failed to request : %s\n", cmd);
1594             return 0;
1595         }
1596     }
1597
1598     // add null character.
1599     out_buf[out_len-1] = '\0';
1600     D("return value: %s\n", out_buf);
1601
1602     return 1;
1603 }
1604
1605 static void load_sdbd_plugin() {
1606     sdbd_plugin_cmd_proc = NULL;
1607
1608     g_sdbd_plugin_handle = dlopen(SDBD_PLUGIN_PATH, RTLD_NOW);
1609     if (!g_sdbd_plugin_handle) {
1610         D("failed to dlopen(%s). error: %s\n", SDBD_PLUGIN_PATH, dlerror());
1611         sdbd_plugin_cmd_proc = default_cmd_proc;
1612         return;
1613     }
1614
1615     sdbd_plugin_cmd_proc = dlsym(g_sdbd_plugin_handle, SDBD_PLUGIN_INTF);
1616     if (!sdbd_plugin_cmd_proc) {
1617         D("failed to get the sdbd plugin interface. error: %s\n", dlerror());
1618         dlclose(g_sdbd_plugin_handle);
1619         g_sdbd_plugin_handle = NULL;
1620         sdbd_plugin_cmd_proc = default_cmd_proc;
1621         return;
1622     }
1623
1624     D("using sdbd plugin interface.(%s)\n", SDBD_PLUGIN_PATH);
1625 }
1626
1627 static void init_sdk_requirements() {
1628     struct stat st;
1629
1630     // set env variable for temporary
1631     // TODO: should use pam instead later!!
1632     if (!getenv("TERM")) {
1633         putenv("TERM=linux");
1634     }
1635
1636     if (!getenv("HOME")) {
1637         putenv("HOME=/root");
1638     }
1639
1640     if (stat(ONDEMAND_ROOT_PATH, &st) == -1) {
1641         return;
1642     }
1643     if (st.st_uid != SID_DEVELOPER || st.st_gid != GID_DEVELOPER) {
1644         char cmd[128];
1645         snprintf(cmd, sizeof(cmd), "chown %s:%s %s -R", DEV_NAME, DEV_NAME, ONDEMAND_ROOT_PATH);
1646         if (system(cmd) < 0) {
1647             D("failed to change ownership to developer to %s\n", ONDEMAND_ROOT_PATH);
1648         }
1649     }
1650
1651     execute_required_process();
1652
1653     register_pwlock_cb();
1654
1655     if (is_emulator()) {
1656         register_bootdone_cb();
1657     }
1658 }
1659 #endif /* !SDB_HOST */
1660
1661 int request_plugin_verification(const char* cmd, const char* in_buf) {
1662     char out_buf[32] = {0,};
1663
1664     if(!request_plugin_cmd(cmd, in_buf, out_buf, sizeof(out_buf))) {
1665         D("failed to request plugin command. : %s\n", SDBD_CMD_VERIFY_LAUNCH);
1666         return 0;
1667     }
1668
1669     if (strlen(out_buf) == 7 && !strncmp(out_buf, SDBD_RET_INVALID, 7)) {
1670         D("[%s] is NOT verified.\n", cmd);
1671         return 0;
1672     }
1673
1674     D("[%s] is verified.\n", cmd);
1675     return 1;
1676 }
1677
1678 static char* get_cpu_architecture()
1679 {
1680     int ret = 0;
1681     bool b_value = false;
1682
1683     ret = system_info_get_platform_bool(
1684             "http://tizen.org/feature/platform.core.cpu.arch.armv6", &b_value);
1685     if (ret == SYSTEM_INFO_ERROR_NONE && b_value) {
1686         return CPUARCH_ARMV6;
1687     }
1688
1689     ret = system_info_get_platform_bool(
1690             "http://tizen.org/feature/platform.core.cpu.arch.armv7", &b_value);
1691     if (ret == SYSTEM_INFO_ERROR_NONE && b_value) {
1692         return CPUARCH_ARMV7;
1693     }
1694
1695     ret = system_info_get_platform_bool(
1696             "http://tizen.org/feature/platform.core.cpu.arch.x86", &b_value);
1697     if (ret == SYSTEM_INFO_ERROR_NONE && b_value) {
1698         return CPUARCH_X86;
1699     }
1700
1701     D("fail to get the CPU architecture of model:%d\n", errno);
1702     return UNKNOWN;
1703 }
1704
1705 static void init_capabilities(void) {
1706     int ret = -1;
1707     char *value = NULL;
1708
1709     memset(&g_capabilities, 0, sizeof(g_capabilities));
1710
1711     // CPU Architecture of model
1712     snprintf(g_capabilities.cpu_arch, sizeof(g_capabilities.cpu_arch),
1713                 "%s", get_cpu_architecture());
1714
1715
1716     // Secure protocol support
1717     if(!request_plugin_cmd(SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_SECURE,
1718                             g_capabilities.secure_protocol,
1719                             sizeof(g_capabilities.secure_protocol))) {
1720         D("failed to request. (%s:%s) \n", SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_SECURE);
1721         snprintf(g_capabilities.secure_protocol, sizeof(g_capabilities.secure_protocol),
1722                     "%s", DISABLED);
1723     }
1724
1725
1726     // Interactive shell support
1727     if(!request_plugin_cmd(SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_INTER_SHELL,
1728                             g_capabilities.intershell_support,
1729                             sizeof(g_capabilities.intershell_support))) {
1730         D("failed to request. (%s:%s) \n", SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_INTER_SHELL);
1731         snprintf(g_capabilities.intershell_support, sizeof(g_capabilities.intershell_support),
1732                     "%s", DISABLED);
1733     }
1734
1735
1736     // File push/pull support
1737     if(!request_plugin_cmd(SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_FILESYNC,
1738                             g_capabilities.filesync_support,
1739                             sizeof(g_capabilities.filesync_support))) {
1740         D("failed to request. (%s:%s) \n", SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_FILESYNC);
1741         snprintf(g_capabilities.filesync_support, sizeof(g_capabilities.filesync_support),
1742                     "%s", DISABLED);
1743     }
1744
1745
1746     // USB protocol support
1747     if(!request_plugin_cmd(SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_USBPROTO,
1748                             g_capabilities.usbproto_support,
1749                             sizeof(g_capabilities.usbproto_support))) {
1750         D("failed to request. (%s:%s) \n", SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_USBPROTO);
1751         snprintf(g_capabilities.usbproto_support, sizeof(g_capabilities.usbproto_support),
1752                     "%s", DISABLED);
1753     }
1754
1755
1756     // Socket protocol support
1757     if(!request_plugin_cmd(SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_SOCKPROTO,
1758                             g_capabilities.sockproto_support,
1759                             sizeof(g_capabilities.sockproto_support))) {
1760         D("failed to request. (%s:%s) \n", SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_SOCKPROTO);
1761         snprintf(g_capabilities.sockproto_support, sizeof(g_capabilities.sockproto_support),
1762                     "%s", DISABLED);
1763     }
1764
1765
1766     // Root command support
1767     if(!request_plugin_cmd(SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_ROOTONOFF,
1768                             g_capabilities.rootonoff_support,
1769                             sizeof(g_capabilities.rootonoff_support))) {
1770         D("failed to request. (%s:%s) \n", SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_ROOTONOFF);
1771         snprintf(g_capabilities.rootonoff_support, sizeof(g_capabilities.rootonoff_support),
1772                     "%s", DISABLED);
1773     }
1774
1775
1776     // Zone support
1777     ret = is_container_enabled();
1778     snprintf(g_capabilities.zone_support, sizeof(g_capabilities.zone_support),
1779                 "%s", ret == 1 ? ENABLED : DISABLED);
1780
1781
1782     // Multi-User support
1783     // TODO: get this information from platform.
1784     snprintf(g_capabilities.multiuser_support, sizeof(g_capabilities.multiuser_support),
1785                 "%s", DISABLED);
1786
1787
1788     // Window size synchronization support
1789     snprintf(g_capabilities.syncwinsz_support, sizeof(g_capabilities.syncwinsz_support),
1790                 "%s", ENABLED);
1791
1792
1793     // Profile name
1794     ret = system_info_get_platform_string("http://tizen.org/feature/profile", &value);
1795     if (ret != SYSTEM_INFO_ERROR_NONE) {
1796         snprintf(g_capabilities.profile_name, sizeof(g_capabilities.profile_name),
1797                     "%s", UNKNOWN);
1798         D("fail to get profile name:%d\n", errno);
1799     } else {
1800         snprintf(g_capabilities.profile_name, sizeof(g_capabilities.profile_name),
1801                     "%s", value);
1802         if (value != NULL) {
1803             free(value);
1804         }
1805     }
1806
1807
1808     // Vendor name
1809     ret = system_info_get_platform_string("http://tizen.org/system/manufacturer", &value);
1810     if (ret != SYSTEM_INFO_ERROR_NONE) {
1811         snprintf(g_capabilities.vendor_name, sizeof(g_capabilities.vendor_name),
1812                     "%s", UNKNOWN);
1813         D("fail to get the Vendor name:%d\n", errno);
1814     } else {
1815         snprintf(g_capabilities.vendor_name, sizeof(g_capabilities.vendor_name),
1816                     "%s", value);
1817         if (value != NULL) {
1818             free(value);
1819         }
1820     }
1821
1822
1823     // Platform version
1824     ret = system_info_get_platform_string("http://tizen.org/feature/platform.version", &value);
1825     if (ret != SYSTEM_INFO_ERROR_NONE) {
1826         snprintf(g_capabilities.platform_version, sizeof(g_capabilities.platform_version),
1827                     "%s", UNKNOWN);
1828         D("fail to get platform version:%d\n", errno);
1829     } else {
1830         snprintf(g_capabilities.platform_version, sizeof(g_capabilities.platform_version),
1831                     "%s", value);
1832         if (value != NULL) {
1833             free(value);
1834         }
1835     }
1836
1837
1838     // Product version
1839     if(!request_plugin_cmd(SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_PRODUCT_VER,
1840                             g_capabilities.product_version,
1841                             sizeof(g_capabilities.product_version))) {
1842         D("failed to request. (%s:%s) \n", SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_PRODUCT_VER);
1843         snprintf(g_capabilities.product_version, sizeof(g_capabilities.product_version),
1844                     "%s", UNKNOWN);
1845     }
1846
1847
1848     // Sdbd version
1849     snprintf(g_capabilities.sdbd_version, sizeof(g_capabilities.sdbd_version),
1850                 "%d.%d.%d", SDB_VERSION_MAJOR, SDB_VERSION_MINOR, SDB_VERSION_PATCH);
1851
1852
1853     // Sdbd plugin version
1854     if(!request_plugin_cmd(SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_PLUGIN_VER,
1855                             g_capabilities.sdbd_plugin_version,
1856                             sizeof(g_capabilities.sdbd_plugin_version))) {
1857         D("failed to request. (%s:%s) \n", SDBD_CMD_PLUGIN_CAP, SDBD_CAP_TYPE_PLUGIN_VER);
1858         snprintf(g_capabilities.sdbd_plugin_version, sizeof(g_capabilities.sdbd_plugin_version),
1859                     "%s", UNKNOWN);
1860     }
1861 }
1862
1863 static int is_support_usbproto()
1864 {
1865     return (!strncmp(g_capabilities.usbproto_support, SDBD_CAP_RET_ENABLED, strlen(SDBD_CAP_RET_ENABLED)));
1866 }
1867
1868 static int is_support_sockproto()
1869 {
1870     return (!strncmp(g_capabilities.sockproto_support, SDBD_CAP_RET_ENABLED, strlen(SDBD_CAP_RET_ENABLED)));
1871 }
1872
1873 int sdb_main(int is_daemon, int server_port)
1874 {
1875 #if !SDB_HOST
1876     load_sdbd_plugin();
1877     init_capabilities();
1878
1879     init_drop_privileges();
1880     init_sdk_requirements();
1881     if (!request_plugin_verification(SDBD_CMD_VERIFY_LAUNCH, NULL)) {
1882         D("sdbd should be launched in develop mode.\n");
1883         return -1;
1884     }
1885
1886     umask(000);
1887 #endif
1888
1889     atexit(sdb_cleanup);
1890 #ifdef HAVE_WIN32_PROC
1891     SetConsoleCtrlHandler( ctrlc_handler, TRUE );
1892 #elif defined(HAVE_FORKEXEC)
1893     // No SIGCHLD. Let the service subproc handle its children.
1894     signal(SIGPIPE, SIG_IGN);
1895 #endif
1896
1897     init_transport_registration();
1898
1899
1900 #if SDB_HOST
1901     HOST = 1;
1902     usb_vendors_init();
1903     usb_init();
1904     local_init(DEFAULT_SDB_LOCAL_TRANSPORT_PORT);
1905
1906     char local_name[30];
1907     build_local_name(local_name, sizeof(local_name), server_port);
1908     if(install_listener(local_name, "*smartsocket*", NULL)) {
1909         exit(1);
1910     }
1911 #else
1912     /* don't listen on a port (default 5037) if running in secure mode */
1913     /* don't run as root if we are running in secure mode */
1914
1915     if (should_drop_privileges()) {
1916 # if 0
1917         struct __user_cap_header_struct header;
1918         struct __user_cap_data_struct cap;
1919
1920         if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1921             exit(1);
1922         }
1923         /* add extra groups:
1924         ** SID_TTY to access /dev/ptmx
1925         */
1926         gid_t groups[] = { SID_TTY, SID_APP_LOGGING, SID_SYS_LOGGING };
1927         if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
1928             exit(1);
1929         }
1930         /* then switch user and group to "developer" */
1931         if (setgid(GID_DEVELOPER) != 0) {
1932             fprintf(stderr, "set group id failed errno: %d\n", errno);
1933             exit(1);
1934         }
1935         if (setuid(SID_DEVELOPER) != 0) {
1936             fprintf(stderr, "set user id failed errno: %d\n", errno);
1937             exit(1);
1938         }
1939
1940         /* set CAP_SYS_BOOT capability, so "sdb reboot" will succeed */
1941         header.version = _LINUX_CAPABILITY_VERSION;
1942         header.pid = 0;
1943         cap.effective = cap.permitted = (1 << CAP_SYS_BOOT);
1944         cap.inheritable = 0;
1945         capset(&header, &cap);
1946 #endif
1947         D("Local port disabled\n");
1948     } else {
1949         char local_name[30];
1950         build_local_name(local_name, sizeof(local_name), server_port);
1951         if(install_listener(local_name, "*smartsocket*", NULL)) {
1952             exit(1);
1953         }
1954     }
1955
1956     if (is_support_usbproto()) {
1957         /* choose the usb gadget backend */
1958         if (access(USB_NODE_FILE, F_OK) == 0) {
1959             /* legacy kernel-based sdb gadget */
1960             usb_init =    &linux_usb_init;
1961             usb_cleanup = &linux_usb_cleanup;
1962             usb_write =   &linux_usb_write;
1963             usb_read =    &linux_usb_read;
1964             usb_close =   &linux_usb_close;
1965             usb_kick =    &linux_usb_kick;
1966         } else {
1967             /* functionfs based gadget */
1968             usb_init =    &ffs_usb_init;
1969             usb_cleanup = &ffs_usb_cleanup;
1970             usb_write =   &ffs_usb_write;
1971             usb_read =    &ffs_usb_read;
1972             usb_close =   &ffs_usb_close;
1973             usb_kick =    &ffs_usb_kick;
1974         }
1975
1976         // listen on USB
1977         usb_init();
1978     }
1979     if (is_support_sockproto()) {
1980         /* by default don't listen on local transport but
1981          * listen if suitable command line argument has been provided */
1982         if (sdbd_commandline_args.sdbd_port >= 0) {
1983             local_init(sdbd_commandline_args.sdbd_port);
1984         } else {
1985             local_init(DEFAULT_SDB_LOCAL_TRANSPORT_PORT);
1986         }
1987     }
1988
1989 #if 0 /* tizen specific */
1990     D("sdb_main(): pre init_jdwp()\n");
1991     init_jdwp();
1992     D("sdb_main(): post init_jdwp()\n");
1993 #endif
1994 #endif
1995
1996     if (is_daemon)
1997     {
1998         // inform our parent that we are up and running.
1999 #ifdef HAVE_WIN32_PROC
2000         DWORD  count;
2001         WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL );
2002 #elif defined(HAVE_FORKEXEC)
2003         fprintf(stderr, "OK\n");
2004 #endif
2005         start_logging();
2006     }
2007
2008     D("Event loop starting\n");
2009
2010     fdevent_loop();
2011
2012     usb_cleanup();
2013
2014     return 0;
2015 }
2016
2017 #if SDB_HOST
2018 void connect_device(char* host, char* buffer, int buffer_size)
2019 {
2020     int port, fd;
2021     char* portstr = strchr(host, ':');
2022     char hostbuf[100];
2023     char serial[100];
2024
2025     s_strncpy(hostbuf, host, sizeof(hostbuf) - 1);
2026     if (portstr) {
2027         if (portstr - host >= sizeof(hostbuf)) {
2028             snprintf(buffer, buffer_size, "bad host name %s", host);
2029             return;
2030         }
2031         // zero terminate the host at the point we found the colon
2032         hostbuf[portstr - host] = 0;
2033         if (sscanf(portstr + 1, "%d", &port) == 0) {
2034             snprintf(buffer, buffer_size, "bad port number %s", portstr);
2035             return;
2036         }
2037     } else {
2038         port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
2039     }
2040
2041     snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
2042     if (find_transport(serial)) {
2043         snprintf(buffer, buffer_size, "already connected to %s", serial);
2044         return;
2045     }
2046
2047     fd = socket_network_client(hostbuf, port, SOCK_STREAM);
2048     if (fd < 0) {
2049         snprintf(buffer, buffer_size, "unable to connect to %s", host);
2050         return;
2051     }
2052
2053     D("client: connected on remote on fd %d\n", fd);
2054     close_on_exec(fd);
2055     disable_tcp_nagle(fd);
2056     register_socket_transport(fd, serial, port, 0, NULL);
2057     snprintf(buffer, buffer_size, "connected to %s", serial);
2058 }
2059
2060 void connect_emulator(char* port_spec, char* buffer, int buffer_size)
2061 {
2062     char* port_separator = strchr(port_spec, ',');
2063     if (!port_separator) {
2064         snprintf(buffer, buffer_size,
2065                 "unable to parse '%s' as <console port>,<sdb port>",
2066                 port_spec);
2067         return;
2068     }
2069
2070     // Zero-terminate console port and make port_separator point to 2nd port.
2071     *port_separator++ = 0;
2072     int console_port = strtol(port_spec, NULL, 0);
2073     int sdb_port = strtol(port_separator, NULL, 0);
2074     if (!(console_port > 0 && sdb_port > 0)) {
2075         *(port_separator - 1) = ',';
2076         snprintf(buffer, buffer_size,
2077                 "Invalid port numbers: Expected positive numbers, got '%s'",
2078                 port_spec);
2079         return;
2080     }
2081
2082     /* Check if the emulator is already known.
2083      * Note: There's a small but harmless race condition here: An emulator not
2084      * present just yet could be registered by another invocation right
2085      * after doing this check here. However, local_connect protects
2086      * against double-registration too. From here, a better error message
2087      * can be produced. In the case of the race condition, the very specific
2088      * error message won't be shown, but the data doesn't get corrupted. */
2089     atransport* known_emulator = find_emulator_transport_by_sdb_port(sdb_port);
2090     if (known_emulator != NULL) {
2091         snprintf(buffer, buffer_size,
2092                 "Emulator on port %d already registered.", sdb_port);
2093         return;
2094     }
2095
2096     /* Check if more emulators can be registered. Similar unproblematic
2097      * race condition as above. */
2098     int candidate_slot = get_available_local_transport_index();
2099     if (candidate_slot < 0) {
2100         snprintf(buffer, buffer_size, "Cannot accept more emulators.");
2101         return;
2102     }
2103
2104     /* Preconditions met, try to connect to the emulator. */
2105     if (!local_connect_arbitrary_ports(console_port, sdb_port, NULL)) {
2106         snprintf(buffer, buffer_size,
2107                 "Connected to emulator on ports %d,%d", console_port, sdb_port);
2108     } else {
2109         snprintf(buffer, buffer_size,
2110                 "Could not connect to emulator on ports %d,%d",
2111                 console_port, sdb_port);
2112     }
2113 }
2114 #endif
2115
2116 int copy_packet(apacket* dest, apacket* src) {
2117
2118     if(dest == NULL) {
2119         D("dest packet is NULL\n");
2120         return -1;
2121     }
2122
2123     if(src == NULL) {
2124         D("src packet is NULL\n");
2125         return -1;
2126     }
2127
2128     dest->next = src->next;
2129     dest->ptr = src->ptr;
2130     dest->len = src->len;
2131
2132     int data_length = src->msg.data_length;
2133     if(data_length > MAX_PAYLOAD) {
2134         data_length = MAX_PAYLOAD;
2135     }
2136     memcpy(&(dest->msg), &(src->msg), sizeof(amessage) + data_length);
2137
2138     return 0;
2139 }
2140
2141 int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
2142 {
2143     atransport *transport = NULL;
2144     char buf[4096];
2145
2146     if(!strcmp(service, "kill")) {
2147         fprintf(stderr,"sdb server killed by remote request\n");
2148         fflush(stdout);
2149         sdb_write(reply_fd, "OKAY", 4);
2150         usb_cleanup();
2151         exit(0);
2152     }
2153
2154 #if SDB_HOST
2155     // "transport:" is used for switching transport with a specified serial number
2156     // "transport-usb:" is used for switching transport to the only USB transport
2157     // "transport-local:" is used for switching transport to the only local transport
2158     // "transport-any:" is used for switching transport to the only transport
2159     if (!strncmp(service, "transport", strlen("transport"))) {
2160         char* error_string = "unknown failure";
2161         transport_type type = kTransportAny;
2162
2163         if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
2164             type = kTransportUsb;
2165         } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
2166             type = kTransportLocal;
2167         } else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
2168             type = kTransportAny;
2169         } else if (!strncmp(service, "transport:", strlen("transport:"))) {
2170             service += strlen("transport:");
2171             serial = service;
2172         }
2173
2174         transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
2175
2176         if (transport) {
2177             s->transport = transport;
2178             sdb_write(reply_fd, "OKAY", 4);
2179         } else {
2180             sendfailmsg(reply_fd, error_string);
2181         }
2182         return 1;
2183     }
2184
2185     // return a list of all connected devices
2186     if (!strcmp(service, "devices")) {
2187         char buffer[4096];
2188         memset(buf, 0, sizeof(buf));
2189         memset(buffer, 0, sizeof(buffer));
2190         D("Getting device list \n");
2191         list_transports(buffer, sizeof(buffer));
2192         snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
2193         D("Wrote device list \n");
2194         writex(reply_fd, buf, strlen(buf));
2195         return 0;
2196     }
2197
2198     // add a new TCP transport, device or emulator
2199     if (!strncmp(service, "connect:", 8)) {
2200         char buffer[4096];
2201         char* host = service + 8;
2202         if (!strncmp(host, "emu:", 4)) {
2203             connect_emulator(host + 4, buffer, sizeof(buffer));
2204         } else {
2205             connect_device(host, buffer, sizeof(buffer));
2206         }
2207         // Send response for emulator and device
2208         snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
2209         writex(reply_fd, buf, strlen(buf));
2210         return 0;
2211     }
2212
2213     // remove TCP transport
2214     if (!strncmp(service, "disconnect:", 11)) {
2215         char buffer[4096];
2216         memset(buffer, 0, sizeof(buffer));
2217         char* serial = service + 11;
2218         if (serial[0] == 0) {
2219             // disconnect from all TCP devices
2220             unregister_all_tcp_transports();
2221         } else {
2222             char hostbuf[100];
2223             // assume port 26101 if no port is specified
2224             if (!strchr(serial, ':')) {
2225                 snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:26101", serial);
2226                 serial = hostbuf;
2227             }
2228             atransport *t = find_transport(serial);
2229
2230             if (t) {
2231                 unregister_transport(t);
2232             } else {
2233                 snprintf(buffer, sizeof(buffer), "No such device %s", serial);
2234             }
2235         }
2236
2237         snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
2238         writex(reply_fd, buf, strlen(buf));
2239         return 0;
2240     }
2241
2242     // returns our value for SDB_SERVER_VERSION
2243     if (!strcmp(service, "version")) {
2244         char version[12];
2245         snprintf(version, sizeof version, "%04x", SDB_SERVER_VERSION);
2246         snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);
2247         writex(reply_fd, buf, strlen(buf));
2248         return 0;
2249     }
2250
2251     if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
2252         char *out = "unknown";
2253          transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
2254        if (transport && transport->serial) {
2255             out = transport->serial;
2256         }
2257         snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
2258         writex(reply_fd, buf, strlen(buf));
2259         return 0;
2260     }
2261     // indicates a new emulator instance has started
2262        if (!strncmp(service,"emulator:",9)) { /* tizen specific */
2263            char *tmp = strtok(service+9, DEVICEMAP_SEPARATOR);
2264            int  port = 0;
2265
2266            if (tmp == NULL) {
2267                port = atoi(service+9);
2268            } else {
2269                port = atoi(tmp);
2270                tmp = strtok(NULL, DEVICEMAP_SEPARATOR);
2271                if (tmp != NULL) {
2272                    local_connect(port, tmp);
2273                }
2274            }
2275            local_connect(port, NULL);
2276         return 0;
2277     }
2278 #endif // SDB_HOST
2279
2280     if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) {
2281         char *local, *remote, *err;
2282         int r;
2283         atransport *transport;
2284
2285         int createForward = strncmp(service,"kill",4);
2286
2287         local = service + (createForward ? 8 : 12);
2288         remote = strchr(local,';');
2289         if(remote == 0) {
2290             sendfailmsg(reply_fd, "malformed forward spec");
2291             return 0;
2292         }
2293
2294         *remote++ = 0;
2295         if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
2296             sendfailmsg(reply_fd, "malformed forward spec");
2297             return 0;
2298         }
2299
2300         transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
2301         if (!transport) {
2302             sendfailmsg(reply_fd, err);
2303             return 0;
2304         }
2305
2306         if (createForward) {
2307             r = install_listener(local, remote, transport);
2308         } else {
2309             r = remove_listener(local, remote, transport);
2310         }
2311         if(r == 0) {
2312                 /* 1st OKAY is connect, 2nd OKAY is status */
2313             writex(reply_fd, "OKAYOKAY", 8);
2314             return 0;
2315         }
2316
2317         if (createForward) {
2318             sendfailmsg(reply_fd, (r == -1) ? "cannot rebind smartsocket" : "cannot bind socket");
2319         } else {
2320             sendfailmsg(reply_fd, "cannot remove listener");
2321         }
2322         return 0;
2323     }
2324
2325     if(!strncmp(service,"get-state",strlen("get-state"))) {
2326         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
2327         char *state = connection_state_name(transport);
2328         snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state);
2329         writex(reply_fd, buf, strlen(buf));
2330         return 0;
2331     }
2332     return -1;
2333 }
2334
2335 #if !SDB_HOST
2336 int recovery_mode = 0;
2337 #endif
2338
2339 int main(int argc, char **argv)
2340 {
2341     sdb_trace_init(); /* tizen specific */
2342 #if SDB_HOST
2343     sdb_sysdeps_init();
2344     sdb_trace_init();
2345     return sdb_commandline(argc - 1, argv + 1);
2346 #else
2347     /* If sdbd runs inside the emulator this will enable sdb tracing via
2348      * sdb-debug qemud service in the emulator. */
2349 #if 0 /* tizen specific */
2350     sdb_qemu_trace_init();
2351     if((argc > 1) && (!strcmp(argv[1],"recovery"))) {
2352         sdb_device_banner = "recovery";
2353         recovery_mode = 1;
2354     }
2355 #endif
2356
2357     apply_sdbd_commandline_defaults(&sdbd_commandline_args);
2358     int parse_ret = parse_sdbd_commandline(&sdbd_commandline_args, argc, argv);
2359
2360     // TODO: Add detailed error messages
2361     // TODO: Add individual messages for help and usage
2362     if(parse_ret != SDBD_COMMANDLINE_SUCCESS) {
2363         if (parse_ret == SDBD_COMMANDLINE_HELP
2364                 || parse_ret == SDBD_COMMANDLINE_USAGE) {
2365             // User requested help or usage
2366             print_sdbd_usage_message(stdout);
2367             return EXIT_SUCCESS;
2368         }
2369
2370         // Print usage message because of invalid options
2371         print_sdbd_usage_message(stderr);
2372         return EXIT_FAILURE;
2373     }
2374
2375 #if !SDB_HOST
2376     if (daemonize() < 0)
2377         fatal("daemonize() failed: errno:%d", errno);
2378 #endif
2379
2380     start_device_log();
2381     D("Handling main()\n");
2382
2383     //sdbd will never die on emulator!
2384     signal(SIGTERM, handle_sig_term); /* tizen specific */
2385     return sdb_main(0, DEFAULT_SDB_PORT);
2386 #endif
2387 }