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