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