apply sdbd smack rule
[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
30 #include "sysdeps.h"
31 #include "sdb.h"
32
33 #if !SDB_HOST
34 //#include <private/android_filesystem_config.h> eric
35 #include <linux/capability.h>
36 #include <linux/prctl.h>
37 #define SDB_PIDPATH "/tmp/.sdbd.pid"
38 #else
39 #include "usb_vendors.h"
40 #endif
41
42 #if SDB_TRACE
43 SDB_MUTEX_DEFINE( D_lock );
44 #endif
45
46 int HOST = 0;
47
48 void handle_sig_term(int sig) {
49 #ifdef SDB_PIDPATH
50     if (access(SDB_PIDPATH, F_OK) == 0)
51         sdb_unlink(SDB_PIDPATH);
52 #endif
53     //kill(getpgid(getpid()),SIGTERM);
54     //killpg(getpgid(getpid()),SIGTERM);
55     if (access("/dev/samsung_sdb", F_OK) == 0) {
56         exit(0);
57     } else {
58         // do nothing on a emulator
59     }
60 }
61
62 static const char *sdb_device_banner = "device";
63
64 void fatal(const char *fmt, ...)
65 {
66     va_list ap;
67     va_start(ap, fmt);
68     fprintf(stderr, "error: ");
69     vfprintf(stderr, fmt, ap);
70     fprintf(stderr, "\n");
71     va_end(ap);
72     exit(-1);
73 }
74
75 void fatal_errno(const char *fmt, ...)
76 {
77     va_list ap;
78     va_start(ap, fmt);
79     fprintf(stderr, "error: %s: ", strerror(errno));
80     vfprintf(stderr, fmt, ap);
81     fprintf(stderr, "\n");
82     va_end(ap);
83     exit(-1);
84 }
85
86 int   sdb_trace_mask;
87
88 /* read a comma/space/colum/semi-column separated list of tags
89  * from the SDB_TRACE environment variable and build the trace
90  * mask from it. note that '1' and 'all' are special cases to
91  * enable all tracing
92  */
93 void  sdb_trace_init(void)
94 {
95     const char*  p = getenv("SDB_TRACE");
96     const char*  q;
97
98     static const struct {
99         const char*  tag;
100         int           flag;
101     } tags[] = {
102         { "1", 0 },
103         { "all", 0 },
104         { "sdb", TRACE_SDB },
105         { "sockets", TRACE_SOCKETS },
106         { "packets", TRACE_PACKETS },
107         { "rwx", TRACE_RWX },
108         { "usb", TRACE_USB },
109         { "sync", TRACE_SYNC },
110         { "sysdeps", TRACE_SYSDEPS },
111         { "transport", TRACE_TRANSPORT },
112         { "jdwp", TRACE_JDWP },
113         { "services", TRACE_SERVICES },
114         { "properties", TRACE_PROPERTIES },
115         { "sdktools", TRACE_SDKTOOLS },
116         { NULL, 0 }
117     };
118
119     if (p == NULL)
120             return;
121
122     /* use a comma/column/semi-colum/space separated list */
123     while (*p) {
124         int  len, tagn;
125
126         q = strpbrk(p, " ,:;");
127         if (q == NULL) {
128             q = p + strlen(p);
129         }
130         len = q - p;
131
132         for (tagn = 0; tags[tagn].tag != NULL; tagn++)
133         {
134             int  taglen = strlen(tags[tagn].tag);
135
136             if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
137             {
138                 int  flag = tags[tagn].flag;
139                 if (flag == 0) {
140                     sdb_trace_mask = ~0;
141                     return;
142                 }
143                 sdb_trace_mask |= (1 << flag);
144                 break;
145             }
146         }
147         p = q;
148         if (*p)
149             p++;
150     }
151 }
152
153 #if !SDB_HOST
154 /*
155  * Implements SDB tracing inside the emulator.
156  */
157
158 #include <stdarg.h>
159
160 /*
161  * Redefine open and write for qemu_pipe.h that contains inlined references
162  * to those routines. We will redifine them back after qemu_pipe.h inclusion.
163  */
164
165 #undef open
166 #undef write
167 #define open    sdb_open
168 #define write   sdb_write
169 #include "qemu_pipe.h"
170 #undef open
171 #undef write
172 #define open    ___xxx_open
173 #define write   ___xxx_write
174
175 /* A handle to sdb-debug qemud service in the emulator. */
176 int   sdb_debug_qemu = -1;
177
178 /* Initializes connection with the sdb-debug qemud service in the emulator. */
179 #if 0 /* doen't support in Tizen */
180 static int sdb_qemu_trace_init(void)
181 {
182     char con_name[32];
183
184     if (sdb_debug_qemu >= 0) {
185         return 0;
186     }
187
188     /* sdb debugging QEMUD service connection request. */
189     snprintf(con_name, sizeof(con_name), "qemud:sdb-debug");
190     sdb_debug_qemu = qemu_pipe_open(con_name);
191     return (sdb_debug_qemu >= 0) ? 0 : -1;
192 }
193
194 void sdb_qemu_trace(const char* fmt, ...)
195 {
196     va_list args;
197     va_start(args, fmt);
198     char msg[1024];
199
200     if (sdb_debug_qemu >= 0) {
201         vsnprintf(msg, sizeof(msg), fmt, args);
202         sdb_write(sdb_debug_qemu, msg, strlen(msg));
203     }
204 }
205 #endif
206 #endif  /* !SDB_HOST */
207
208 apacket *get_apacket(void)
209 {
210     apacket *p = malloc(sizeof(apacket));
211     if(p == 0) fatal("failed to allocate an apacket");
212     memset(p, 0, sizeof(apacket) - MAX_PAYLOAD);
213     return p;
214 }
215
216 void put_apacket(apacket *p)
217 {
218     if (p != NULL) {
219         free(p);
220         p = NULL;
221     }
222 }
223
224 void handle_online(void)
225 {
226     D("sdb: online\n");
227 }
228
229 void handle_offline(atransport *t)
230 {
231     D("sdb: offline\n");
232     //Close the associated usb
233     run_transport_disconnects(t);
234 }
235
236 #if TRACE_PACKETS
237 #define DUMPMAX 32
238 void print_packet(const char *label, apacket *p)
239 {
240     char *tag;
241     char *x;
242     unsigned count;
243
244     switch(p->msg.command){
245     case A_SYNC: tag = "SYNC"; break;
246     case A_CNXN: tag = "CNXN" ; break;
247     case A_OPEN: tag = "OPEN"; break;
248     case A_OKAY: tag = "OKAY"; break;
249     case A_CLSE: tag = "CLSE"; break;
250     case A_WRTE: tag = "WRTE"; break;
251     default: tag = "????"; break;
252     }
253
254     fprintf(stderr, "%s: %s %08x %08x %04x \"",
255             label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
256     count = p->msg.data_length;
257     x = (char*) p->data;
258     if(count > DUMPMAX) {
259         count = DUMPMAX;
260         tag = "\n";
261     } else {
262         tag = "\"\n";
263     }
264     while(count-- > 0){
265         if((*x >= ' ') && (*x < 127)) {
266             fputc(*x, stderr);
267         } else {
268             fputc('.', stderr);
269         }
270         x++;
271     }
272     fprintf(stderr, tag);
273 }
274 #endif
275
276 static void send_ready(unsigned local, unsigned remote, atransport *t)
277 {
278     D("Calling send_ready \n");
279     apacket *p = get_apacket();
280     p->msg.command = A_OKAY;
281     p->msg.arg0 = local;
282     p->msg.arg1 = remote;
283     send_packet(p, t);
284 }
285
286 static void send_close(unsigned local, unsigned remote, atransport *t)
287 {
288     D("Calling send_close \n");
289     apacket *p = get_apacket();
290     p->msg.command = A_CLSE;
291     p->msg.arg0 = local;
292     p->msg.arg1 = remote;
293     send_packet(p, t);
294 }
295
296 static void send_connect(atransport *t)
297 {
298     D("Calling send_connect \n");
299     apacket *cp = get_apacket();
300     cp->msg.command = A_CNXN;
301     cp->msg.arg0 = A_VERSION;
302     cp->msg.arg1 = MAX_PAYLOAD;
303     snprintf((char*) cp->data, sizeof cp->data, "%s::",
304             HOST ? "host" : sdb_device_banner);
305     cp->msg.data_length = strlen((char*) cp->data) + 1;
306     send_packet(cp, t);
307 #if SDB_HOST
308         /* XXX why sleep here? */
309     // allow the device some time to respond to the connect message
310     sdb_sleep_ms(1000);
311 #endif
312 }
313
314 static char *connection_state_name(atransport *t)
315 {
316     if (t == NULL) {
317         return "unknown";
318     }
319
320     switch(t->connection_state) {
321     case CS_BOOTLOADER:
322         return "bootloader";
323     case CS_DEVICE:
324         return "device";
325     case CS_OFFLINE:
326         return "offline";
327     default:
328         return "unknown";
329     }
330 }
331
332 void parse_banner(char *banner, atransport *t)
333 {
334     char *type, *product, *end;
335
336     D("parse_banner: %s\n", banner);
337     type = banner;
338     product = strchr(type, ':');
339     if(product) {
340         *product++ = 0;
341     } else {
342         product = "";
343     }
344
345         /* remove trailing ':' */
346     end = strchr(product, ':');
347     if(end) *end = 0;
348
349         /* save product name in device structure */
350     if (t->product == NULL) {
351         t->product = strdup(product);
352     } else if (strcmp(product, t->product) != 0) {
353         free(t->product);
354         t->product = strdup(product);
355     }
356
357     if(!strcmp(type, "bootloader")){
358         D("setting connection_state to CS_BOOTLOADER\n");
359         t->connection_state = CS_BOOTLOADER;
360         update_transports();
361         return;
362     }
363
364     if(!strcmp(type, "device")) {
365         D("setting connection_state to CS_DEVICE\n");
366         t->connection_state = CS_DEVICE;
367         update_transports();
368         return;
369     }
370
371     if(!strcmp(type, "recovery")) {
372         D("setting connection_state to CS_RECOVERY\n");
373         t->connection_state = CS_RECOVERY;
374         update_transports();
375         return;
376     }
377
378     if(!strcmp(type, "sideload")) {
379         D("setting connection_state to CS_SIDELOAD\n");
380         t->connection_state = CS_SIDELOAD;
381         update_transports();
382         return;
383     }
384
385     t->connection_state = CS_HOST;
386 }
387
388 void handle_packet(apacket *p, atransport *t)
389 {
390     asocket *s;
391
392     D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
393                 ((char*) (&(p->msg.command)))[1],
394                 ((char*) (&(p->msg.command)))[2],
395                 ((char*) (&(p->msg.command)))[3]);
396
397     print_packet("recv", p);
398
399     switch(p->msg.command){
400     case A_SYNC:
401         if(p->msg.arg0){
402             send_packet(p, t);
403             if(HOST) send_connect(t);
404         } else {
405             t->connection_state = CS_OFFLINE;
406             handle_offline(t);
407             send_packet(p, t);
408         }
409         return;
410
411     case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
412             /* XXX verify version, etc */
413         if(t->connection_state != CS_OFFLINE) {
414             t->connection_state = CS_OFFLINE;
415             handle_offline(t);
416         }
417         parse_banner((char*) p->data, t);
418         handle_online();
419         if(!HOST) send_connect(t);
420         break;
421
422     case A_OPEN: /* OPEN(local-id, 0, "destination") */
423         if(t->connection_state != CS_OFFLINE) {
424             char *name = (char*) p->data;
425             name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
426             s = create_local_service_socket(name);
427             if(s == 0) {
428                 send_close(0, p->msg.arg0, t);
429             } else {
430                 s->peer = create_remote_socket(p->msg.arg0, t);
431                 s->peer->peer = s;
432                 send_ready(s->id, s->peer->id, t);
433                 s->ready(s);
434             }
435         }
436         break;
437
438     case A_OKAY: /* READY(local-id, remote-id, "") */
439         if(t->connection_state != CS_OFFLINE) {
440             if((s = find_local_socket(p->msg.arg1))) {
441                 if(s->peer == 0) {
442                     s->peer = create_remote_socket(p->msg.arg0, t);
443                     s->peer->peer = s;
444                 }
445                 s->ready(s);
446             }
447         }
448         break;
449
450     case A_CLSE: /* CLOSE(local-id, remote-id, "") */
451         if(t->connection_state != CS_OFFLINE) {
452             if((s = find_local_socket(p->msg.arg1))) {
453                 s->close(s);
454             }
455         }
456         break;
457
458     case A_WRTE:
459         if(t->connection_state != CS_OFFLINE) {
460             if((s = find_local_socket(p->msg.arg1))) {
461                 unsigned rid = p->msg.arg0;
462                 p->len = p->msg.data_length;
463
464                 if(s->enqueue(s, p) == 0) {
465                     D("Enqueue the socket\n");
466                     send_ready(s->id, rid, t);
467                 }
468                 return;
469             }
470         }
471         break;
472
473     default:
474         printf("handle_packet: what is %08x?!\n", p->msg.command);
475     }
476
477     put_apacket(p);
478 }
479
480 alistener listener_list = {
481     .next = &listener_list,
482     .prev = &listener_list,
483 };
484
485 static void ss_listener_event_func(int _fd, unsigned ev, void *_l)
486 {
487     asocket *s;
488
489     if(ev & FDE_READ) {
490         struct sockaddr addr;
491         socklen_t alen;
492         int fd;
493
494         alen = sizeof(addr);
495         fd = sdb_socket_accept(_fd, &addr, &alen);
496         if(fd < 0) return;
497
498         sdb_socket_setbufsize(fd, CHUNK_SIZE);
499
500         s = create_local_socket(fd);
501         if(s) {
502             connect_to_smartsocket(s);
503             return;
504         }
505
506         sdb_close(fd);
507     }
508 }
509
510 static void listener_event_func(int _fd, unsigned ev, void *_l)
511 {
512     alistener *l = _l;
513     asocket *s;
514
515     if(ev & FDE_READ) {
516         struct sockaddr addr;
517         socklen_t alen;
518         int fd;
519
520         alen = sizeof(addr);
521         fd = sdb_socket_accept(_fd, &addr, &alen);
522         if(fd < 0) return;
523
524         s = create_local_socket(fd);
525         if(s) {
526             s->transport = l->transport;
527             connect_to_remote(s, l->connect_to);
528             return;
529         }
530
531         sdb_close(fd);
532     }
533 }
534
535 static void  free_listener(alistener*  l)
536 {
537     if (l->next) {
538         l->next->prev = l->prev;
539         l->prev->next = l->next;
540         l->next = l->prev = l;
541     }
542
543     // closes the corresponding fd
544     fdevent_remove(&l->fde);
545
546     if (l->local_name)
547         free((char*)l->local_name);
548
549     if (l->connect_to)
550         free((char*)l->connect_to);
551
552     if (l->transport) {
553         remove_transport_disconnect(l->transport, &l->disconnect);
554     }
555     free(l);
556 }
557
558 static void listener_disconnect(void*  _l, atransport*  t)
559 {
560     alistener*  l = _l;
561
562     free_listener(l);
563 }
564
565 int local_name_to_fd(const char *name)
566 {
567     int port;
568
569     if(!strncmp("tcp:", name, 4)){
570         int  ret;
571         port = atoi(name + 4);
572         ret = socket_loopback_server(port, SOCK_STREAM);
573         return ret;
574     }
575 #ifndef HAVE_WIN32_IPC  /* no Unix-domain sockets on Win32 */
576     // It's non-sensical to support the "reserved" space on the sdb host side
577     if(!strncmp(name, "local:", 6)) {
578         return socket_local_server(name + 6,
579                 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
580     } else if(!strncmp(name, "localabstract:", 14)) {
581         return socket_local_server(name + 14,
582                 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
583     } else if(!strncmp(name, "localfilesystem:", 16)) {
584         return socket_local_server(name + 16,
585                 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
586     }
587
588 #endif
589     printf("unknown local portname '%s'\n", name);
590     return -1;
591 }
592
593 static int remove_listener(const char *local_name, const char *connect_to, atransport* transport)
594 {
595     alistener *l;
596
597     for (l = listener_list.next; l != &listener_list; l = l->next) {
598         if (!strcmp(local_name, l->local_name) &&
599             !strcmp(connect_to, l->connect_to) &&
600             l->transport && l->transport == transport) {
601
602             listener_disconnect(l, transport);
603             return 0;
604         }
605     }
606
607     return -1;
608 }
609
610 static int install_listener(const char *local_name, const char *connect_to, atransport* transport)
611 {
612     alistener *l;
613
614     //printf("install_listener('%s','%s')\n", local_name, connect_to);
615
616     for(l = listener_list.next; l != &listener_list; l = l->next){
617         if(strcmp(local_name, l->local_name) == 0) {
618             char *cto;
619
620                 /* can't repurpose a smartsocket */
621             if(l->connect_to[0] == '*') {
622                 return -1;
623             }
624
625             cto = strdup(connect_to);
626             if(cto == 0) {
627                 return -1;
628             }
629
630             //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
631             free((void*) l->connect_to);
632             l->connect_to = cto;
633             if (l->transport != transport) {
634                 remove_transport_disconnect(l->transport, &l->disconnect);
635                 l->transport = transport;
636                 add_transport_disconnect(l->transport, &l->disconnect);
637             }
638             return 0;
639         }
640     }
641
642     if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
643     if((l->local_name = strdup(local_name)) == 0) goto nomem;
644     if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
645
646
647     l->fd = local_name_to_fd(local_name);
648     if(l->fd < 0) {
649         free((void*) l->local_name);
650         free((void*) l->connect_to);
651         free(l);
652         printf("cannot bind '%s'\n", local_name);
653         return -2;
654     }
655
656     if (close_on_exec(l->fd) < 0) {
657         D("fail to close fd exec:%d\n",l->fd);
658     }
659     if(!strcmp(l->connect_to, "*smartsocket*")) {
660         fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
661     } else {
662         fdevent_install(&l->fde, l->fd, listener_event_func, l);
663     }
664     fdevent_set(&l->fde, FDE_READ);
665
666     l->next = &listener_list;
667     l->prev = listener_list.prev;
668     l->next->prev = l;
669     l->prev->next = l;
670     l->transport = transport;
671
672     if (transport) {
673         l->disconnect.opaque = l;
674         l->disconnect.func   = listener_disconnect;
675         add_transport_disconnect(transport, &l->disconnect);
676     }
677     return 0;
678
679 nomem:
680     fatal("cannot allocate listener");
681     return 0;
682 }
683
684 #ifdef HAVE_WIN32_PROC
685 static BOOL WINAPI ctrlc_handler(DWORD type)
686 {
687     exit(STATUS_CONTROL_C_EXIT);
688     return TRUE;
689 }
690 #endif
691
692 static void sdb_cleanup(void)
693 {
694     usb_cleanup();
695 }
696
697 void start_logging(void)
698 {
699 #ifdef HAVE_WIN32_PROC
700     char    temp[ MAX_PATH ];
701     FILE*   fnul;
702     FILE*   flog;
703
704     GetTempPath( sizeof(temp) - 8, temp );
705     strcat( temp, "sdb.log" );
706
707     /* Win32 specific redirections */
708     fnul = fopen( "NUL", "rt" );
709     if (fnul != NULL)
710         stdin[0] = fnul[0];
711
712     flog = fopen( temp, "at" );
713     if (flog == NULL)
714         flog = fnul;
715
716     setvbuf( flog, NULL, _IONBF, 0 );
717
718     stdout[0] = flog[0];
719     stderr[0] = flog[0];
720     fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid());
721 #else
722     int fd;
723
724     fd = unix_open("/dev/null", O_RDONLY);
725     if (fd < 0) {
726         // hopefully not gonna happen
727         return;
728     }
729     dup2(fd, 0);
730     sdb_close(fd);
731
732     fd = unix_open("/tmp/sdb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
733     if(fd < 0) {
734         fd = unix_open("/dev/null", O_WRONLY);
735         if (fd < 0) {
736             // hopefully not gonna happen
737             return;
738         }
739     }
740     dup2(fd, 1);
741     dup2(fd, 2);
742     sdb_close(fd);
743     fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid());
744 #endif
745 }
746
747 #if !SDB_HOST
748 void start_device_log(void)
749 {
750     int fd;
751     char    path[PATH_MAX];
752     struct tm now;
753     time_t t;
754 //    char value[PROPERTY_VALUE_MAX];
755     const char* p = getenv("SDB_TRACE");
756     // read the trace mask from persistent property persist.sdb.trace_mask
757     // give up if the property is not set or cannot be parsed
758 #if 0 /* tizen specific */
759     property_get("persist.sdb.trace_mask", value, "");
760     if (sscanf(value, "%x", &sdb_trace_mask) != 1)
761         return;
762 #endif
763
764     if (p == NULL) {
765         return;
766     }
767     tzset();
768     time(&t);
769     localtime_r(&t, &now);
770     strftime(path, sizeof(path),
771                 "/tmp/sdbd-%Y-%m-%d-%H-%M-%S.txt",
772                 &now);
773     fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
774     if (fd < 0) {
775         return;
776     }
777
778     // redirect stdout and stderr to the log file
779     dup2(fd, 1);
780     dup2(fd, 2);
781     fprintf(stderr,"--- sdbd starting (pid %d) ---\n", getpid());
782     sdb_close(fd);
783
784     fd = unix_open("/dev/null", O_RDONLY);
785     if (fd < 0) {
786         // hopefully not gonna happen
787         return;
788     }
789     dup2(fd, 0);
790     sdb_close(fd);
791 }
792
793 int daemonize(void) {
794
795     // set file creation mask to 0
796     umask(0);
797
798     switch (fork()) {
799     case -1:
800         return -1;
801     case 0:
802         break;
803     default:
804         _exit(0);
805     }
806 #ifdef SDB_PIDPATH
807     FILE *f = fopen(SDB_PIDPATH, "w");
808
809     if (f != NULL) {
810         fprintf(f, "%d\n", getpid());
811         fclose(f);
812     }
813 #endif
814     if (setsid() == -1)
815         return -1;
816
817     if (chdir("/") < 0)
818         D("sdbd: unable to change working directory to /\n");
819
820     return 0;
821 }
822 #endif
823
824 #if SDB_HOST
825 int launch_server(int server_port)
826 {
827 #ifdef HAVE_WIN32_PROC
828     /* we need to start the server in the background                    */
829     /* we create a PIPE that will be used to wait for the server's "OK" */
830     /* message since the pipe handles must be inheritable, we use a     */
831     /* security attribute                                               */
832     HANDLE                pipe_read, pipe_write;
833     SECURITY_ATTRIBUTES   sa;
834     STARTUPINFO           startup;
835     PROCESS_INFORMATION   pinfo;
836     char                  program_path[ MAX_PATH ];
837     int                   ret;
838
839     sa.nLength = sizeof(sa);
840     sa.lpSecurityDescriptor = NULL;
841     sa.bInheritHandle = TRUE;
842
843     /* create pipe, and ensure its read handle isn't inheritable */
844     ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
845     if (!ret) {
846         fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
847         return -1;
848     }
849
850     SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
851
852     ZeroMemory( &startup, sizeof(startup) );
853     startup.cb = sizeof(startup);
854     startup.hStdInput  = GetStdHandle( STD_INPUT_HANDLE );
855     startup.hStdOutput = pipe_write;
856     startup.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
857     startup.dwFlags    = STARTF_USESTDHANDLES;
858
859     ZeroMemory( &pinfo, sizeof(pinfo) );
860
861     /* get path of current program */
862     GetModuleFileName( NULL, program_path, sizeof(program_path) );
863
864     ret = CreateProcess(
865             program_path,                              /* program path  */
866             "sdb fork-server server",
867                                     /* the fork-server argument will set the
868                                        debug = 2 in the child           */
869             NULL,                   /* process handle is not inheritable */
870             NULL,                    /* thread handle is not inheritable */
871             TRUE,                          /* yes, inherit some handles */
872             DETACHED_PROCESS, /* the new process doesn't have a console */
873             NULL,                     /* use parent's environment block */
874             NULL,                    /* use parent's starting directory */
875             &startup,                 /* startup info, i.e. std handles */
876             &pinfo );
877
878     CloseHandle( pipe_write );
879
880     if (!ret) {
881         fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
882         CloseHandle( pipe_read );
883         return -1;
884     }
885
886     CloseHandle( pinfo.hProcess );
887     CloseHandle( pinfo.hThread );
888
889     /* wait for the "OK\n" message */
890     {
891         char  temp[3];
892         DWORD  count;
893
894         ret = ReadFile( pipe_read, temp, 3, &count, NULL );
895         CloseHandle( pipe_read );
896         if ( !ret ) {
897             fprintf(stderr, "could not read ok from SDB Server, error = %ld\n", GetLastError() );
898             return -1;
899         }
900         if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
901             fprintf(stderr, "SDB server didn't ACK\n" );
902             return -1;
903         }
904     }
905 #elif defined(HAVE_FORKEXEC)
906     char    path[PATH_MAX];
907     int     fd[2];
908
909     // set up a pipe so the child can tell us when it is ready.
910     // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
911     if (pipe(fd)) {
912         fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
913         return -1;
914     }
915     get_my_path(path, PATH_MAX);
916     pid_t pid = fork();
917     if(pid < 0) return -1;
918
919     if (pid == 0) {
920         // child side of the fork
921
922         // redirect stderr to the pipe
923         // we use stderr instead of stdout due to stdout's buffering behavior.
924         sdb_close(fd[0]);
925         dup2(fd[1], STDERR_FILENO);
926         sdb_close(fd[1]);
927
928         // child process
929         int result = execl(path, "sdb", "fork-server", "server", NULL);
930         // this should not return
931         fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
932     } else  {
933         // parent side of the fork
934
935         char  temp[3];
936
937         temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
938         // wait for the "OK\n" message
939         sdb_close(fd[1]);
940         int ret = sdb_read(fd[0], temp, 3);
941         int saved_errno = errno;
942         sdb_close(fd[0]);
943         if (ret < 0) {
944             fprintf(stderr, "could not read ok from SDB Server, errno = %d\n", saved_errno);
945             return -1;
946         }
947         if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
948             fprintf(stderr, "SDB server didn't ACK\n" );
949             return -1;
950         }
951
952         setsid();
953     }
954 #else
955 #error "cannot implement background server start on this platform"
956 #endif
957     return 0;
958 }
959 #endif
960
961 /* Constructs a local name of form tcp:port.
962  * target_str points to the target string, it's content will be overwritten.
963  * target_size is the capacity of the target string.
964  * server_port is the port number to use for the local name.
965  */
966 void build_local_name(char* target_str, size_t target_size, int server_port)
967 {
968   snprintf(target_str, target_size, "tcp:%d", server_port);
969 }
970
971 #if !SDB_HOST
972 static void init_drop_privileges() {
973 #ifdef _DROP_PRIVILEGE
974     rootshell_mode = 0;
975 #else
976     rootshell_mode = 1;
977 #endif
978 }
979
980 int should_drop_privileges() {
981     if (rootshell_mode == 1) { // if root, then don't drop
982         return 0;
983     }
984     return 1;
985 }
986
987 int set_developer_privileges() {
988     gid_t groups[] = { SID_DEVELOPER, SID_APP_LOGGING, SID_SYS_LOGGING, SID_INPUT };
989     if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) {
990         fprintf(stderr, "set groups failed (errno: %d, %s)\n", errno, strerror(errno));
991         //exit(1);
992     }
993
994     // then switch user and group to developer
995     if (setgid(SID_DEVELOPER) != 0) {
996         fprintf(stderr, "set group id failed (errno: %d, %s)\n", errno, strerror(errno));
997         //exit(1);
998         return -1;
999     }
1000
1001     if (setuid(SID_DEVELOPER) != 0) {
1002         fprintf(stderr, "set user id failed (errno: %d, %s)\n", errno, strerror(errno));
1003         //exit(1);
1004         return -1;
1005     }
1006
1007     if (chdir("/home/developer") < 0) {
1008         D("sdbd: unable to change working directory to /home/developer\n");
1009     } else {
1010         if (chdir("/") < 0) {
1011             D("sdbd: unable to change working directory to /\n");
1012         }
1013     }
1014     return 1;
1015 }
1016 #define ONDEMAND_ROOT_PATH "/home/developer"
1017
1018 static void init_sdk_requirements() {
1019     struct stat st;
1020
1021     if (!getenv("TERM")) {
1022         putenv("TERM=linux");
1023     }
1024
1025     if (stat(ONDEMAND_ROOT_PATH, &st) == -1) {
1026         return;
1027     }
1028     if (st.st_uid != SID_DEVELOPER || st.st_gid != SID_DEVELOPER) {
1029         char cmd[128];
1030         snprintf(cmd, sizeof(cmd), "chown developer:developer %s -R", ONDEMAND_ROOT_PATH);
1031         if (system(cmd) < 0) {
1032             D("failed to change ownership to developer to %s\n", ONDEMAND_ROOT_PATH);
1033         }
1034     }
1035 }
1036 #endif /* !SDB_HOST */
1037
1038 int sdb_main(int is_daemon, int server_port)
1039 {
1040 #if !SDB_HOST
1041
1042     init_drop_privileges();
1043     init_sdk_requirements();
1044     umask(000);
1045 #endif
1046
1047     atexit(sdb_cleanup);
1048 #ifdef HAVE_WIN32_PROC
1049     SetConsoleCtrlHandler( ctrlc_handler, TRUE );
1050 #elif defined(HAVE_FORKEXEC)
1051     // No SIGCHLD. Let the service subproc handle its children.
1052     signal(SIGPIPE, SIG_IGN);
1053 #endif
1054
1055     init_transport_registration();
1056
1057
1058 #if SDB_HOST
1059     HOST = 1;
1060     usb_vendors_init();
1061     usb_init();
1062     local_init(DEFAULT_SDB_LOCAL_TRANSPORT_PORT);
1063
1064     char local_name[30];
1065     build_local_name(local_name, sizeof(local_name), server_port);
1066     if(install_listener(local_name, "*smartsocket*", NULL)) {
1067         exit(1);
1068     }
1069 #else
1070     /* don't listen on a port (default 5037) if running in secure mode */
1071     /* don't run as root if we are running in secure mode */
1072
1073     if (should_drop_privileges()) {
1074 # if 0
1075         struct __user_cap_header_struct header;
1076         struct __user_cap_data_struct cap;
1077
1078         if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1079             exit(1);
1080         }
1081         /* add extra groups:
1082         ** SID_TTY to access /dev/ptmx
1083         */
1084         gid_t groups[] = { SID_TTY, SID_APP_LOGGING, SID_SYS_LOGGING };
1085         if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
1086             exit(1);
1087         }
1088         /* then switch user and group to "developer" */
1089         if (setgid(SID_DEVELOPER) != 0) {
1090             fprintf(stderr, "set group id failed errno: %d\n", errno);
1091             exit(1);
1092         }
1093         if (setuid(SID_DEVELOPER) != 0) {
1094             fprintf(stderr, "set user id failed errno: %d\n", errno);
1095             exit(1);
1096         }
1097
1098         /* set CAP_SYS_BOOT capability, so "sdb reboot" will succeed */
1099         header.version = _LINUX_CAPABILITY_VERSION;
1100         header.pid = 0;
1101         cap.effective = cap.permitted = (1 << CAP_SYS_BOOT);
1102         cap.inheritable = 0;
1103         capset(&header, &cap);
1104 #endif
1105         D("Local port disabled\n");
1106     } else {
1107         char local_name[30];
1108         build_local_name(local_name, sizeof(local_name), server_port);
1109         if(install_listener(local_name, "*smartsocket*", NULL)) {
1110             exit(1);
1111         }
1112     }
1113
1114     if (access("/dev/samsung_sdb", F_OK) == 0) {
1115         // listen on USB
1116         usb_init();
1117         // listen on tcp
1118         //local_init(DEFAULT_SDB_LOCAL_TRANSPORT_PORT);
1119     } else {
1120         // listen on default port
1121         local_init(DEFAULT_SDB_LOCAL_TRANSPORT_PORT);
1122     }
1123
1124 #if 0 /* tizen specific */
1125     D("sdb_main(): pre init_jdwp()\n");
1126     init_jdwp();
1127     D("sdb_main(): post init_jdwp()\n");
1128 #endif
1129 #endif
1130
1131     if (is_daemon)
1132     {
1133         // inform our parent that we are up and running.
1134 #ifdef HAVE_WIN32_PROC
1135         DWORD  count;
1136         WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL );
1137 #elif defined(HAVE_FORKEXEC)
1138         fprintf(stderr, "OK\n");
1139 #endif
1140         start_logging();
1141     }
1142     D("Event loop starting\n");
1143
1144     fdevent_loop();
1145
1146     usb_cleanup();
1147
1148     return 0;
1149 }
1150
1151 #if SDB_HOST
1152 void connect_device(char* host, char* buffer, int buffer_size)
1153 {
1154     int port, fd;
1155     char* portstr = strchr(host, ':');
1156     char hostbuf[100];
1157     char serial[100];
1158
1159     strncpy(hostbuf, host, sizeof(hostbuf) - 1);
1160     if (portstr) {
1161         if (portstr - host >= sizeof(hostbuf)) {
1162             snprintf(buffer, buffer_size, "bad host name %s", host);
1163             return;
1164         }
1165         // zero terminate the host at the point we found the colon
1166         hostbuf[portstr - host] = 0;
1167         if (sscanf(portstr + 1, "%d", &port) == 0) {
1168             snprintf(buffer, buffer_size, "bad port number %s", portstr);
1169             return;
1170         }
1171     } else {
1172         port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
1173     }
1174
1175     snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
1176     if (find_transport(serial)) {
1177         snprintf(buffer, buffer_size, "already connected to %s", serial);
1178         return;
1179     }
1180
1181     fd = socket_network_client(hostbuf, port, SOCK_STREAM);
1182     if (fd < 0) {
1183         snprintf(buffer, buffer_size, "unable to connect to %s", host);
1184         return;
1185     }
1186
1187     D("client: connected on remote on fd %d\n", fd);
1188     close_on_exec(fd);
1189     disable_tcp_nagle(fd);
1190     register_socket_transport(fd, serial, port, 0, NULL);
1191     snprintf(buffer, buffer_size, "connected to %s", serial);
1192 }
1193
1194 void connect_emulator(char* port_spec, char* buffer, int buffer_size)
1195 {
1196     char* port_separator = strchr(port_spec, ',');
1197     if (!port_separator) {
1198         snprintf(buffer, buffer_size,
1199                 "unable to parse '%s' as <console port>,<sdb port>",
1200                 port_spec);
1201         return;
1202     }
1203
1204     // Zero-terminate console port and make port_separator point to 2nd port.
1205     *port_separator++ = 0;
1206     int console_port = strtol(port_spec, NULL, 0);
1207     int sdb_port = strtol(port_separator, NULL, 0);
1208     if (!(console_port > 0 && sdb_port > 0)) {
1209         *(port_separator - 1) = ',';
1210         snprintf(buffer, buffer_size,
1211                 "Invalid port numbers: Expected positive numbers, got '%s'",
1212                 port_spec);
1213         return;
1214     }
1215
1216     /* Check if the emulator is already known.
1217      * Note: There's a small but harmless race condition here: An emulator not
1218      * present just yet could be registered by another invocation right
1219      * after doing this check here. However, local_connect protects
1220      * against double-registration too. From here, a better error message
1221      * can be produced. In the case of the race condition, the very specific
1222      * error message won't be shown, but the data doesn't get corrupted. */
1223     atransport* known_emulator = find_emulator_transport_by_sdb_port(sdb_port);
1224     if (known_emulator != NULL) {
1225         snprintf(buffer, buffer_size,
1226                 "Emulator on port %d already registered.", sdb_port);
1227         return;
1228     }
1229
1230     /* Check if more emulators can be registered. Similar unproblematic
1231      * race condition as above. */
1232     int candidate_slot = get_available_local_transport_index();
1233     if (candidate_slot < 0) {
1234         snprintf(buffer, buffer_size, "Cannot accept more emulators.");
1235         return;
1236     }
1237
1238     /* Preconditions met, try to connect to the emulator. */
1239     if (!local_connect_arbitrary_ports(console_port, sdb_port, NULL)) {
1240         snprintf(buffer, buffer_size,
1241                 "Connected to emulator on ports %d,%d", console_port, sdb_port);
1242     } else {
1243         snprintf(buffer, buffer_size,
1244                 "Could not connect to emulator on ports %d,%d",
1245                 console_port, sdb_port);
1246     }
1247 }
1248 #endif
1249
1250 int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
1251 {
1252     atransport *transport = NULL;
1253     char buf[4096];
1254
1255     if(!strcmp(service, "kill")) {
1256         fprintf(stderr,"sdb server killed by remote request\n");
1257         fflush(stdout);
1258         sdb_write(reply_fd, "OKAY", 4);
1259         usb_cleanup();
1260         exit(0);
1261     }
1262
1263 #if SDB_HOST
1264     // "transport:" is used for switching transport with a specified serial number
1265     // "transport-usb:" is used for switching transport to the only USB transport
1266     // "transport-local:" is used for switching transport to the only local transport
1267     // "transport-any:" is used for switching transport to the only transport
1268     if (!strncmp(service, "transport", strlen("transport"))) {
1269         char* error_string = "unknown failure";
1270         transport_type type = kTransportAny;
1271
1272         if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
1273             type = kTransportUsb;
1274         } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
1275             type = kTransportLocal;
1276         } else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
1277             type = kTransportAny;
1278         } else if (!strncmp(service, "transport:", strlen("transport:"))) {
1279             service += strlen("transport:");
1280             serial = service;
1281         }
1282
1283         transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
1284
1285         if (transport) {
1286             s->transport = transport;
1287             sdb_write(reply_fd, "OKAY", 4);
1288         } else {
1289             sendfailmsg(reply_fd, error_string);
1290         }
1291         return 1;
1292     }
1293
1294     // return a list of all connected devices
1295     if (!strcmp(service, "devices")) {
1296         char buffer[4096];
1297         memset(buf, 0, sizeof(buf));
1298         memset(buffer, 0, sizeof(buffer));
1299         D("Getting device list \n");
1300         list_transports(buffer, sizeof(buffer));
1301         snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
1302         D("Wrote device list \n");
1303         writex(reply_fd, buf, strlen(buf));
1304         return 0;
1305     }
1306
1307     // add a new TCP transport, device or emulator
1308     if (!strncmp(service, "connect:", 8)) {
1309         char buffer[4096];
1310         char* host = service + 8;
1311         if (!strncmp(host, "emu:", 4)) {
1312             connect_emulator(host + 4, buffer, sizeof(buffer));
1313         } else {
1314             connect_device(host, buffer, sizeof(buffer));
1315         }
1316         // Send response for emulator and device
1317         snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
1318         writex(reply_fd, buf, strlen(buf));
1319         return 0;
1320     }
1321
1322     // remove TCP transport
1323     if (!strncmp(service, "disconnect:", 11)) {
1324         char buffer[4096];
1325         memset(buffer, 0, sizeof(buffer));
1326         char* serial = service + 11;
1327         if (serial[0] == 0) {
1328             // disconnect from all TCP devices
1329             unregister_all_tcp_transports();
1330         } else {
1331             char hostbuf[100];
1332             // assume port 26101 if no port is specified
1333             if (!strchr(serial, ':')) {
1334                 snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:26101", serial);
1335                 serial = hostbuf;
1336             }
1337             atransport *t = find_transport(serial);
1338
1339             if (t) {
1340                 unregister_transport(t);
1341             } else {
1342                 snprintf(buffer, sizeof(buffer), "No such device %s", serial);
1343             }
1344         }
1345
1346         snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
1347         writex(reply_fd, buf, strlen(buf));
1348         return 0;
1349     }
1350
1351     // returns our value for SDB_SERVER_VERSION
1352     if (!strcmp(service, "version")) {
1353         char version[12];
1354         snprintf(version, sizeof version, "%04x", SDB_SERVER_VERSION);
1355         snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);
1356         writex(reply_fd, buf, strlen(buf));
1357         return 0;
1358     }
1359
1360     if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
1361         char *out = "unknown";
1362          transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
1363        if (transport && transport->serial) {
1364             out = transport->serial;
1365         }
1366         snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
1367         writex(reply_fd, buf, strlen(buf));
1368         return 0;
1369     }
1370     // indicates a new emulator instance has started
1371        if (!strncmp(service,"emulator:",9)) { /* tizen specific */
1372            char *tmp = strtok(service+9, DEVICEMAP_SEPARATOR);
1373            int  port = 0;
1374
1375            if (tmp == NULL) {
1376                port = atoi(service+9);
1377            } else {
1378                port = atoi(tmp);
1379                tmp = strtok(NULL, DEVICEMAP_SEPARATOR);
1380                if (tmp != NULL) {
1381                    local_connect(port, tmp);
1382                }
1383            }
1384            local_connect(port, NULL);
1385         return 0;
1386     }
1387 #endif // SDB_HOST
1388
1389     if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) {
1390         char *local, *remote, *err;
1391         int r;
1392         atransport *transport;
1393
1394         int createForward = strncmp(service,"kill",4);
1395
1396         local = service + (createForward ? 8 : 12);
1397         remote = strchr(local,';');
1398         if(remote == 0) {
1399             sendfailmsg(reply_fd, "malformed forward spec");
1400             return 0;
1401         }
1402
1403         *remote++ = 0;
1404         if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
1405             sendfailmsg(reply_fd, "malformed forward spec");
1406             return 0;
1407         }
1408
1409         transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
1410         if (!transport) {
1411             sendfailmsg(reply_fd, err);
1412             return 0;
1413         }
1414
1415         if (createForward) {
1416             r = install_listener(local, remote, transport);
1417         } else {
1418             r = remove_listener(local, remote, transport);
1419         }
1420         if(r == 0) {
1421                 /* 1st OKAY is connect, 2nd OKAY is status */
1422             writex(reply_fd, "OKAYOKAY", 8);
1423             return 0;
1424         }
1425
1426         if (createForward) {
1427             sendfailmsg(reply_fd, (r == -1) ? "cannot rebind smartsocket" : "cannot bind socket");
1428         } else {
1429             sendfailmsg(reply_fd, "cannot remove listener");
1430         }
1431         return 0;
1432     }
1433
1434     if(!strncmp(service,"get-state",strlen("get-state"))) {
1435         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
1436         char *state = connection_state_name(transport);
1437         snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state);
1438         writex(reply_fd, buf, strlen(buf));
1439         return 0;
1440     }
1441     return -1;
1442 }
1443
1444 #if !SDB_HOST
1445 int recovery_mode = 0;
1446 #endif
1447
1448 int main(int argc, char **argv)
1449 {
1450     sdb_trace_init(); /* tizen specific */
1451 #if SDB_HOST
1452     sdb_sysdeps_init();
1453     sdb_trace_init();
1454     return sdb_commandline(argc - 1, argv + 1);
1455 #else
1456     /* If sdbd runs inside the emulator this will enable sdb tracing via
1457      * sdb-debug qemud service in the emulator. */
1458 #if 0 /* tizen specific */
1459     sdb_qemu_trace_init();
1460     if((argc > 1) && (!strcmp(argv[1],"recovery"))) {
1461         sdb_device_banner = "recovery";
1462         recovery_mode = 1;
1463     }
1464 #endif
1465 #if !SDB_HOST
1466     if (daemonize() < 0)
1467         fatal("daemonize() failed: %.200s", strerror(errno));
1468 #endif
1469
1470     start_device_log();
1471     D("Handling main()\n");
1472
1473     //sdbd will never die on emulator!
1474     signal(SIGTERM, handle_sig_term); /* tizen specific */
1475     return sdb_main(0, DEFAULT_SDB_PORT);
1476 #endif
1477 }