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