blob: bd71bfeff82a555f65092619cdc3122bfde256bb [file] [log] [blame]
The Android Open Source Project9ca14dc2009-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 Project9ca14dc2009-03-03 19:32:55 -080040static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
41
Alexey Tarasov857f17a2009-10-22 02:55:00 +110042void get_my_path(char *s, size_t maxLen);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080043int find_sync_dirs(const char *srcarg,
44 char **android_srcdir_out, char **data_srcdir_out);
45int install_app(transport_type transport, char* serial, int argc, char** argv);
46int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
47
48static const char *gProductOutPath = NULL;
49
50static char *product_file(const char *extra)
51{
52 int n;
53 char *x;
54
55 if (gProductOutPath == NULL) {
56 fprintf(stderr, "adb: Product directory not specified; "
57 "use -p or define ANDROID_PRODUCT_OUT\n");
58 exit(1);
59 }
60
61 n = strlen(gProductOutPath) + strlen(extra) + 2;
62 x = malloc(n);
63 if (x == 0) {
64 fprintf(stderr, "adb: Out of memory (product_file())\n");
65 exit(1);
66 }
67
68 snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
69 return x;
70}
71
72void version(FILE * out) {
73 fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
74 ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
75}
76
77void help()
78{
79 version(stderr);
80
81 fprintf(stderr,
82 "\n"
83 " -d - directs command to the only connected USB device\n"
84 " returns an error if more than one USB device is present.\n"
85 " -e - directs command to the only running emulator.\n"
86 " returns an error if more than one emulator is running.\n"
87 " -s <serial number> - directs command to the USB device or emulator with\n"
Nick Pellyaf2fe9b2009-05-07 12:48:03 -070088 " the given serial number. Overrides ANDROID_SERIAL\n"
Elliott Hughesec424ad2009-10-07 15:38:53 -070089 " environment variable.\n"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080090 " -p <product name or path> - simple product name like 'sooner', or\n"
91 " a relative/absolute path to a product\n"
92 " out directory like 'out/target/product/sooner'.\n"
93 " If -p is not specified, the ANDROID_PRODUCT_OUT\n"
94 " environment variable is used, which must\n"
95 " be an absolute path.\n"
96 " devices - list all connected devices\n"
Mike Lockwood01c2c302010-05-24 10:44:35 -040097 " connect <host>[:<port>] - connect to a device via TCP/IP\n"
98 " Port 5555 is used by default if no port number is specified.\n"
99 " disconnect [<host>[:<port>]] - disconnect from a TCP/IP device.\n"
100 " Port 5555 is used by default if no port number is specified.\n"
101 " Using this ocmmand with no additional arguments\n"
102 " will disconnect from all connected TCP/IP devices.\n"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800103 "\n"
104 "device commands:\n"
105 " adb push <local> <remote> - copy file/dir to device\n"
Joe Onorato23595b02010-01-05 13:42:25 -0800106 " adb pull <remote> [<local>] - copy file/dir from device\n"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800107 " adb sync [ <directory> ] - copy host->device only if changed\n"
Anthony Newnamdd2db142010-02-22 08:36:49 -0600108 " (-l means list but don't copy)\n"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800109 " (see 'adb help all')\n"
110 " adb shell - run remote shell interactively\n"
111 " adb shell <command> - run remote shell command\n"
112 " adb emu <command> - run emulator console command\n"
113 " adb logcat [ <filter-spec> ] - View device log\n"
114 " adb forward <local> <remote> - forward socket connections\n"
115 " forward specs are one of: \n"
116 " tcp:<port>\n"
117 " localabstract:<unix domain socket name>\n"
118 " localreserved:<unix domain socket name>\n"
119 " localfilesystem:<unix domain socket name>\n"
120 " dev:<character device name>\n"
121 " jdwp:<process pid> (remote only)\n"
122 " adb jdwp - list PIDs of processes hosting a JDWP transport\n"
Mike Lockwood4cc5c012010-02-19 17:53:27 -0500123 " adb install [-l] [-r] [-s] <file> - push this package file to the device and install it\n"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800124 " ('-l' means forward-lock the app)\n"
125 " ('-r' means reinstall the app, keeping its data)\n"
Mike Lockwood4cc5c012010-02-19 17:53:27 -0500126 " ('-s' means install on SD card instead of internal storage)\n"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800127 " adb uninstall [-k] <package> - remove this app package from the device\n"
128 " ('-k' means keep the data and cache directories)\n"
129 " adb bugreport - return all information from the device\n"
130 " that should be included in a bug report.\n"
131 "\n"
132 " adb help - show this help message\n"
133 " adb version - show version num\n"
134 "\n"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800135 "scripting:\n"
136 " adb wait-for-device - block until device is online\n"
137 " adb start-server - ensure that there is a server running\n"
138 " adb kill-server - kill the server if it is running\n"
139 " adb get-state - prints: offline | bootloader | device\n"
140 " adb get-serialno - prints: <serial-number>\n"
141 " adb status-window - continuously print device status for a specified device\n"
142 " adb remount - remounts the /system partition on the device read-write\n"
Mike Lockwood12a35ea2009-08-04 20:37:51 -0400143 " adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
Romain Guyf925d912009-12-14 14:42:17 -0800144 " adb reboot-bootloader - reboots the device into the bootloader\n"
Mike Lockwood26b88e32009-08-24 15:58:40 -0700145 " adb root - restarts the adbd daemon with root permissions\n"
Romain Guyf925d912009-12-14 14:42:17 -0800146 " adb usb - restarts the adbd daemon listening on USB\n"
Mike Lockwood26b88e32009-08-24 15:58:40 -0700147 " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800148 "\n"
149 "networking:\n"
150 " adb ppp <tty> [parameters] - Run PPP over USB.\n"
Kenny Rootf8eb5782009-06-08 14:40:30 -0500151 " Note: you should not automatically start a PPP connection.\n"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800152 " <tty> refers to the tty for PPP stream. Eg. dev:/dev/omap_csmi_tty1\n"
153 " [parameters] - Eg. defaultroute debug dump local notty usepeerdns\n"
154 "\n"
155 "adb sync notes: adb sync [ <directory> ]\n"
156 " <localdir> can be interpreted in several ways:\n"
157 "\n"
158 " - If <directory> is not specified, both /system and /data partitions will be updated.\n"
159 "\n"
160 " - If it is \"system\" or \"data\", only the corresponding partition\n"
161 " is updated.\n"
Tim1b29ed32010-02-16 20:18:29 +0000162 "\n"
163 "environmental variables:\n"
164 " ADB_TRACE - Print debug information. A comma separated list of the following values\n"
165 " 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n"
166 " ANDROID_SERIAL - The serial number to connect to. -s takes priority over this if given.\n"
167 " ANDROID_LOG_TAGS - When used with the logcat option, only these debug tags are printed.\n"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800168 );
169}
170
171int usage()
172{
173 help();
174 return 1;
175}
176
177#ifdef HAVE_TERMIO_H
178static struct termios tio_save;
179
180static void stdin_raw_init(int fd)
181{
182 struct termios tio;
183
184 if(tcgetattr(fd, &tio)) return;
185 if(tcgetattr(fd, &tio_save)) return;
186
187 tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
188
189 /* no timeout but request at least one character per read */
190 tio.c_cc[VTIME] = 0;
191 tio.c_cc[VMIN] = 1;
192
193 tcsetattr(fd, TCSANOW, &tio);
194 tcflush(fd, TCIFLUSH);
195}
196
197static void stdin_raw_restore(int fd)
198{
199 tcsetattr(fd, TCSANOW, &tio_save);
200 tcflush(fd, TCIFLUSH);
201}
202#endif
203
204static void read_and_dump(int fd)
205{
206 char buf[4096];
207 int len;
208
209 while(fd >= 0) {
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700210 D("read_and_dump(): pre adb_read(fd=%d)\n", fd);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800211 len = adb_read(fd, buf, 4096);
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700212 D("read_and_dump(): post adb_read(fd=%d): len=%d\n", fd, len);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800213 if(len == 0) {
214 break;
215 }
216
217 if(len < 0) {
218 if(errno == EINTR) continue;
219 break;
220 }
Mike Lockwood597ea9a2009-09-22 01:18:40 -0400221 fwrite(buf, 1, len, stdout);
222 fflush(stdout);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800223 }
224}
225
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800226static void *stdin_read_thread(void *x)
227{
228 int fd, fdi;
229 unsigned char buf[1024];
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800230 int r, n;
231 int state = 0;
232
233 int *fds = (int*) x;
234 fd = fds[0];
235 fdi = fds[1];
236 free(fds);
237
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800238 for(;;) {
239 /* fdi is really the client's stdin, so use read, not adb_read here */
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700240 D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800241 r = unix_read(fdi, buf, 1024);
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700242 D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800243 if(r == 0) break;
244 if(r < 0) {
245 if(errno == EINTR) continue;
246 break;
247 }
Mike Lockwood18ab0d62010-05-25 13:40:15 -0400248 for(n = 0; n < r; n++){
249 switch(buf[n]) {
250 case '\n':
251 state = 1;
252 break;
253 case '\r':
254 state = 1;
255 break;
256 case '~':
257 if(state == 1) state++;
258 break;
259 case '.':
260 if(state == 2) {
261 fprintf(stderr,"\n* disconnect *\n");
262#ifdef HAVE_TERMIO_H
263 stdin_raw_restore(fdi);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800264#endif
Mike Lockwood18ab0d62010-05-25 13:40:15 -0400265 exit(0);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800266 }
Mike Lockwood18ab0d62010-05-25 13:40:15 -0400267 default:
268 state = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800269 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800270 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800271 r = adb_write(fd, buf, r);
272 if(r <= 0) {
273 break;
274 }
275 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800276 return 0;
277}
278
279int interactive_shell(void)
280{
281 adb_thread_t thr;
282 int fdi, fd;
283 int *fds;
284
285 fd = adb_connect("shell:");
286 if(fd < 0) {
287 fprintf(stderr,"error: %s\n", adb_error());
288 return 1;
289 }
290 fdi = 0; //dup(0);
291
292 fds = malloc(sizeof(int) * 2);
293 fds[0] = fd;
294 fds[1] = fdi;
295
296#ifdef HAVE_TERMIO_H
297 stdin_raw_init(fdi);
298#endif
299 adb_thread_create(&thr, stdin_read_thread, fds);
300 read_and_dump(fd);
301#ifdef HAVE_TERMIO_H
302 stdin_raw_restore(fdi);
303#endif
304 return 0;
305}
306
307
308static void format_host_command(char* buffer, size_t buflen, const char* command, transport_type ttype, const char* serial)
309{
310 if (serial) {
311 snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
312 } else {
313 const char* prefix = "host";
314 if (ttype == kTransportUsb)
315 prefix = "host-usb";
316 else if (ttype == kTransportLocal)
317 prefix = "host-local";
318
319 snprintf(buffer, buflen, "%s:%s", prefix, command);
320 }
321}
322
323static void status_window(transport_type ttype, const char* serial)
324{
325 char command[4096];
326 char *state = 0;
327 char *laststate = 0;
328
329 /* silence stderr */
330#ifdef _WIN32
331 /* XXX: TODO */
332#else
333 int fd;
334 fd = unix_open("/dev/null", O_WRONLY);
335 dup2(fd, 2);
336 adb_close(fd);
337#endif
338
339 format_host_command(command, sizeof command, "get-state", ttype, serial);
340
341 for(;;) {
342 adb_sleep_ms(250);
343
344 if(state) {
345 free(state);
346 state = 0;
347 }
348
349 state = adb_query(command);
350
351 if(state) {
352 if(laststate && !strcmp(state,laststate)){
353 continue;
354 } else {
355 if(laststate) free(laststate);
356 laststate = strdup(state);
357 }
358 }
359
360 printf("%c[2J%c[2H", 27, 27);
361 printf("Android Debug Bridge\n");
362 printf("State: %s\n", state ? state : "offline");
363 fflush(stdout);
364 }
365}
366
367/** duplicate string and quote all \ " ( ) chars + space character. */
368static char *
369dupAndQuote(const char *s)
370{
371 const char *ts;
372 size_t alloc_len;
373 char *ret;
374 char *dest;
375
376 ts = s;
377
378 alloc_len = 0;
379
380 for( ;*ts != '\0'; ts++) {
381 alloc_len++;
382 if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
383 alloc_len++;
384 }
385 }
386
387 ret = (char *)malloc(alloc_len + 1);
388
389 ts = s;
390 dest = ret;
391
392 for ( ;*ts != '\0'; ts++) {
393 if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
394 *dest++ = '\\';
395 }
396
397 *dest++ = *ts;
398 }
399
400 *dest++ = '\0';
401
402 return ret;
403}
404
405/**
406 * Run ppp in "notty" mode against a resource listed as the first parameter
407 * eg:
408 *
409 * ppp dev:/dev/omap_csmi_tty0 <ppp options>
410 *
411 */
412int ppp(int argc, char **argv)
413{
414#ifdef HAVE_WIN32_PROC
415 fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
416 return -1;
417#else
418 char *adb_service_name;
419 pid_t pid;
420 int fd;
421
422 if (argc < 2) {
423 fprintf(stderr, "usage: adb %s <adb service name> [ppp opts]\n",
424 argv[0]);
425
426 return 1;
427 }
428
429 adb_service_name = argv[1];
430
431 fd = adb_connect(adb_service_name);
432
433 if(fd < 0) {
434 fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n",
435 adb_service_name, adb_error());
436 return 1;
437 }
438
439 pid = fork();
440
441 if (pid < 0) {
442 perror("from fork()");
443 return 1;
444 } else if (pid == 0) {
445 int err;
446 int i;
447 const char **ppp_args;
448
449 // copy args
450 ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
451 ppp_args[0] = "pppd";
452 for (i = 2 ; i < argc ; i++) {
453 //argv[2] and beyond become ppp_args[1] and beyond
454 ppp_args[i - 1] = argv[i];
455 }
456 ppp_args[i-1] = NULL;
457
458 // child side
459
460 dup2(fd, STDIN_FILENO);
461 dup2(fd, STDOUT_FILENO);
462 adb_close(STDERR_FILENO);
463 adb_close(fd);
464
465 err = execvp("pppd", (char * const *)ppp_args);
466
467 if (err < 0) {
468 perror("execing pppd");
469 }
470 exit(-1);
471 } else {
472 // parent side
473
474 adb_close(fd);
475 return 0;
476 }
477#endif /* !HAVE_WIN32_PROC */
478}
479
480static int send_shellcommand(transport_type transport, char* serial, char* buf)
481{
482 int fd, ret;
483
484 for(;;) {
485 fd = adb_connect(buf);
486 if(fd >= 0)
487 break;
488 fprintf(stderr,"- waiting for device -\n");
489 adb_sleep_ms(1000);
490 do_cmd(transport, serial, "wait-for-device", 0);
491 }
492
493 read_and_dump(fd);
494 ret = adb_close(fd);
495 if (ret)
496 perror("close");
497
498 return ret;
499}
500
501static int logcat(transport_type transport, char* serial, int argc, char **argv)
502{
503 char buf[4096];
504
505 char *log_tags;
506 char *quoted_log_tags;
507
508 log_tags = getenv("ANDROID_LOG_TAGS");
509 quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
510
511 snprintf(buf, sizeof(buf),
512 "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
513 quoted_log_tags);
514
515 free(quoted_log_tags);
516
517 argc -= 1;
518 argv += 1;
519 while(argc-- > 0) {
520 char *quoted;
521
522 quoted = dupAndQuote (*argv++);
523
524 strncat(buf, " ", sizeof(buf)-1);
525 strncat(buf, quoted, sizeof(buf)-1);
526 free(quoted);
527 }
528
529 send_shellcommand(transport, serial, buf);
530 return 0;
531}
532
533#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
534static int top_works(const char *top)
535{
536 if (top != NULL && adb_is_absolute_host_path(top)) {
537 char path_buf[PATH_MAX];
538 snprintf(path_buf, sizeof(path_buf),
539 "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
540 return access(path_buf, F_OK) == 0;
541 }
542 return 0;
543}
544
545static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
546{
547 strcpy(path_buf, indir);
548 while (1) {
549 if (top_works(path_buf)) {
550 return path_buf;
551 }
552 char *s = adb_dirstop(path_buf);
553 if (s != NULL) {
554 *s = '\0';
555 } else {
556 path_buf[0] = '\0';
557 return NULL;
558 }
559 }
560}
561
562static char *find_top(char path_buf[PATH_MAX])
563{
564 char *top = getenv("ANDROID_BUILD_TOP");
565 if (top != NULL && top[0] != '\0') {
566 if (!top_works(top)) {
567 fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
568 return NULL;
569 }
570 } else {
571 top = getenv("TOP");
572 if (top != NULL && top[0] != '\0') {
573 if (!top_works(top)) {
574 fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
575 return NULL;
576 }
577 } else {
578 top = NULL;
579 }
580 }
581
582 if (top != NULL) {
583 /* The environment pointed to a top directory that works.
584 */
585 strcpy(path_buf, top);
586 return path_buf;
587 }
588
589 /* The environment didn't help. Walk up the tree from the CWD
590 * to see if we can find the top.
591 */
592 char dir[PATH_MAX];
593 top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
594 if (top == NULL) {
595 /* If the CWD isn't under a good-looking top, see if the
596 * executable is.
597 */
Alexey Tarasov857f17a2009-10-22 02:55:00 +1100598 get_my_path(dir, PATH_MAX);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800599 top = find_top_from(dir, path_buf);
600 }
601 return top;
602}
603
604/* <hint> may be:
605 * - A simple product name
606 * e.g., "sooner"
607TODO: debug? sooner-debug, sooner:debug?
608 * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
609 * e.g., "out/target/product/sooner"
610 * - An absolute path to the PRODUCT_OUT dir
611 * e.g., "/src/device/out/target/product/sooner"
612 *
613 * Given <hint>, try to construct an absolute path to the
614 * ANDROID_PRODUCT_OUT dir.
615 */
616static const char *find_product_out_path(const char *hint)
617{
618 static char path_buf[PATH_MAX];
619
620 if (hint == NULL || hint[0] == '\0') {
621 return NULL;
622 }
623
624 /* If it's already absolute, don't bother doing any work.
625 */
626 if (adb_is_absolute_host_path(hint)) {
627 strcpy(path_buf, hint);
628 return path_buf;
629 }
630
631 /* If there are any slashes in it, assume it's a relative path;
632 * make it absolute.
633 */
634 if (adb_dirstart(hint) != NULL) {
635 if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
636 fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
637 return NULL;
638 }
639 if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
640 fprintf(stderr, "adb: Couldn't assemble path\n");
641 return NULL;
642 }
643 strcat(path_buf, OS_PATH_SEPARATOR_STR);
644 strcat(path_buf, hint);
645 return path_buf;
646 }
647
648 /* It's a string without any slashes. Try to do something with it.
649 *
650 * Try to find the root of the build tree, and build a PRODUCT_OUT
651 * path from there.
652 */
653 char top_buf[PATH_MAX];
654 const char *top = find_top(top_buf);
655 if (top == NULL) {
656 fprintf(stderr, "adb: Couldn't find top of build tree\n");
657 return NULL;
658 }
659//TODO: if we have a way to indicate debug, look in out/debug/target/...
660 snprintf(path_buf, sizeof(path_buf),
661 "%s" OS_PATH_SEPARATOR_STR
662 "out" OS_PATH_SEPARATOR_STR
663 "target" OS_PATH_SEPARATOR_STR
664 "product" OS_PATH_SEPARATOR_STR
665 "%s", top_buf, hint);
666 if (access(path_buf, F_OK) < 0) {
667 fprintf(stderr, "adb: Couldn't find a product dir "
668 "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
669 return NULL;
670 }
671 return path_buf;
672}
673
674int adb_commandline(int argc, char **argv)
675{
676 char buf[4096];
677 int no_daemon = 0;
678 int is_daemon = 0;
David 'Digit' Turner6826db62011-01-31 14:23:56 +0100679 int is_server = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800680 int persist = 0;
681 int r;
682 int quote;
683 transport_type ttype = kTransportAny;
684 char* serial = NULL;
Stefan Hilzinger92ca4fa2010-04-19 12:21:12 +0100685 char* server_port_str = NULL;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800686
687 /* If defined, this should be an absolute path to
688 * the directory containing all of the various system images
689 * for a particular product. If not defined, and the adb
690 * command requires this information, then the user must
691 * specify the path using "-p".
692 */
693 gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
694 if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
695 gProductOutPath = NULL;
696 }
697 // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
698
Nick Pellyaf2fe9b2009-05-07 12:48:03 -0700699 serial = getenv("ANDROID_SERIAL");
700
Stefan Hilzinger92ca4fa2010-04-19 12:21:12 +0100701 /* Validate and assign the server port */
702 server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
703 int server_port = DEFAULT_ADB_PORT;
704 if (server_port_str && strlen(server_port_str) > 0) {
705 server_port = (int) strtol(server_port_str, NULL, 0);
706 if (server_port <= 0) {
707 fprintf(stderr,
708 "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number. Got \"%s\"\n",
709 server_port_str);
710 return usage();
711 }
712 }
713
714 /* modifiers and flags */
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800715 while(argc > 0) {
David 'Digit' Turner6826db62011-01-31 14:23:56 +0100716 if(!strcmp(argv[0],"server")) {
717 is_server = 1;
718 } else if(!strcmp(argv[0],"nodaemon")) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800719 no_daemon = 1;
720 } else if (!strcmp(argv[0], "fork-server")) {
721 /* this is a special flag used only when the ADB client launches the ADB Server */
722 is_daemon = 1;
723 } else if(!strcmp(argv[0],"persist")) {
724 persist = 1;
725 } else if(!strncmp(argv[0], "-p", 2)) {
726 const char *product = NULL;
727 if (argv[0][2] == '\0') {
728 if (argc < 2) return usage();
729 product = argv[1];
730 argc--;
731 argv++;
732 } else {
733 product = argv[1] + 2;
734 }
735 gProductOutPath = find_product_out_path(product);
736 if (gProductOutPath == NULL) {
737 fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
738 product);
739 return usage();
740 }
741 } else if (argv[0][0]=='-' && argv[0][1]=='s') {
742 if (isdigit(argv[0][2])) {
743 serial = argv[0] + 2;
744 } else {
Stefan Hilzinger92ca4fa2010-04-19 12:21:12 +0100745 if(argc < 2 || argv[0][2] != '\0') return usage();
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800746 serial = argv[1];
747 argc--;
748 argv++;
749 }
750 } else if (!strcmp(argv[0],"-d")) {
751 ttype = kTransportUsb;
752 } else if (!strcmp(argv[0],"-e")) {
753 ttype = kTransportLocal;
754 } else {
755 /* out of recognized modifiers and flags */
756 break;
757 }
758 argc--;
759 argv++;
760 }
761
762 adb_set_transport(ttype, serial);
Stefan Hilzinger92ca4fa2010-04-19 12:21:12 +0100763 adb_set_tcp_specifics(server_port);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800764
David 'Digit' Turner6826db62011-01-31 14:23:56 +0100765 if (is_server) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800766 if (no_daemon || is_daemon) {
Stefan Hilzinger92ca4fa2010-04-19 12:21:12 +0100767 r = adb_main(is_daemon, server_port);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800768 } else {
Stefan Hilzinger92ca4fa2010-04-19 12:21:12 +0100769 r = launch_server(server_port);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800770 }
771 if(r) {
772 fprintf(stderr,"* could not start server *\n");
773 }
774 return r;
775 }
776
777top:
778 if(argc == 0) {
779 return usage();
780 }
781
782 /* adb_connect() commands */
783
784 if(!strcmp(argv[0], "devices")) {
785 char *tmp;
786 snprintf(buf, sizeof buf, "host:%s", argv[0]);
787 tmp = adb_query(buf);
788 if(tmp) {
789 printf("List of devices attached \n");
790 printf("%s\n", tmp);
791 return 0;
792 } else {
793 return 1;
794 }
795 }
796
Mike Lockwood01c2c302010-05-24 10:44:35 -0400797 if(!strcmp(argv[0], "connect")) {
Mike Lockwood26b88e32009-08-24 15:58:40 -0700798 char *tmp;
799 if (argc != 2) {
Mike Lockwood01c2c302010-05-24 10:44:35 -0400800 fprintf(stderr, "Usage: adb connect <host>[:<port>]\n");
Mike Lockwood26b88e32009-08-24 15:58:40 -0700801 return 1;
802 }
Mike Lockwood01c2c302010-05-24 10:44:35 -0400803 snprintf(buf, sizeof buf, "host:connect:%s", argv[1]);
804 tmp = adb_query(buf);
805 if(tmp) {
806 printf("%s\n", tmp);
807 return 0;
808 } else {
809 return 1;
810 }
811 }
812
813 if(!strcmp(argv[0], "disconnect")) {
814 char *tmp;
815 if (argc > 2) {
816 fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n");
817 return 1;
818 }
819 if (argc == 2) {
820 snprintf(buf, sizeof buf, "host:disconnect:%s", argv[1]);
821 } else {
822 snprintf(buf, sizeof buf, "host:disconnect:");
823 }
Mike Lockwood26b88e32009-08-24 15:58:40 -0700824 tmp = adb_query(buf);
825 if(tmp) {
826 printf("%s\n", tmp);
827 return 0;
828 } else {
829 return 1;
830 }
831 }
832
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800833 if (!strcmp(argv[0], "emu")) {
834 return adb_send_emulator_command(argc, argv);
835 }
836
Daniel Sandlerd9bc2372010-08-19 01:10:18 -0400837 if(!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800838 int r;
839 int fd;
840
Daniel Sandlerd9bc2372010-08-19 01:10:18 -0400841 char h = (argv[0][0] == 'h');
842
843 if (h) {
844 printf("\x1b[41;33m");
845 fflush(stdout);
846 }
847
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800848 if(argc < 2) {
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700849 D("starting interactive shell\n");
Daniel Sandlerd9bc2372010-08-19 01:10:18 -0400850 r = interactive_shell();
851 if (h) {
852 printf("\x1b[0m");
853 fflush(stdout);
854 }
855 return r;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800856 }
857
858 snprintf(buf, sizeof buf, "shell:%s", argv[1]);
859 argc -= 2;
860 argv += 2;
861 while(argc-- > 0) {
862 strcat(buf, " ");
863
864 /* quote empty strings and strings with spaces */
865 quote = (**argv == 0 || strchr(*argv, ' '));
866 if (quote)
Stefan Hilzinger92ca4fa2010-04-19 12:21:12 +0100867 strcat(buf, "\"");
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800868 strcat(buf, *argv++);
869 if (quote)
Stefan Hilzinger92ca4fa2010-04-19 12:21:12 +0100870 strcat(buf, "\"");
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800871 }
872
873 for(;;) {
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700874 D("interactive shell loop. buff=%s\n", buf);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800875 fd = adb_connect(buf);
876 if(fd >= 0) {
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700877 D("about to read_and_dump(fd=%d)\n", fd);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800878 read_and_dump(fd);
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700879 D("read_and_dump() done.\n");
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800880 adb_close(fd);
881 r = 0;
882 } else {
883 fprintf(stderr,"error: %s\n", adb_error());
884 r = -1;
885 }
886
887 if(persist) {
888 fprintf(stderr,"\n- waiting for device -\n");
889 adb_sleep_ms(1000);
890 do_cmd(ttype, serial, "wait-for-device", 0);
891 } else {
Daniel Sandlerd9bc2372010-08-19 01:10:18 -0400892 if (h) {
893 printf("\x1b[0m");
894 fflush(stdout);
895 }
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700896 D("interactive shell loop. return r=%d\n", r);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800897 return r;
898 }
899 }
900 }
901
902 if(!strcmp(argv[0], "kill-server")) {
903 int fd;
904 fd = _adb_connect("host:kill");
905 if(fd == -1) {
906 fprintf(stderr,"* server not running *\n");
907 return 1;
908 }
909 return 0;
910 }
911
Mike Lockwood26b88e32009-08-24 15:58:40 -0700912 if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
Romain Guyf925d912009-12-14 14:42:17 -0800913 || !strcmp(argv[0], "reboot-bootloader")
Mike Lockwood26b88e32009-08-24 15:58:40 -0700914 || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
Mike Lockwood78589f32009-09-03 14:54:58 -0400915 || !strcmp(argv[0], "root")) {
Mike Lockwood26b88e32009-08-24 15:58:40 -0700916 char command[100];
Romain Guyf925d912009-12-14 14:42:17 -0800917 if (!strcmp(argv[0], "reboot-bootloader"))
918 snprintf(command, sizeof(command), "reboot:bootloader");
919 else if (argc > 1)
Mike Lockwood26b88e32009-08-24 15:58:40 -0700920 snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
Mike Lockwood12a35ea2009-08-04 20:37:51 -0400921 else
Mike Lockwood26b88e32009-08-24 15:58:40 -0700922 snprintf(command, sizeof(command), "%s:", argv[0]);
923 int fd = adb_connect(command);
The Android Open Source Project9c753402009-03-13 13:04:37 -0700924 if(fd >= 0) {
925 read_and_dump(fd);
926 adb_close(fd);
927 return 0;
928 }
929 fprintf(stderr,"error: %s\n", adb_error());
930 return 1;
931 }
932
Mike Lockwood78589f32009-09-03 14:54:58 -0400933 if(!strcmp(argv[0], "bugreport")) {
Dan Egnor2857f312010-01-20 13:50:36 -0800934 if (argc != 1) return usage();
935 do_cmd(ttype, serial, "shell", "bugreport", 0);
Mike Lockwood78589f32009-09-03 14:54:58 -0400936 return 0;
937 }
938
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800939 /* adb_command() wrapper commands */
940
941 if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
942 char* service = argv[0];
943 if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
944 if (ttype == kTransportUsb) {
945 service = "wait-for-usb";
946 } else if (ttype == kTransportLocal) {
947 service = "wait-for-local";
948 } else {
949 service = "wait-for-any";
950 }
951 }
952
953 format_host_command(buf, sizeof buf, service, ttype, serial);
954
955 if (adb_command(buf)) {
956 D("failure: %s *\n",adb_error());
957 fprintf(stderr,"error: %s\n", adb_error());
958 return 1;
959 }
960
961 /* Allow a command to be run after wait-for-device,
962 * e.g. 'adb wait-for-device shell'.
963 */
964 if(argc > 1) {
965 argc--;
966 argv++;
967 goto top;
968 }
969 return 0;
970 }
971
972 if(!strcmp(argv[0], "forward")) {
973 if(argc != 3) return usage();
974 if (serial) {
Mike Lockwood47b41622009-11-28 12:46:13 -0500975 snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial, argv[1], argv[2]);
976 } else if (ttype == kTransportUsb) {
977 snprintf(buf, sizeof buf, "host-usb:forward:%s;%s", argv[1], argv[2]);
978 } else if (ttype == kTransportLocal) {
979 snprintf(buf, sizeof buf, "host-local:forward:%s;%s", argv[1], argv[2]);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800980 } else {
Mike Lockwood47b41622009-11-28 12:46:13 -0500981 snprintf(buf, sizeof buf, "host:forward:%s;%s", argv[1], argv[2]);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800982 }
983 if(adb_command(buf)) {
984 fprintf(stderr,"error: %s\n", adb_error());
985 return 1;
986 }
987 return 0;
988 }
989
990 /* do_sync_*() commands */
991
992 if(!strcmp(argv[0], "ls")) {
993 if(argc != 2) return usage();
994 return do_sync_ls(argv[1]);
995 }
996
997 if(!strcmp(argv[0], "push")) {
998 if(argc != 3) return usage();
999 return do_sync_push(argv[1], argv[2], 0 /* no verify APK */);
1000 }
1001
1002 if(!strcmp(argv[0], "pull")) {
Joe Onorato23595b02010-01-05 13:42:25 -08001003 if (argc == 2) {
1004 return do_sync_pull(argv[1], ".");
1005 } else if (argc == 3) {
1006 return do_sync_pull(argv[1], argv[2]);
1007 } else {
1008 return usage();
1009 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001010 }
1011
1012 if(!strcmp(argv[0], "install")) {
1013 if (argc < 2) return usage();
1014 return install_app(ttype, serial, argc, argv);
1015 }
1016
1017 if(!strcmp(argv[0], "uninstall")) {
1018 if (argc < 2) return usage();
1019 return uninstall_app(ttype, serial, argc, argv);
1020 }
1021
1022 if(!strcmp(argv[0], "sync")) {
1023 char *srcarg, *android_srcpath, *data_srcpath;
Anthony Newnamdd2db142010-02-22 08:36:49 -06001024 int listonly = 0;
1025
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001026 int ret;
1027 if(argc < 2) {
1028 /* No local path was specified. */
1029 srcarg = NULL;
Anthony Newnamdd2db142010-02-22 08:36:49 -06001030 } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
1031 listonly = 1;
1032 if (argc == 3) {
1033 srcarg = argv[2];
1034 } else {
1035 srcarg = NULL;
1036 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001037 } else if(argc == 2) {
1038 /* A local path or "android"/"data" arg was specified. */
1039 srcarg = argv[1];
1040 } else {
1041 return usage();
1042 }
1043 ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
1044 if(ret != 0) return usage();
1045
1046 if(android_srcpath != NULL)
Anthony Newnamdd2db142010-02-22 08:36:49 -06001047 ret = do_sync_sync(android_srcpath, "/system", listonly);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001048 if(ret == 0 && data_srcpath != NULL)
Anthony Newnamdd2db142010-02-22 08:36:49 -06001049 ret = do_sync_sync(data_srcpath, "/data", listonly);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001050
1051 free(android_srcpath);
1052 free(data_srcpath);
1053 return ret;
1054 }
1055
1056 /* passthrough commands */
1057
1058 if(!strcmp(argv[0],"get-state") ||
1059 !strcmp(argv[0],"get-serialno"))
1060 {
1061 char *tmp;
1062
1063 format_host_command(buf, sizeof buf, argv[0], ttype, serial);
1064 tmp = adb_query(buf);
1065 if(tmp) {
1066 printf("%s\n", tmp);
1067 return 0;
1068 } else {
1069 return 1;
1070 }
1071 }
1072
1073 /* other commands */
1074
1075 if(!strcmp(argv[0],"status-window")) {
1076 status_window(ttype, serial);
1077 return 0;
1078 }
1079
1080 if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat")) {
1081 return logcat(ttype, serial, argc, argv);
1082 }
1083
1084 if(!strcmp(argv[0],"ppp")) {
1085 return ppp(argc, argv);
1086 }
1087
1088 if (!strcmp(argv[0], "start-server")) {
1089 return adb_connect("host:start-server");
1090 }
1091
1092 if (!strcmp(argv[0], "jdwp")) {
1093 int fd = adb_connect("jdwp");
1094 if (fd >= 0) {
1095 read_and_dump(fd);
1096 adb_close(fd);
1097 return 0;
1098 } else {
1099 fprintf(stderr, "error: %s\n", adb_error());
1100 return -1;
1101 }
1102 }
1103
1104 /* "adb /?" is a common idiom under Windows */
1105 if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
1106 help();
1107 return 0;
1108 }
1109
1110 if(!strcmp(argv[0], "version")) {
1111 version(stdout);
1112 return 0;
1113 }
1114
1115 usage();
1116 return 1;
1117}
1118
1119static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
1120{
1121 char *argv[16];
1122 int argc;
1123 va_list ap;
1124
1125 va_start(ap, cmd);
1126 argc = 0;
1127
1128 if (serial) {
1129 argv[argc++] = "-s";
1130 argv[argc++] = serial;
1131 } else if (ttype == kTransportUsb) {
1132 argv[argc++] = "-d";
1133 } else if (ttype == kTransportLocal) {
1134 argv[argc++] = "-e";
1135 }
1136
1137 argv[argc++] = cmd;
1138 while((argv[argc] = va_arg(ap, char*)) != 0) argc++;
1139 va_end(ap);
1140
1141#if 0
1142 int n;
1143 fprintf(stderr,"argc = %d\n",argc);
1144 for(n = 0; n < argc; n++) {
1145 fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
1146 }
1147#endif
1148
1149 return adb_commandline(argc, argv);
1150}
1151
1152int find_sync_dirs(const char *srcarg,
1153 char **android_srcdir_out, char **data_srcdir_out)
1154{
1155 char *android_srcdir, *data_srcdir;
1156
1157 if(srcarg == NULL) {
1158 android_srcdir = product_file("system");
1159 data_srcdir = product_file("data");
1160 } else {
1161 /* srcarg may be "data", "system" or NULL.
1162 * if srcarg is NULL, then both data and system are synced
1163 */
1164 if(strcmp(srcarg, "system") == 0) {
1165 android_srcdir = product_file("system");
1166 data_srcdir = NULL;
1167 } else if(strcmp(srcarg, "data") == 0) {
1168 android_srcdir = NULL;
1169 data_srcdir = product_file("data");
1170 } else {
1171 /* It's not "system" or "data".
1172 */
1173 return 1;
1174 }
1175 }
1176
1177 if(android_srcdir_out != NULL)
1178 *android_srcdir_out = android_srcdir;
1179 else
1180 free(android_srcdir);
1181
1182 if(data_srcdir_out != NULL)
1183 *data_srcdir_out = data_srcdir;
1184 else
1185 free(data_srcdir);
1186
1187 return 0;
1188}
1189
1190static int pm_command(transport_type transport, char* serial,
1191 int argc, char** argv)
1192{
1193 char buf[4096];
1194
1195 snprintf(buf, sizeof(buf), "shell:pm");
1196
1197 while(argc-- > 0) {
1198 char *quoted;
1199
1200 quoted = dupAndQuote(*argv++);
1201
1202 strncat(buf, " ", sizeof(buf)-1);
1203 strncat(buf, quoted, sizeof(buf)-1);
1204 free(quoted);
1205 }
1206
1207 send_shellcommand(transport, serial, buf);
1208 return 0;
1209}
1210
1211int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
1212{
1213 /* if the user choose the -k option, we refuse to do it until devices are
1214 out with the option to uninstall the remaining data somehow (adb/ui) */
1215 if (argc == 3 && strcmp(argv[1], "-k") == 0)
1216 {
1217 printf(
1218 "The -k option uninstalls the application while retaining the data/cache.\n"
1219 "At the moment, there is no way to remove the remaining data.\n"
1220 "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
1221 "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
1222 return -1;
1223 }
1224
1225 /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
1226 return pm_command(transport, serial, argc, argv);
1227}
1228
1229static int delete_file(transport_type transport, char* serial, char* filename)
1230{
1231 char buf[4096];
1232 char* quoted;
1233
1234 snprintf(buf, sizeof(buf), "shell:rm ");
1235 quoted = dupAndQuote(filename);
1236 strncat(buf, quoted, sizeof(buf)-1);
1237 free(quoted);
1238
1239 send_shellcommand(transport, serial, buf);
1240 return 0;
1241}
1242
1243int install_app(transport_type transport, char* serial, int argc, char** argv)
1244{
1245 struct stat st;
1246 int err;
Mike Lockwood4cc5c012010-02-19 17:53:27 -05001247 const char *const DATA_DEST = "/data/local/tmp/%s";
1248 const char *const SD_DEST = "/sdcard/tmp/%s";
1249 const char* where = DATA_DEST;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001250 char to[PATH_MAX];
1251 char* filename = argv[argc - 1];
1252 const char* p;
Mike Lockwood4cc5c012010-02-19 17:53:27 -05001253 int i;
1254
1255 for (i = 0; i < argc; i++) {
1256 if (!strcmp(argv[i], "-s"))
1257 where = SD_DEST;
1258 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001259
1260 p = adb_dirstop(filename);
1261 if (p) {
1262 p++;
Mike Lockwood4cc5c012010-02-19 17:53:27 -05001263 snprintf(to, sizeof to, where, p);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001264 } else {
Mike Lockwood4cc5c012010-02-19 17:53:27 -05001265 snprintf(to, sizeof to, where, filename);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001266 }
1267 if (p[0] == '\0') {
1268 }
1269
1270 err = stat(filename, &st);
1271 if (err != 0) {
1272 fprintf(stderr, "can't find '%s' to install\n", filename);
1273 return 1;
1274 }
1275 if (!S_ISREG(st.st_mode)) {
1276 fprintf(stderr, "can't install '%s' because it's not a file\n",
1277 filename);
1278 return 1;
1279 }
1280
1281 if (!(err = do_sync_push(filename, to, 1 /* verify APK */))) {
1282 /* file in place; tell the Package Manager to install it */
1283 argv[argc - 1] = to; /* destination name, not source location */
1284 pm_command(transport, serial, argc, argv);
1285 delete_file(transport, serial, to);
1286 }
1287
1288 return err;
1289}