commandline.c revision 3523412f43ec616775a73f5fb8a2615370a1ee3a
1/*
2 * Copyright (C) 2007 The Android Open Source Project
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_ADB
36#include "adb.h"
37#include "adb_client.h"
38#include "file_sync_service.h"
39
40#ifdef SH_HISTORY
41#include "shlist.h"
42#include "history.h"
43#endif
44
45enum {
46    IGNORE_DATA,
47    WIPE_DATA,
48    FLASH_DATA
49};
50
51static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
52
53void get_my_path(char *s, size_t maxLen);
54int find_sync_dirs(const char *srcarg,
55        char **android_srcdir_out, char **data_srcdir_out);
56int install_app(transport_type transport, char* serial, int argc, char** argv);
57int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
58
59static const char *gProductOutPath = NULL;
60
61static char *product_file(const char *extra)
62{
63    int n;
64    char *x;
65
66    if (gProductOutPath == NULL) {
67        fprintf(stderr, "adb: Product directory not specified; "
68                "use -p or define ANDROID_PRODUCT_OUT\n");
69        exit(1);
70    }
71
72    n = strlen(gProductOutPath) + strlen(extra) + 2;
73    x = malloc(n);
74    if (x == 0) {
75        fprintf(stderr, "adb: Out of memory (product_file())\n");
76        exit(1);
77    }
78
79    snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
80    return x;
81}
82
83void version(FILE * out) {
84    fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
85         ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
86}
87
88void help()
89{
90    version(stderr);
91
92    fprintf(stderr,
93        "\n"
94        " -d                            - directs command to the only connected USB device\n"
95        "                                 returns an error if more than one USB device is present.\n"
96        " -e                            - directs command to the only running emulator.\n"
97        "                                 returns an error if more than one emulator is running.\n"
98        " -s <serial number>            - directs command to the USB device or emulator with\n"
99        "                                 the given serial number. Overrides ANDROID_SERIAL\n"
100        "                                 environment variable.\n"
101        " -p <product name or path>     - simple product name like 'sooner', or\n"
102        "                                 a relative/absolute path to a product\n"
103        "                                 out directory like 'out/target/product/sooner'.\n"
104        "                                 If -p is not specified, the ANDROID_PRODUCT_OUT\n"
105        "                                 environment variable is used, which must\n"
106        "                                 be an absolute path.\n"
107        " devices                       - list all connected devices\n"
108        " connect <host>:<port>         - connect to a device via TCP/IP\n"
109        " disconnect <host>:<port>      - disconnect from a TCP/IP device\n"
110        "\n"
111        "device commands:\n"
112        "  adb push <local> <remote>    - copy file/dir to device\n"
113        "  adb pull <remote> [<local>]  - copy file/dir from device\n"
114        "  adb sync [ <directory> ]     - copy host->device only if changed\n"
115        "                                 (-l means list but don't copy)\n"
116        "                                 (see 'adb help all')\n"
117        "  adb shell                    - run remote shell interactively\n"
118        "  adb shell <command>          - run remote shell command\n"
119        "  adb emu <command>            - run emulator console command\n"
120        "  adb logcat [ <filter-spec> ] - View device log\n"
121        "  adb forward <local> <remote> - forward socket connections\n"
122        "                                 forward specs are one of: \n"
123        "                                   tcp:<port>\n"
124        "                                   localabstract:<unix domain socket name>\n"
125        "                                   localreserved:<unix domain socket name>\n"
126        "                                   localfilesystem:<unix domain socket name>\n"
127        "                                   dev:<character device name>\n"
128        "                                   jdwp:<process pid> (remote only)\n"
129        "  adb jdwp                     - list PIDs of processes hosting a JDWP transport\n"
130        "  adb install [-l] [-r] [-s] <file> - push this package file to the device and install it\n"
131        "                                 ('-l' means forward-lock the app)\n"
132        "                                 ('-r' means reinstall the app, keeping its data)\n"
133        "                                 ('-s' means install on SD card instead of internal storage)\n"
134        "  adb uninstall [-k] <package> - remove this app package from the device\n"
135        "                                 ('-k' means keep the data and cache directories)\n"
136        "  adb bugreport                - return all information from the device\n"
137        "                                 that should be included in a bug report.\n"
138        "\n"
139        "  adb help                     - show this help message\n"
140        "  adb version                  - show version num\n"
141        "\n"
142        "DATAOPTS:\n"
143        " (no option)                   - don't touch the data partition\n"
144        "  -w                           - wipe the data partition\n"
145        "  -d                           - flash the data partition\n"
146        "\n"
147        "scripting:\n"
148        "  adb wait-for-device          - block until device is online\n"
149        "  adb start-server             - ensure that there is a server running\n"
150        "  adb kill-server              - kill the server if it is running\n"
151        "  adb get-state                - prints: offline | bootloader | device\n"
152        "  adb get-serialno             - prints: <serial-number>\n"
153        "  adb status-window            - continuously print device status for a specified device\n"
154        "  adb remount                  - remounts the /system partition on the device read-write\n"
155        "  adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
156        "  adb reboot-bootloader        - reboots the device into the bootloader\n"
157        "  adb root                     - restarts the adbd daemon with root permissions\n"
158        "  adb usb                      - restarts the adbd daemon listening on USB\n"
159        "  adb tcpip <port>             - restarts the adbd daemon listening on TCP on the specified port"
160        "\n"
161        "networking:\n"
162        "  adb ppp <tty> [parameters]   - Run PPP over USB.\n"
163        " Note: you should not automatically start a PPP connection.\n"
164        " <tty> refers to the tty for PPP stream. Eg. dev:/dev/omap_csmi_tty1\n"
165        " [parameters] - Eg. defaultroute debug dump local notty usepeerdns\n"
166        "\n"
167        "adb sync notes: adb sync [ <directory> ]\n"
168        "  <localdir> can be interpreted in several ways:\n"
169        "\n"
170        "  - If <directory> is not specified, both /system and /data partitions will be updated.\n"
171        "\n"
172        "  - If it is \"system\" or \"data\", only the corresponding partition\n"
173        "    is updated.\n"
174        );
175}
176
177int usage()
178{
179    help();
180    return 1;
181}
182
183#ifdef HAVE_TERMIO_H
184static struct termios tio_save;
185
186static void stdin_raw_init(int fd)
187{
188    struct termios tio;
189
190    if(tcgetattr(fd, &tio)) return;
191    if(tcgetattr(fd, &tio_save)) return;
192
193    tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
194
195        /* no timeout but request at least one character per read */
196    tio.c_cc[VTIME] = 0;
197    tio.c_cc[VMIN] = 1;
198
199    tcsetattr(fd, TCSANOW, &tio);
200    tcflush(fd, TCIFLUSH);
201}
202
203static void stdin_raw_restore(int fd)
204{
205    tcsetattr(fd, TCSANOW, &tio_save);
206    tcflush(fd, TCIFLUSH);
207}
208#endif
209
210static void read_and_dump(int fd)
211{
212    char buf[4096];
213    int len;
214
215    while(fd >= 0) {
216        len = adb_read(fd, buf, 4096);
217        if(len == 0) {
218            break;
219        }
220
221        if(len < 0) {
222            if(errno == EINTR) continue;
223            break;
224        }
225        fwrite(buf, 1, len, stdout);
226        fflush(stdout);
227    }
228}
229
230#ifdef SH_HISTORY
231int shItemCmp( void *val, void *idata )
232{
233    return( (strcmp( val, idata ) == 0) );
234}
235#endif
236
237static void *stdin_read_thread(void *x)
238{
239    int fd, fdi;
240    unsigned char buf[1024];
241#ifdef SH_HISTORY
242    unsigned char realbuf[1024], *buf_ptr;
243    SHLIST history;
244    SHLIST *item = &history;
245    int cmdlen = 0, ins_flag = 0;
246#endif
247    int r, n;
248    int state = 0;
249
250    int *fds = (int*) x;
251    fd = fds[0];
252    fdi = fds[1];
253    free(fds);
254
255#ifdef SH_HISTORY
256    shListInitList( &history );
257#endif
258    for(;;) {
259        /* fdi is really the client's stdin, so use read, not adb_read here */
260        r = unix_read(fdi, buf, 1024);
261        if(r == 0) break;
262        if(r < 0) {
263            if(errno == EINTR) continue;
264            break;
265        }
266#ifdef SH_HISTORY
267        if( (r == 3) &&                                       /* Arrow processing */
268            (memcmp( (void *)buf, SH_ARROW_ANY, 2 ) == 0) ) {
269            switch( buf[2] ) {
270                case SH_ARROW_UP:
271                    item = shListGetNextItem( &history, item );
272                    break;
273                case SH_ARROW_DOWN:
274                    item = shListGetPrevItem( &history, item );
275                    break;
276                default:
277                    item = NULL;
278                    break;
279            }
280            memset( buf, SH_DEL_CHAR, cmdlen );
281            if( item != NULL ) {
282                n = snprintf( (char *)(&buf[cmdlen]), sizeof buf - cmdlen, "%s", (char *)(item->data) );
283                memcpy( realbuf, item->data, n );
284            }
285            else { /* Clean buffer */
286                item = &history;
287                n = 0;
288            }
289            r = n + cmdlen;
290            cmdlen = n;
291            ins_flag = 0;
292            if( r == 0 )
293                continue;
294        }
295        else {
296#endif
297            for(n = 0; n < r; n++){
298                switch(buf[n]) {
299                case '\n':
300#ifdef SH_HISTORY
301                    if( ins_flag && (SH_BLANK_CHAR <= realbuf[0]) ) {
302                        buf_ptr = malloc(cmdlen + 1);
303                        if( buf_ptr != NULL ) {
304                            memcpy( buf_ptr, realbuf, cmdlen );
305                            buf_ptr[cmdlen] = '\0';
306                            if( (item = shListFindItem( &history, (void *)buf_ptr, shItemCmp )) == NULL ) {
307                                shListInsFirstItem( &history, (void *)buf_ptr );
308                                item = &history;
309                            }
310                        }
311                    }
312                    cmdlen = 0;
313                    ins_flag = 0;
314#endif
315                    state = 1;
316                    break;
317                case '\r':
318                    state = 1;
319                    break;
320                case '~':
321                    if(state == 1) state++;
322                    break;
323                case '.':
324                    if(state == 2) {
325                        fprintf(stderr,"\n* disconnect *\n");
326    #ifdef HAVE_TERMIO_H
327                        stdin_raw_restore(fdi);
328    #endif
329                        exit(0);
330                    }
331                default:
332#ifdef SH_HISTORY
333                    if( buf[n] == SH_DEL_CHAR ) {
334                        if( cmdlen > 0 )
335                            cmdlen--;
336                    }
337                    else {
338                        realbuf[cmdlen] = buf[n];
339                        cmdlen++;
340                    }
341                    ins_flag = 1;
342#endif
343                    state = 0;
344                }
345            }
346#ifdef SH_HISTORY
347        }
348#endif
349        r = adb_write(fd, buf, r);
350        if(r <= 0) {
351            break;
352        }
353    }
354#ifdef SH_HISTORY
355    shListDelAllItems( &history, (shListFree)free );
356#endif
357    return 0;
358}
359
360int interactive_shell(void)
361{
362    adb_thread_t thr;
363    int fdi, fd;
364    int *fds;
365
366    fd = adb_connect("shell:");
367    if(fd < 0) {
368        fprintf(stderr,"error: %s\n", adb_error());
369        return 1;
370    }
371    fdi = 0; //dup(0);
372
373    fds = malloc(sizeof(int) * 2);
374    fds[0] = fd;
375    fds[1] = fdi;
376
377#ifdef HAVE_TERMIO_H
378    stdin_raw_init(fdi);
379#endif
380    adb_thread_create(&thr, stdin_read_thread, fds);
381    read_and_dump(fd);
382#ifdef HAVE_TERMIO_H
383    stdin_raw_restore(fdi);
384#endif
385    return 0;
386}
387
388
389static void format_host_command(char* buffer, size_t  buflen, const char* command, transport_type ttype, const char* serial)
390{
391    if (serial) {
392        snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
393    } else {
394        const char* prefix = "host";
395        if (ttype == kTransportUsb)
396            prefix = "host-usb";
397        else if (ttype == kTransportLocal)
398            prefix = "host-local";
399
400        snprintf(buffer, buflen, "%s:%s", prefix, command);
401    }
402}
403
404static void status_window(transport_type ttype, const char* serial)
405{
406    char command[4096];
407    char *state = 0;
408    char *laststate = 0;
409
410        /* silence stderr */
411#ifdef _WIN32
412    /* XXX: TODO */
413#else
414    int  fd;
415    fd = unix_open("/dev/null", O_WRONLY);
416    dup2(fd, 2);
417    adb_close(fd);
418#endif
419
420    format_host_command(command, sizeof command, "get-state", ttype, serial);
421
422    for(;;) {
423        adb_sleep_ms(250);
424
425        if(state) {
426            free(state);
427            state = 0;
428        }
429
430        state = adb_query(command);
431
432        if(state) {
433            if(laststate && !strcmp(state,laststate)){
434                continue;
435            } else {
436                if(laststate) free(laststate);
437                laststate = strdup(state);
438            }
439        }
440
441        printf("%c[2J%c[2H", 27, 27);
442        printf("Android Debug Bridge\n");
443        printf("State: %s\n", state ? state : "offline");
444        fflush(stdout);
445    }
446}
447
448/** duplicate string and quote all \ " ( ) chars + space character. */
449static char *
450dupAndQuote(const char *s)
451{
452    const char *ts;
453    size_t alloc_len;
454    char *ret;
455    char *dest;
456
457    ts = s;
458
459    alloc_len = 0;
460
461    for( ;*ts != '\0'; ts++) {
462        alloc_len++;
463        if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
464            alloc_len++;
465        }
466    }
467
468    ret = (char *)malloc(alloc_len + 1);
469
470    ts = s;
471    dest = ret;
472
473    for ( ;*ts != '\0'; ts++) {
474        if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
475            *dest++ = '\\';
476        }
477
478        *dest++ = *ts;
479    }
480
481    *dest++ = '\0';
482
483    return ret;
484}
485
486/**
487 * Run ppp in "notty" mode against a resource listed as the first parameter
488 * eg:
489 *
490 * ppp dev:/dev/omap_csmi_tty0 <ppp options>
491 *
492 */
493int ppp(int argc, char **argv)
494{
495#ifdef HAVE_WIN32_PROC
496    fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
497    return -1;
498#else
499    char *adb_service_name;
500    pid_t pid;
501    int fd;
502
503    if (argc < 2) {
504        fprintf(stderr, "usage: adb %s <adb service name> [ppp opts]\n",
505                argv[0]);
506
507        return 1;
508    }
509
510    adb_service_name = argv[1];
511
512    fd = adb_connect(adb_service_name);
513
514    if(fd < 0) {
515        fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n",
516                adb_service_name, adb_error());
517        return 1;
518    }
519
520    pid = fork();
521
522    if (pid < 0) {
523        perror("from fork()");
524        return 1;
525    } else if (pid == 0) {
526        int err;
527        int i;
528        const char **ppp_args;
529
530        // copy args
531        ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
532        ppp_args[0] = "pppd";
533        for (i = 2 ; i < argc ; i++) {
534            //argv[2] and beyond become ppp_args[1] and beyond
535            ppp_args[i - 1] = argv[i];
536        }
537        ppp_args[i-1] = NULL;
538
539        // child side
540
541        dup2(fd, STDIN_FILENO);
542        dup2(fd, STDOUT_FILENO);
543        adb_close(STDERR_FILENO);
544        adb_close(fd);
545
546        err = execvp("pppd", (char * const *)ppp_args);
547
548        if (err < 0) {
549            perror("execing pppd");
550        }
551        exit(-1);
552    } else {
553        // parent side
554
555        adb_close(fd);
556        return 0;
557    }
558#endif /* !HAVE_WIN32_PROC */
559}
560
561static int send_shellcommand(transport_type transport, char* serial, char* buf)
562{
563    int fd, ret;
564
565    for(;;) {
566        fd = adb_connect(buf);
567        if(fd >= 0)
568            break;
569        fprintf(stderr,"- waiting for device -\n");
570        adb_sleep_ms(1000);
571        do_cmd(transport, serial, "wait-for-device", 0);
572    }
573
574    read_and_dump(fd);
575    ret = adb_close(fd);
576    if (ret)
577        perror("close");
578
579    return ret;
580}
581
582static int logcat(transport_type transport, char* serial, int argc, char **argv)
583{
584    char buf[4096];
585
586    char *log_tags;
587    char *quoted_log_tags;
588
589    log_tags = getenv("ANDROID_LOG_TAGS");
590    quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
591
592    snprintf(buf, sizeof(buf),
593        "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
594        quoted_log_tags);
595
596    free(quoted_log_tags);
597
598    argc -= 1;
599    argv += 1;
600    while(argc-- > 0) {
601        char *quoted;
602
603        quoted = dupAndQuote (*argv++);
604
605        strncat(buf, " ", sizeof(buf)-1);
606        strncat(buf, quoted, sizeof(buf)-1);
607        free(quoted);
608    }
609
610    send_shellcommand(transport, serial, buf);
611    return 0;
612}
613
614#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
615static int top_works(const char *top)
616{
617    if (top != NULL && adb_is_absolute_host_path(top)) {
618        char path_buf[PATH_MAX];
619        snprintf(path_buf, sizeof(path_buf),
620                "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
621        return access(path_buf, F_OK) == 0;
622    }
623    return 0;
624}
625
626static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
627{
628    strcpy(path_buf, indir);
629    while (1) {
630        if (top_works(path_buf)) {
631            return path_buf;
632        }
633        char *s = adb_dirstop(path_buf);
634        if (s != NULL) {
635            *s = '\0';
636        } else {
637            path_buf[0] = '\0';
638            return NULL;
639        }
640    }
641}
642
643static char *find_top(char path_buf[PATH_MAX])
644{
645    char *top = getenv("ANDROID_BUILD_TOP");
646    if (top != NULL && top[0] != '\0') {
647        if (!top_works(top)) {
648            fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
649            return NULL;
650        }
651    } else {
652        top = getenv("TOP");
653        if (top != NULL && top[0] != '\0') {
654            if (!top_works(top)) {
655                fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
656                return NULL;
657            }
658        } else {
659            top = NULL;
660        }
661    }
662
663    if (top != NULL) {
664        /* The environment pointed to a top directory that works.
665         */
666        strcpy(path_buf, top);
667        return path_buf;
668    }
669
670    /* The environment didn't help.  Walk up the tree from the CWD
671     * to see if we can find the top.
672     */
673    char dir[PATH_MAX];
674    top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
675    if (top == NULL) {
676        /* If the CWD isn't under a good-looking top, see if the
677         * executable is.
678         */
679        get_my_path(dir, PATH_MAX);
680        top = find_top_from(dir, path_buf);
681    }
682    return top;
683}
684
685/* <hint> may be:
686 * - A simple product name
687 *   e.g., "sooner"
688TODO: debug?  sooner-debug, sooner:debug?
689 * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
690 *   e.g., "out/target/product/sooner"
691 * - An absolute path to the PRODUCT_OUT dir
692 *   e.g., "/src/device/out/target/product/sooner"
693 *
694 * Given <hint>, try to construct an absolute path to the
695 * ANDROID_PRODUCT_OUT dir.
696 */
697static const char *find_product_out_path(const char *hint)
698{
699    static char path_buf[PATH_MAX];
700
701    if (hint == NULL || hint[0] == '\0') {
702        return NULL;
703    }
704
705    /* If it's already absolute, don't bother doing any work.
706     */
707    if (adb_is_absolute_host_path(hint)) {
708        strcpy(path_buf, hint);
709        return path_buf;
710    }
711
712    /* If there are any slashes in it, assume it's a relative path;
713     * make it absolute.
714     */
715    if (adb_dirstart(hint) != NULL) {
716        if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
717            fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
718            return NULL;
719        }
720        if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
721            fprintf(stderr, "adb: Couldn't assemble path\n");
722            return NULL;
723        }
724        strcat(path_buf, OS_PATH_SEPARATOR_STR);
725        strcat(path_buf, hint);
726        return path_buf;
727    }
728
729    /* It's a string without any slashes.  Try to do something with it.
730     *
731     * Try to find the root of the build tree, and build a PRODUCT_OUT
732     * path from there.
733     */
734    char top_buf[PATH_MAX];
735    const char *top = find_top(top_buf);
736    if (top == NULL) {
737        fprintf(stderr, "adb: Couldn't find top of build tree\n");
738        return NULL;
739    }
740//TODO: if we have a way to indicate debug, look in out/debug/target/...
741    snprintf(path_buf, sizeof(path_buf),
742            "%s" OS_PATH_SEPARATOR_STR
743            "out" OS_PATH_SEPARATOR_STR
744            "target" OS_PATH_SEPARATOR_STR
745            "product" OS_PATH_SEPARATOR_STR
746            "%s", top_buf, hint);
747    if (access(path_buf, F_OK) < 0) {
748        fprintf(stderr, "adb: Couldn't find a product dir "
749                "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
750        return NULL;
751    }
752    return path_buf;
753}
754
755int adb_commandline(int argc, char **argv)
756{
757    char buf[4096];
758    int no_daemon = 0;
759    int is_daemon = 0;
760    int persist = 0;
761    int r;
762    int quote;
763    transport_type ttype = kTransportAny;
764    char* serial = NULL;
765
766        /* If defined, this should be an absolute path to
767         * the directory containing all of the various system images
768         * for a particular product.  If not defined, and the adb
769         * command requires this information, then the user must
770         * specify the path using "-p".
771         */
772    gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
773    if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
774        gProductOutPath = NULL;
775    }
776    // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
777
778    serial = getenv("ANDROID_SERIAL");
779
780        /* modifiers and flags */
781    while(argc > 0) {
782        if(!strcmp(argv[0],"nodaemon")) {
783            no_daemon = 1;
784        } else if (!strcmp(argv[0], "fork-server")) {
785            /* this is a special flag used only when the ADB client launches the ADB Server */
786            is_daemon = 1;
787        } else if(!strcmp(argv[0],"persist")) {
788            persist = 1;
789        } else if(!strncmp(argv[0], "-p", 2)) {
790            const char *product = NULL;
791            if (argv[0][2] == '\0') {
792                if (argc < 2) return usage();
793                product = argv[1];
794                argc--;
795                argv++;
796            } else {
797                product = argv[1] + 2;
798            }
799            gProductOutPath = find_product_out_path(product);
800            if (gProductOutPath == NULL) {
801                fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
802                        product);
803                return usage();
804            }
805        } else if (argv[0][0]=='-' && argv[0][1]=='s') {
806            if (isdigit(argv[0][2])) {
807                serial = argv[0] + 2;
808            } else {
809                if(argc < 2) return usage();
810                serial = argv[1];
811                argc--;
812                argv++;
813            }
814        } else if (!strcmp(argv[0],"-d")) {
815            ttype = kTransportUsb;
816        } else if (!strcmp(argv[0],"-e")) {
817            ttype = kTransportLocal;
818        } else {
819                /* out of recognized modifiers and flags */
820            break;
821        }
822        argc--;
823        argv++;
824    }
825
826    adb_set_transport(ttype, serial);
827
828    if ((argc > 0) && (!strcmp(argv[0],"server"))) {
829        if (no_daemon || is_daemon) {
830            r = adb_main(is_daemon);
831        } else {
832            r = launch_server();
833        }
834        if(r) {
835            fprintf(stderr,"* could not start server *\n");
836        }
837        return r;
838    }
839
840top:
841    if(argc == 0) {
842        return usage();
843    }
844
845    /* adb_connect() commands */
846
847    if(!strcmp(argv[0], "devices")) {
848        char *tmp;
849        snprintf(buf, sizeof buf, "host:%s", argv[0]);
850        tmp = adb_query(buf);
851        if(tmp) {
852            printf("List of devices attached \n");
853            printf("%s\n", tmp);
854            return 0;
855        } else {
856            return 1;
857        }
858    }
859
860    if(!strcmp(argv[0], "connect") || !strcmp(argv[0], "disconnect")) {
861        char *tmp;
862        if (argc != 2) {
863            fprintf(stderr, "Usage: adb %s <host>:<port>\n", argv[0]);
864            return 1;
865        }
866        snprintf(buf, sizeof buf, "host:%s:%s", argv[0], argv[1]);
867        tmp = adb_query(buf);
868        if(tmp) {
869            printf("%s\n", tmp);
870            return 0;
871        } else {
872            return 1;
873        }
874    }
875
876    if (!strcmp(argv[0], "emu")) {
877        return adb_send_emulator_command(argc, argv);
878    }
879
880    if(!strcmp(argv[0], "shell")) {
881        int r;
882        int fd;
883
884        if(argc < 2) {
885            return interactive_shell();
886        }
887
888        snprintf(buf, sizeof buf, "shell:%s", argv[1]);
889        argc -= 2;
890        argv += 2;
891        while(argc-- > 0) {
892            strcat(buf, " ");
893
894            /* quote empty strings and strings with spaces */
895            quote = (**argv == 0 || strchr(*argv, ' '));
896            if (quote)
897            	strcat(buf, "\"");
898            strcat(buf, *argv++);
899            if (quote)
900            	strcat(buf, "\"");
901        }
902
903        for(;;) {
904            fd = adb_connect(buf);
905            if(fd >= 0) {
906                read_and_dump(fd);
907                adb_close(fd);
908                r = 0;
909            } else {
910                fprintf(stderr,"error: %s\n", adb_error());
911                r = -1;
912            }
913
914            if(persist) {
915                fprintf(stderr,"\n- waiting for device -\n");
916                adb_sleep_ms(1000);
917                do_cmd(ttype, serial, "wait-for-device", 0);
918            } else {
919                return r;
920            }
921        }
922    }
923
924    if(!strcmp(argv[0], "kill-server")) {
925        int fd;
926        fd = _adb_connect("host:kill");
927        if(fd == -1) {
928            fprintf(stderr,"* server not running *\n");
929            return 1;
930        }
931        return 0;
932    }
933
934    if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
935            || !strcmp(argv[0], "reboot-bootloader")
936            || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
937            || !strcmp(argv[0], "root")) {
938        char command[100];
939        if (!strcmp(argv[0], "reboot-bootloader"))
940            snprintf(command, sizeof(command), "reboot:bootloader");
941        else if (argc > 1)
942            snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
943        else
944            snprintf(command, sizeof(command), "%s:", argv[0]);
945        int fd = adb_connect(command);
946        if(fd >= 0) {
947            read_and_dump(fd);
948            adb_close(fd);
949            return 0;
950        }
951        fprintf(stderr,"error: %s\n", adb_error());
952        return 1;
953    }
954
955    if(!strcmp(argv[0], "bugreport")) {
956        if (argc != 1) return usage();
957        do_cmd(ttype, serial, "shell", "bugreport", 0);
958        return 0;
959    }
960
961    /* adb_command() wrapper commands */
962
963    if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
964        char* service = argv[0];
965        if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
966            if (ttype == kTransportUsb) {
967                service = "wait-for-usb";
968            } else if (ttype == kTransportLocal) {
969                service = "wait-for-local";
970            } else {
971                service = "wait-for-any";
972            }
973        }
974
975        format_host_command(buf, sizeof buf, service, ttype, serial);
976
977        if (adb_command(buf)) {
978            D("failure: %s *\n",adb_error());
979            fprintf(stderr,"error: %s\n", adb_error());
980            return 1;
981        }
982
983        /* Allow a command to be run after wait-for-device,
984            * e.g. 'adb wait-for-device shell'.
985            */
986        if(argc > 1) {
987            argc--;
988            argv++;
989            goto top;
990        }
991        return 0;
992    }
993
994    if(!strcmp(argv[0], "forward")) {
995        if(argc != 3) return usage();
996        if (serial) {
997            snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial, argv[1], argv[2]);
998        } else if (ttype == kTransportUsb) {
999            snprintf(buf, sizeof buf, "host-usb:forward:%s;%s", argv[1], argv[2]);
1000        } else if (ttype == kTransportLocal) {
1001            snprintf(buf, sizeof buf, "host-local:forward:%s;%s", argv[1], argv[2]);
1002        } else {
1003            snprintf(buf, sizeof buf, "host:forward:%s;%s", argv[1], argv[2]);
1004        }
1005        if(adb_command(buf)) {
1006            fprintf(stderr,"error: %s\n", adb_error());
1007            return 1;
1008        }
1009        return 0;
1010    }
1011
1012    /* do_sync_*() commands */
1013
1014    if(!strcmp(argv[0], "ls")) {
1015        if(argc != 2) return usage();
1016        return do_sync_ls(argv[1]);
1017    }
1018
1019    if(!strcmp(argv[0], "push")) {
1020        if(argc != 3) return usage();
1021        return do_sync_push(argv[1], argv[2], 0 /* no verify APK */);
1022    }
1023
1024    if(!strcmp(argv[0], "pull")) {
1025        if (argc == 2) {
1026            return do_sync_pull(argv[1], ".");
1027        } else if (argc == 3) {
1028            return do_sync_pull(argv[1], argv[2]);
1029        } else {
1030            return usage();
1031        }
1032    }
1033
1034    if(!strcmp(argv[0], "install")) {
1035        if (argc < 2) return usage();
1036        return install_app(ttype, serial, argc, argv);
1037    }
1038
1039    if(!strcmp(argv[0], "uninstall")) {
1040        if (argc < 2) return usage();
1041        return uninstall_app(ttype, serial, argc, argv);
1042    }
1043
1044    if(!strcmp(argv[0], "sync")) {
1045        char *srcarg, *android_srcpath, *data_srcpath;
1046        int listonly = 0;
1047
1048        int ret;
1049        if(argc < 2) {
1050            /* No local path was specified. */
1051            srcarg = NULL;
1052        } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
1053            listonly = 1;
1054            if (argc == 3) {
1055                srcarg = argv[2];
1056            } else {
1057                srcarg = NULL;
1058            }
1059        } else if(argc == 2) {
1060            /* A local path or "android"/"data" arg was specified. */
1061            srcarg = argv[1];
1062        } else {
1063            return usage();
1064        }
1065        ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
1066        if(ret != 0) return usage();
1067
1068        if(android_srcpath != NULL)
1069            ret = do_sync_sync(android_srcpath, "/system", listonly);
1070        if(ret == 0 && data_srcpath != NULL)
1071            ret = do_sync_sync(data_srcpath, "/data", listonly);
1072
1073        free(android_srcpath);
1074        free(data_srcpath);
1075        return ret;
1076    }
1077
1078    /* passthrough commands */
1079
1080    if(!strcmp(argv[0],"get-state") ||
1081        !strcmp(argv[0],"get-serialno"))
1082    {
1083        char *tmp;
1084
1085        format_host_command(buf, sizeof buf, argv[0], ttype, serial);
1086        tmp = adb_query(buf);
1087        if(tmp) {
1088            printf("%s\n", tmp);
1089            return 0;
1090        } else {
1091            return 1;
1092        }
1093    }
1094
1095    /* other commands */
1096
1097    if(!strcmp(argv[0],"status-window")) {
1098        status_window(ttype, serial);
1099        return 0;
1100    }
1101
1102    if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat")) {
1103        return logcat(ttype, serial, argc, argv);
1104    }
1105
1106    if(!strcmp(argv[0],"ppp")) {
1107        return ppp(argc, argv);
1108    }
1109
1110    if (!strcmp(argv[0], "start-server")) {
1111        return adb_connect("host:start-server");
1112    }
1113
1114    if (!strcmp(argv[0], "jdwp")) {
1115        int  fd = adb_connect("jdwp");
1116        if (fd >= 0) {
1117            read_and_dump(fd);
1118            adb_close(fd);
1119            return 0;
1120        } else {
1121            fprintf(stderr, "error: %s\n", adb_error());
1122            return -1;
1123        }
1124    }
1125
1126    /* "adb /?" is a common idiom under Windows */
1127    if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
1128        help();
1129        return 0;
1130    }
1131
1132    if(!strcmp(argv[0], "version")) {
1133        version(stdout);
1134        return 0;
1135    }
1136
1137    usage();
1138    return 1;
1139}
1140
1141static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
1142{
1143    char *argv[16];
1144    int argc;
1145    va_list ap;
1146
1147    va_start(ap, cmd);
1148    argc = 0;
1149
1150    if (serial) {
1151        argv[argc++] = "-s";
1152        argv[argc++] = serial;
1153    } else if (ttype == kTransportUsb) {
1154        argv[argc++] = "-d";
1155    } else if (ttype == kTransportLocal) {
1156        argv[argc++] = "-e";
1157    }
1158
1159    argv[argc++] = cmd;
1160    while((argv[argc] = va_arg(ap, char*)) != 0) argc++;
1161    va_end(ap);
1162
1163#if 0
1164    int n;
1165    fprintf(stderr,"argc = %d\n",argc);
1166    for(n = 0; n < argc; n++) {
1167        fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
1168    }
1169#endif
1170
1171    return adb_commandline(argc, argv);
1172}
1173
1174int find_sync_dirs(const char *srcarg,
1175        char **android_srcdir_out, char **data_srcdir_out)
1176{
1177    char *android_srcdir, *data_srcdir;
1178
1179    if(srcarg == NULL) {
1180        android_srcdir = product_file("system");
1181        data_srcdir = product_file("data");
1182    } else {
1183        /* srcarg may be "data", "system" or NULL.
1184         * if srcarg is NULL, then both data and system are synced
1185         */
1186        if(strcmp(srcarg, "system") == 0) {
1187            android_srcdir = product_file("system");
1188            data_srcdir = NULL;
1189        } else if(strcmp(srcarg, "data") == 0) {
1190            android_srcdir = NULL;
1191            data_srcdir = product_file("data");
1192        } else {
1193            /* It's not "system" or "data".
1194             */
1195            return 1;
1196        }
1197    }
1198
1199    if(android_srcdir_out != NULL)
1200        *android_srcdir_out = android_srcdir;
1201    else
1202        free(android_srcdir);
1203
1204    if(data_srcdir_out != NULL)
1205        *data_srcdir_out = data_srcdir;
1206    else
1207        free(data_srcdir);
1208
1209    return 0;
1210}
1211
1212static int pm_command(transport_type transport, char* serial,
1213                      int argc, char** argv)
1214{
1215    char buf[4096];
1216
1217    snprintf(buf, sizeof(buf), "shell:pm");
1218
1219    while(argc-- > 0) {
1220        char *quoted;
1221
1222        quoted = dupAndQuote(*argv++);
1223
1224        strncat(buf, " ", sizeof(buf)-1);
1225        strncat(buf, quoted, sizeof(buf)-1);
1226        free(quoted);
1227    }
1228
1229    send_shellcommand(transport, serial, buf);
1230    return 0;
1231}
1232
1233int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
1234{
1235    /* if the user choose the -k option, we refuse to do it until devices are
1236       out with the option to uninstall the remaining data somehow (adb/ui) */
1237    if (argc == 3 && strcmp(argv[1], "-k") == 0)
1238    {
1239        printf(
1240            "The -k option uninstalls the application while retaining the data/cache.\n"
1241            "At the moment, there is no way to remove the remaining data.\n"
1242            "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
1243            "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
1244        return -1;
1245    }
1246
1247    /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
1248    return pm_command(transport, serial, argc, argv);
1249}
1250
1251static int delete_file(transport_type transport, char* serial, char* filename)
1252{
1253    char buf[4096];
1254    char* quoted;
1255
1256    snprintf(buf, sizeof(buf), "shell:rm ");
1257    quoted = dupAndQuote(filename);
1258    strncat(buf, quoted, sizeof(buf)-1);
1259    free(quoted);
1260
1261    send_shellcommand(transport, serial, buf);
1262    return 0;
1263}
1264
1265int install_app(transport_type transport, char* serial, int argc, char** argv)
1266{
1267    struct stat st;
1268    int err;
1269    const char *const DATA_DEST = "/data/local/tmp/%s";
1270    const char *const SD_DEST = "/sdcard/tmp/%s";
1271    const char* where = DATA_DEST;
1272    char to[PATH_MAX];
1273    char* filename = argv[argc - 1];
1274    const char* p;
1275    int i;
1276
1277    for (i = 0; i < argc; i++) {
1278        if (!strcmp(argv[i], "-s"))
1279            where = SD_DEST;
1280    }
1281
1282    p = adb_dirstop(filename);
1283    if (p) {
1284        p++;
1285        snprintf(to, sizeof to, where, p);
1286    } else {
1287        snprintf(to, sizeof to, where, filename);
1288    }
1289    if (p[0] == '\0') {
1290    }
1291
1292    err = stat(filename, &st);
1293    if (err != 0) {
1294        fprintf(stderr, "can't find '%s' to install\n", filename);
1295        return 1;
1296    }
1297    if (!S_ISREG(st.st_mode)) {
1298        fprintf(stderr, "can't install '%s' because it's not a file\n",
1299                filename);
1300        return 1;
1301    }
1302
1303    if (!(err = do_sync_push(filename, to, 1 /* verify APK */))) {
1304        /* file in place; tell the Package Manager to install it */
1305        argv[argc - 1] = to;       /* destination name, not source location */
1306        pm_command(transport, serial, argc, argv);
1307        delete_file(transport, serial, to);
1308    }
1309
1310    return err;
1311}
1312