Merge branch 'tizen_2.4_merge' into tizen
[sdk/target/sdbd.git] / src / commandline.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <limits.h>
23 #include <stdarg.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <ctype.h>
27 #include <assert.h>
28
29 #include "sysdeps.h"
30
31 #ifdef HAVE_TERMIO_H
32 #include <termios.h>
33 #endif
34
35 #define  TRACE_TAG  TRACE_SDB
36 #include "sdb.h"
37 #include "sdb_client.h"
38 #include "file_sync_service.h"
39 #include <tzplatform_config.h>
40
41 static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
42
43 void get_my_path(char *s, size_t maxLen);
44 int find_sync_dirs(const char *srcarg,
45         char **android_srcdir_out, char **data_srcdir_out);
46 int install_app(transport_type transport, char* serial, int argc, char** argv);
47 int uninstall_app_sdb(const char *app_id);
48 int install_app_sdb(const char *srcpath);
49 int launch_app(transport_type transport, char* serial, int argc, char** argv);
50 int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
51 int sdb_command2(const char* cmd);
52 void version_sdbd(transport_type ttype, char* serial);
53
54 static const char *gProductOutPath = NULL;
55
56 static char *product_file(const char *extra)
57 {
58     int n;
59     char *x;
60
61     if (gProductOutPath == NULL) {
62         fprintf(stderr, "sdb: Product directory not specified; "
63                 "use -p or define ANDROID_PRODUCT_OUT\n");
64         exit(1);
65     }
66
67     n = strlen(gProductOutPath) + strlen(extra) + 2;
68     x = malloc(n);
69     if (x == 0) {
70         fprintf(stderr, "sdb: Out of memory (product_file())\n");
71         exit(1);
72     }
73
74     snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
75     return x;
76 }
77
78 void version(FILE * out) {
79     fprintf(out, "Smart Development Bridge version %d.%d.%d\n",
80          SDB_VERSION_MAJOR, SDB_VERSION_MINOR, SDB_SERVER_VERSION);
81 }
82
83 void help()
84 {
85     version(stderr);
86
87     fprintf(stderr,
88     "\n"
89     " Usage : sdb [option] <command> [parameters]\n"
90         "\n"
91     " options:\n"
92     " -d                            - direct command to the only connected USB device\n"
93     "                                 return an error if more than one USB device is present.\n"
94     " -e                            - direct command to the only running emulator.\n"
95     "                                 return an error if more than one emulator is running.\n"
96     " -s <serial number>            - direct command to the USB device or emulator with\n"
97     "                                 the given serial number.\n"
98     " devices                       - list all connected devices\n"
99     " connect <host>[:<port>]       - connect to a device via TCP/IP\n"
100     "                                 Port 26101 is used by default if no port number is specified.\n"
101     " disconnect [<host>[:<port>]]  - disconnect from a TCP/IP device.\n"
102     "                                 Port 26101 is used by default if no port number is specified.\n"
103     "                                 Using this command with no additional arguments\n"
104     "                                 will disconnect from all connected TCP/IP devices.\n"
105     "\n"
106     " commands:\n"
107     "  sdb push <local> <remote> [--with-utf8]\n"
108     "                               - copy file/dir to device\n"
109     "                                 (--with-utf8 means to create the remote file with utf-8 character encoding)\n"
110     "  sdb pull <remote> [<local>]  - copy file/dir from device\n"
111     "  sdb shell                    - run remote shell interactively\n"
112     "  sdb shell <command>          - run remote shell \n"
113     "  sdb dlog [<filter-spec>]     - view device log\n"
114     "  sdb install <path-to-tpk>    - push tpk package file and install it\n"
115     "  sdb uninstall <appid>        - uninstall this app from the device\n"
116     "  sdb forward <local> <remote> - forward socket connections\n"
117
118     "                                 forward spec is : \n"
119     "                                   tcp:<port>\n"
120     "  sdb help                     - show this help message\n"
121     "  sdb version                  - show version num\n"
122     "\n"
123     "  sdb start-server             - ensure that there is a server running\n"
124     "  sdb kill-server              - kill the server if it is running\n"
125     "  sdb get-state                - print: offline | bootloader | device\n"
126     "  sdb get-serialno             - print: <serial-number>\n"
127     "  sdb status-window            - continuously print device status for a specified device\n"
128 //    "  sdb usb                      - restarts the sdbd daemon listing on USB\n"
129 //    "  sdb tcpip                    - restarts the sdbd daemon listing on TCP\n"
130     "  sdb root <on|off>            - switch to root or developer account mode\n"
131     "                                 'on' means to root mode, and vice versa"
132     "\n"
133         );
134 }
135
136 int usage()
137 {
138     help();
139     return 1;
140 }
141
142 #ifdef HAVE_TERMIO_H
143 static struct termios tio_save;
144
145 static void stdin_raw_init(int fd)
146 {
147     struct termios tio;
148
149     if(tcgetattr(fd, &tio)) return;
150     if(tcgetattr(fd, &tio_save)) return;
151
152     tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
153
154         /* no timeout but request at least one character per read */
155     tio.c_cc[VTIME] = 0;
156     tio.c_cc[VMIN] = 1;
157
158     tcsetattr(fd, TCSANOW, &tio);
159     tcflush(fd, TCIFLUSH);
160 }
161
162 static void stdin_raw_restore(int fd)
163 {
164     tcsetattr(fd, TCSANOW, &tio_save);
165     tcflush(fd, TCIFLUSH);
166 }
167 #endif
168
169 static void read_and_dump(int fd)
170 {
171     char buf[4096];
172     int len;
173
174     while(fd >= 0) {
175         D("read_and_dump(): pre sdb_read(fd=%d)\n", fd);
176         len = sdb_read(fd, buf, 4096);
177         D("read_and_dump(): post sdb_read(fd=%d): len=%d\n", fd, len);
178         if(len == 0) {
179             break;
180         }
181
182         if(len < 0) {
183             if(errno == EINTR) continue;
184             break;
185         }
186         fwrite(buf, 1, len, stdout);
187         fflush(stdout);
188     }
189 }
190
191 static void copy_to_file(int inFd, int outFd) {
192     const size_t BUFSIZE = 32 * 1024;
193     char* buf = (char*) malloc(BUFSIZE);
194     int len;
195     long total = 0;
196
197     D("copy_to_file(%d -> %d)\n", inFd, outFd);
198     for (;;) {
199         len = sdb_read(inFd, buf, BUFSIZE);
200         if (len == 0) {
201             D("copy_to_file() : read 0 bytes; exiting\n");
202             break;
203         }
204         if (len < 0) {
205             if (errno == EINTR) {
206                 D("copy_to_file() : EINTR, retrying\n");
207                 continue;
208             }
209             D("copy_to_file() : error %d\n", errno);
210             break;
211         }
212         sdb_write(outFd, buf, len);
213         total += len;
214     }
215     D("copy_to_file() finished after %lu bytes\n", total);
216     free(buf);
217 }
218
219 static void *stdin_read_thread(void *x)
220 {
221     int fd, fdi;
222     unsigned char buf[1024];
223     int r, n;
224     int state = 0;
225
226     int *fds = (int*) x;
227     fd = fds[0];
228     fdi = fds[1];
229     free(fds);
230
231     for(;;) {
232         /* fdi is really the client's stdin, so use read, not sdb_read here */
233         D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
234         r = unix_read(fdi, buf, 1024);
235         D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
236         if(r == 0) break;
237         if(r < 0) {
238             if(errno == EINTR) continue;
239             break;
240         }
241         for(n = 0; n < r; n++){
242             switch(buf[n]) {
243             case '\n':
244                 state = 1;
245                 break;
246             case '\r':
247                 state = 1;
248                 break;
249             case '~':
250                 if(state == 1) state++;
251                 break;
252             case '.':
253                 if(state == 2) {
254                     fprintf(stderr,"\n* disconnect *\n");
255 #ifdef HAVE_TERMIO_H
256                     stdin_raw_restore(fdi);
257 #endif
258                     exit(0);
259                 }
260             default:
261                 state = 0;
262             }
263         }
264         r = sdb_write(fd, buf, r);
265         if(r <= 0) {
266             break;
267         }
268     }
269     return 0;
270 }
271
272 int interactive_shell(void)
273 {
274     sdb_thread_t thr;
275     int fdi, fd;
276     int *fds;
277
278     fd = sdb_connect("shell:");
279     if(fd < 0) {
280         fprintf(stderr,"error: %s\n", sdb_error());
281         return 1;
282     }
283     fdi = 0; //dup(0);
284
285     fds = malloc(sizeof(int) * 2);
286     fds[0] = fd;
287     fds[1] = fdi;
288
289 #ifdef HAVE_TERMIO_H
290     stdin_raw_init(fdi);
291 #endif
292     sdb_thread_create(&thr, stdin_read_thread, fds);
293     read_and_dump(fd);
294 #ifdef HAVE_TERMIO_H
295     stdin_raw_restore(fdi);
296 #endif
297     return 0;
298 }
299
300
301 static void format_host_command(char* buffer, size_t  buflen, const char* command, transport_type ttype, const char* serial)
302 {
303     if (serial) {
304         snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
305     } else {
306         const char* prefix = "host";
307         if (ttype == kTransportUsb)
308             prefix = "host-usb";
309         else if (ttype == kTransportLocal)
310             prefix = "host-local";
311
312         snprintf(buffer, buflen, "%s:%s", prefix, command);
313     }
314 }
315 #if 0 /* tizen specific */
316 int sdb_download_buffer(const char *service, const void* data, int sz,
317                         unsigned progress)
318 {
319     char buf[4096];
320     unsigned total;
321     int fd;
322     const unsigned char *ptr;
323
324     sprintf(buf,"%s:%d", service, sz);
325     fd = sdb_connect(buf);
326     if(fd < 0) {
327         fprintf(stderr,"error: %s\n", sdb_error());
328         return -1;
329     }
330
331     int opt = CHUNK_SIZE;
332     opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt));
333
334     total = sz;
335     ptr = data;
336
337     if(progress) {
338         char *x = strrchr(service, ':');
339         if(x) service = x + 1;
340     }
341
342     while(sz > 0) {
343         unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz;
344         if(writex(fd, ptr, xfer)) {
345             sdb_status(fd);
346             fprintf(stderr,"* failed to write data '%s' *\n", sdb_error());
347             return -1;
348         }
349         sz -= xfer;
350         ptr += xfer;
351         if(progress) {
352             printf("sending: '%s' %4d%%    \r", service, (int)(100LL - ((100LL * sz) / (total))));
353             fflush(stdout);
354         }
355     }
356     if(progress) {
357         printf("\n");
358     }
359
360     if(readx(fd, buf, 4)){
361         fprintf(stderr,"* error reading response *\n");
362         sdb_close(fd);
363         return -1;
364     }
365     if(memcmp(buf, "OKAY", 4)) {
366         buf[4] = 0;
367         fprintf(stderr,"* error response '%s' *\n", buf);
368         sdb_close(fd);
369         return -1;
370     }
371
372     sdb_close(fd);
373     return 0;
374 }
375
376 int sdb_download(const char *service, const char *fn, unsigned progress)
377 {
378     void *data;
379     unsigned sz;
380
381     data = load_file(fn, &sz);
382     if(data == 0) {
383         fprintf(stderr,"* cannot read '%s' *\n", service);
384         return -1;
385     }
386
387     int status = sdb_download_buffer(service, data, sz, progress);
388     free(data);
389     return status;
390 }
391 #endif
392 static void status_window(transport_type ttype, const char* serial)
393 {
394     char command[4096];
395     char *state = 0;
396     char *laststate = 0;
397
398         /* silence stderr */
399 #ifdef _WIN32
400     /* XXX: TODO */
401 #else
402     int  fd;
403     fd = unix_open("/dev/null", O_WRONLY);
404     dup2(fd, 2);
405     sdb_close(fd);
406 #endif
407
408     format_host_command(command, sizeof command, "get-state", ttype, serial);
409
410     for(;;) {
411         sdb_sleep_ms(250);
412
413         if(state) {
414             free(state);
415             state = 0;
416         }
417
418         state = sdb_query(command);
419
420         if(state) {
421             if(laststate && !strcmp(state,laststate)){
422                 continue;
423             } else {
424                 if(laststate) free(laststate);
425                 laststate = strdup(state);
426             }
427         }
428
429         printf("%c[2J%c[2H", 27, 27);
430         printf("Samsung Development Bridge\n");
431         printf("State: %s\n", state ? state : "offline");
432         fflush(stdout);
433     }
434 }
435
436 /** duplicate string and quote all \ " ( ) chars + space character. */
437 static char *
438 dupAndQuote(const char *s)
439 {
440     const char *ts;
441     size_t alloc_len;
442     char *ret;
443     char *dest;
444
445     ts = s;
446
447     alloc_len = 0;
448
449     for( ;*ts != '\0'; ts++) {
450         alloc_len++;
451         if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
452             alloc_len++;
453         }
454     }
455
456     ret = (char *)malloc(alloc_len + 1);
457
458     ts = s;
459     dest = ret;
460
461     for ( ;*ts != '\0'; ts++) {
462         if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
463             *dest++ = '\\';
464         }
465
466         *dest++ = *ts;
467     }
468
469     *dest++ = '\0';
470
471     return ret;
472 }
473
474 /**
475  * Run ppp in "notty" mode against a resource listed as the first parameter
476  * eg:
477  *
478  * ppp dev:/dev/omap_csmi_tty0 <ppp options>
479  *
480  */
481 int ppp(int argc, char **argv)
482 {
483 #ifdef HAVE_WIN32_PROC
484     fprintf(stderr, "error: sdb %s not implemented on Win32\n", argv[0]);
485     return -1;
486 #else
487     char *sdb_service_name;
488     pid_t pid;
489     int fd;
490
491     if (argc < 2) {
492         fprintf(stderr, "usage: sdb %s <sdb service name> [ppp opts]\n",
493                 argv[0]);
494
495         return 1;
496     }
497
498     sdb_service_name = argv[1];
499
500     fd = sdb_connect(sdb_service_name);
501
502     if(fd < 0) {
503         fprintf(stderr,"Error: Could not open sdb service: %s. Error: %s\n",
504                 sdb_service_name, sdb_error());
505         return 1;
506     }
507
508     pid = fork();
509
510     if (pid < 0) {
511         perror("from fork()");
512         return 1;
513     } else if (pid == 0) {
514         int err;
515         int i;
516         const char **ppp_args;
517
518         // copy args
519         ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
520         ppp_args[0] = "pppd";
521         for (i = 2 ; i < argc ; i++) {
522             //argv[2] and beyond become ppp_args[1] and beyond
523             ppp_args[i - 1] = argv[i];
524         }
525         ppp_args[i-1] = NULL;
526
527         // child side
528
529         dup2(fd, STDIN_FILENO);
530         dup2(fd, STDOUT_FILENO);
531         sdb_close(STDERR_FILENO);
532         sdb_close(fd);
533
534         err = execvp("pppd", (char * const *)ppp_args);
535
536         if (err < 0) {
537             perror("execing pppd");
538         }
539         exit(-1);
540     } else {
541         // parent side
542
543         sdb_close(fd);
544         return 0;
545     }
546 #endif /* !HAVE_WIN32_PROC */
547 }
548
549 static int send_shellcommand(transport_type transport, char* serial, char* buf)
550 {
551     int fd, ret;
552
553     for(;;) {
554         fd = sdb_connect(buf);
555         if(fd >= 0)
556             break;
557         fprintf(stderr,"- waiting for device -\n");
558         sdb_sleep_ms(1000);
559         do_cmd(transport, serial, "wait-for-device", 0);
560     }
561
562     read_and_dump(fd);
563     ret = sdb_close(fd);
564     if (ret)
565         perror("close");
566
567     return ret;
568 }
569
570 static int logcat(transport_type transport, char* serial, int argc, char **argv)
571 {
572     char buf[4096];
573
574     snprintf(buf, sizeof(buf),
575         "shell:/usr/bin/dlogutil");
576
577 /*
578     if (!strcmp(argv[0],"longcat")) {
579         strncat(buf, " -v long", sizeof(buf)-1);
580     }
581 */
582
583     argc -= 1;
584     argv += 1;
585     while(argc-- > 0) {
586         char *quoted;
587
588         quoted = dupAndQuote (*argv++);
589
590         strncat(buf, " ", sizeof(buf)-1);
591         strncat(buf, quoted, sizeof(buf)-1);
592         free(quoted);
593     }
594
595     send_shellcommand(transport, serial, buf);
596     return 0;
597 }
598
599 static int mkdirs(char *path)
600 {
601     int ret;
602     char *x = path + 1;
603
604     for(;;) {
605         x = sdb_dirstart(x);
606         if(x == 0) return 0;
607         *x = 0;
608         ret = sdb_mkdir(path, 0775);
609         *x = OS_PATH_SEPARATOR;
610         if((ret < 0) && (errno != EEXIST)) {
611             return ret;
612         }
613         x++;
614     }
615     return 0;
616 }
617
618 static int backup(int argc, char** argv) {
619     char buf[4096];
620     char default_name[32];
621     const char* filename = strcpy(default_name, "./backup.ab");
622     int fd, outFd;
623     int i, j;
624
625     /* find, extract, and use any -f argument */
626     for (i = 1; i < argc; i++) {
627         if (!strcmp("-f", argv[i])) {
628             if (i == argc-1) {
629                 fprintf(stderr, "sdb: -f passed with no filename\n");
630                 return usage();
631             }
632             filename = argv[i+1];
633             for (j = i+2; j <= argc; ) {
634                 argv[i++] = argv[j++];
635             }
636             argc -= 2;
637             argv[argc] = NULL;
638         }
639     }
640
641     /* bare "sdb backup" or "sdb backup -f filename" are not valid invocations */
642     if (argc < 2) return usage();
643
644     sdb_unlink(filename);
645     mkdirs((char *)filename);
646     outFd = sdb_creat(filename, 0640);
647     if (outFd < 0) {
648         fprintf(stderr, "sdb: unable to open file %s\n", filename);
649         return -1;
650     }
651
652     snprintf(buf, sizeof(buf), "backup");
653     for (argc--, argv++; argc; argc--, argv++) {
654         strncat(buf, ":", sizeof(buf) - strlen(buf) - 1);
655         strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1);
656     }
657
658     D("backup. filename=%s buf=%s\n", filename, buf);
659     fd = sdb_connect(buf);
660     if (fd < 0) {
661         fprintf(stderr, "sdb: unable to connect for backup\n");
662         sdb_close(outFd);
663         return -1;
664     }
665
666     printf("Now unlock your device and confirm the backup operation.\n");
667     copy_to_file(fd, outFd);
668
669     sdb_close(fd);
670     sdb_close(outFd);
671     return 0;
672 }
673
674 static int restore(int argc, char** argv) {
675     const char* filename;
676     int fd, tarFd;
677
678     if (argc != 2) return usage();
679
680     filename = argv[1];
681     tarFd = sdb_open(filename, O_RDONLY);
682     if (tarFd < 0) {
683         fprintf(stderr, "sdb: unable to open file %s\n", filename);
684         return -1;
685     }
686
687     fd = sdb_connect("restore:");
688     if (fd < 0) {
689         fprintf(stderr, "sdb: unable to connect for backup\n");
690         sdb_close(tarFd);
691         return -1;
692     }
693
694     printf("Now unlock your device and confirm the restore operation.\n");
695     copy_to_file(tarFd, fd);
696
697     sdb_close(fd);
698     sdb_close(tarFd);
699     return 0;
700 }
701
702 #define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
703 static int top_works(const char *top)
704 {
705     if (top != NULL && sdb_is_absolute_host_path(top)) {
706         char path_buf[PATH_MAX];
707         snprintf(path_buf, sizeof(path_buf),
708                 "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
709         return access(path_buf, F_OK) == 0;
710     }
711     return 0;
712 }
713
714 static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
715 {
716     strcpy(path_buf, indir);
717     while (1) {
718         if (top_works(path_buf)) {
719             return path_buf;
720         }
721         char *s = sdb_dirstop(path_buf);
722         if (s != NULL) {
723             *s = '\0';
724         } else {
725             path_buf[0] = '\0';
726             return NULL;
727         }
728     }
729 }
730
731 static char *find_top(char path_buf[PATH_MAX])
732 {
733     char *top = getenv("ANDROID_BUILD_TOP");
734     if (top != NULL && top[0] != '\0') {
735         if (!top_works(top)) {
736             fprintf(stderr, "sdb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
737             return NULL;
738         }
739     } else {
740         top = getenv("TOP");
741         if (top != NULL && top[0] != '\0') {
742             if (!top_works(top)) {
743                 fprintf(stderr, "sdb: bad TOP value \"%s\"\n", top);
744                 return NULL;
745             }
746         } else {
747             top = NULL;
748         }
749     }
750
751     if (top != NULL) {
752         /* The environment pointed to a top directory that works.
753          */
754         strcpy(path_buf, top);
755         return path_buf;
756     }
757
758     /* The environment didn't help.  Walk up the tree from the CWD
759      * to see if we can find the top.
760      */
761     char dir[PATH_MAX];
762     top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
763     if (top == NULL) {
764         /* If the CWD isn't under a good-looking top, see if the
765          * executable is.
766          */
767         get_my_path(dir, PATH_MAX);
768         top = find_top_from(dir, path_buf);
769     }
770     return top;
771 }
772
773 /* <hint> may be:
774  * - A simple product name
775  *   e.g., "sooner"
776 TODO: debug?  sooner-debug, sooner:debug?
777  * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
778  *   e.g., "out/target/product/sooner"
779  * - An absolute path to the PRODUCT_OUT dir
780  *   e.g., "/src/device/out/target/product/sooner"
781  *
782  * Given <hint>, try to construct an absolute path to the
783  * ANDROID_PRODUCT_OUT dir.
784  */
785 static const char *find_product_out_path(const char *hint)
786 {
787     static char path_buf[PATH_MAX];
788
789     if (hint == NULL || hint[0] == '\0') {
790         return NULL;
791     }
792
793     /* If it's already absolute, don't bother doing any work.
794      */
795     if (sdb_is_absolute_host_path(hint)) {
796         strcpy(path_buf, hint);
797         return path_buf;
798     }
799
800     /* If there are any slashes in it, assume it's a relative path;
801      * make it absolute.
802      */
803     if (sdb_dirstart(hint) != NULL) {
804         if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
805             fprintf(stderr, "sdb: Couldn't get CWD: errno:%d\n", errno);
806             return NULL;
807         }
808         if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
809             fprintf(stderr, "sdb: Couldn't assemble path\n");
810             return NULL;
811         }
812         strcat(path_buf, OS_PATH_SEPARATOR_STR);
813         strcat(path_buf, hint);
814         return path_buf;
815     }
816
817     /* It's a string without any slashes.  Try to do something with it.
818      *
819      * Try to find the root of the build tree, and build a PRODUCT_OUT
820      * path from there.
821      */
822     char top_buf[PATH_MAX];
823     const char *top = find_top(top_buf);
824     if (top == NULL) {
825         fprintf(stderr, "sdb: Couldn't find top of build tree\n");
826         return NULL;
827     }
828 //TODO: if we have a way to indicate debug, look in out/debug/target/...
829     snprintf(path_buf, sizeof(path_buf),
830             "%s" OS_PATH_SEPARATOR_STR
831             "out" OS_PATH_SEPARATOR_STR
832             "target" OS_PATH_SEPARATOR_STR
833             "product" OS_PATH_SEPARATOR_STR
834             "%s", top_buf, hint);
835     if (access(path_buf, F_OK) < 0) {
836         fprintf(stderr, "sdb: Couldn't find a product dir "
837                 "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
838         return NULL;
839     }
840     return path_buf;
841 }
842
843 int sdb_commandline(int argc, char **argv)
844 {
845     char buf[4096];
846     int no_daemon = 0;
847     int is_daemon = 0;
848     int is_server = 0;
849     int persist = 0;
850     int r;
851     int quote;
852     transport_type ttype = kTransportAny;
853     char* serial = NULL;
854     char* server_port_str = NULL;
855
856         /* If defined, this should be an absolute path to
857          * the directory containing all of the various system images
858          * for a particular product.  If not defined, and the sdb
859          * command requires this information, then the user must
860          * specify the path using "-p".
861          */
862     gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
863     if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
864         gProductOutPath = NULL;
865     }
866     // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
867
868     serial = getenv("ANDROID_SERIAL");
869
870     /* Validate and assign the server port */
871     server_port_str = getenv("ANDROID_SDB_SERVER_PORT");
872     int server_port = DEFAULT_SDB_PORT;
873     if (server_port_str && strlen(server_port_str) > 0) {
874         server_port = (int) strtol(server_port_str, NULL, 0);
875         if (server_port <= 0) {
876             fprintf(stderr,
877                     "sdb: Env var ANDROID_SDB_SERVER_PORT must be a positive number. Got \"%s\"\n",
878                     server_port_str);
879             return usage();
880         }
881     }
882
883     /* modifiers and flags */
884     while(argc > 0) {
885         if(!strcmp(argv[0],"server")) {
886             is_server = 1;
887         } else if(!strcmp(argv[0],"nodaemon")) {
888             no_daemon = 1;
889         } else if (!strcmp(argv[0], "fork-server")) {
890             /* this is a special flag used only when the SDB client launches the SDB Server */
891             is_daemon = 1;
892         } else if(!strcmp(argv[0],"persist")) {
893             persist = 1;
894         } else if(!strncmp(argv[0], "-p", 2)) {
895             const char *product = NULL;
896             if (argv[0][2] == '\0') {
897                 if (argc < 2) return usage();
898                 product = argv[1];
899                 argc--;
900                 argv++;
901             } else {
902                 product = argv[1] + 2;
903             }
904             gProductOutPath = find_product_out_path(product);
905             if (gProductOutPath == NULL) {
906                 fprintf(stderr, "sdb: could not resolve \"-p %s\"\n",
907                         product);
908                 return usage();
909             }
910         } else if (argv[0][0]=='-' && argv[0][1]=='s') {
911             if (isdigit(argv[0][2])) {
912                 serial = argv[0] + 2;
913             } else {
914                 if(argc < 2 || argv[0][2] != '\0') return usage();
915                 serial = argv[1];
916                 argc--;
917                 argv++;
918             }
919         } else if (!strcmp(argv[0],"-d")) {
920             ttype = kTransportUsb;
921         } else if (!strcmp(argv[0],"-e")) {
922             ttype = kTransportLocal;
923         } else {
924                 /* out of recognized modifiers and flags */
925             break;
926         }
927         argc--;
928         argv++;
929     }
930
931
932 //    sdb_set_transport(ttype, serial);
933 //    sdb_set_tcp_specifics(server_port);
934
935     if (is_server) {
936         if (no_daemon || is_daemon) {
937             r = sdb_main(is_daemon, server_port);
938         } else {
939             r = launch_server(server_port);
940         }
941         if(r) {
942             fprintf(stderr,"* could not start server *\n");
943         }
944         return r;
945     }
946
947 top:
948     if(argc == 0) {
949         return usage();
950     }
951
952     // first, get the uniq device from the partial serial with prefix matching
953     if (serial) {
954         char *tmp;
955         snprintf(buf, sizeof(buf), "host:serial-match:%s", serial);
956         tmp = sdb_query(buf);
957         if (tmp) {
958             //printf("connect to device: %s\n", tmp);
959             serial = strdup(tmp);
960             sdb_set_transport(ttype, serial);
961             sdb_set_tcp_specifics(server_port);
962         } else {
963             return 1;
964         }
965     } else {
966         sdb_set_transport(ttype, serial);
967         sdb_set_tcp_specifics(server_port);
968     }
969     /* sdb_connect() commands */
970
971     if(!strcmp(argv[0], "devices")) {
972         char *tmp;
973         snprintf(buf, sizeof buf, "host:%s", argv[0]);
974         tmp = sdb_query(buf);
975         if(tmp) {
976             printf("List of devices attached \n");
977             printf("%s", tmp);
978             return 0;
979         } else {
980             return 1;
981         }
982     }
983
984     if(!strcmp(argv[0], "connect")) {
985         char *tmp;
986         if (argc != 2) {
987             fprintf(stderr, "Usage: sdb connect <host>[:<port>]\n");
988             return 1;
989         }
990         snprintf(buf, sizeof buf, "host:connect:%s", argv[1]);
991         tmp = sdb_query(buf);
992         if(tmp) {
993             printf("%s\n", tmp);
994             return 0;
995         } else {
996             return 1;
997         }
998     }
999
1000     if(!strcmp(argv[0], "disconnect")) {
1001         char *tmp;
1002         if (argc > 2) {
1003             fprintf(stderr, "Usage: sdb disconnect [<host>[:<port>]]\n");
1004             return 1;
1005         }
1006         if (argc == 2) {
1007             snprintf(buf, sizeof buf, "host:disconnect:%s", argv[1]);
1008         } else {
1009             snprintf(buf, sizeof buf, "host:disconnect:");
1010         }
1011         tmp = sdb_query(buf);
1012         if(tmp) {
1013             printf("%s\n", tmp);
1014             return 0;
1015         } else {
1016             return 1;
1017         }
1018     }
1019
1020     if (!strcmp(argv[0], "emu")) {
1021         return sdb_send_emulator_command(argc, argv);
1022     }
1023
1024     if(!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
1025         int r;
1026         int fd;
1027
1028         char h = (argv[0][0] == 'h');
1029
1030         if (h) {
1031             printf("\x1b[41;33m");
1032             fflush(stdout);
1033         }
1034
1035         if(argc < 2) {
1036             D("starting interactive shell\n");
1037             r = interactive_shell();
1038             if (h) {
1039                 printf("\x1b[0m");
1040                 fflush(stdout);
1041             }
1042             return r;
1043         }
1044
1045         snprintf(buf, sizeof buf, "shell:%s", argv[1]);
1046         argc -= 2;
1047         argv += 2;
1048         while(argc-- > 0) {
1049             strcat(buf, " ");
1050
1051             /* quote empty strings and strings with spaces */
1052             quote = (**argv == 0 || strchr(*argv, ' '));
1053             if (quote)
1054                 strcat(buf, "\"");
1055             strcat(buf, *argv++);
1056             if (quote)
1057                 strcat(buf, "\"");
1058         }
1059
1060         for(;;) {
1061             D("interactive shell loop. buff=%s\n", buf);
1062             fd = sdb_connect(buf);
1063             if(fd >= 0) {
1064                 D("about to read_and_dump(fd=%d)\n", fd);
1065                 read_and_dump(fd);
1066                 D("read_and_dump() done.\n");
1067                 sdb_close(fd);
1068                 r = 0;
1069             } else {
1070                 fprintf(stderr,"error: %s\n", sdb_error());
1071                 r = -1;
1072             }
1073
1074             if(persist) {
1075                 fprintf(stderr,"\n- waiting for device -\n");
1076                 sdb_sleep_ms(1000);
1077                 do_cmd(ttype, serial, "wait-for-device", 0);
1078             } else {
1079                 if (h) {
1080                     printf("\x1b[0m");
1081                     fflush(stdout);
1082                 }
1083                 D("interactive shell loop. return r=%d\n", r);
1084                 return r;
1085             }
1086         }
1087     }
1088
1089     if(!strcmp(argv[0], "kill-server")) {
1090         int fd;
1091         fd = _sdb_connect("host:kill");
1092         if(fd == -1) {
1093             fprintf(stderr,"* server not running *\n");
1094             return 1;
1095         }
1096         return 0;
1097     }
1098 #if 0 /* tizen specific */
1099     if(!strcmp(argv[0], "sideload")) {
1100         if(argc != 2) return usage();
1101         if(sdb_download("sideload", argv[1], 1)) {
1102             return 1;
1103         } else {
1104             return 0;
1105         }
1106     }
1107 #endif
1108     if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
1109             || !strcmp(argv[0], "reboot-bootloader")
1110             || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
1111             || !strcmp(argv[0], "root")) {
1112         char command[100];
1113         if (!strcmp(argv[0], "reboot-bootloader"))
1114             snprintf(command, sizeof(command), "reboot:bootloader");
1115         else if (argc > 1)
1116             snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
1117         else
1118             snprintf(command, sizeof(command), "%s:", argv[0]);
1119         int fd = sdb_connect(command);
1120         if(fd >= 0) {
1121             read_and_dump(fd);
1122             sdb_close(fd);
1123             return 0;
1124         }
1125         fprintf(stderr,"error: %s\n", sdb_error());
1126         return 1;
1127     }
1128
1129     if(!strcmp(argv[0], "bugreport")) {
1130         if (argc != 1) return usage();
1131         do_cmd(ttype, serial, "shell", "bugreport", 0);
1132         return 0;
1133     }
1134
1135     /* sdb_command() wrapper commands */
1136
1137     if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
1138         char* service = argv[0];
1139         if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
1140             if (ttype == kTransportUsb) {
1141                 service = "wait-for-usb";
1142             } else if (ttype == kTransportLocal) {
1143                 service = "wait-for-local";
1144             } else {
1145                 service = "wait-for-any";
1146             }
1147         }
1148
1149         format_host_command(buf, sizeof buf, service, ttype, serial);
1150
1151         if (sdb_command(buf)) {
1152             D("failure: %s *\n",sdb_error());
1153             fprintf(stderr,"error: %s\n", sdb_error());
1154             return 1;
1155         }
1156
1157         /* Allow a command to be run after wait-for-device,
1158             * e.g. 'sdb wait-for-device shell'.
1159             */
1160         if(argc > 1) {
1161             argc--;
1162             argv++;
1163             goto top;
1164         }
1165         return 0;
1166     }
1167
1168     if(!strcmp(argv[0], "forward")) {
1169         if(argc != 3) return usage();
1170         if (serial) {
1171             snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial, argv[1], argv[2]);
1172         } else if (ttype == kTransportUsb) {
1173             snprintf(buf, sizeof buf, "host-usb:forward:%s;%s", argv[1], argv[2]);
1174         } else if (ttype == kTransportLocal) {
1175             snprintf(buf, sizeof buf, "host-local:forward:%s;%s", argv[1], argv[2]);
1176         } else {
1177             snprintf(buf, sizeof buf, "host:forward:%s;%s", argv[1], argv[2]);
1178         }
1179         if(sdb_command(buf)) {
1180             fprintf(stderr,"error: %s\n", sdb_error());
1181             return 1;
1182         }
1183         return 0;
1184     }
1185
1186     /* do_sync_*() commands */
1187
1188     if(!strcmp(argv[0], "ls")) {
1189         if(argc != 2) return usage();
1190         return do_sync_ls(argv[1]);
1191     }
1192
1193     if(!strcmp(argv[0], "push")) {
1194         int i=0;
1195         int utf8=0;
1196
1197         if(argc < 3) return usage();
1198         if (argv[argc-1][0] == '-') {
1199             if (!strcmp(argv[argc-1], "--with-utf8")) {
1200                 utf8 = 1;
1201                 argc = argc - 1;
1202             } else {
1203                 return usage();
1204             }
1205         }
1206         for (i=1; i<argc-1; i++) {
1207             do_sync_push(argv[i], argv[argc-1], 0 /* no verify APK */, utf8);
1208         }
1209         return 0;
1210     }
1211
1212     if(!strcmp(argv[0], "install")) {
1213         if(argc != 2) return usage();
1214
1215         return install_app_sdb(argv[1]);
1216     }
1217
1218     if(!strcmp(argv[0], "uninstall")) {
1219         if(argc != 2) return usage();
1220
1221         return uninstall_app_sdb(argv[1]);
1222     }
1223
1224     if(!strcmp(argv[0], "pull")) {
1225         if (argc == 2) {
1226             return do_sync_pull(argv[1], ".");
1227         } else if (argc == 3) {
1228             return do_sync_pull(argv[1], argv[2]);
1229         } else {
1230             return usage();
1231         }
1232     }
1233
1234     if(!strcmp(argv[0], "install")) {
1235         if (argc < 2) return usage();
1236         return install_app(ttype, serial, argc, argv);
1237     }
1238
1239     if(!strcmp(argv[0], "uninstall")) {
1240         if (argc < 2) return usage();
1241         return uninstall_app(ttype, serial, argc, argv);
1242     }
1243
1244     if(!strcmp(argv[0], "launch")) {
1245         //if (argc < 2) return usage();
1246         return launch_app(ttype, serial, argc, argv);
1247     }
1248
1249     if(!strcmp(argv[0], "sync")) {
1250         char *srcarg, *android_srcpath, *data_srcpath;
1251         int listonly = 0;
1252
1253         int ret;
1254         if(argc < 2) {
1255             /* No local path was specified. */
1256             srcarg = NULL;
1257         } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
1258             listonly = 1;
1259             if (argc == 3) {
1260                 srcarg = argv[2];
1261             } else {
1262                 srcarg = NULL;
1263             }
1264         } else if(argc == 2) {
1265             /* A local path or "android"/"data" arg was specified. */
1266             srcarg = argv[1];
1267         } else {
1268             return usage();
1269         }
1270         ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
1271         if(ret != 0) return usage();
1272
1273         if(android_srcpath != NULL)
1274             ret = do_sync_sync(android_srcpath, "/system", listonly);
1275         if(ret == 0 && data_srcpath != NULL)
1276             ret = do_sync_sync(data_srcpath, "/data", listonly);
1277
1278         free(android_srcpath);
1279         free(data_srcpath);
1280         return ret;
1281     }
1282
1283     /* passthrough commands */
1284
1285     if(!strcmp(argv[0],"get-state") ||
1286         !strcmp(argv[0],"get-serialno"))
1287     {
1288         char *tmp;
1289
1290         format_host_command(buf, sizeof buf, argv[0], ttype, serial);
1291         tmp = sdb_query(buf);
1292         if(tmp) {
1293             printf("%s\n", tmp);
1294             return 0;
1295         } else {
1296             return 1;
1297         }
1298     }
1299
1300     /* other commands */
1301
1302     if(!strcmp(argv[0],"status-window")) {
1303         status_window(ttype, serial);
1304         return 0;
1305     }
1306
1307     if(!strcmp(argv[0],"dlog")) {
1308         return logcat(ttype, serial, argc, argv);
1309     }
1310
1311     if(!strcmp(argv[0],"ppp")) {
1312         return ppp(argc, argv);
1313     }
1314
1315     if (!strcmp(argv[0], "start-server")) {
1316         return sdb_connect("host:start-server");
1317     }
1318
1319     if (!strcmp(argv[0], "backup")) {
1320         return backup(argc, argv);
1321     }
1322
1323     if (!strcmp(argv[0], "restore")) {
1324         return restore(argc, argv);
1325     }
1326
1327     if (!strcmp(argv[0], "jdwp")) {
1328         int  fd = sdb_connect("jdwp");
1329         if (fd >= 0) {
1330             read_and_dump(fd);
1331             sdb_close(fd);
1332             return 0;
1333         } else {
1334             fprintf(stderr, "error: %s\n", sdb_error());
1335             return -1;
1336         }
1337     }
1338
1339     /* "sdb /?" is a common idiom under Windows */
1340     if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
1341         help();
1342         return 0;
1343     }
1344
1345     if(!strcmp(argv[0], "version")) {
1346         if (ttype == kTransportUsb || ttype == kTransportLocal) {
1347             version_sdbd(ttype, serial);
1348         } else {
1349             version(stdout);
1350         }
1351         return 0;
1352     }
1353
1354     usage();
1355     return 1;
1356 }
1357
1358 static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
1359 {
1360     char *argv[16];
1361     int argc;
1362     va_list ap;
1363
1364     va_start(ap, cmd);
1365     argc = 0;
1366
1367     if (serial) {
1368         argv[argc++] = "-s";
1369         argv[argc++] = serial;
1370     } else if (ttype == kTransportUsb) {
1371         argv[argc++] = "-d";
1372     } else if (ttype == kTransportLocal) {
1373         argv[argc++] = "-e";
1374     }
1375
1376     argv[argc++] = cmd;
1377     while((argv[argc] = va_arg(ap, char*)) != 0) {
1378         argc++;
1379     }
1380     va_end(ap);
1381
1382 #if 0
1383     int n;
1384     fprintf(stderr,"argc = %d\n",argc);
1385     for(n = 0; n < argc; n++) {
1386         fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
1387     }
1388 #endif
1389
1390     return sdb_commandline(argc, argv);
1391 }
1392
1393 int find_sync_dirs(const char *srcarg,
1394         char **android_srcdir_out, char **data_srcdir_out)
1395 {
1396     char *android_srcdir, *data_srcdir;
1397
1398     if(srcarg == NULL) {
1399         android_srcdir = product_file("system");
1400         data_srcdir = product_file("data");
1401     } else {
1402         /* srcarg may be "data", "system" or NULL.
1403          * if srcarg is NULL, then both data and system are synced
1404          */
1405         if(strcmp(srcarg, "system") == 0) {
1406             android_srcdir = product_file("system");
1407             data_srcdir = NULL;
1408         } else if(strcmp(srcarg, "data") == 0) {
1409             android_srcdir = NULL;
1410             data_srcdir = product_file("data");
1411         } else {
1412             /* It's not "system" or "data".
1413              */
1414             return 1;
1415         }
1416     }
1417
1418     if(android_srcdir_out != NULL)
1419         *android_srcdir_out = android_srcdir;
1420     else
1421         free(android_srcdir);
1422
1423     if(data_srcdir_out != NULL)
1424         *data_srcdir_out = data_srcdir;
1425     else
1426         free(data_srcdir);
1427
1428     return 0;
1429 }
1430
1431 static int pm_command(transport_type transport, char* serial,
1432                       int argc, char** argv)
1433 {
1434     char buf[4096];
1435
1436     snprintf(buf, sizeof(buf), "shell:pm");
1437
1438     while(argc-- > 0) {
1439         char *quoted;
1440
1441         quoted = dupAndQuote(*argv++);
1442
1443         strncat(buf, " ", sizeof(buf)-1);
1444         strncat(buf, quoted, sizeof(buf)-1);
1445         free(quoted);
1446     }
1447
1448     send_shellcommand(transport, serial, buf);
1449     return 0;
1450 }
1451
1452 int sdb_command2(const char* cmd) {
1453     int result = sdb_connect(cmd);
1454
1455     if(result < 0) {
1456         return result;
1457     }
1458
1459     D("about to read_and_dump(fd=%d)\n", result);
1460     read_and_dump(result);
1461     D("read_and_dump() done.\n");
1462     sdb_close(result);
1463
1464     return 0;
1465 }
1466
1467 int install_app_sdb(const char *srcpath) {
1468     D("Install start\n");
1469     const char * APP_DEST = tzplatform_mkpath(TZ_SYS_RW_APP,"PKGS/%s");
1470     const char* filename = sdb_dirstop(srcpath);
1471     char destination[PATH_MAX];
1472
1473     if (filename) {
1474         filename++;
1475         snprintf(destination, sizeof destination, APP_DEST, filename);
1476     } else {
1477         snprintf(destination, sizeof destination, APP_DEST, srcpath);
1478     }
1479
1480     D("Push file: %s to %s\n", srcpath, destination);
1481     int result = do_sync_push(srcpath, destination, 0, 0);
1482
1483     if(result < 0) {
1484         fprintf(stderr, "error: %s\n", sdb_error());
1485         return -1;
1486     }
1487
1488     const char* SHELL_INSTALL_CMD ="shell:pkgcmd -i -t tpk -p %s -q";
1489     char full_cmd[PATH_MAX];
1490     snprintf(full_cmd, sizeof full_cmd, SHELL_INSTALL_CMD, destination);
1491     D("Install command: %s\n", full_cmd);
1492     result = sdb_command2(full_cmd);
1493
1494     if(result < 0) {
1495         fprintf(stderr, "error: %s\n", sdb_error());
1496         return result;
1497     }
1498
1499     const char* SHELL_REMOVE_CMD = "shell:rm %s";
1500     snprintf(full_cmd, sizeof full_cmd, SHELL_REMOVE_CMD, destination);
1501     D("Remove file command: %s\n", full_cmd);
1502     result = sdb_command2(full_cmd);
1503
1504     if(result < 0) {
1505         fprintf(stderr, "error: %s\n", sdb_error());
1506         return result;
1507     }
1508
1509     return 0;
1510 }
1511
1512 int uninstall_app_sdb(const char *appid) {
1513     const char* SHELL_UNINSTALL_CMD ="shell:pkgcmd -u -t tpk -n %s -q";
1514     char full_cmd[PATH_MAX];
1515     int result = 0;
1516     snprintf(full_cmd, sizeof full_cmd, SHELL_UNINSTALL_CMD, appid);
1517     result = sdb_command2(full_cmd);
1518
1519     if(result < 0) {
1520         fprintf(stderr, "error: %s\n", sdb_error());
1521         return result;
1522     }
1523
1524     return 0;
1525 }
1526
1527 int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
1528 {
1529     /* if the user choose the -k option, we refuse to do it until devices are
1530        out with the option to uninstall the remaining data somehow (sdb/ui) */
1531     if (argc == 3 && strcmp(argv[1], "-k") == 0)
1532     {
1533         printf(
1534             "The -k option uninstalls the application while retaining the data/cache.\n"
1535             "At the moment, there is no way to remove the remaining data.\n"
1536             "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
1537             "If you truly wish to continue, execute 'sdb shell pm uninstall -k %s'\n", argv[2]);
1538         return -1;
1539     }
1540
1541     /* 'sdb uninstall' takes the same arguments as 'pm uninstall' on device */
1542     return pm_command(transport, serial, argc, argv);
1543 }
1544
1545 static int delete_file(transport_type transport, char* serial, char* filename)
1546 {
1547     char buf[4096];
1548     char* quoted;
1549
1550     snprintf(buf, sizeof(buf), "shell:rm ");
1551     quoted = dupAndQuote(filename);
1552     strncat(buf, quoted, sizeof(buf)-1);
1553     free(quoted);
1554
1555     send_shellcommand(transport, serial, buf);
1556     return 0;
1557 }
1558
1559 const char* get_basename(const char* filename)
1560 {
1561     const char* basename = sdb_dirstop(filename);
1562     if (basename) {
1563         basename++;
1564         return basename;
1565     } else {
1566         return filename;
1567     }
1568 }
1569
1570 static int check_file(const char* filename)
1571 {
1572     struct stat st;
1573
1574     if (filename == NULL) {
1575         return 0;
1576     }
1577
1578     if (stat(filename, &st) != 0) {
1579         fprintf(stderr, "can't find '%s' to install\n", filename);
1580         return 1;
1581     }
1582
1583     if (!S_ISREG(st.st_mode)) {
1584         fprintf(stderr, "can't install '%s' because it's not a file\n", filename);
1585         return 1;
1586     }
1587
1588     return 0;
1589 }
1590
1591 int install_app(transport_type transport, char* serial, int argc, char** argv)
1592 {
1593     static const char *const DATA_DEST = "/data/local/tmp/%s";
1594     static const char *const SD_DEST = "/sdcard/tmp/%s";
1595     const char* where = DATA_DEST;
1596     char apk_dest[PATH_MAX];
1597     char verification_dest[PATH_MAX];
1598     char* apk_file;
1599     char* verification_file = NULL;
1600     int file_arg = -1;
1601     int err;
1602     int i;
1603     int verify_apk = 1;
1604
1605     for (i = 1; i < argc; i++) {
1606         if (*argv[i] != '-') {
1607             file_arg = i;
1608             break;
1609         } else if (!strcmp(argv[i], "-i")) {
1610             // Skip the installer package name.
1611             i++;
1612         } else if (!strcmp(argv[i], "-s")) {
1613             where = SD_DEST;
1614         } else if (!strcmp(argv[i], "--algo")) {
1615             verify_apk = 0;
1616             i++;
1617         } else if (!strcmp(argv[i], "--iv")) {
1618             verify_apk = 0;
1619             i++;
1620         } else if (!strcmp(argv[i], "--key")) {
1621             verify_apk = 0;
1622             i++;
1623         }
1624     }
1625
1626     if (file_arg < 0) {
1627         fprintf(stderr, "can't find filename in arguments\n");
1628         return 1;
1629     } else if (file_arg + 2 < argc) {
1630         fprintf(stderr, "too many files specified; only takes APK file and verifier file\n");
1631         return 1;
1632     }
1633
1634     apk_file = argv[file_arg];
1635
1636     if (file_arg != argc - 1) {
1637         verification_file = argv[file_arg + 1];
1638     }
1639
1640     if (check_file(apk_file) || check_file(verification_file)) {
1641         return 1;
1642     }
1643
1644     snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
1645     if (verification_file != NULL) {
1646         snprintf(verification_dest, sizeof(verification_dest), where, get_basename(verification_file));
1647
1648         if (!strcmp(apk_dest, verification_dest)) {
1649             fprintf(stderr, "APK and verification file can't have the same name\n");
1650             return 1;
1651         }
1652     }
1653
1654     err = do_sync_push(apk_file, apk_dest, verify_apk, 0);
1655     if (err) {
1656         goto cleanup_apk;
1657     } else {
1658         argv[file_arg] = apk_dest; /* destination name, not source location */
1659     }
1660
1661     if (verification_file != NULL) {
1662         err = do_sync_push(verification_file, verification_dest, 0 /* no verify APK */, 0);
1663         if (err) {
1664             goto cleanup_apk;
1665         } else {
1666             argv[file_arg + 1] = verification_dest; /* destination name, not source location */
1667         }
1668     }
1669
1670     pm_command(transport, serial, argc, argv);
1671
1672 cleanup_apk:
1673     if (verification_file != NULL) {
1674         delete_file(transport, serial, verification_dest);
1675     }
1676
1677     delete_file(transport, serial, apk_dest);
1678
1679     return err;
1680 }
1681
1682 int launch_app(transport_type transport, char* serial, int argc, char** argv)
1683 {
1684     static const char *const SHELL_LAUNCH_CMD = "shell:/usr/bin/sdk_launch_app ";
1685     char full_cmd[PATH_MAX];
1686     int i;
1687     int result = 0;
1688
1689     snprintf(full_cmd, sizeof full_cmd, "%s", SHELL_LAUNCH_CMD);
1690
1691     //TODO: check argument validation
1692
1693     for (i=1 ; i<argc ; i++) {
1694         strncat(full_cmd, " ", sizeof(full_cmd)-strlen(" ")-1);
1695         strncat(full_cmd, argv[i], sizeof(full_cmd)-strlen(argv[i])-1);
1696     }
1697
1698     D("launch command: %s\n", full_cmd);
1699     result = sdb_command2(full_cmd);
1700
1701     if(result < 0) {
1702         fprintf(stderr, "error: %s\n", sdb_error());
1703         return result;
1704     }
1705
1706     if(result < 0) {
1707         fprintf(stderr, "error: %s\n", sdb_error());
1708         return result;
1709     }
1710     sdb_close(result);
1711     return 0;
1712
1713 }
1714
1715
1716 void version_sdbd(transport_type ttype, char* serial) {
1717     char* VERSION_QUERY ="shell:rpm -qa | grep sdbd";
1718     send_shellcommand(ttype, serial, VERSION_QUERY);
1719 }