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