--- /dev/null
+## Description: add some description
+## Origin/Author: add some origin or author
+## Bug: bug URL
+Index: android-tools-4.2.2+git20130218/core/adbd/adb.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/adb.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,1719 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#define TRACE_TAG TRACE_ADB
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <ctype.h>
++#include <stdarg.h>
++#include <errno.h>
++#include <stddef.h>
++#include <string.h>
++#include <time.h>
++#include <sys/time.h>
++#include <stdint.h>
++
++#include "sysdeps.h"
++#include "adb.h"
++#include "adb_auth.h"
++
++#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
++
++#if !ADB_HOST
++#include "android_filesystem_config.h"
++#include <linux/capability.h>
++#include <linux/prctl.h>
++#include <sys/mount.h>
++#else
++#include "usb_vendors.h"
++#endif
++
++#if ADB_TRACE
++ADB_MUTEX_DEFINE( D_lock );
++#endif
++
++int HOST = 0;
++int gListenAll = 0;
++
++static int auth_enabled = 0;
++
++#if !ADB_HOST
++static const char *adb_device_banner = "device";
++#endif
++
++void fatal(const char *fmt, ...)
++{
++ va_list ap;
++ va_start(ap, fmt);
++ fprintf(stderr, "error: ");
++ vfprintf(stderr, fmt, ap);
++ fprintf(stderr, "\n");
++ va_end(ap);
++ exit(-1);
++}
++
++void fatal_errno(const char *fmt, ...)
++{
++ va_list ap;
++ va_start(ap, fmt);
++ fprintf(stderr, "error: %s: ", strerror(errno));
++ vfprintf(stderr, fmt, ap);
++ fprintf(stderr, "\n");
++ va_end(ap);
++ exit(-1);
++}
++
++int adb_trace_mask;
++
++/* read a comma/space/colum/semi-column separated list of tags
++ * from the ADB_TRACE environment variable and build the trace
++ * mask from it. note that '1' and 'all' are special cases to
++ * enable all tracing
++ */
++void adb_trace_init(void)
++{
++ const char* p = getenv("ADB_TRACE");
++ const char* q;
++
++ static const struct {
++ const char* tag;
++ int flag;
++ } tags[] = {
++ { "1", 0 },
++ { "all", 0 },
++ { "adb", TRACE_ADB },
++ { "sockets", TRACE_SOCKETS },
++ { "packets", TRACE_PACKETS },
++ { "rwx", TRACE_RWX },
++ { "usb", TRACE_USB },
++ { "sync", TRACE_SYNC },
++ { "sysdeps", TRACE_SYSDEPS },
++ { "transport", TRACE_TRANSPORT },
++ { "jdwp", TRACE_JDWP },
++ { "services", TRACE_SERVICES },
++ { "auth", TRACE_AUTH },
++ { NULL, 0 }
++ };
++
++ if (p == NULL)
++ return;
++
++ /* use a comma/column/semi-colum/space separated list */
++ while (*p) {
++ int len, tagn;
++
++ q = strpbrk(p, " ,:;");
++ if (q == NULL) {
++ q = p + strlen(p);
++ }
++ len = q - p;
++
++ for (tagn = 0; tags[tagn].tag != NULL; tagn++)
++ {
++ int taglen = strlen(tags[tagn].tag);
++
++ if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
++ {
++ int flag = tags[tagn].flag;
++ if (flag == 0) {
++ adb_trace_mask = ~0;
++ return;
++ }
++ adb_trace_mask |= (1 << flag);
++ break;
++ }
++ }
++ p = q;
++ if (*p)
++ p++;
++ }
++}
++
++#if !ADB_HOST
++/*
++ * Implements ADB tracing inside the emulator.
++ */
++
++#include <stdarg.h>
++
++/*
++ * Redefine open and write for qemu_pipe.h that contains inlined references
++ * to those routines. We will redifine them back after qemu_pipe.h inclusion.
++ */
++
++#undef open
++#undef write
++#define open adb_open
++#define write adb_write
++#include "qemu_pipe.h"
++#undef open
++#undef write
++#define open ___xxx_open
++#define write ___xxx_write
++
++/* A handle to adb-debug qemud service in the emulator. */
++int adb_debug_qemu = -1;
++
++/* Initializes connection with the adb-debug qemud service in the emulator. */
++static int adb_qemu_trace_init(void)
++{
++ char con_name[32];
++
++ if (adb_debug_qemu >= 0) {
++ return 0;
++ }
++
++ /* adb debugging QEMUD service connection request. */
++ snprintf(con_name, sizeof(con_name), "qemud:adb-debug");
++ adb_debug_qemu = qemu_pipe_open(con_name);
++ return (adb_debug_qemu >= 0) ? 0 : -1;
++}
++
++void adb_qemu_trace(const char* fmt, ...)
++{
++ va_list args;
++ va_start(args, fmt);
++ char msg[1024];
++
++ if (adb_debug_qemu >= 0) {
++ vsnprintf(msg, sizeof(msg), fmt, args);
++ adb_write(adb_debug_qemu, msg, strlen(msg));
++ }
++}
++#endif /* !ADB_HOST */
++
++apacket *get_apacket(void)
++{
++ apacket *p = malloc(sizeof(apacket));
++ if(p == 0) fatal("failed to allocate an apacket");
++ memset(p, 0, sizeof(apacket) - MAX_PAYLOAD);
++ return p;
++}
++
++void put_apacket(apacket *p)
++{
++ free(p);
++}
++
++void handle_online(atransport *t)
++{
++ D("adb: online\n");
++ t->online = 1;
++}
++
++void handle_offline(atransport *t)
++{
++ D("adb: offline\n");
++ //Close the associated usb
++ t->online = 0;
++ run_transport_disconnects(t);
++}
++
++#if DEBUG_PACKETS
++#define DUMPMAX 32
++void print_packet(const char *label, apacket *p)
++{
++ char *tag;
++ char *x;
++ unsigned count;
++
++ switch(p->msg.command){
++ case A_SYNC: tag = "SYNC"; break;
++ case A_CNXN: tag = "CNXN" ; break;
++ case A_OPEN: tag = "OPEN"; break;
++ case A_OKAY: tag = "OKAY"; break;
++ case A_CLSE: tag = "CLSE"; break;
++ case A_WRTE: tag = "WRTE"; break;
++ case A_AUTH: tag = "AUTH"; break;
++ default: tag = "????"; break;
++ }
++
++ fprintf(stderr, "%s: %s %08x %08x %04x \"",
++ label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
++ count = p->msg.data_length;
++ x = (char*) p->data;
++ if(count > DUMPMAX) {
++ count = DUMPMAX;
++ tag = "\n";
++ } else {
++ tag = "\"\n";
++ }
++ while(count-- > 0){
++ if((*x >= ' ') && (*x < 127)) {
++ fputc(*x, stderr);
++ } else {
++ fputc('.', stderr);
++ }
++ x++;
++ }
++ fputs(tag, stderr);
++}
++#endif
++
++static void send_ready(unsigned local, unsigned remote, atransport *t)
++{
++ D("Calling send_ready \n");
++ apacket *p = get_apacket();
++ p->msg.command = A_OKAY;
++ p->msg.arg0 = local;
++ p->msg.arg1 = remote;
++ send_packet(p, t);
++}
++
++static void send_close(unsigned local, unsigned remote, atransport *t)
++{
++ D("Calling send_close \n");
++ apacket *p = get_apacket();
++ p->msg.command = A_CLSE;
++ p->msg.arg0 = local;
++ p->msg.arg1 = remote;
++ send_packet(p, t);
++}
++
++static size_t fill_connect_data(char *buf, size_t bufsize)
++{
++#if ADB_HOST
++ return snprintf(buf, bufsize, "host::") + 1;
++#else
++ static const char *cnxn_props[] = {
++ "ro.product.name",
++ "ro.product.model",
++ "ro.product.device",
++ };
++ static const int num_cnxn_props = ARRAY_SIZE(cnxn_props);
++ static const char *values[] = {
++ "occam",
++ "Nexus 4",
++ "mako",
++ };
++ int i;
++ size_t remaining = bufsize;
++ size_t len;
++
++ len = snprintf(buf, remaining, "%s::", adb_device_banner);
++ remaining -= len;
++ buf += len;
++ for (i = 0; i < num_cnxn_props; i++) {
++ char value[PROPERTY_VALUE_MAX];
++ //property_get(cnxn_props[i], value, "");
++ len = snprintf(buf, remaining, "%s=%s;", cnxn_props[i], values[i]);
++ remaining -= len;
++ buf += len;
++ }
++
++ return bufsize - remaining + 1;
++#endif
++}
++
++static void send_connect(atransport *t)
++{
++ D("Calling send_connect \n");
++ apacket *cp = get_apacket();
++ cp->msg.command = A_CNXN;
++ cp->msg.arg0 = A_VERSION;
++ cp->msg.arg1 = MAX_PAYLOAD;
++ cp->msg.data_length = fill_connect_data((char *)cp->data,
++ sizeof(cp->data));
++ send_packet(cp, t);
++}
++
++static void send_auth_request(atransport *t)
++{
++ D("Calling send_auth_request\n");
++ apacket *p;
++ int ret;
++
++ ret = adb_auth_generate_token(t->token, sizeof(t->token));
++ if (ret != sizeof(t->token)) {
++ D("Error generating token ret=%d\n", ret);
++ return;
++ }
++
++ p = get_apacket();
++ memcpy(p->data, t->token, ret);
++ p->msg.command = A_AUTH;
++ p->msg.arg0 = ADB_AUTH_TOKEN;
++ p->msg.data_length = ret;
++ send_packet(p, t);
++}
++
++static void send_auth_response(uint8_t *token, size_t token_size, atransport *t)
++{
++ D("Calling send_auth_response\n");
++ apacket *p = get_apacket();
++ int ret;
++
++ ret = adb_auth_sign(t->key, token, token_size, p->data);
++ if (!ret) {
++ D("Error signing the token\n");
++ put_apacket(p);
++ return;
++ }
++
++ p->msg.command = A_AUTH;
++ p->msg.arg0 = ADB_AUTH_SIGNATURE;
++ p->msg.data_length = ret;
++ send_packet(p, t);
++}
++
++static void send_auth_publickey(atransport *t)
++{
++ D("Calling send_auth_publickey\n");
++ apacket *p = get_apacket();
++ int ret;
++
++ ret = adb_auth_get_userkey(p->data, sizeof(p->data));
++ if (!ret) {
++ D("Failed to get user public key\n");
++ put_apacket(p);
++ return;
++ }
++
++ p->msg.command = A_AUTH;
++ p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
++ p->msg.data_length = ret;
++ send_packet(p, t);
++}
++
++void adb_auth_verified(atransport *t)
++{
++ handle_online(t);
++ send_connect(t);
++}
++
++static char *connection_state_name(atransport *t)
++{
++ if (t == NULL) {
++ return "unknown";
++ }
++
++ switch(t->connection_state) {
++ case CS_BOOTLOADER:
++ return "bootloader";
++ case CS_DEVICE:
++ return "device";
++ case CS_OFFLINE:
++ return "offline";
++ default:
++ return "unknown";
++ }
++}
++
++/* qual_overwrite is used to overwrite a qualifier string. dst is a
++ * pointer to a char pointer. It is assumed that if *dst is non-NULL, it
++ * was malloc'ed and needs to freed. *dst will be set to a dup of src.
++ */
++static void qual_overwrite(char **dst, const char *src)
++{
++ if (!dst)
++ return;
++
++ free(*dst);
++ *dst = NULL;
++
++ if (!src || !*src)
++ return;
++
++ *dst = strdup(src);
++}
++
++void parse_banner(char *banner, atransport *t)
++{
++ static const char *prop_seps = ";";
++ static const char key_val_sep = '=';
++ char *cp;
++ char *type;
++
++ D("parse_banner: %s\n", banner);
++ type = banner;
++ cp = strchr(type, ':');
++ if (cp) {
++ *cp++ = 0;
++ /* Nothing is done with second field. */
++ cp = strchr(cp, ':');
++ if (cp) {
++ char *save;
++ char *key;
++ key = adb_strtok_r(cp + 1, prop_seps, &save);
++ while (key) {
++ cp = strchr(key, key_val_sep);
++ if (cp) {
++ *cp++ = '\0';
++ if (!strcmp(key, "ro.product.name"))
++ qual_overwrite(&t->product, cp);
++ else if (!strcmp(key, "ro.product.model"))
++ qual_overwrite(&t->model, cp);
++ else if (!strcmp(key, "ro.product.device"))
++ qual_overwrite(&t->device, cp);
++ }
++ key = adb_strtok_r(NULL, prop_seps, &save);
++ }
++ }
++ }
++
++ if(!strcmp(type, "bootloader")){
++ D("setting connection_state to CS_BOOTLOADER\n");
++ t->connection_state = CS_BOOTLOADER;
++ update_transports();
++ return;
++ }
++
++ if(!strcmp(type, "device")) {
++ D("setting connection_state to CS_DEVICE\n");
++ t->connection_state = CS_DEVICE;
++ update_transports();
++ return;
++ }
++
++ if(!strcmp(type, "recovery")) {
++ D("setting connection_state to CS_RECOVERY\n");
++ t->connection_state = CS_RECOVERY;
++ update_transports();
++ return;
++ }
++
++ if(!strcmp(type, "sideload")) {
++ D("setting connection_state to CS_SIDELOAD\n");
++ t->connection_state = CS_SIDELOAD;
++ update_transports();
++ return;
++ }
++
++ t->connection_state = CS_HOST;
++}
++
++void handle_packet(apacket *p, atransport *t)
++{
++ asocket *s;
++
++ D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
++ ((char*) (&(p->msg.command)))[1],
++ ((char*) (&(p->msg.command)))[2],
++ ((char*) (&(p->msg.command)))[3]);
++ print_packet("recv", p);
++
++ switch(p->msg.command){
++ case A_SYNC:
++ if(p->msg.arg0){
++ send_packet(p, t);
++ if(HOST) send_connect(t);
++ } else {
++ t->connection_state = CS_OFFLINE;
++ handle_offline(t);
++ send_packet(p, t);
++ }
++ return;
++
++ case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
++ /* XXX verify version, etc */
++ if(t->connection_state != CS_OFFLINE) {
++ t->connection_state = CS_OFFLINE;
++ handle_offline(t);
++ }
++
++ parse_banner((char*) p->data, t);
++
++ if (HOST || !auth_enabled) {
++ handle_online(t);
++ if(!HOST) send_connect(t);
++ } else {
++ send_auth_request(t);
++ }
++ break;
++
++ case A_AUTH:
++ if (p->msg.arg0 == ADB_AUTH_TOKEN) {
++ t->key = adb_auth_nextkey(t->key);
++ if (t->key) {
++ send_auth_response(p->data, p->msg.data_length, t);
++ } else {
++ /* No more private keys to try, send the public key */
++ send_auth_publickey(t);
++ }
++ } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
++ if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
++ adb_auth_verified(t);
++ t->failed_auth_attempts = 0;
++ } else {
++ if (t->failed_auth_attempts++ > 10)
++ adb_sleep_ms(1000);
++ send_auth_request(t);
++ }
++ } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
++ adb_auth_confirm_key(p->data, p->msg.data_length, t);
++ }
++ break;
++
++ case A_OPEN: /* OPEN(local-id, 0, "destination") */
++ if (t->online) {
++ char *name = (char*) p->data;
++ name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
++ s = create_local_service_socket(name);
++ if(s == 0) {
++ send_close(0, p->msg.arg0, t);
++ } else {
++ s->peer = create_remote_socket(p->msg.arg0, t);
++ s->peer->peer = s;
++ send_ready(s->id, s->peer->id, t);
++ s->ready(s);
++ }
++ }
++ break;
++
++ case A_OKAY: /* READY(local-id, remote-id, "") */
++ if (t->online) {
++ if((s = find_local_socket(p->msg.arg1))) {
++ if(s->peer == 0) {
++ s->peer = create_remote_socket(p->msg.arg0, t);
++ s->peer->peer = s;
++ }
++ s->ready(s);
++ }
++ }
++ break;
++
++ case A_CLSE: /* CLOSE(local-id, remote-id, "") */
++ if (t->online) {
++ if((s = find_local_socket(p->msg.arg1))) {
++ s->close(s);
++ }
++ }
++ break;
++
++ case A_WRTE:
++ if (t->online) {
++ if((s = find_local_socket(p->msg.arg1))) {
++ unsigned rid = p->msg.arg0;
++ p->len = p->msg.data_length;
++
++ if(s->enqueue(s, p) == 0) {
++ D("Enqueue the socket\n");
++ send_ready(s->id, rid, t);
++ }
++ return;
++ }
++ }
++ break;
++
++ default:
++ printf("handle_packet: what is %08x?!\n", p->msg.command);
++ }
++
++ put_apacket(p);
++}
++
++alistener listener_list = {
++ .next = &listener_list,
++ .prev = &listener_list,
++};
++
++static void ss_listener_event_func(int _fd, unsigned ev, void *_l)
++{
++ asocket *s;
++
++ if(ev & FDE_READ) {
++ struct sockaddr addr;
++ socklen_t alen;
++ int fd;
++
++ alen = sizeof(addr);
++ fd = adb_socket_accept(_fd, &addr, &alen);
++ if(fd < 0) return;
++
++ adb_socket_setbufsize(fd, CHUNK_SIZE);
++
++ s = create_local_socket(fd);
++ if(s) {
++ connect_to_smartsocket(s);
++ return;
++ }
++
++ adb_close(fd);
++ }
++}
++
++static void listener_event_func(int _fd, unsigned ev, void *_l)
++{
++ alistener *l = _l;
++ asocket *s;
++
++ if(ev & FDE_READ) {
++ struct sockaddr addr;
++ socklen_t alen;
++ int fd;
++
++ alen = sizeof(addr);
++ fd = adb_socket_accept(_fd, &addr, &alen);
++ if(fd < 0) return;
++
++ s = create_local_socket(fd);
++ if(s) {
++ s->transport = l->transport;
++ connect_to_remote(s, l->connect_to);
++ return;
++ }
++
++ adb_close(fd);
++ }
++}
++
++static void free_listener(alistener* l)
++{
++ if (l->next) {
++ l->next->prev = l->prev;
++ l->prev->next = l->next;
++ l->next = l->prev = l;
++ }
++
++ // closes the corresponding fd
++ fdevent_remove(&l->fde);
++
++ if (l->local_name)
++ free((char*)l->local_name);
++
++ if (l->connect_to)
++ free((char*)l->connect_to);
++
++ if (l->transport) {
++ remove_transport_disconnect(l->transport, &l->disconnect);
++ }
++ free(l);
++}
++
++static void listener_disconnect(void* _l, atransport* t)
++{
++ alistener* l = _l;
++
++ free_listener(l);
++}
++
++int local_name_to_fd(const char *name)
++{
++ int port;
++
++ if(!strncmp("tcp:", name, 4)){
++ int ret;
++ port = atoi(name + 4);
++
++ if (gListenAll > 0) {
++ ret = socket_inaddr_any_server(port, SOCK_STREAM);
++ } else {
++ ret = socket_loopback_server(port, SOCK_STREAM);
++ }
++
++ return ret;
++ }
++#ifndef HAVE_WIN32_IPC /* no Unix-domain sockets on Win32 */
++ // It's non-sensical to support the "reserved" space on the adb host side
++ if(!strncmp(name, "local:", 6)) {
++ return socket_local_server(name + 6,
++ ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
++ } else if(!strncmp(name, "localabstract:", 14)) {
++ return socket_local_server(name + 14,
++ ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
++ } else if(!strncmp(name, "localfilesystem:", 16)) {
++ return socket_local_server(name + 16,
++ ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
++ }
++
++#endif
++ printf("unknown local portname '%s'\n", name);
++ return -1;
++}
++
++// Write a single line describing a listener to a user-provided buffer.
++// Appends a trailing zero, even in case of truncation, but the function
++// returns the full line length.
++// If |buffer| is NULL, does not write but returns required size.
++static int format_listener(alistener* l, char* buffer, size_t buffer_len) {
++ // Format is simply:
++ //
++ // <device-serial> " " <local-name> " " <remote-name> "\n"
++ //
++ int local_len = strlen(l->local_name);
++ int connect_len = strlen(l->connect_to);
++ int serial_len = strlen(l->transport->serial);
++
++ if (buffer != NULL) {
++ snprintf(buffer, buffer_len, "%s %s %s\n",
++ l->transport->serial, l->local_name, l->connect_to);
++ }
++ // NOTE: snprintf() on Windows returns -1 in case of truncation, so
++ // return the computed line length instead.
++ return local_len + connect_len + serial_len + 3;
++}
++
++// Write the list of current listeners (network redirections) into a
++// user-provided buffer. Appends a trailing zero, even in case of
++// trunctaion, but return the full size in bytes.
++// If |buffer| is NULL, does not write but returns required size.
++static int format_listeners(char* buf, size_t buflen)
++{
++ alistener* l;
++ int result = 0;
++ for (l = listener_list.next; l != &listener_list; l = l->next) {
++ // Ignore special listeners like those for *smartsocket*
++ if (l->connect_to[0] == '*')
++ continue;
++ int len = format_listener(l, buf, buflen);
++ // Ensure there is space for the trailing zero.
++ result += len;
++ if (buf != NULL) {
++ buf += len;
++ buflen -= len;
++ if (buflen <= 0)
++ break;
++ }
++ }
++ return result;
++}
++
++static int remove_listener(const char *local_name, atransport* transport)
++{
++ alistener *l;
++
++ for (l = listener_list.next; l != &listener_list; l = l->next) {
++ if (!strcmp(local_name, l->local_name)) {
++ listener_disconnect(l, l->transport);
++ return 0;
++ }
++ }
++ return -1;
++}
++
++static void remove_all_listeners(void)
++{
++ alistener *l, *l_next;
++ for (l = listener_list.next; l != &listener_list; l = l_next) {
++ l_next = l->next;
++ // Never remove smart sockets.
++ if (l->connect_to[0] == '*')
++ continue;
++ listener_disconnect(l, l->transport);
++ }
++}
++
++// error/status codes for install_listener.
++typedef enum {
++ INSTALL_STATUS_OK = 0,
++ INSTALL_STATUS_INTERNAL_ERROR = -1,
++ INSTALL_STATUS_CANNOT_BIND = -2,
++ INSTALL_STATUS_CANNOT_REBIND = -3,
++} install_status_t;
++
++static install_status_t install_listener(const char *local_name,
++ const char *connect_to,
++ atransport* transport,
++ int no_rebind)
++{
++ alistener *l;
++
++ printf("install_listener('%s','%s')\n", local_name, connect_to);
++
++ for(l = listener_list.next; l != &listener_list; l = l->next){
++ if(strcmp(local_name, l->local_name) == 0) {
++ char *cto;
++
++ /* can't repurpose a smartsocket */
++ if(l->connect_to[0] == '*') {
++ return INSTALL_STATUS_INTERNAL_ERROR;
++ }
++
++ /* can't repurpose a listener if 'no_rebind' is true */
++ if (no_rebind) {
++ return INSTALL_STATUS_CANNOT_REBIND;
++ }
++
++ cto = strdup(connect_to);
++ if(cto == 0) {
++ return INSTALL_STATUS_INTERNAL_ERROR;
++ }
++
++ //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
++ free((void*) l->connect_to);
++ l->connect_to = cto;
++ if (l->transport != transport) {
++ remove_transport_disconnect(l->transport, &l->disconnect);
++ l->transport = transport;
++ add_transport_disconnect(l->transport, &l->disconnect);
++ }
++ return INSTALL_STATUS_OK;
++ }
++ }
++
++ if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
++ if((l->local_name = strdup(local_name)) == 0) goto nomem;
++ if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
++
++
++ l->fd = local_name_to_fd(local_name);
++ if(l->fd < 0) {
++ free((void*) l->local_name);
++ free((void*) l->connect_to);
++ free(l);
++ printf("cannot bind '%s'\n", local_name);
++ return -2;
++ }
++
++ close_on_exec(l->fd);
++ if(!strcmp(l->connect_to, "*smartsocket*")) {
++ fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
++ } else {
++ fdevent_install(&l->fde, l->fd, listener_event_func, l);
++ }
++ fdevent_set(&l->fde, FDE_READ);
++
++ l->next = &listener_list;
++ l->prev = listener_list.prev;
++ l->next->prev = l;
++ l->prev->next = l;
++ l->transport = transport;
++
++ if (transport) {
++ l->disconnect.opaque = l;
++ l->disconnect.func = listener_disconnect;
++ add_transport_disconnect(transport, &l->disconnect);
++ }
++ return INSTALL_STATUS_OK;
++
++nomem:
++ fatal("cannot allocate listener");
++ return INSTALL_STATUS_INTERNAL_ERROR;
++}
++
++#ifdef HAVE_WIN32_PROC
++static BOOL WINAPI ctrlc_handler(DWORD type)
++{
++ exit(STATUS_CONTROL_C_EXIT);
++ return TRUE;
++}
++#endif
++
++static void adb_cleanup(void)
++{
++ usb_cleanup();
++}
++
++void start_logging(void)
++{
++#ifdef HAVE_WIN32_PROC
++ char temp[ MAX_PATH ];
++ FILE* fnul;
++ FILE* flog;
++
++ GetTempPath( sizeof(temp) - 8, temp );
++ strcat( temp, "adb.log" );
++
++ /* Win32 specific redirections */
++ fnul = fopen( "NUL", "rt" );
++ if (fnul != NULL)
++ stdin[0] = fnul[0];
++
++ flog = fopen( temp, "at" );
++ if (flog == NULL)
++ flog = fnul;
++
++ setvbuf( flog, NULL, _IONBF, 0 );
++
++ stdout[0] = flog[0];
++ stderr[0] = flog[0];
++ fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
++#else
++ int fd;
++
++ fd = unix_open("/dev/null", O_RDONLY);
++ dup2(fd, 0);
++ adb_close(fd);
++
++ fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
++ if(fd < 0) {
++ fd = unix_open("/dev/null", O_WRONLY);
++ }
++ dup2(fd, 1);
++ dup2(fd, 2);
++ adb_close(fd);
++ fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
++#endif
++}
++
++#if !ADB_HOST
++void start_device_log(void)
++{
++ int fd;
++ char path[PATH_MAX];
++ struct tm now;
++ time_t t;
++ char value[PROPERTY_VALUE_MAX];
++
++ // read the trace mask from persistent property persist.adb.trace_mask
++ // give up if the property is not set or cannot be parsed
++ //property_get("persist.adb.trace_mask", value, "");
++ //if (sscanf(value, "%x", &adb_trace_mask) != 1)
++ return;
++
++ adb_mkdir("/data/adb", 0775);
++ tzset();
++ time(&t);
++ localtime_r(&t, &now);
++ strftime(path, sizeof(path),
++ "/data/adb/adb-%Y-%m-%d-%H-%M-%S.txt",
++ &now);
++ fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
++ if (fd < 0)
++ return;
++
++ // redirect stdout and stderr to the log file
++ dup2(fd, 1);
++ dup2(fd, 2);
++ fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
++ adb_close(fd);
++
++ fd = unix_open("/dev/null", O_RDONLY);
++ dup2(fd, 0);
++ adb_close(fd);
++}
++#endif
++
++#if ADB_HOST
++int launch_server(int server_port)
++{
++#ifdef HAVE_WIN32_PROC
++ /* we need to start the server in the background */
++ /* we create a PIPE that will be used to wait for the server's "OK" */
++ /* message since the pipe handles must be inheritable, we use a */
++ /* security attribute */
++ HANDLE pipe_read, pipe_write;
++ HANDLE stdout_handle, stderr_handle;
++ SECURITY_ATTRIBUTES sa;
++ STARTUPINFO startup;
++ PROCESS_INFORMATION pinfo;
++ char program_path[ MAX_PATH ];
++ int ret;
++
++ sa.nLength = sizeof(sa);
++ sa.lpSecurityDescriptor = NULL;
++ sa.bInheritHandle = TRUE;
++
++ /* create pipe, and ensure its read handle isn't inheritable */
++ ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
++ if (!ret) {
++ fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
++ return -1;
++ }
++
++ SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
++
++ /* Some programs want to launch an adb command and collect its output by
++ * calling CreateProcess with inheritable stdout/stderr handles, then
++ * using read() to get its output. When this happens, the stdout/stderr
++ * handles passed to the adb client process will also be inheritable.
++ * When starting the adb server here, care must be taken to reset them
++ * to non-inheritable.
++ * Otherwise, something bad happens: even if the adb command completes,
++ * the calling process is stuck while read()-ing from the stdout/stderr
++ * descriptors, because they're connected to corresponding handles in the
++ * adb server process (even if the latter never uses/writes to them).
++ */
++ stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE );
++ stderr_handle = GetStdHandle( STD_ERROR_HANDLE );
++ if (stdout_handle != INVALID_HANDLE_VALUE) {
++ SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 );
++ }
++ if (stderr_handle != INVALID_HANDLE_VALUE) {
++ SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 );
++ }
++
++ ZeroMemory( &startup, sizeof(startup) );
++ startup.cb = sizeof(startup);
++ startup.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
++ startup.hStdOutput = pipe_write;
++ startup.hStdError = GetStdHandle( STD_ERROR_HANDLE );
++ startup.dwFlags = STARTF_USESTDHANDLES;
++
++ ZeroMemory( &pinfo, sizeof(pinfo) );
++
++ /* get path of current program */
++ GetModuleFileName( NULL, program_path, sizeof(program_path) );
++
++ ret = CreateProcess(
++ program_path, /* program path */
++ "adb fork-server server",
++ /* the fork-server argument will set the
++ debug = 2 in the child */
++ NULL, /* process handle is not inheritable */
++ NULL, /* thread handle is not inheritable */
++ TRUE, /* yes, inherit some handles */
++ DETACHED_PROCESS, /* the new process doesn't have a console */
++ NULL, /* use parent's environment block */
++ NULL, /* use parent's starting directory */
++ &startup, /* startup info, i.e. std handles */
++ &pinfo );
++
++ CloseHandle( pipe_write );
++
++ if (!ret) {
++ fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
++ CloseHandle( pipe_read );
++ return -1;
++ }
++
++ CloseHandle( pinfo.hProcess );
++ CloseHandle( pinfo.hThread );
++
++ /* wait for the "OK\n" message */
++ {
++ char temp[3];
++ DWORD count;
++
++ ret = ReadFile( pipe_read, temp, 3, &count, NULL );
++ CloseHandle( pipe_read );
++ if ( !ret ) {
++ fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
++ return -1;
++ }
++ if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
++ fprintf(stderr, "ADB server didn't ACK\n" );
++ return -1;
++ }
++ }
++#elif defined(HAVE_FORKEXEC)
++ char path[PATH_MAX];
++ int fd[2];
++
++ // set up a pipe so the child can tell us when it is ready.
++ // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
++ if (pipe(fd)) {
++ fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
++ return -1;
++ }
++ get_my_path(path, PATH_MAX);
++ pid_t pid = fork();
++ if(pid < 0) return -1;
++
++ if (pid == 0) {
++ // child side of the fork
++
++ // redirect stderr to the pipe
++ // we use stderr instead of stdout due to stdout's buffering behavior.
++ adb_close(fd[0]);
++ dup2(fd[1], STDERR_FILENO);
++ adb_close(fd[1]);
++
++ char str_port[30];
++ snprintf(str_port, sizeof(str_port), "%d", server_port);
++ // child process
++ int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL);
++ // this should not return
++ fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
++ } else {
++ // parent side of the fork
++
++ char temp[3];
++
++ temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
++ // wait for the "OK\n" message
++ adb_close(fd[1]);
++ int ret = adb_read(fd[0], temp, 3);
++ int saved_errno = errno;
++ adb_close(fd[0]);
++ if (ret < 0) {
++ fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno);
++ return -1;
++ }
++ if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
++ fprintf(stderr, "ADB server didn't ACK\n" );
++ return -1;
++ }
++
++ setsid();
++ }
++#else
++#error "cannot implement background server start on this platform"
++#endif
++ return 0;
++}
++#endif
++
++/* Constructs a local name of form tcp:port.
++ * target_str points to the target string, it's content will be overwritten.
++ * target_size is the capacity of the target string.
++ * server_port is the port number to use for the local name.
++ */
++void build_local_name(char* target_str, size_t target_size, int server_port)
++{
++ snprintf(target_str, target_size, "tcp:%d", server_port);
++}
++
++#if !ADB_HOST
++static int should_drop_privileges() {
++#ifndef ALLOW_ADBD_ROOT
++ return 1;
++#else /* ALLOW_ADBD_ROOT */
++ int secure = 0;
++ char value[PROPERTY_VALUE_MAX];
++
++ return 0;
++ /* run adbd in secure mode if ro.secure is set and
++ ** we are not in the emulator
++ */
++// property_get("ro.kernel.qemu", value, "");
++ if (strcmp(value, "1") != 0) {
++// property_get("ro.secure", value, "1");
++ if (strcmp(value, "1") == 0) {
++ // don't run as root if ro.secure is set...
++ secure = 1;
++
++ // ... except we allow running as root in userdebug builds if the
++ // service.adb.root property has been set by the "adb root" command
++// property_get("ro.debuggable", value, "");
++ if (strcmp(value, "1") == 0) {
++// property_get("service.adb.root", value, "");
++ if (strcmp(value, "1") == 0) {
++ secure = 0;
++ }
++ }
++ }
++ }
++ return secure;
++#endif /* ALLOW_ADBD_ROOT */
++}
++#endif /* !ADB_HOST */
++
++int adb_main(int is_daemon, int server_port)
++{
++#if !ADB_HOST
++ int port;
++ char value[PROPERTY_VALUE_MAX];
++
++ umask(000);
++#endif
++
++ atexit(adb_cleanup);
++#ifdef HAVE_WIN32_PROC
++ SetConsoleCtrlHandler( ctrlc_handler, TRUE );
++#elif defined(HAVE_FORKEXEC)
++ // No SIGCHLD. Let the service subproc handle its children.
++ signal(SIGPIPE, SIG_IGN);
++#endif
++
++ init_transport_registration();
++
++#if ADB_HOST
++ HOST = 1;
++ usb_vendors_init();
++ usb_init();
++ local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
++ adb_auth_init();
++
++ char local_name[30];
++ build_local_name(local_name, sizeof(local_name), server_port);
++ if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
++ exit(1);
++ }
++#else
++ //property_get("ro.adb.secure", value, "0");
++ auth_enabled = 0;//!strcmp(value, "1");
++ if (auth_enabled)
++ adb_auth_init();
++
++ // Our external storage path may be different than apps, since
++ // we aren't able to bind mount after dropping root.
++ const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
++ if (NULL != adb_external_storage) {
++ setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
++ } else {
++ D("Warning: ADB_EXTERNAL_STORAGE is not set. Leaving EXTERNAL_STORAGE"
++ " unchanged.\n");
++ }
++
++ /* don't listen on a port (default 5037) if running in secure mode */
++ /* don't run as root if we are running in secure mode */
++ if (should_drop_privileges()) {
++ struct __user_cap_header_struct header;
++ struct __user_cap_data_struct cap[2];
++
++ if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
++ exit(1);
++ }
++
++ /* add extra groups:
++ ** AID_ADB to access the USB driver
++ ** AID_LOG to read system logs (adb logcat)
++ ** AID_INPUT to diagnose input issues (getevent)
++ ** AID_INET to diagnose network issues (netcfg, ping)
++ ** AID_GRAPHICS to access the frame buffer
++ ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
++ ** AID_SDCARD_R to allow reading from the SD card
++ ** AID_SDCARD_RW to allow writing to the SD card
++ ** AID_MOUNT to allow unmounting the SD card before rebooting
++ ** AID_NET_BW_STATS to read out qtaguid statistics
++ */
++ gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
++ AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
++ AID_MOUNT, AID_NET_BW_STATS };
++ if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
++ exit(1);
++ }
++
++ /* then switch user and group to "shell" */
++ if (setgid(AID_SHELL) != 0) {
++ exit(1);
++ }
++ if (setuid(AID_SHELL) != 0) {
++ exit(1);
++ }
++
++ memset(&header, 0, sizeof(header));
++ memset(cap, 0, sizeof(cap));
++
++ /* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */
++ header.version = _LINUX_CAPABILITY_VERSION_3;
++ header.pid = 0;
++ cap[CAP_TO_INDEX(CAP_SYS_BOOT)].effective |= CAP_TO_MASK(CAP_SYS_BOOT);
++ cap[CAP_TO_INDEX(CAP_SYS_BOOT)].permitted |= CAP_TO_MASK(CAP_SYS_BOOT);
++ capset(&header, cap);
++
++ D("Local port disabled\n");
++ } else {
++ char local_name[30];
++ build_local_name(local_name, sizeof(local_name), server_port);
++ if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
++ exit(1);
++ }
++ }
++
++ int usb = 0;
++ if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {
++ // listen on USB
++ usb_init();
++ usb = 1;
++ }
++
++ // If one of these properties is set, also listen on that port
++ // If one of the properties isn't set and we couldn't listen on usb,
++ // listen on the default port.
++ //property_get("service.adb.tcp.port", value, "");
++ //if (!value[0]) {
++ //property_get("persist.adb.tcp.port", value, "");
++ //}
++ //if (sscanf(value, "%d", &port) == 1 && port > 0) {
++ // printf("using port=%d\n", port);
++ // listen on TCP port specified by service.adb.tcp.port property
++ // local_init(port);
++ //} else
++ if (!usb) {
++ printf("Using USB\n");
++ // listen on default port
++ local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
++ }
++
++ D("adb_main(): pre init_jdwp()\n");
++ init_jdwp();
++ D("adb_main(): post init_jdwp()\n");
++#endif
++
++ if (is_daemon)
++ {
++ // inform our parent that we are up and running.
++#ifdef HAVE_WIN32_PROC
++ DWORD count;
++ WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL );
++#elif defined(HAVE_FORKEXEC)
++ fprintf(stderr, "OK\n");
++#endif
++ start_logging();
++ }
++ D("Event loop starting\n");
++
++ fdevent_loop();
++
++ usb_cleanup();
++
++ return 0;
++}
++
++#if ADB_HOST
++void connect_device(char* host, char* buffer, int buffer_size)
++{
++ int port, fd;
++ char* portstr = strchr(host, ':');
++ char hostbuf[100];
++ char serial[100];
++
++ strncpy(hostbuf, host, sizeof(hostbuf) - 1);
++ if (portstr) {
++ if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) {
++ snprintf(buffer, buffer_size, "bad host name %s", host);
++ return;
++ }
++ // zero terminate the host at the point we found the colon
++ hostbuf[portstr - host] = 0;
++ if (sscanf(portstr + 1, "%d", &port) == 0) {
++ snprintf(buffer, buffer_size, "bad port number %s", portstr);
++ return;
++ }
++ } else {
++ port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
++ }
++
++ snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
++ if (find_transport(serial)) {
++ snprintf(buffer, buffer_size, "already connected to %s", serial);
++ return;
++ }
++
++ fd = socket_network_client(hostbuf, port, SOCK_STREAM);
++ if (fd < 0) {
++ snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
++ return;
++ }
++
++ D("client: connected on remote on fd %d\n", fd);
++ close_on_exec(fd);
++ disable_tcp_nagle(fd);
++ register_socket_transport(fd, serial, port, 0);
++ snprintf(buffer, buffer_size, "connected to %s", serial);
++}
++
++void connect_emulator(char* port_spec, char* buffer, int buffer_size)
++{
++ char* port_separator = strchr(port_spec, ',');
++ if (!port_separator) {
++ snprintf(buffer, buffer_size,
++ "unable to parse '%s' as <console port>,<adb port>",
++ port_spec);
++ return;
++ }
++
++ // Zero-terminate console port and make port_separator point to 2nd port.
++ *port_separator++ = 0;
++ int console_port = strtol(port_spec, NULL, 0);
++ int adb_port = strtol(port_separator, NULL, 0);
++ if (!(console_port > 0 && adb_port > 0)) {
++ *(port_separator - 1) = ',';
++ snprintf(buffer, buffer_size,
++ "Invalid port numbers: Expected positive numbers, got '%s'",
++ port_spec);
++ return;
++ }
++
++ /* Check if the emulator is already known.
++ * Note: There's a small but harmless race condition here: An emulator not
++ * present just yet could be registered by another invocation right
++ * after doing this check here. However, local_connect protects
++ * against double-registration too. From here, a better error message
++ * can be produced. In the case of the race condition, the very specific
++ * error message won't be shown, but the data doesn't get corrupted. */
++ atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
++ if (known_emulator != NULL) {
++ snprintf(buffer, buffer_size,
++ "Emulator on port %d already registered.", adb_port);
++ return;
++ }
++
++ /* Check if more emulators can be registered. Similar unproblematic
++ * race condition as above. */
++ int candidate_slot = get_available_local_transport_index();
++ if (candidate_slot < 0) {
++ snprintf(buffer, buffer_size, "Cannot accept more emulators.");
++ return;
++ }
++
++ /* Preconditions met, try to connect to the emulator. */
++ if (!local_connect_arbitrary_ports(console_port, adb_port)) {
++ snprintf(buffer, buffer_size,
++ "Connected to emulator on ports %d,%d", console_port, adb_port);
++ } else {
++ snprintf(buffer, buffer_size,
++ "Could not connect to emulator on ports %d,%d",
++ console_port, adb_port);
++ }
++}
++#endif
++
++int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
++{
++ atransport *transport = NULL;
++ char buf[4096];
++
++ if(!strcmp(service, "kill")) {
++ fprintf(stderr,"adb server killed by remote request\n");
++ fflush(stdout);
++ adb_write(reply_fd, "OKAY", 4);
++ usb_cleanup();
++ exit(0);
++ }
++
++#if ADB_HOST
++ // "transport:" is used for switching transport with a specified serial number
++ // "transport-usb:" is used for switching transport to the only USB transport
++ // "transport-local:" is used for switching transport to the only local transport
++ // "transport-any:" is used for switching transport to the only transport
++ if (!strncmp(service, "transport", strlen("transport"))) {
++ char* error_string = "unknown failure";
++ transport_type type = kTransportAny;
++
++ if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
++ type = kTransportUsb;
++ } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
++ type = kTransportLocal;
++ } else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
++ type = kTransportAny;
++ } else if (!strncmp(service, "transport:", strlen("transport:"))) {
++ service += strlen("transport:");
++ serial = service;
++ }
++
++ transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
++
++ if (transport) {
++ s->transport = transport;
++ adb_write(reply_fd, "OKAY", 4);
++ } else {
++ sendfailmsg(reply_fd, error_string);
++ }
++ return 1;
++ }
++
++ // return a list of all connected devices
++ if (!strncmp(service, "devices", 7)) {
++ char buffer[4096];
++ int use_long = !strcmp(service+7, "-l");
++ if (use_long || service[7] == 0) {
++ memset(buf, 0, sizeof(buf));
++ memset(buffer, 0, sizeof(buffer));
++ D("Getting device list \n");
++ list_transports(buffer, sizeof(buffer), use_long);
++ snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
++ D("Wrote device list \n");
++ writex(reply_fd, buf, strlen(buf));
++ return 0;
++ }
++ }
++
++ // add a new TCP transport, device or emulator
++ if (!strncmp(service, "connect:", 8)) {
++ char buffer[4096];
++ char* host = service + 8;
++ if (!strncmp(host, "emu:", 4)) {
++ connect_emulator(host + 4, buffer, sizeof(buffer));
++ } else {
++ connect_device(host, buffer, sizeof(buffer));
++ }
++ // Send response for emulator and device
++ snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
++ writex(reply_fd, buf, strlen(buf));
++ return 0;
++ }
++
++ // remove TCP transport
++ if (!strncmp(service, "disconnect:", 11)) {
++ char buffer[4096];
++ memset(buffer, 0, sizeof(buffer));
++ char* serial = service + 11;
++ if (serial[0] == 0) {
++ // disconnect from all TCP devices
++ unregister_all_tcp_transports();
++ } else {
++ char hostbuf[100];
++ // assume port 5555 if no port is specified
++ if (!strchr(serial, ':')) {
++ snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial);
++ serial = hostbuf;
++ }
++ atransport *t = find_transport(serial);
++
++ if (t) {
++ unregister_transport(t);
++ } else {
++ snprintf(buffer, sizeof(buffer), "No such device %s", serial);
++ }
++ }
++
++ snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
++ writex(reply_fd, buf, strlen(buf));
++ return 0;
++ }
++
++ // returns our value for ADB_SERVER_VERSION
++ if (!strcmp(service, "version")) {
++ char version[12];
++ snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
++ snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);
++ writex(reply_fd, buf, strlen(buf));
++ return 0;
++ }
++
++ if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
++ char *out = "unknown";
++ transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
++ if (transport && transport->serial) {
++ out = transport->serial;
++ }
++ snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
++ writex(reply_fd, buf, strlen(buf));
++ return 0;
++ }
++ if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
++ char *out = "unknown";
++ transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
++ if (transport && transport->devpath) {
++ out = transport->devpath;
++ }
++ snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
++ writex(reply_fd, buf, strlen(buf));
++ return 0;
++ }
++ // indicates a new emulator instance has started
++ if (!strncmp(service,"emulator:",9)) {
++ int port = atoi(service+9);
++ local_connect(port);
++ /* we don't even need to send a reply */
++ return 0;
++ }
++#endif // ADB_HOST
++
++ if(!strcmp(service,"list-forward")) {
++ // Create the list of forward redirections.
++ char header[9];
++ int buffer_size = format_listeners(NULL, 0);
++ // Add one byte for the trailing zero.
++ char* buffer = malloc(buffer_size+1);
++ (void) format_listeners(buffer, buffer_size+1);
++ snprintf(header, sizeof header, "OKAY%04x", buffer_size);
++ writex(reply_fd, header, 8);
++ writex(reply_fd, buffer, buffer_size);
++ free(buffer);
++ return 0;
++ }
++
++ if (!strcmp(service,"killforward-all")) {
++ remove_all_listeners();
++ adb_write(reply_fd, "OKAYOKAY", 8);
++ return 0;
++ }
++
++ if(!strncmp(service,"forward:",8) ||
++ !strncmp(service,"killforward:",12)) {
++ char *local, *remote, *err;
++ int r;
++ atransport *transport;
++
++ int createForward = strncmp(service,"kill",4);
++ int no_rebind = 0;
++
++ local = strchr(service, ':') + 1;
++
++ // Handle forward:norebind:<local>... here
++ if (createForward && !strncmp(local, "norebind:", 9)) {
++ no_rebind = 1;
++ local = strchr(local, ':') + 1;
++ }
++
++ remote = strchr(local,';');
++
++ if (createForward) {
++ // Check forward: parameter format: '<local>;<remote>'
++ if(remote == 0) {
++ sendfailmsg(reply_fd, "malformed forward spec");
++ return 0;
++ }
++
++ *remote++ = 0;
++ if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
++ sendfailmsg(reply_fd, "malformed forward spec");
++ return 0;
++ }
++ } else {
++ // Check killforward: parameter format: '<local>'
++ if (local[0] == 0) {
++ sendfailmsg(reply_fd, "malformed forward spec");
++ return 0;
++ }
++ }
++
++ transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
++ if (!transport) {
++ sendfailmsg(reply_fd, err);
++ return 0;
++ }
++
++ if (createForward) {
++ r = install_listener(local, remote, transport, no_rebind);
++ } else {
++ r = remove_listener(local, transport);
++ }
++ if(r == 0) {
++ /* 1st OKAY is connect, 2nd OKAY is status */
++ writex(reply_fd, "OKAYOKAY", 8);
++ return 0;
++ }
++
++ if (createForward) {
++ const char* message;
++ switch (r) {
++ case INSTALL_STATUS_CANNOT_BIND:
++ message = "cannot bind to socket";
++ break;
++ case INSTALL_STATUS_CANNOT_REBIND:
++ message = "cannot rebind existing socket";
++ break;
++ default:
++ message = "internal error";
++ }
++ sendfailmsg(reply_fd, message);
++ } else {
++ sendfailmsg(reply_fd, "cannot remove listener");
++ }
++ return 0;
++ }
++
++ if(!strncmp(service,"get-state",strlen("get-state"))) {
++ transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
++ char *state = connection_state_name(transport);
++ snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state);
++ writex(reply_fd, buf, strlen(buf));
++ return 0;
++ }
++ return -1;
++}
++
++#if !ADB_HOST
++int recovery_mode = 0;
++#endif
++
++int main(int argc, char **argv)
++{
++#if ADB_HOST
++ adb_sysdeps_init();
++ adb_trace_init();
++ D("Handling commandline()\n");
++ return adb_commandline(argc - 1, argv + 1);
++#else
++ /* If adbd runs inside the emulator this will enable adb tracing via
++ * adb-debug qemud service in the emulator. */
++ adb_qemu_trace_init();
++ if((argc > 1) && (!strcmp(argv[1],"recovery"))) {
++ adb_device_banner = "recovery";
++ recovery_mode = 1;
++ }
++
++ start_device_log();
++ D("Handling main()\n");
++ return adb_main(0, DEFAULT_ADB_PORT);
++#endif
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/adb.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/adb.h 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,491 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef __ADB_H
++#define __ADB_H
++
++#include <limits.h>
++
++#include "transport.h" /* readx(), writex() */
++
++#define MAX_PAYLOAD 4096
++
++#define A_SYNC 0x434e5953
++#define A_CNXN 0x4e584e43
++#define A_OPEN 0x4e45504f
++#define A_OKAY 0x59414b4f
++#define A_CLSE 0x45534c43
++#define A_WRTE 0x45545257
++#define A_AUTH 0x48545541
++
++#define A_VERSION 0x01000000 // ADB protocol version
++
++#define ADB_VERSION_MAJOR 1 // Used for help/version information
++#define ADB_VERSION_MINOR 0 // Used for help/version information
++
++#define ADB_SERVER_VERSION 31 // Increment this when we want to force users to start a new adb server
++
++typedef struct amessage amessage;
++typedef struct apacket apacket;
++typedef struct asocket asocket;
++typedef struct alistener alistener;
++typedef struct aservice aservice;
++typedef struct atransport atransport;
++typedef struct adisconnect adisconnect;
++typedef struct usb_handle usb_handle;
++
++struct amessage {
++ unsigned command; /* command identifier constant */
++ unsigned arg0; /* first argument */
++ unsigned arg1; /* second argument */
++ unsigned data_length; /* length of payload (0 is allowed) */
++ unsigned data_check; /* checksum of data payload */
++ unsigned magic; /* command ^ 0xffffffff */
++};
++
++struct apacket
++{
++ apacket *next;
++
++ unsigned len;
++ unsigned char *ptr;
++
++ amessage msg;
++ unsigned char data[MAX_PAYLOAD];
++};
++
++/* An asocket represents one half of a connection between a local and
++** remote entity. A local asocket is bound to a file descriptor. A
++** remote asocket is bound to the protocol engine.
++*/
++struct asocket {
++ /* chain pointers for the local/remote list of
++ ** asockets that this asocket lives in
++ */
++ asocket *next;
++ asocket *prev;
++
++ /* the unique identifier for this asocket
++ */
++ unsigned id;
++
++ /* flag: set when the socket's peer has closed
++ ** but packets are still queued for delivery
++ */
++ int closing;
++
++ /* flag: quit adbd when both ends close the
++ ** local service socket
++ */
++ int exit_on_close;
++
++ /* the asocket we are connected to
++ */
++
++ asocket *peer;
++
++ /* For local asockets, the fde is used to bind
++ ** us to our fd event system. For remote asockets
++ ** these fields are not used.
++ */
++ fdevent fde;
++ int fd;
++
++ /* queue of apackets waiting to be written
++ */
++ apacket *pkt_first;
++ apacket *pkt_last;
++
++ /* enqueue is called by our peer when it has data
++ ** for us. It should return 0 if we can accept more
++ ** data or 1 if not. If we return 1, we must call
++ ** peer->ready() when we once again are ready to
++ ** receive data.
++ */
++ int (*enqueue)(asocket *s, apacket *pkt);
++
++ /* ready is called by the peer when it is ready for
++ ** us to send data via enqueue again
++ */
++ void (*ready)(asocket *s);
++
++ /* close is called by the peer when it has gone away.
++ ** we are not allowed to make any further calls on the
++ ** peer once our close method is called.
++ */
++ void (*close)(asocket *s);
++
++ /* socket-type-specific extradata */
++ void *extra;
++
++ /* A socket is bound to atransport */
++ atransport *transport;
++};
++
++
++/* the adisconnect structure is used to record a callback that
++** will be called whenever a transport is disconnected (e.g. by the user)
++** this should be used to cleanup objects that depend on the
++** transport (e.g. remote sockets, listeners, etc...)
++*/
++struct adisconnect
++{
++ void (*func)(void* opaque, atransport* t);
++ void* opaque;
++ adisconnect* next;
++ adisconnect* prev;
++};
++
++
++/* a transport object models the connection to a remote device or emulator
++** there is one transport per connected device/emulator. a "local transport"
++** connects through TCP (for the emulator), while a "usb transport" through
++** USB (for real devices)
++**
++** note that kTransportHost doesn't really correspond to a real transport
++** object, it's a special value used to indicate that a client wants to
++** connect to a service implemented within the ADB server itself.
++*/
++typedef enum transport_type {
++ kTransportUsb,
++ kTransportLocal,
++ kTransportAny,
++ kTransportHost,
++} transport_type;
++
++#define TOKEN_SIZE 20
++
++struct atransport
++{
++ atransport *next;
++ atransport *prev;
++
++ int (*read_from_remote)(apacket *p, atransport *t);
++ int (*write_to_remote)(apacket *p, atransport *t);
++ void (*close)(atransport *t);
++ void (*kick)(atransport *t);
++
++ int fd;
++ int transport_socket;
++ fdevent transport_fde;
++ int ref_count;
++ unsigned sync_token;
++ int connection_state;
++ int online;
++ transport_type type;
++
++ /* usb handle or socket fd as needed */
++ usb_handle *usb;
++ int sfd;
++
++ /* used to identify transports for clients */
++ char *serial;
++ char *product;
++ char *model;
++ char *device;
++ char *devpath;
++ int adb_port; // Use for emulators (local transport)
++
++ /* a list of adisconnect callbacks called when the transport is kicked */
++ int kicked;
++ adisconnect disconnects;
++
++ void *key;
++ unsigned char token[TOKEN_SIZE];
++ fdevent auth_fde;
++ unsigned failed_auth_attempts;
++};
++
++
++/* A listener is an entity which binds to a local port
++** and, upon receiving a connection on that port, creates
++** an asocket to connect the new local connection to a
++** specific remote service.
++**
++** TODO: some listeners read from the new connection to
++** determine what exact service to connect to on the far
++** side.
++*/
++struct alistener
++{
++ alistener *next;
++ alistener *prev;
++
++ fdevent fde;
++ int fd;
++
++ const char *local_name;
++ const char *connect_to;
++ atransport *transport;
++ adisconnect disconnect;
++};
++
++
++void print_packet(const char *label, apacket *p);
++
++asocket *find_local_socket(unsigned id);
++void install_local_socket(asocket *s);
++void remove_socket(asocket *s);
++void close_all_sockets(atransport *t);
++
++#define LOCAL_CLIENT_PREFIX "emulator-"
++
++asocket *create_local_socket(int fd);
++asocket *create_local_service_socket(const char *destination);
++
++asocket *create_remote_socket(unsigned id, atransport *t);
++void connect_to_remote(asocket *s, const char *destination);
++void connect_to_smartsocket(asocket *s);
++
++void fatal(const char *fmt, ...);
++void fatal_errno(const char *fmt, ...);
++
++void handle_packet(apacket *p, atransport *t);
++void send_packet(apacket *p, atransport *t);
++
++void get_my_path(char *s, size_t maxLen);
++int launch_server(int server_port);
++int adb_main(int is_daemon, int server_port);
++
++
++/* transports are ref-counted
++** get_device_transport does an acquire on your behalf before returning
++*/
++void init_transport_registration(void);
++int list_transports(char *buf, size_t bufsize, int long_listing);
++void update_transports(void);
++
++asocket* create_device_tracker(void);
++
++/* Obtain a transport from the available transports.
++** If state is != CS_ANY, only transports in that state are considered.
++** If serial is non-NULL then only the device with that serial will be chosen.
++** If no suitable transport is found, error is set.
++*/
++atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out);
++void add_transport_disconnect( atransport* t, adisconnect* dis );
++void remove_transport_disconnect( atransport* t, adisconnect* dis );
++void run_transport_disconnects( atransport* t );
++void kick_transport( atransport* t );
++
++/* initialize a transport object's func pointers and state */
++#if ADB_HOST
++int get_available_local_transport_index();
++#endif
++int init_socket_transport(atransport *t, int s, int port, int local);
++void init_usb_transport(atransport *t, usb_handle *usb, int state);
++
++/* for MacOS X cleanup */
++void close_usb_devices();
++
++/* cause new transports to be init'd and added to the list */
++void register_socket_transport(int s, const char *serial, int port, int local);
++
++/* these should only be used for the "adb disconnect" command */
++void unregister_transport(atransport *t);
++void unregister_all_tcp_transports();
++
++void register_usb_transport(usb_handle *h, const char *serial, const char *devpath, unsigned writeable);
++
++/* this should only be used for transports with connection_state == CS_NOPERM */
++void unregister_usb_transport(usb_handle *usb);
++
++atransport *find_transport(const char *serial);
++#if ADB_HOST
++atransport* find_emulator_transport_by_adb_port(int adb_port);
++#endif
++
++int service_to_fd(const char *name);
++#if ADB_HOST
++asocket *host_service_to_socket(const char* name, const char *serial);
++#endif
++
++#if !ADB_HOST
++int init_jdwp(void);
++asocket* create_jdwp_service_socket();
++asocket* create_jdwp_tracker_service_socket();
++int create_jdwp_connection_fd(int jdwp_pid);
++#endif
++
++#if !ADB_HOST
++typedef enum {
++ BACKUP,
++ RESTORE
++} BackupOperation;
++int backup_service(BackupOperation operation, char* args);
++void framebuffer_service(int fd, void *cookie);
++void log_service(int fd, void *cookie);
++void remount_service(int fd, void *cookie);
++char * get_log_file_path(const char * log_name);
++#endif
++
++/* packet allocator */
++apacket *get_apacket(void);
++void put_apacket(apacket *p);
++
++int check_header(apacket *p);
++int check_data(apacket *p);
++
++/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
++
++#define ADB_TRACE 1
++
++/* IMPORTANT: if you change the following list, don't
++ * forget to update the corresponding 'tags' table in
++ * the adb_trace_init() function implemented in adb.c
++ */
++typedef enum {
++ TRACE_ADB = 0, /* 0x001 */
++ TRACE_SOCKETS,
++ TRACE_PACKETS,
++ TRACE_TRANSPORT,
++ TRACE_RWX, /* 0x010 */
++ TRACE_USB,
++ TRACE_SYNC,
++ TRACE_SYSDEPS,
++ TRACE_JDWP, /* 0x100 */
++ TRACE_SERVICES,
++ TRACE_AUTH,
++} AdbTrace;
++
++#if ADB_TRACE
++
++#if !ADB_HOST
++/*
++ * When running inside the emulator, guest's adbd can connect to 'adb-debug'
++ * qemud service that can display adb trace messages (on condition that emulator
++ * has been started with '-debug adb' option).
++ */
++
++/* Delivers a trace message to the emulator via QEMU pipe. */
++void adb_qemu_trace(const char* fmt, ...);
++/* Macro to use to send ADB trace messages to the emulator. */
++#define DQ(...) adb_qemu_trace(__VA_ARGS__)
++#else
++#define DQ(...) ((void)0)
++#endif /* !ADB_HOST */
++
++ extern int adb_trace_mask;
++ extern unsigned char adb_trace_output_count;
++ void adb_trace_init(void);
++
++# define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
++
++ /* you must define TRACE_TAG before using this macro */
++# define D(...) \
++ do { \
++ if (ADB_TRACING) { \
++ int save_errno = errno; \
++ adb_mutex_lock(&D_lock); \
++ fprintf(stderr, "%s::%s():", \
++ __FILE__, __FUNCTION__); \
++ errno = save_errno; \
++ fprintf(stderr, __VA_ARGS__ ); \
++ fflush(stderr); \
++ adb_mutex_unlock(&D_lock); \
++ errno = save_errno; \
++ } \
++ } while (0)
++# define DR(...) \
++ do { \
++ if (ADB_TRACING) { \
++ int save_errno = errno; \
++ adb_mutex_lock(&D_lock); \
++ errno = save_errno; \
++ fprintf(stderr, __VA_ARGS__ ); \
++ fflush(stderr); \
++ adb_mutex_unlock(&D_lock); \
++ errno = save_errno; \
++ } \
++ } while (0)
++#else
++# define D(...) ((void)0)
++# define DR(...) ((void)0)
++# define ADB_TRACING 0
++#endif
++
++
++#if !DEBUG_PACKETS
++#define print_packet(tag,p) do {} while (0)
++#endif
++
++#if ADB_HOST_ON_TARGET
++/* adb and adbd are coexisting on the target, so use 5038 for adb
++ * to avoid conflicting with adbd's usage of 5037
++ */
++# define DEFAULT_ADB_PORT 5038
++#else
++# define DEFAULT_ADB_PORT 5037
++#endif
++
++#define DEFAULT_ADB_LOCAL_TRANSPORT_PORT 5555
++
++#define ADB_CLASS 0xff
++#define ADB_SUBCLASS 0x42
++#define ADB_PROTOCOL 0x1
++
++
++void local_init(int port);
++int local_connect(int port);
++int local_connect_arbitrary_ports(int console_port, int adb_port);
++
++/* usb host/client interface */
++void usb_init();
++void usb_cleanup();
++int usb_write(usb_handle *h, const void *data, int len);
++int usb_read(usb_handle *h, void *data, int len);
++int usb_close(usb_handle *h);
++void usb_kick(usb_handle *h);
++
++/* used for USB device detection */
++#if ADB_HOST
++int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
++#endif
++
++unsigned host_to_le32(unsigned n);
++int adb_commandline(int argc, char **argv);
++
++int connection_state(atransport *t);
++
++#define CS_ANY -1
++#define CS_OFFLINE 0
++#define CS_BOOTLOADER 1
++#define CS_DEVICE 2
++#define CS_HOST 3
++#define CS_RECOVERY 4
++#define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */
++#define CS_SIDELOAD 6
++
++extern int HOST;
++extern int SHELL_EXIT_NOTIFY_FD;
++
++#define CHUNK_SIZE (64*1024)
++
++#if !ADB_HOST
++#define USB_ADB_PATH "/dev/android_adb"
++
++#define USB_FFS_ADB_PATH "/dev/usb-ffs/adb/"
++#define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH#x
++
++#define USB_FFS_ADB_EP0 USB_FFS_ADB_EP(ep0)
++#define USB_FFS_ADB_OUT USB_FFS_ADB_EP(ep1)
++#define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2)
++#endif
++
++int sendfailmsg(int fd, const char *reason);
++int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
++
++#endif
+Index: android-tools-4.2.2+git20130218/core/adbd/adb_auth.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/adb_auth.h 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,54 @@
++/*
++ * Copyright (C) 2012 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef __ADB_AUTH_H
++#define __ADB_AUTH_H
++
++void adb_auth_init(void);
++void adb_auth_verified(atransport *t);
++
++/* AUTH packets first argument */
++/* Request */
++#define ADB_AUTH_TOKEN 1
++/* Response */
++#define ADB_AUTH_SIGNATURE 2
++#define ADB_AUTH_RSAPUBLICKEY 3
++
++#if ADB_HOST
++
++int adb_auth_sign(void *key, void *token, size_t token_size, void *sig);
++void *adb_auth_nextkey(void *current);
++int adb_auth_get_userkey(unsigned char *data, size_t len);
++
++static inline int adb_auth_generate_token(void *token, size_t token_size) { return 0; }
++static inline int adb_auth_verify(void *token, void *sig, int siglen) { return 0; }
++static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t) { }
++static inline void adb_auth_reload_keys(void) { }
++
++#else // !ADB_HOST
++
++static inline int adb_auth_sign(void* key, void *token, size_t token_size, void *sig) { return 0; }
++static inline void *adb_auth_nextkey(void *current) { return NULL; }
++static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return 0; }
++
++int adb_auth_generate_token(void *token, size_t token_size);
++int adb_auth_verify(void *token, void *sig, int siglen);
++void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t);
++void adb_auth_reload_keys(void);
++
++#endif // ADB_HOST
++
++#endif // __ADB_AUTH_H
+Index: android-tools-4.2.2+git20130218/core/adbd/adb_auth_client.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/adb_auth_client.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,245 @@
++/*
++ * Copyright (C) 2012 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <resolv.h>
++#include <cutils/list.h>
++#include <cutils/sockets.h>
++
++#include "sysdeps.h"
++#include "adb.h"
++#include "adb_auth.h"
++#include "fdevent.h"
++#include "mincrypt/rsa.h"
++
++#define TRACE_TAG TRACE_AUTH
++
++
++struct adb_public_key {
++ struct listnode node;
++ RSAPublicKey key;
++};
++
++static struct listnode key_list;
++
++static char *key_paths[] = {
++ "/adb_keys",
++ "/data/misc/adb/adb_keys",
++ NULL
++};
++
++static fdevent listener_fde;
++static int framework_fd = -1;
++
++
++static void read_keys(const char *file, struct listnode *list)
++{
++ struct adb_public_key *key;
++ FILE *f;
++ char buf[MAX_PAYLOAD];
++ char *sep;
++ int ret;
++
++ f = fopen(file, "r");
++ if (!f) {
++ D("Can't open '%s'\n", file);
++ return;
++ }
++
++ while (fgets(buf, sizeof(buf), f)) {
++ /* Allocate 4 extra bytes to decode the base64 data in-place */
++ key = calloc(1, sizeof(*key) + 4);
++ if (!key) {
++ D("Can't malloc key\n");
++ break;
++ }
++
++ sep = strpbrk(buf, " \t");
++ if (sep)
++ *sep = '\0';
++
++ ret = __b64_pton(buf, (u_char *)&key->key, sizeof(key->key) + 4);
++ if (ret != sizeof(key->key)) {
++ D("%s: Invalid base64 data ret=%d\n", file, ret);
++ free(key);
++ continue;
++ }
++
++ if (key->key.len != RSANUMWORDS) {
++ D("%s: Invalid key len %d\n", file, key->key.len);
++ free(key);
++ continue;
++ }
++
++ list_add_tail(list, &key->node);
++ }
++
++ fclose(f);
++}
++
++static void free_keys(struct listnode *list)
++{
++ struct listnode *item;
++
++ while (!list_empty(list)) {
++ item = list_head(list);
++ list_remove(item);
++ free(node_to_item(item, struct adb_public_key, node));
++ }
++}
++
++void adb_auth_reload_keys(void)
++{
++ char *path;
++ char **paths = key_paths;
++ struct stat buf;
++
++ free_keys(&key_list);
++
++ while ((path = *paths++)) {
++ if (!stat(path, &buf)) {
++ D("Loading keys from '%s'\n", path);
++ read_keys(path, &key_list);
++ }
++ }
++}
++
++int adb_auth_generate_token(void *token, size_t token_size)
++{
++ FILE *f;
++ int ret;
++
++ f = fopen("/dev/urandom", "r");
++ if (!f)
++ return 0;
++
++ ret = fread(token, token_size, 1, f);
++
++ fclose(f);
++ return ret * token_size;
++}
++
++int adb_auth_verify(void *token, void *sig, int siglen)
++{
++ struct listnode *item;
++ struct adb_public_key *key;
++ int ret;
++
++ if (siglen != RSANUMBYTES)
++ return 0;
++
++ list_for_each(item, &key_list) {
++ key = node_to_item(item, struct adb_public_key, node);
++ ret = RSA_verify(&key->key, sig, siglen, token);
++ if (ret)
++ return 1;
++ }
++
++ return 0;
++}
++
++static void adb_auth_event(int fd, unsigned events, void *data)
++{
++ atransport *t = data;
++ char response[2];
++ int ret;
++
++ if (events & FDE_READ) {
++ ret = unix_read(fd, response, sizeof(response));
++ if (ret < 0) {
++ D("Disconnect");
++ fdevent_remove(&t->auth_fde);
++ framework_fd = -1;
++ }
++ else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
++ adb_auth_reload_keys();
++ adb_auth_verified(t);
++ }
++ }
++}
++
++void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t)
++{
++ char msg[MAX_PAYLOAD];
++ int ret;
++
++ if (framework_fd < 0) {
++ D("Client not connected\n");
++ return;
++ }
++
++ if (key[len - 1] != '\0') {
++ D("Key must be a null-terminated string\n");
++ return;
++ }
++
++ ret = snprintf(msg, sizeof(msg), "PK%s", key);
++ if (ret >= (signed)sizeof(msg)) {
++ D("Key too long. ret=%d", ret);
++ return;
++ }
++ D("Sending '%s'\n", msg);
++
++ ret = unix_write(framework_fd, msg, ret);
++ if (ret < 0) {
++ D("Failed to write PK, errno=%d\n", errno);
++ return;
++ }
++
++ fdevent_install(&t->auth_fde, framework_fd, adb_auth_event, t);
++ fdevent_add(&t->auth_fde, FDE_READ);
++}
++
++static void adb_auth_listener(int fd, unsigned events, void *data)
++{
++ struct sockaddr addr;
++ socklen_t alen;
++ int s;
++
++ alen = sizeof(addr);
++
++ s = adb_socket_accept(fd, &addr, &alen);
++ if (s < 0) {
++ D("Failed to accept: errno=%d\n", errno);
++ return;
++ }
++
++ framework_fd = s;
++}
++
++void adb_auth_init(void)
++{
++ int fd, ret;
++
++ list_init(&key_list);
++ adb_auth_reload_keys();
++
++ fd = android_get_control_socket("adbd");
++ if (fd < 0) {
++ D("Failed to get adbd socket\n");
++ return;
++ }
++
++ ret = listen(fd, 4);
++ if (ret < 0) {
++ D("Failed to listen on '%d'\n", fd);
++ return;
++ }
++
++ fdevent_install(&listener_fde, fd, adb_auth_listener, NULL);
++ fdevent_add(&listener_fde, FDE_READ);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/adb_auth_host.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/adb_auth_host.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,426 @@
++/*
++ * Copyright (C) 2012 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdio.h>
++
++#ifdef _WIN32
++# define WIN32_LEAN_AND_MEAN
++# include "windows.h"
++# include "shlobj.h"
++#else
++# include <sys/types.h>
++# include <sys/stat.h>
++# include <unistd.h>
++#endif
++#include <string.h>
++
++#include "sysdeps.h"
++#include "adb.h"
++#include "adb_auth.h"
++
++/* HACK: we need the RSAPublicKey struct
++ * but RSA_verify conflits with openssl */
++#define RSA_verify RSA_verify_mincrypt
++#include "mincrypt/rsa.h"
++#undef RSA_verify
++
++#include <cutils/list.h>
++
++#include <openssl/evp.h>
++#include <openssl/objects.h>
++#include <openssl/pem.h>
++#include <openssl/rsa.h>
++#include <openssl/sha.h>
++
++#define TRACE_TAG TRACE_AUTH
++
++#define ANDROID_PATH ".android"
++#define ADB_KEY_FILE "adbkey"
++
++
++struct adb_private_key {
++ struct listnode node;
++ RSA *rsa;
++};
++
++static struct listnode key_list;
++
++
++/* Convert OpenSSL RSA private key to android pre-computed RSAPublicKey format */
++static int RSA_to_RSAPublicKey(RSA *rsa, RSAPublicKey *pkey)
++{
++ int ret = 1;
++ unsigned int i;
++
++ BN_CTX* ctx = BN_CTX_new();
++ BIGNUM* r32 = BN_new();
++ BIGNUM* rr = BN_new();
++ BIGNUM* r = BN_new();
++ BIGNUM* rem = BN_new();
++ BIGNUM* n = BN_new();
++ BIGNUM* n0inv = BN_new();
++
++ if (RSA_size(rsa) != RSANUMBYTES) {
++ ret = 0;
++ goto out;
++ }
++
++ BN_set_bit(r32, 32);
++ BN_copy(n, rsa->n);
++ BN_set_bit(r, RSANUMWORDS * 32);
++ BN_mod_sqr(rr, r, n, ctx);
++ BN_div(NULL, rem, n, r32, ctx);
++ BN_mod_inverse(n0inv, rem, r32, ctx);
++
++ pkey->len = RSANUMWORDS;
++ pkey->n0inv = 0 - BN_get_word(n0inv);
++ for (i = 0; i < RSANUMWORDS; i++) {
++ BN_div(rr, rem, rr, r32, ctx);
++ pkey->rr[i] = BN_get_word(rem);
++ BN_div(n, rem, n, r32, ctx);
++ pkey->n[i] = BN_get_word(rem);
++ }
++ pkey->exponent = BN_get_word(rsa->e);
++
++out:
++ BN_free(n0inv);
++ BN_free(n);
++ BN_free(rem);
++ BN_free(r);
++ BN_free(rr);
++ BN_free(r32);
++ BN_CTX_free(ctx);
++
++ return ret;
++}
++
++static void get_user_info(char *buf, size_t len)
++{
++ char hostname[1024], username[1024];
++ int ret;
++
++#ifndef _WIN32
++ ret = gethostname(hostname, sizeof(hostname));
++ if (ret < 0)
++#endif
++ strcpy(hostname, "unknown");
++
++#if !defined _WIN32 && !defined ADB_HOST_ON_TARGET
++ ret = getlogin_r(username, sizeof(username));
++ if (ret < 0)
++#endif
++ strcpy(username, "unknown");
++
++ ret = snprintf(buf, len, " %s@%s", username, hostname);
++ if (ret >= (signed)len)
++ buf[len - 1] = '\0';
++}
++
++static int write_public_keyfile(RSA *private_key, const char *private_key_path)
++{
++ RSAPublicKey pkey;
++ BIO *bio, *b64, *bfile;
++ char path[PATH_MAX], info[MAX_PAYLOAD];
++ int ret;
++
++ ret = snprintf(path, sizeof(path), "%s.pub", private_key_path);
++ if (ret >= (signed)sizeof(path))
++ return 0;
++
++ ret = RSA_to_RSAPublicKey(private_key, &pkey);
++ if (!ret) {
++ D("Failed to convert to publickey\n");
++ return 0;
++ }
++
++ bfile = BIO_new_file(path, "w");
++ if (!bfile) {
++ D("Failed to open '%s'\n", path);
++ return 0;
++ }
++
++ D("Writing public key to '%s'\n", path);
++
++ b64 = BIO_new(BIO_f_base64());
++ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
++
++ bio = BIO_push(b64, bfile);
++ BIO_write(bio, &pkey, sizeof(pkey));
++ BIO_flush(bio);
++ BIO_pop(b64);
++ BIO_free(b64);
++
++ get_user_info(info, sizeof(info));
++ BIO_write(bfile, info, strlen(info));
++ BIO_flush(bfile);
++ BIO_free_all(bfile);
++
++ return 1;
++}
++
++static int generate_key(const char *file)
++{
++ EVP_PKEY* pkey = EVP_PKEY_new();
++ BIGNUM* exponent = BN_new();
++ RSA* rsa = RSA_new();
++ mode_t old_mask;
++ FILE *f = NULL;
++ int ret = 0;
++
++ D("generate_key '%s'\n", file);
++
++ if (!pkey || !exponent || !rsa) {
++ D("Failed to allocate key\n");
++ goto out;
++ }
++
++ BN_set_word(exponent, RSA_F4);
++ RSA_generate_key_ex(rsa, 2048, exponent, NULL);
++ EVP_PKEY_set1_RSA(pkey, rsa);
++
++ old_mask = umask(077);
++
++ f = fopen(file, "w");
++ if (!f) {
++ D("Failed to open '%s'\n", file);
++ umask(old_mask);
++ goto out;
++ }
++
++ umask(old_mask);
++
++ if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
++ D("Failed to write key\n");
++ goto out;
++ }
++
++ if (!write_public_keyfile(rsa, file)) {
++ D("Failed to write public key\n");
++ goto out;
++ }
++
++ ret = 1;
++
++out:
++ if (f)
++ fclose(f);
++ EVP_PKEY_free(pkey);
++ RSA_free(rsa);
++ BN_free(exponent);
++ return ret;
++}
++
++static int read_key(const char *file, struct listnode *list)
++{
++ struct adb_private_key *key;
++ FILE *f;
++
++ D("read_key '%s'\n", file);
++
++ f = fopen(file, "r");
++ if (!f) {
++ D("Failed to open '%s'\n", file);
++ return 0;
++ }
++
++ key = malloc(sizeof(*key));
++ if (!key) {
++ D("Failed to alloc key\n");
++ fclose(f);
++ return 0;
++ }
++ key->rsa = RSA_new();
++
++ if (!PEM_read_RSAPrivateKey(f, &key->rsa, NULL, NULL)) {
++ D("Failed to read key\n");
++ fclose(f);
++ RSA_free(key->rsa);
++ free(key);
++ return 0;
++ }
++
++ fclose(f);
++ list_add_tail(list, &key->node);
++ return 1;
++}
++
++static int get_user_keyfilepath(char *filename, size_t len)
++{
++ const char *format, *home;
++ char android_dir[PATH_MAX];
++ struct stat buf;
++#ifdef _WIN32
++ char path[PATH_MAX];
++ home = getenv("ANDROID_SDK_HOME");
++ if (!home) {
++ SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, path);
++ home = path;
++ }
++ format = "%s\\%s";
++#else
++ home = getenv("HOME");
++ if (!home)
++ return -1;
++ format = "%s/%s";
++#endif
++
++ D("home '%s'\n", home);
++
++ if (snprintf(android_dir, sizeof(android_dir), format, home,
++ ANDROID_PATH) >= (int)sizeof(android_dir))
++ return -1;
++
++ if (stat(android_dir, &buf)) {
++ if (adb_mkdir(android_dir, 0750) < 0) {
++ D("Cannot mkdir '%s'", android_dir);
++ return -1;
++ }
++ }
++
++ return snprintf(filename, len, format, android_dir, ADB_KEY_FILE);
++}
++
++static int get_user_key(struct listnode *list)
++{
++ struct stat buf;
++ char path[PATH_MAX];
++ int ret;
++
++ ret = get_user_keyfilepath(path, sizeof(path));
++ if (ret < 0 || ret >= (signed)sizeof(path)) {
++ D("Error getting user key filename");
++ return 0;
++ }
++
++ D("user key '%s'\n", path);
++
++ if (stat(path, &buf) == -1) {
++ if (!generate_key(path)) {
++ D("Failed to generate new key\n");
++ return 0;
++ }
++ }
++
++ return read_key(path, list);
++}
++
++static void get_vendor_keys(struct listnode *list)
++{
++ const char *adb_keys_path;
++ char keys_path[MAX_PAYLOAD];
++ char *path;
++ char *save;
++ struct stat buf;
++
++ adb_keys_path = getenv("ADB_VENDOR_KEYS");
++ if (!adb_keys_path)
++ return;
++ strncpy(keys_path, adb_keys_path, sizeof(keys_path));
++
++ path = adb_strtok_r(keys_path, ENV_PATH_SEPARATOR_STR, &save);
++ while (path) {
++ D("Reading: '%s'\n", path);
++
++ if (stat(path, &buf))
++ D("Can't read '%s'\n", path);
++ else if (!read_key(path, list))
++ D("Failed to read '%s'\n", path);
++
++ path = adb_strtok_r(NULL, ENV_PATH_SEPARATOR_STR, &save);
++ }
++}
++
++int adb_auth_sign(void *node, void *token, size_t token_size, void *sig)
++{
++ unsigned int len;
++ struct adb_private_key *key = node_to_item(node, struct adb_private_key, node);
++
++ if (!RSA_sign(NID_sha1, token, token_size, sig, &len, key->rsa)) {
++ return 0;
++ }
++
++ D("adb_auth_sign len=%d\n", len);
++ return (int)len;
++}
++
++void *adb_auth_nextkey(void *current)
++{
++ struct listnode *item;
++
++ if (list_empty(&key_list))
++ return NULL;
++
++ if (!current)
++ return list_head(&key_list);
++
++ list_for_each(item, &key_list) {
++ if (item == current) {
++ /* current is the last item, we tried all the keys */
++ if (item->next == &key_list)
++ return NULL;
++ return item->next;
++ }
++ }
++
++ return NULL;
++}
++
++int adb_auth_get_userkey(unsigned char *data, size_t len)
++{
++ char path[PATH_MAX];
++ char *file;
++ int ret;
++
++ ret = get_user_keyfilepath(path, sizeof(path) - 4);
++ if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) {
++ D("Error getting user key filename");
++ return 0;
++ }
++ strcat(path, ".pub");
++
++ file = load_file(path, (unsigned*)&ret);
++ if (!file) {
++ D("Can't load '%s'\n", path);
++ return 0;
++ }
++
++ if (len < (size_t)(ret + 1)) {
++ D("%s: Content too large ret=%d\n", path, ret);
++ return 0;
++ }
++
++ memcpy(data, file, ret);
++ data[ret] = '\0';
++
++ return ret + 1;
++}
++
++void adb_auth_init(void)
++{
++ int ret;
++
++ D("adb_auth_init\n");
++
++ list_init(&key_list);
++
++ ret = get_user_key(&key_list);
++ if (!ret) {
++ D("Failed to get user key\n");
++ return;
++ }
++
++ get_vendor_keys(&key_list);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/adb_client.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/adb_client.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,340 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <limits.h>
++#include <stdarg.h>
++#include <zipfile/zipfile.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++
++#include "sysdeps.h"
++
++#define TRACE_TAG TRACE_ADB
++#include "adb_client.h"
++
++static transport_type __adb_transport = kTransportAny;
++static const char* __adb_serial = NULL;
++
++static int __adb_server_port = DEFAULT_ADB_PORT;
++static const char* __adb_server_name = NULL;
++
++void adb_set_transport(transport_type type, const char* serial)
++{
++ __adb_transport = type;
++ __adb_serial = serial;
++}
++
++void adb_set_tcp_specifics(int server_port)
++{
++ __adb_server_port = server_port;
++}
++
++void adb_set_tcp_name(const char* hostname)
++{
++ __adb_server_name = hostname;
++}
++
++int adb_get_emulator_console_port(void)
++{
++ const char* serial = __adb_serial;
++ int port;
++
++ if (serial == NULL) {
++ /* if no specific device was specified, we need to look at */
++ /* the list of connected devices, and extract an emulator */
++ /* name from it. two emulators is an error */
++ char* tmp = adb_query("host:devices");
++ char* p = tmp;
++ if(!tmp) {
++ printf("no emulator connected\n");
++ return -1;
++ }
++ while (*p) {
++ char* q = strchr(p, '\n');
++ if (q != NULL)
++ *q++ = 0;
++ else
++ q = p + strlen(p);
++
++ if (!memcmp(p, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1)) {
++ if (serial != NULL) { /* more than one emulator listed */
++ free(tmp);
++ return -2;
++ }
++ serial = p;
++ }
++
++ p = q;
++ }
++ free(tmp);
++
++ if (serial == NULL)
++ return -1; /* no emulator found */
++ }
++ else {
++ if (memcmp(serial, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1) != 0)
++ return -1; /* not an emulator */
++ }
++
++ serial += sizeof(LOCAL_CLIENT_PREFIX)-1;
++ port = strtol(serial, NULL, 10);
++ return port;
++}
++
++static char __adb_error[256] = { 0 };
++
++const char *adb_error(void)
++{
++ return __adb_error;
++}
++
++static int switch_socket_transport(int fd)
++{
++ char service[64];
++ char tmp[5];
++ int len;
++
++ if (__adb_serial)
++ snprintf(service, sizeof service, "host:transport:%s", __adb_serial);
++ else {
++ char* transport_type = "???";
++
++ switch (__adb_transport) {
++ case kTransportUsb:
++ transport_type = "transport-usb";
++ break;
++ case kTransportLocal:
++ transport_type = "transport-local";
++ break;
++ case kTransportAny:
++ transport_type = "transport-any";
++ break;
++ case kTransportHost:
++ // no switch necessary
++ return 0;
++ break;
++ }
++
++ snprintf(service, sizeof service, "host:%s", transport_type);
++ }
++ len = strlen(service);
++ snprintf(tmp, sizeof tmp, "%04x", len);
++
++ if(writex(fd, tmp, 4) || writex(fd, service, len)) {
++ strcpy(__adb_error, "write failure during connection");
++ adb_close(fd);
++ return -1;
++ }
++ D("Switch transport in progress\n");
++
++ if(adb_status(fd)) {
++ adb_close(fd);
++ D("Switch transport failed\n");
++ return -1;
++ }
++ D("Switch transport success\n");
++ return 0;
++}
++
++int adb_status(int fd)
++{
++ unsigned char buf[5];
++ unsigned len;
++
++ if(readx(fd, buf, 4)) {
++ strcpy(__adb_error, "protocol fault (no status)");
++ return -1;
++ }
++
++ if(!memcmp(buf, "OKAY", 4)) {
++ return 0;
++ }
++
++ if(memcmp(buf, "FAIL", 4)) {
++ sprintf(__adb_error,
++ "protocol fault (status %02x %02x %02x %02x?!)",
++ buf[0], buf[1], buf[2], buf[3]);
++ return -1;
++ }
++
++ if(readx(fd, buf, 4)) {
++ strcpy(__adb_error, "protocol fault (status len)");
++ return -1;
++ }
++ buf[4] = 0;
++ len = strtoul((char*)buf, 0, 16);
++ if(len > 255) len = 255;
++ if(readx(fd, __adb_error, len)) {
++ strcpy(__adb_error, "protocol fault (status read)");
++ return -1;
++ }
++ __adb_error[len] = 0;
++ return -1;
++}
++
++int _adb_connect(const char *service)
++{
++ char tmp[5];
++ int len;
++ int fd;
++
++ D("_adb_connect: %s\n", service);
++ len = strlen(service);
++ if((len < 1) || (len > 1024)) {
++ strcpy(__adb_error, "service name too long");
++ return -1;
++ }
++ snprintf(tmp, sizeof tmp, "%04x", len);
++
++ if (__adb_server_name)
++ fd = socket_network_client(__adb_server_name, __adb_server_port, SOCK_STREAM);
++ else
++ fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
++
++ if(fd < 0) {
++ strcpy(__adb_error, "cannot connect to daemon");
++ return -2;
++ }
++
++ if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd)) {
++ return -1;
++ }
++
++ if(writex(fd, tmp, 4) || writex(fd, service, len)) {
++ strcpy(__adb_error, "write failure during connection");
++ adb_close(fd);
++ return -1;
++ }
++
++ if(adb_status(fd)) {
++ adb_close(fd);
++ return -1;
++ }
++
++ D("_adb_connect: return fd %d\n", fd);
++ return fd;
++}
++
++int adb_connect(const char *service)
++{
++ // first query the adb server's version
++ int fd = _adb_connect("host:version");
++
++ D("adb_connect: service %s\n", service);
++ if(fd == -2 && __adb_server_name) {
++ fprintf(stderr,"** Cannot start server on remote host\n");
++ return fd;
++ } else if(fd == -2) {
++ fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
++ __adb_server_port);
++ start_server:
++ if(launch_server(__adb_server_port)) {
++ fprintf(stderr,"* failed to start daemon *\n");
++ return -1;
++ } else {
++ fprintf(stdout,"* daemon started successfully *\n");
++ }
++ /* give the server some time to start properly and detect devices */
++ adb_sleep_ms(3000);
++ // fall through to _adb_connect
++ } else {
++ // if server was running, check its version to make sure it is not out of date
++ char buf[100];
++ int n;
++ int version = ADB_SERVER_VERSION - 1;
++
++ // if we have a file descriptor, then parse version result
++ if(fd >= 0) {
++ if(readx(fd, buf, 4)) goto error;
++
++ buf[4] = 0;
++ n = strtoul(buf, 0, 16);
++ if(n > (int)sizeof(buf)) goto error;
++ if(readx(fd, buf, n)) goto error;
++ adb_close(fd);
++
++ if (sscanf(buf, "%04x", &version) != 1) goto error;
++ } else {
++ // if fd is -1, then check for "unknown host service",
++ // which would indicate a version of adb that does not support the version command
++ if (strcmp(__adb_error, "unknown host service") != 0)
++ return fd;
++ }
++
++ if(version != ADB_SERVER_VERSION) {
++ printf("adb server is out of date. killing...\n");
++ fd = _adb_connect("host:kill");
++ adb_close(fd);
++
++ /* XXX can we better detect its death? */
++ adb_sleep_ms(2000);
++ goto start_server;
++ }
++ }
++
++ // if the command is start-server, we are done.
++ if (!strcmp(service, "host:start-server"))
++ return 0;
++
++ fd = _adb_connect(service);
++ if(fd == -2) {
++ fprintf(stderr,"** daemon still not running\n");
++ }
++ D("adb_connect: return fd %d\n", fd);
++
++ return fd;
++error:
++ adb_close(fd);
++ return -1;
++}
++
++
++int adb_command(const char *service)
++{
++ int fd = adb_connect(service);
++ if(fd < 0) {
++ return -1;
++ }
++
++ if(adb_status(fd)) {
++ adb_close(fd);
++ return -1;
++ }
++
++ return 0;
++}
++
++char *adb_query(const char *service)
++{
++ char buf[5];
++ unsigned n;
++ char *tmp;
++
++ D("adb_query: %s\n", service);
++ int fd = adb_connect(service);
++ if(fd < 0) {
++ fprintf(stderr,"error: %s\n", __adb_error);
++ return 0;
++ }
++
++ if(readx(fd, buf, 4)) goto oops;
++
++ buf[4] = 0;
++ n = strtoul(buf, 0, 16);
++ if(n > 1024) goto oops;
++
++ tmp = malloc(n + 1);
++ if(tmp == 0) goto oops;
++
++ if(readx(fd, tmp, n) == 0) {
++ tmp[n] = 0;
++ adb_close(fd);
++ return tmp;
++ }
++ free(tmp);
++
++oops:
++ adb_close(fd);
++ return 0;
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/adb_client.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/adb_client.h 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,57 @@
++#ifndef _ADB_CLIENT_H_
++#define _ADB_CLIENT_H_
++
++#include "adb.h"
++
++/* connect to adb, connect to the named service, and return
++** a valid fd for interacting with that service upon success
++** or a negative number on failure
++*/
++int adb_connect(const char *service);
++int _adb_connect(const char *service);
++
++/* connect to adb, connect to the named service, return 0 if
++** the connection succeeded AND the service returned OKAY
++*/
++int adb_command(const char *service);
++
++/* connect to adb, connect to the named service, return
++** a malloc'd string of its response upon success or NULL
++** on failure.
++*/
++char *adb_query(const char *service);
++
++/* Set the preferred transport to connect to.
++*/
++void adb_set_transport(transport_type type, const char* serial);
++
++/* Set TCP specifics of the transport to use
++*/
++void adb_set_tcp_specifics(int server_port);
++
++/* Set TCP Hostname of the transport to use
++*/
++void adb_set_tcp_name(const char* hostname);
++
++/* Return the console port of the currently connected emulator (if any)
++ * of -1 if there is no emulator, and -2 if there is more than one.
++ * assumes adb_set_transport() was alled previously...
++ */
++int adb_get_emulator_console_port(void);
++
++/* send commands to the current emulator instance. will fail if there
++ * is zero, or more than one emulator connected (or if you use -s <serial>
++ * with a <serial> that does not designate an emulator)
++ */
++int adb_send_emulator_command(int argc, char** argv);
++
++/* return verbose error string from last operation */
++const char *adb_error(void);
++
++/* read a standard adb status response (OKAY|FAIL) and
++** return 0 in the event of OKAY, -1 in the event of FAIL
++** or protocol error
++*/
++int adb_status(int fd);
++
++#endif
+Index: android-tools-4.2.2+git20130218/core/adbd/android_filesystem_config.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/android_filesystem_config.h 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,302 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++/* This file is used to define the properties of the filesystem
++** images generated by build tools (mkbootfs and mkyaffs2image) and
++** by the device side of adb.
++*/
++
++#ifndef _ANDROID_FILESYSTEM_CONFIG_H_
++#define _ANDROID_FILESYSTEM_CONFIG_H_
++
++#include <string.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++
++/* This is the master Users and Groups config for the platform.
++** DO NOT EVER RENUMBER.
++*/
++
++#define AID_ROOT 0 /* traditional unix root user */
++
++#define AID_SYSTEM 1000 /* system server */
++
++#define AID_RADIO 1001 /* telephony subsystem, RIL */
++#define AID_BLUETOOTH 1002 /* bluetooth subsystem */
++#define AID_GRAPHICS 1003 /* graphics devices */
++#define AID_INPUT 1004 /* input devices */
++#define AID_AUDIO 1005 /* audio devices */
++#define AID_CAMERA 1006 /* camera devices */
++#define AID_LOG 1007 /* log devices */
++#define AID_COMPASS 1008 /* compass device */
++#define AID_MOUNT 1009 /* mountd socket */
++#define AID_WIFI 1010 /* wifi subsystem */
++#define AID_ADB 1011 /* android debug bridge (adbd) */
++#define AID_INSTALL 1012 /* group for installing packages */
++#define AID_MEDIA 1013 /* mediaserver process */
++#define AID_DHCP 1014 /* dhcp client */
++#define AID_SDCARD_RW 1015 /* external storage write access */
++#define AID_VPN 1016 /* vpn system */
++#define AID_KEYSTORE 1017 /* keystore subsystem */
++#define AID_USB 1018 /* USB devices */
++#define AID_DRM 1019 /* DRM server */
++#define AID_MDNSR 1020 /* MulticastDNSResponder (service discovery) */
++#define AID_GPS 1021 /* GPS daemon */
++#define AID_UNUSED1 1022 /* deprecated, DO NOT USE */
++#define AID_MEDIA_RW 1023 /* internal media storage write access */
++#define AID_MTP 1024 /* MTP USB driver access */
++#define AID_UNUSED2 1025 /* deprecated, DO NOT USE */
++#define AID_DRMRPC 1026 /* group for drm rpc */
++#define AID_NFC 1027 /* nfc subsystem */
++#define AID_SDCARD_R 1028 /* external storage read access */
++
++#define AID_SHELL 2000 /* adb and debug shell user */
++#define AID_CACHE 2001 /* cache access */
++#define AID_DIAG 2002 /* access to diagnostic resources */
++
++/* The 3000 series are intended for use as supplemental group id's only.
++ * They indicate special Android capabilities that the kernel is aware of. */
++#define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */
++#define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm or l2cap sockets */
++#define AID_INET 3003 /* can create AF_INET and AF_INET6 sockets */
++#define AID_NET_RAW 3004 /* can create raw INET sockets */
++#define AID_NET_ADMIN 3005 /* can configure interfaces and routing tables. */
++#define AID_NET_BW_STATS 3006 /* read bandwidth statistics */
++#define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */
++#define AID_NET_BT_STACK 3008 /* bluetooth: access config files */
++#define AID_QCOM_ONCRPC 3009 /* can read/write /dev/oncrpc files */
++#define AID_QCOM_DIAG 3010 /* can read/write /dev/diag */
++
++#if defined(MOTOROLA_UIDS)
++#define AID_MOT_OSH 5000 /* OSH */
++#define AID_MOT_ACCY 9000 /* access to accessory */
++#define AID_MOT_PWRIC 9001 /* power IC */
++#define AID_MOT_USB 9002 /* mot usb */
++#define AID_MOT_DRM 9003 /* can access DRM resource. */
++#define AID_MOT_TCMD 9004 /* mot_tcmd */
++#define AID_MOT_SEC_RTC 9005 /* mot cpcap rtc */
++#define AID_MOT_TOMBSTONE 9006
++#define AID_MOT_TPAPI 9007 /* mot_tpapi */
++#define AID_MOT_SECCLKD 9008 /* mot_secclkd */
++#define AID_MOT_WHISPER 9009 /* Whisper Protocol access */
++#define AID_MOT_CAIF 9010 /* can create CAIF sockets */
++#define AID_MOT_DLNA 9011 /* DLNA native */
++#endif // MOTOROLA_UIDS
++
++#define AID_MISC 9998 /* access to misc storage */
++#define AID_NOBODY 9999
++
++#define AID_APP 10000 /* first app user */
++
++#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
++#define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */
++
++#define AID_USER 100000 /* offset for uid ranges for each user */
++
++#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
++#define AID_SHARED_GID_END 59999 /* start of gids for apps in each user to share */
++
++#if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)
++struct android_id_info {
++ const char *name;
++ unsigned aid;
++};
++
++static const struct android_id_info android_ids[] = {
++ { "root", AID_ROOT, },
++ { "system", AID_SYSTEM, },
++ { "radio", AID_RADIO, },
++ { "bluetooth", AID_BLUETOOTH, },
++ { "graphics", AID_GRAPHICS, },
++ { "input", AID_INPUT, },
++ { "audio", AID_AUDIO, },
++ { "camera", AID_CAMERA, },
++ { "log", AID_LOG, },
++ { "compass", AID_COMPASS, },
++ { "mount", AID_MOUNT, },
++ { "wifi", AID_WIFI, },
++ { "dhcp", AID_DHCP, },
++ { "adb", AID_ADB, },
++ { "install", AID_INSTALL, },
++ { "media", AID_MEDIA, },
++ { "drm", AID_DRM, },
++ { "mdnsr", AID_MDNSR, },
++ { "nfc", AID_NFC, },
++ { "drmrpc", AID_DRMRPC, },
++ { "shell", AID_SHELL, },
++ { "cache", AID_CACHE, },
++ { "diag", AID_DIAG, },
++ { "net_bt_admin", AID_NET_BT_ADMIN, },
++ { "net_bt", AID_NET_BT, },
++ { "net_bt_stack", AID_NET_BT_STACK, },
++ { "sdcard_r", AID_SDCARD_R, },
++ { "sdcard_rw", AID_SDCARD_RW, },
++ { "media_rw", AID_MEDIA_RW, },
++ { "vpn", AID_VPN, },
++ { "keystore", AID_KEYSTORE, },
++ { "usb", AID_USB, },
++ { "mtp", AID_MTP, },
++ { "gps", AID_GPS, },
++ { "inet", AID_INET, },
++ { "net_raw", AID_NET_RAW, },
++ { "net_admin", AID_NET_ADMIN, },
++ { "net_bw_stats", AID_NET_BW_STATS, },
++ { "net_bw_acct", AID_NET_BW_ACCT, },
++ { "qcom_oncrpc", AID_QCOM_ONCRPC, },
++ { "qcom_diag", AID_QCOM_DIAG, },
++#if defined(MOTOROLA_UIDS)
++ { "mot_osh", AID_MOT_OSH, },
++ { "mot_accy", AID_MOT_ACCY, },
++ { "mot_pwric", AID_MOT_PWRIC, },
++ { "mot_usb", AID_MOT_USB, },
++ { "mot_drm", AID_MOT_DRM, },
++ { "mot_tcmd", AID_MOT_TCMD, },
++ { "mot_sec_rtc", AID_MOT_SEC_RTC, },
++ { "mot_tombstone", AID_MOT_TOMBSTONE, },
++ { "mot_tpapi", AID_MOT_TPAPI, },
++ { "mot_secclkd", AID_MOT_SECCLKD, },
++ { "mot_whisper", AID_MOT_WHISPER, },
++ { "mot_caif", AID_MOT_CAIF, },
++ { "mot_dlna", AID_MOT_DLNA, },
++#endif
++ { "misc", AID_MISC, },
++ { "nobody", AID_NOBODY, },
++};
++
++#define android_id_count \
++ (sizeof(android_ids) / sizeof(android_ids[0]))
++
++struct fs_path_config {
++ unsigned mode;
++ unsigned uid;
++ unsigned gid;
++ const char *prefix;
++};
++
++/* Rules for directories.
++** These rules are applied based on "first match", so they
++** should start with the most specific path and work their
++** way up to the root.
++*/
++
++static struct fs_path_config android_dirs[] = {
++ { 00770, AID_SYSTEM, AID_CACHE, "cache" },
++ { 00771, AID_SYSTEM, AID_SYSTEM, "data/app" },
++ { 00771, AID_SYSTEM, AID_SYSTEM, "data/app-private" },
++ { 00771, AID_SYSTEM, AID_SYSTEM, "data/dalvik-cache" },
++ { 00771, AID_SYSTEM, AID_SYSTEM, "data/data" },
++ { 00771, AID_SHELL, AID_SHELL, "data/local/tmp" },
++ { 00771, AID_SHELL, AID_SHELL, "data/local" },
++ { 01771, AID_SYSTEM, AID_MISC, "data/misc" },
++ { 00770, AID_DHCP, AID_DHCP, "data/misc/dhcp" },
++ { 00775, AID_MEDIA_RW, AID_MEDIA_RW, "data/media" },
++ { 00775, AID_MEDIA_RW, AID_MEDIA_RW, "data/media/Music" },
++ { 00771, AID_SYSTEM, AID_SYSTEM, "data" },
++ { 00750, AID_ROOT, AID_SHELL, "sbin" },
++ { 00755, AID_ROOT, AID_ROOT, "system/addon.d" },
++ { 00755, AID_ROOT, AID_SHELL, "system/bin" },
++ { 00755, AID_ROOT, AID_SHELL, "system/vendor" },
++ { 00755, AID_ROOT, AID_SHELL, "system/xbin" },
++ { 00755, AID_ROOT, AID_ROOT, "system/etc/ppp" },
++ { 00777, AID_ROOT, AID_ROOT, "sdcard" },
++ { 00755, AID_ROOT, AID_ROOT, 0 },
++};
++
++/* Rules for files.
++** These rules are applied based on "first match", so they
++** should start with the most specific path and work their
++** way up to the root. Prefixes ending in * denotes wildcard
++** and will allow partial matches.
++*/
++static struct fs_path_config android_files[] = {
++ { 00440, AID_ROOT, AID_SHELL, "system/etc/init.goldfish.rc" },
++ { 00550, AID_ROOT, AID_SHELL, "system/etc/init.goldfish.sh" },
++ { 00440, AID_ROOT, AID_SHELL, "system/etc/init.trout.rc" },
++ { 00550, AID_ROOT, AID_SHELL, "system/etc/init.ril" },
++ { 00550, AID_ROOT, AID_SHELL, "system/etc/init.testmenu" },
++ { 00550, AID_DHCP, AID_SHELL, "system/etc/dhcpcd/dhcpcd-run-hooks" },
++ { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/dbus.conf" },
++ { 00444, AID_RADIO, AID_AUDIO, "system/etc/AudioPara4.csv" },
++ { 00555, AID_ROOT, AID_ROOT, "system/etc/ppp/*" },
++ { 00555, AID_ROOT, AID_ROOT, "system/etc/rc.*" },
++ { 00755, AID_ROOT, AID_ROOT, "system/addon.d/*" },
++ { 00644, AID_SYSTEM, AID_SYSTEM, "data/app/*" },
++ { 00644, AID_MEDIA_RW, AID_MEDIA_RW, "data/media/*" },
++ { 00644, AID_SYSTEM, AID_SYSTEM, "data/app-private/*" },
++ { 00644, AID_APP, AID_APP, "data/data/*" },
++ /* the following two files are INTENTIONALLY set-gid and not set-uid.
++ * Do not change. */
++ { 02755, AID_ROOT, AID_NET_RAW, "system/bin/ping" },
++ { 02750, AID_ROOT, AID_INET, "system/bin/netcfg" },
++ /* the following five files are INTENTIONALLY set-uid, but they
++ * are NOT included on user builds. */
++ { 06755, AID_ROOT, AID_ROOT, "system/xbin/su" },
++ { 06755, AID_ROOT, AID_ROOT, "system/xbin/librank" },
++ { 06755, AID_ROOT, AID_ROOT, "system/xbin/procrank" },
++ { 06755, AID_ROOT, AID_ROOT, "system/xbin/procmem" },
++ { 06755, AID_ROOT, AID_ROOT, "system/xbin/tcpdump" },
++ { 04770, AID_ROOT, AID_RADIO, "system/bin/pppd-ril" },
++ /* the following file is INTENTIONALLY set-uid, and IS included
++ * in user builds. */
++ { 06750, AID_ROOT, AID_SHELL, "system/bin/run-as" },
++ { 06750, AID_ROOT, AID_SYSTEM, "system/bin/rebootcmd" },
++ { 00755, AID_ROOT, AID_SHELL, "system/bin/*" },
++ { 00755, AID_ROOT, AID_ROOT, "system/lib/valgrind/*" },
++ { 00755, AID_ROOT, AID_SHELL, "system/xbin/*" },
++ { 00755, AID_ROOT, AID_SHELL, "system/vendor/bin/*" },
++ { 00750, AID_ROOT, AID_SHELL, "sbin/*" },
++ { 00755, AID_ROOT, AID_ROOT, "bin/*" },
++ { 00750, AID_ROOT, AID_SHELL, "init*" },
++ { 00750, AID_ROOT, AID_SHELL, "charger*" },
++ { 00750, AID_ROOT, AID_SHELL, "sbin/fs_mgr" },
++ { 00640, AID_ROOT, AID_SHELL, "fstab.*" },
++ { 00755, AID_ROOT, AID_SHELL, "system/etc/init.d/*" },
++ { 00644, AID_ROOT, AID_ROOT, 0 },
++};
++
++static inline void fs_config(const char *path, int dir,
++ unsigned *uid, unsigned *gid, unsigned *mode)
++{
++ struct fs_path_config *pc;
++ int plen;
++
++ pc = dir ? android_dirs : android_files;
++ plen = strlen(path);
++ for(; pc->prefix; pc++){
++ int len = strlen(pc->prefix);
++ if (dir) {
++ if(plen < len) continue;
++ if(!strncmp(pc->prefix, path, len)) break;
++ continue;
++ }
++ /* If name ends in * then allow partial matches. */
++ if (pc->prefix[len -1] == '*') {
++ if(!strncmp(pc->prefix, path, len - 1)) break;
++ } else if (plen == len){
++ if(!strncmp(pc->prefix, path, len)) break;
++ }
++ }
++ *uid = pc->uid;
++ *gid = pc->gid;
++ *mode = (*mode & (~07777)) | pc->mode;
++
++#if 0
++ fprintf(stderr,"< '%s' '%s' %d %d %o >\n",
++ path, pc->prefix ? pc->prefix : "", *uid, *gid, *mode);
++#endif
++}
++#endif
++#endif
+Index: android-tools-4.2.2+git20130218/core/adbd/arpa_nameser.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/arpa_nameser.h 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,577 @@
++/* $NetBSD: nameser.h,v 1.19 2005/12/26 19:01:47 perry Exp $ */
++
++/*
++ * Copyright (c) 1983, 1989, 1993
++ * The Regents of the University of California. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. Neither the name of the University nor the names of its contributors
++ * may be used to endorse or promote products derived from this software
++ * without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++/*
++ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
++ * Copyright (c) 1996-1999 by Internet Software Consortium.
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
++ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Id: nameser.h,v 1.2.2.4.4.1 2004/03/09 08:33:30 marka Exp
++ */
++
++#ifndef _ARPA_NAMESER_H_
++#define _ARPA_NAMESER_H_
++
++#define BIND_4_COMPAT
++
++#include <sys/types.h>
++#include <sys/cdefs.h>
++
++/*
++ * Revision information. This is the release date in YYYYMMDD format.
++ * It can change every day so the right thing to do with it is use it
++ * in preprocessor commands such as "#if (__NAMESER > 19931104)". Do not
++ * compare for equality; rather, use it to determine whether your libbind.a
++ * contains a new enough lib/nameser/ to support the feature you need.
++ */
++
++#define __NAMESER 19991006 /* New interface version stamp. */
++
++/*
++ * Define constants based on RFC 883, RFC 1034, RFC 1035
++ */
++#define NS_PACKETSZ 512 /* default UDP packet size */
++#define NS_MAXDNAME 1025 /* maximum domain name */
++#define NS_MAXMSG 65535 /* maximum message size */
++#define NS_MAXCDNAME 255 /* maximum compressed domain name */
++#define NS_MAXLABEL 63 /* maximum length of domain label */
++#define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */
++#define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */
++#define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
++#define NS_INT32SZ 4 /* #/bytes of data in a uint32_t */
++#define NS_INT16SZ 2 /* #/bytes of data in a uint16_t */
++#define NS_INT8SZ 1 /* #/bytes of data in a uint8_t */
++#define NS_INADDRSZ 4 /* IPv4 T_A */
++#define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */
++#define NS_CMPRSFLGS 0xc0 /* Flag bits indicating name compression. */
++#define NS_DEFAULTPORT 53 /* For both TCP and UDP. */
++
++/*
++ * These can be expanded with synonyms, just keep ns_parse.c:ns_parserecord()
++ * in synch with it.
++ */
++typedef enum __ns_sect {
++ ns_s_qd = 0, /* Query: Question. */
++ ns_s_zn = 0, /* Update: Zone. */
++ ns_s_an = 1, /* Query: Answer. */
++ ns_s_pr = 1, /* Update: Prerequisites. */
++ ns_s_ns = 2, /* Query: Name servers. */
++ ns_s_ud = 2, /* Update: Update. */
++ ns_s_ar = 3, /* Query|Update: Additional records. */
++ ns_s_max = 4
++} ns_sect;
++
++/*
++ * This is a message handle. It is caller allocated and has no dynamic data.
++ * This structure is intended to be opaque to all but ns_parse.c, thus the
++ * leading _'s on the member names. Use the accessor functions, not the _'s.
++ */
++typedef struct __ns_msg {
++ const u_char *_msg, *_eom;
++ uint16_t _id, _flags, _counts[ns_s_max];
++ const u_char *_sections[ns_s_max];
++ ns_sect _sect;
++ int _rrnum;
++ const u_char *_msg_ptr;
++} ns_msg;
++
++/* Private data structure - do not use from outside library. */
++struct _ns_flagdata { int mask, shift; };
++extern const struct _ns_flagdata _ns_flagdata[];
++
++/* Accessor macros - this is part of the public interface. */
++
++#define ns_msg_id(handle) ((handle)._id + 0)
++#define ns_msg_base(handle) ((handle)._msg + 0)
++#define ns_msg_end(handle) ((handle)._eom + 0)
++#define ns_msg_size(handle) ((size_t)((handle)._eom - (handle)._msg))
++#define ns_msg_count(handle, section) ((handle)._counts[section] + 0)
++
++/*
++ * This is a parsed record. It is caller allocated and has no dynamic data.
++ */
++typedef struct __ns_rr {
++ char name[NS_MAXDNAME];
++ uint16_t type;
++ uint16_t rr_class;
++ uint32_t ttl;
++ uint16_t rdlength;
++ const u_char * rdata;
++} ns_rr;
++
++/* Accessor macros - this is part of the public interface. */
++#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".")
++#define ns_rr_type(rr) ((ns_type)((rr).type + 0))
++#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0))
++#define ns_rr_ttl(rr) ((u_long)(rr).ttl + 0)
++#define ns_rr_rdlen(rr) ((size_t)(rr).rdlength + 0)
++#define ns_rr_rdata(rr) ((rr).rdata + 0)
++
++/*
++ * These don't have to be in the same order as in the packet flags word,
++ * and they can even overlap in some cases, but they will need to be kept
++ * in synch with ns_parse.c:ns_flagdata[].
++ */
++typedef enum __ns_flag {
++ ns_f_qr, /* Question/Response. */
++ ns_f_opcode, /* Operation code. */
++ ns_f_aa, /* Authoritative Answer. */
++ ns_f_tc, /* Truncation occurred. */
++ ns_f_rd, /* Recursion Desired. */
++ ns_f_ra, /* Recursion Available. */
++ ns_f_z, /* MBZ. */
++ ns_f_ad, /* Authentic Data (DNSSEC). */
++ ns_f_cd, /* Checking Disabled (DNSSEC). */
++ ns_f_rcode, /* Response code. */
++ ns_f_max
++} ns_flag;
++
++/*
++ * Currently defined opcodes.
++ */
++typedef enum __ns_opcode {
++ ns_o_query = 0, /* Standard query. */
++ ns_o_iquery = 1, /* Inverse query (deprecated/unsupported). */
++ ns_o_status = 2, /* Name server status query (unsupported). */
++ /* Opcode 3 is undefined/reserved. */
++ ns_o_notify = 4, /* Zone change notification. */
++ ns_o_update = 5, /* Zone update message. */
++ ns_o_max = 6
++} ns_opcode;
++
++/*
++ * Currently defined response codes.
++ */
++typedef enum __ns_rcode {
++ ns_r_noerror = 0, /* No error occurred. */
++ ns_r_formerr = 1, /* Format error. */
++ ns_r_servfail = 2, /* Server failure. */
++ ns_r_nxdomain = 3, /* Name error. */
++ ns_r_notimpl = 4, /* Unimplemented. */
++ ns_r_refused = 5, /* Operation refused. */
++ /* these are for BIND_UPDATE */
++ ns_r_yxdomain = 6, /* Name exists */
++ ns_r_yxrrset = 7, /* RRset exists */
++ ns_r_nxrrset = 8, /* RRset does not exist */
++ ns_r_notauth = 9, /* Not authoritative for zone */
++ ns_r_notzone = 10, /* Zone of record different from zone section */
++ ns_r_max = 11,
++ /* The following are EDNS extended rcodes */
++ ns_r_badvers = 16,
++ /* The following are TSIG errors */
++ ns_r_badsig = 16,
++ ns_r_badkey = 17,
++ ns_r_badtime = 18
++} ns_rcode;
++
++/* BIND_UPDATE */
++typedef enum __ns_update_operation {
++ ns_uop_delete = 0,
++ ns_uop_add = 1,
++ ns_uop_max = 2
++} ns_update_operation;
++
++/*
++ * This structure is used for TSIG authenticated messages
++ */
++struct ns_tsig_key {
++ char name[NS_MAXDNAME], alg[NS_MAXDNAME];
++ unsigned char *data;
++ int len;
++};
++typedef struct ns_tsig_key ns_tsig_key;
++
++/*
++ * This structure is used for TSIG authenticated TCP messages
++ */
++struct ns_tcp_tsig_state {
++ int counter;
++ struct dst_key *key;
++ void *ctx;
++ unsigned char sig[NS_PACKETSZ];
++ int siglen;
++};
++typedef struct ns_tcp_tsig_state ns_tcp_tsig_state;
++
++#define NS_TSIG_FUDGE 300
++#define NS_TSIG_TCP_COUNT 100
++#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT"
++
++#define NS_TSIG_ERROR_NO_TSIG -10
++#define NS_TSIG_ERROR_NO_SPACE -11
++#define NS_TSIG_ERROR_FORMERR -12
++
++/*
++ * Currently defined type values for resources and queries.
++ */
++typedef enum __ns_type {
++ ns_t_invalid = 0, /* Cookie. */
++ ns_t_a = 1, /* Host address. */
++ ns_t_ns = 2, /* Authoritative server. */
++ ns_t_md = 3, /* Mail destination. */
++ ns_t_mf = 4, /* Mail forwarder. */
++ ns_t_cname = 5, /* Canonical name. */
++ ns_t_soa = 6, /* Start of authority zone. */
++ ns_t_mb = 7, /* Mailbox domain name. */
++ ns_t_mg = 8, /* Mail group member. */
++ ns_t_mr = 9, /* Mail rename name. */
++ ns_t_null = 10, /* Null resource record. */
++ ns_t_wks = 11, /* Well known service. */
++ ns_t_ptr = 12, /* Domain name pointer. */
++ ns_t_hinfo = 13, /* Host information. */
++ ns_t_minfo = 14, /* Mailbox information. */
++ ns_t_mx = 15, /* Mail routing information. */
++ ns_t_txt = 16, /* Text strings. */
++ ns_t_rp = 17, /* Responsible person. */
++ ns_t_afsdb = 18, /* AFS cell database. */
++ ns_t_x25 = 19, /* X_25 calling address. */
++ ns_t_isdn = 20, /* ISDN calling address. */
++ ns_t_rt = 21, /* Router. */
++ ns_t_nsap = 22, /* NSAP address. */
++ ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */
++ ns_t_sig = 24, /* Security signature. */
++ ns_t_key = 25, /* Security key. */
++ ns_t_px = 26, /* X.400 mail mapping. */
++ ns_t_gpos = 27, /* Geographical position (withdrawn). */
++ ns_t_aaaa = 28, /* Ip6 Address. */
++ ns_t_loc = 29, /* Location Information. */
++ ns_t_nxt = 30, /* Next domain (security). */
++ ns_t_eid = 31, /* Endpoint identifier. */
++ ns_t_nimloc = 32, /* Nimrod Locator. */
++ ns_t_srv = 33, /* Server Selection. */
++ ns_t_atma = 34, /* ATM Address */
++ ns_t_naptr = 35, /* Naming Authority PoinTeR */
++ ns_t_kx = 36, /* Key Exchange */
++ ns_t_cert = 37, /* Certification record */
++ ns_t_a6 = 38, /* IPv6 address (deprecates AAAA) */
++ ns_t_dname = 39, /* Non-terminal DNAME (for IPv6) */
++ ns_t_sink = 40, /* Kitchen sink (experimentatl) */
++ ns_t_opt = 41, /* EDNS0 option (meta-RR) */
++ ns_t_apl = 42, /* Address prefix list (RFC 3123) */
++ ns_t_tkey = 249, /* Transaction key */
++ ns_t_tsig = 250, /* Transaction signature. */
++ ns_t_ixfr = 251, /* Incremental zone transfer. */
++ ns_t_axfr = 252, /* Transfer zone of authority. */
++ ns_t_mailb = 253, /* Transfer mailbox records. */
++ ns_t_maila = 254, /* Transfer mail agent records. */
++ ns_t_any = 255, /* Wildcard match. */
++ ns_t_zxfr = 256, /* BIND-specific, nonstandard. */
++ ns_t_max = 65536
++} ns_type;
++
++/* Exclusively a QTYPE? (not also an RTYPE) */
++#define ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \
++ (t) == ns_t_mailb || (t) == ns_t_maila)
++/* Some kind of meta-RR? (not a QTYPE, but also not an RTYPE) */
++#define ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt)
++/* Exclusively an RTYPE? (not also a QTYPE or a meta-RR) */
++#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t))
++#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr)
++#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \
++ (t) == ns_t_zxfr)
++
++/*
++ * Values for class field
++ */
++typedef enum __ns_class {
++ ns_c_invalid = 0, /* Cookie. */
++ ns_c_in = 1, /* Internet. */
++ ns_c_2 = 2, /* unallocated/unsupported. */
++ ns_c_chaos = 3, /* MIT Chaos-net. */
++ ns_c_hs = 4, /* MIT Hesiod. */
++ /* Query class values which do not appear in resource records */
++ ns_c_none = 254, /* for prereq. sections in update requests */
++ ns_c_any = 255, /* Wildcard match. */
++ ns_c_max = 65536
++} ns_class;
++
++/* DNSSEC constants. */
++
++typedef enum __ns_key_types {
++ ns_kt_rsa = 1, /* key type RSA/MD5 */
++ ns_kt_dh = 2, /* Diffie Hellman */
++ ns_kt_dsa = 3, /* Digital Signature Standard (MANDATORY) */
++ ns_kt_private = 254 /* Private key type starts with OID */
++} ns_key_types;
++
++typedef enum __ns_cert_types {
++ cert_t_pkix = 1, /* PKIX (X.509v3) */
++ cert_t_spki = 2, /* SPKI */
++ cert_t_pgp = 3, /* PGP */
++ cert_t_url = 253, /* URL private type */
++ cert_t_oid = 254 /* OID private type */
++} ns_cert_types;
++
++/* Flags field of the KEY RR rdata. */
++#define NS_KEY_TYPEMASK 0xC000 /* Mask for "type" bits */
++#define NS_KEY_TYPE_AUTH_CONF 0x0000 /* Key usable for both */
++#define NS_KEY_TYPE_CONF_ONLY 0x8000 /* Key usable for confidentiality */
++#define NS_KEY_TYPE_AUTH_ONLY 0x4000 /* Key usable for authentication */
++#define NS_KEY_TYPE_NO_KEY 0xC000 /* No key usable for either; no key */
++/* The type bits can also be interpreted independently, as single bits: */
++#define NS_KEY_NO_AUTH 0x8000 /* Key unusable for authentication */
++#define NS_KEY_NO_CONF 0x4000 /* Key unusable for confidentiality */
++#define NS_KEY_RESERVED2 0x2000 /* Security is *mandatory* if bit=0 */
++#define NS_KEY_EXTENDED_FLAGS 0x1000 /* reserved - must be zero */
++#define NS_KEY_RESERVED4 0x0800 /* reserved - must be zero */
++#define NS_KEY_RESERVED5 0x0400 /* reserved - must be zero */
++#define NS_KEY_NAME_TYPE 0x0300 /* these bits determine the type */
++#define NS_KEY_NAME_USER 0x0000 /* key is assoc. with user */
++#define NS_KEY_NAME_ENTITY 0x0200 /* key is assoc. with entity eg host */
++#define NS_KEY_NAME_ZONE 0x0100 /* key is zone key */
++#define NS_KEY_NAME_RESERVED 0x0300 /* reserved meaning */
++#define NS_KEY_RESERVED8 0x0080 /* reserved - must be zero */
++#define NS_KEY_RESERVED9 0x0040 /* reserved - must be zero */
++#define NS_KEY_RESERVED10 0x0020 /* reserved - must be zero */
++#define NS_KEY_RESERVED11 0x0010 /* reserved - must be zero */
++#define NS_KEY_SIGNATORYMASK 0x000F /* key can sign RR's of same name */
++#define NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \
++ NS_KEY_RESERVED4 | \
++ NS_KEY_RESERVED5 | \
++ NS_KEY_RESERVED8 | \
++ NS_KEY_RESERVED9 | \
++ NS_KEY_RESERVED10 | \
++ NS_KEY_RESERVED11 )
++#define NS_KEY_RESERVED_BITMASK2 0xFFFF /* no bits defined here */
++
++/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */
++#define NS_ALG_MD5RSA 1 /* MD5 with RSA */
++#define NS_ALG_DH 2 /* Diffie Hellman KEY */
++#define NS_ALG_DSA 3 /* DSA KEY */
++#define NS_ALG_DSS NS_ALG_DSA
++#define NS_ALG_EXPIRE_ONLY 253 /* No alg, no security */
++#define NS_ALG_PRIVATE_OID 254 /* Key begins with OID giving alg */
++
++/* Protocol values */
++/* value 0 is reserved */
++#define NS_KEY_PROT_TLS 1
++#define NS_KEY_PROT_EMAIL 2
++#define NS_KEY_PROT_DNSSEC 3
++#define NS_KEY_PROT_IPSEC 4
++#define NS_KEY_PROT_ANY 255
++
++/* Signatures */
++#define NS_MD5RSA_MIN_BITS 512 /* Size of a mod or exp in bits */
++#define NS_MD5RSA_MAX_BITS 4096
++ /* Total of binary mod and exp */
++#define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS+7/8)*2+3)
++ /* Max length of text sig block */
++#define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES+2)/3)*4)
++#define NS_MD5RSA_MIN_SIZE ((NS_MD5RSA_MIN_BITS+7)/8)
++#define NS_MD5RSA_MAX_SIZE ((NS_MD5RSA_MAX_BITS+7)/8)
++
++#define NS_DSA_SIG_SIZE 41
++#define NS_DSA_MIN_SIZE 213
++#define NS_DSA_MAX_BYTES 405
++
++/* Offsets into SIG record rdata to find various values */
++#define NS_SIG_TYPE 0 /* Type flags */
++#define NS_SIG_ALG 2 /* Algorithm */
++#define NS_SIG_LABELS 3 /* How many labels in name */
++#define NS_SIG_OTTL 4 /* Original TTL */
++#define NS_SIG_EXPIR 8 /* Expiration time */
++#define NS_SIG_SIGNED 12 /* Signature time */
++#define NS_SIG_FOOT 16 /* Key footprint */
++#define NS_SIG_SIGNER 18 /* Domain name of who signed it */
++
++/* How RR types are represented as bit-flags in NXT records */
++#define NS_NXT_BITS 8
++#define NS_NXT_BIT_SET( n,p) (p[(n)/NS_NXT_BITS] |= (0x80>>((n)%NS_NXT_BITS)))
++#define NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS)))
++#define NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] & (0x80>>((n)%NS_NXT_BITS)))
++#define NS_NXT_MAX 127
++
++/*
++ * EDNS0 extended flags, host order.
++ */
++#define NS_OPT_DNSSEC_OK 0x8000U
++
++/*
++ * Inline versions of get/put short/long. Pointer is advanced.
++ */
++#define NS_GET16(s, cp) do { \
++ const u_char *t_cp = (const u_char *)(cp); \
++ (s) = ((uint16_t)t_cp[0] << 8) \
++ | ((uint16_t)t_cp[1]) \
++ ; \
++ (cp) += NS_INT16SZ; \
++} while (/*CONSTCOND*/0)
++
++#define NS_GET32(l, cp) do { \
++ const u_char *t_cp = (const u_char *)(cp); \
++ (l) = ((uint32_t)t_cp[0] << 24) \
++ | ((uint32_t)t_cp[1] << 16) \
++ | ((uint32_t)t_cp[2] << 8) \
++ | ((uint32_t)t_cp[3]) \
++ ; \
++ (cp) += NS_INT32SZ; \
++} while (/*CONSTCOND*/0)
++
++#define NS_PUT16(s, cp) do { \
++ uint32_t t_s = (uint32_t)(s); \
++ u_char *t_cp = (u_char *)(cp); \
++ *t_cp++ = t_s >> 8; \
++ *t_cp = t_s; \
++ (cp) += NS_INT16SZ; \
++} while (/*CONSTCOND*/0)
++
++#define NS_PUT32(l, cp) do { \
++ uint32_t t_l = (uint32_t)(l); \
++ u_char *t_cp = (u_char *)(cp); \
++ *t_cp++ = t_l >> 24; \
++ *t_cp++ = t_l >> 16; \
++ *t_cp++ = t_l >> 8; \
++ *t_cp = t_l; \
++ (cp) += NS_INT32SZ; \
++} while (/*CONSTCOND*/0)
++
++/*
++ * ANSI C identifier hiding for bind's lib/nameser.
++ */
++#define ns_msg_getflag __ns_msg_getflag
++#define ns_get16 __ns_get16
++#define ns_get32 __ns_get32
++#define ns_put16 __ns_put16
++#define ns_put32 __ns_put32
++#define ns_initparse __ns_initparse
++#define ns_skiprr __ns_skiprr
++#define ns_parserr __ns_parserr
++#define ns_sprintrr __ns_sprintrr
++#define ns_sprintrrf __ns_sprintrrf
++#define ns_format_ttl __ns_format_ttl
++#define ns_parse_ttl __ns_parse_ttl
++#define ns_datetosecs __ns_datetosecs
++#define ns_name_ntol __ns_name_ntol
++#define ns_name_ntop __ns_name_ntop
++#define ns_name_pton __ns_name_pton
++#define ns_name_unpack __ns_name_unpack
++#define ns_name_pack __ns_name_pack
++#define ns_name_compress __ns_name_compress
++#define ns_name_uncompress __ns_name_uncompress
++#define ns_name_skip __ns_name_skip
++#define ns_name_rollback __ns_name_rollback
++#define ns_sign __ns_sign
++#define ns_sign2 __ns_sign2
++#define ns_sign_tcp __ns_sign_tcp
++#define ns_sign_tcp2 __ns_sign_tcp2
++#define ns_sign_tcp_init __ns_sign_tcp_init
++#define ns_find_tsig __ns_find_tsig
++#define ns_verify __ns_verify
++#define ns_verify_tcp __ns_verify_tcp
++#define ns_verify_tcp_init __ns_verify_tcp_init
++#define ns_samedomain __ns_samedomain
++#define ns_subdomain __ns_subdomain
++#define ns_makecanon __ns_makecanon
++#define ns_samename __ns_samename
++
++__BEGIN_DECLS
++int ns_msg_getflag(ns_msg, int);
++uint16_t ns_get16(const u_char *);
++uint32_t ns_get32(const u_char *);
++void ns_put16(uint16_t, u_char *);
++void ns_put32(uint32_t, u_char *);
++int ns_initparse(const u_char *, int, ns_msg *);
++int ns_skiprr(const u_char *, const u_char *, ns_sect, int);
++int ns_parserr(ns_msg *, ns_sect, int, ns_rr *);
++int ns_sprintrr(const ns_msg *, const ns_rr *,
++ const char *, const char *, char *, size_t);
++int ns_sprintrrf(const u_char *, size_t, const char *,
++ ns_class, ns_type, u_long, const u_char *,
++ size_t, const char *, const char *,
++ char *, size_t);
++int ns_format_ttl(u_long, char *, size_t);
++int ns_parse_ttl(const char *, u_long *);
++uint32_t ns_datetosecs(const char *cp, int *errp);
++int ns_name_ntol(const u_char *, u_char *, size_t);
++int ns_name_ntop(const u_char *, char *, size_t);
++int ns_name_pton(const char *, u_char *, size_t);
++int ns_name_unpack(const u_char *, const u_char *,
++ const u_char *, u_char *, size_t);
++int ns_name_pack(const u_char *, u_char *, int,
++ const u_char **, const u_char **);
++int ns_name_uncompress(const u_char *, const u_char *,
++ const u_char *, char *, size_t);
++int ns_name_compress(const char *, u_char *, size_t,
++ const u_char **, const u_char **);
++int ns_name_skip(const u_char **, const u_char *);
++void ns_name_rollback(const u_char *, const u_char **,
++ const u_char **);
++int ns_sign(u_char *, int *, int, int, void *,
++ const u_char *, int, u_char *, int *, time_t);
++int ns_sign2(u_char *, int *, int, int, void *,
++ const u_char *, int, u_char *, int *, time_t,
++ u_char **, u_char **);
++int ns_sign_tcp(u_char *, int *, int, int,
++ ns_tcp_tsig_state *, int);
++int ns_sign_tcp2(u_char *, int *, int, int,
++ ns_tcp_tsig_state *, int,
++ u_char **, u_char **);
++int ns_sign_tcp_init(void *, const u_char *, int,
++ ns_tcp_tsig_state *);
++u_char *ns_find_tsig(u_char *, u_char *);
++int ns_verify(u_char *, int *, void *,
++ const u_char *, int, u_char *, int *,
++ time_t *, int);
++int ns_verify_tcp(u_char *, int *, ns_tcp_tsig_state *, int);
++int ns_verify_tcp_init(void *, const u_char *, int,
++ ns_tcp_tsig_state *);
++int ns_samedomain(const char *, const char *);
++int ns_subdomain(const char *, const char *);
++int ns_makecanon(const char *, char *, size_t);
++int ns_samename(const char *, const char *);
++__END_DECLS
++
++#ifdef BIND_4_COMPAT
++#include "arpa_nameser_compat.h"
++#endif
++
++#if 0
++# include <logd.h>
++# define XLOG(...) \
++ __libc_android_log_print(ANDROID_LOG_DEBUG,"libc",__VA_ARGS__)
++#else
++#define XLOG(...) do {} while (0)
++#endif
++
++#endif /* !_ARPA_NAMESER_H_ */
+Index: android-tools-4.2.2+git20130218/core/adbd/arpa_nameser_compat.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/arpa_nameser_compat.h 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,236 @@
++/* $NetBSD: nameser_compat.h,v 1.1.1.2 2004/11/07 01:28:27 christos Exp $ */
++
++/* Copyright (c) 1983, 1989
++ * The Regents of the University of California. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ * must display the following acknowledgement:
++ * This product includes software developed by the University of
++ * California, Berkeley and its contributors.
++ * 4. Neither the name of the University nor the names of its contributors
++ * may be used to endorse or promote products derived from this software
++ * without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++/*
++ * from nameser.h 8.1 (Berkeley) 6/2/93
++ * Id: nameser_compat.h,v 1.1.2.3.4.2 2004/07/01 04:43:41 marka Exp
++ */
++
++#ifndef _ARPA_NAMESER_COMPAT_
++#define _ARPA_NAMESER_COMPAT_
++
++#define __BIND 19950621 /* (DEAD) interface version stamp. */
++
++#include <endian.h>
++
++#ifndef BYTE_ORDER
++#if (BSD >= 199103)
++# include <machine/endian.h>
++#else
++#ifdef __linux
++# include <endian.h>
++#else
++#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */
++#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */
++#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp)*/
++
++#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \
++ defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \
++ defined(__alpha__) || defined(__alpha) || \
++ (defined(__Lynx__) && defined(__x86__))
++#define BYTE_ORDER LITTLE_ENDIAN
++#endif
++
++#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
++ defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
++ defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\
++ defined(apollo) || defined(__convex__) || defined(_CRAY) || \
++ defined(__hppa) || defined(__hp9000) || \
++ defined(__hp9000s300) || defined(__hp9000s700) || \
++ defined(__hp3000s900) || defined(__hpux) || defined(MPE) || \
++ defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc) || \
++ (defined(__Lynx__) && \
++ (defined(__68k__) || defined(__sparc__) || defined(__powerpc__)))
++#define BYTE_ORDER BIG_ENDIAN
++#endif
++#endif /* __linux */
++#endif /* BSD */
++#endif /* BYTE_ORDER */
++
++#if !defined(BYTE_ORDER) || \
++ (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN && \
++ BYTE_ORDER != PDP_ENDIAN)
++ /* you must determine what the correct bit order is for
++ * your compiler - the next line is an intentional error
++ * which will force your compiles to bomb until you fix
++ * the above macros.
++ */
++ #error "Undefined or invalid BYTE_ORDER";
++#endif
++
++/*
++ * Structure for query header. The order of the fields is machine- and
++ * compiler-dependent, depending on the byte/bit order and the layout
++ * of bit fields. We use bit fields only in int variables, as this
++ * is all ANSI requires. This requires a somewhat confusing rearrangement.
++ */
++
++typedef struct {
++ unsigned id :16; /* query identification number */
++#if BYTE_ORDER == BIG_ENDIAN
++ /* fields in third byte */
++ unsigned qr: 1; /* response flag */
++ unsigned opcode: 4; /* purpose of message */
++ unsigned aa: 1; /* authoritive answer */
++ unsigned tc: 1; /* truncated message */
++ unsigned rd: 1; /* recursion desired */
++ /* fields in fourth byte */
++ unsigned ra: 1; /* recursion available */
++ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
++ unsigned ad: 1; /* authentic data from named */
++ unsigned cd: 1; /* checking disabled by resolver */
++ unsigned rcode :4; /* response code */
++#endif
++#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
++ /* fields in third byte */
++ unsigned rd :1; /* recursion desired */
++ unsigned tc :1; /* truncated message */
++ unsigned aa :1; /* authoritive answer */
++ unsigned opcode :4; /* purpose of message */
++ unsigned qr :1; /* response flag */
++ /* fields in fourth byte */
++ unsigned rcode :4; /* response code */
++ unsigned cd: 1; /* checking disabled by resolver */
++ unsigned ad: 1; /* authentic data from named */
++ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
++ unsigned ra :1; /* recursion available */
++#endif
++ /* remaining bytes */
++ unsigned qdcount :16; /* number of question entries */
++ unsigned ancount :16; /* number of answer entries */
++ unsigned nscount :16; /* number of authority entries */
++ unsigned arcount :16; /* number of resource entries */
++} HEADER;
++
++#define PACKETSZ NS_PACKETSZ
++#define MAXDNAME NS_MAXDNAME
++#define MAXCDNAME NS_MAXCDNAME
++#define MAXLABEL NS_MAXLABEL
++#define HFIXEDSZ NS_HFIXEDSZ
++#define QFIXEDSZ NS_QFIXEDSZ
++#define RRFIXEDSZ NS_RRFIXEDSZ
++#define INT32SZ NS_INT32SZ
++#define INT16SZ NS_INT16SZ
++#define INT8SZ NS_INT8SZ
++#define INADDRSZ NS_INADDRSZ
++#define IN6ADDRSZ NS_IN6ADDRSZ
++#define INDIR_MASK NS_CMPRSFLGS
++#define NAMESERVER_PORT NS_DEFAULTPORT
++
++#define S_ZONE ns_s_zn
++#define S_PREREQ ns_s_pr
++#define S_UPDATE ns_s_ud
++#define S_ADDT ns_s_ar
++
++#define QUERY ns_o_query
++#define IQUERY ns_o_iquery
++#define STATUS ns_o_status
++#define NS_NOTIFY_OP ns_o_notify
++#define NS_UPDATE_OP ns_o_update
++
++#define NOERROR ns_r_noerror
++#define FORMERR ns_r_formerr
++#define SERVFAIL ns_r_servfail
++#define NXDOMAIN ns_r_nxdomain
++#define NOTIMP ns_r_notimpl
++#define REFUSED ns_r_refused
++#define YXDOMAIN ns_r_yxdomain
++#define YXRRSET ns_r_yxrrset
++#define NXRRSET ns_r_nxrrset
++#define NOTAUTH ns_r_notauth
++#define NOTZONE ns_r_notzone
++/*#define BADSIG ns_r_badsig*/
++/*#define BADKEY ns_r_badkey*/
++/*#define BADTIME ns_r_badtime*/
++
++
++#define DELETE ns_uop_delete
++#define ADD ns_uop_add
++
++#define T_A ns_t_a
++#define T_NS ns_t_ns
++#define T_MD ns_t_md
++#define T_MF ns_t_mf
++#define T_CNAME ns_t_cname
++#define T_SOA ns_t_soa
++#define T_MB ns_t_mb
++#define T_MG ns_t_mg
++#define T_MR ns_t_mr
++#define T_NULL ns_t_null
++#define T_WKS ns_t_wks
++#define T_PTR ns_t_ptr
++#define T_HINFO ns_t_hinfo
++#define T_MINFO ns_t_minfo
++#define T_MX ns_t_mx
++#define T_TXT ns_t_txt
++#define T_RP ns_t_rp
++#define T_AFSDB ns_t_afsdb
++#define T_X25 ns_t_x25
++#define T_ISDN ns_t_isdn
++#define T_RT ns_t_rt
++#define T_NSAP ns_t_nsap
++#define T_NSAP_PTR ns_t_nsap_ptr
++#define T_SIG ns_t_sig
++#define T_KEY ns_t_key
++#define T_PX ns_t_px
++#define T_GPOS ns_t_gpos
++#define T_AAAA ns_t_aaaa
++#define T_LOC ns_t_loc
++#define T_NXT ns_t_nxt
++#define T_EID ns_t_eid
++#define T_NIMLOC ns_t_nimloc
++#define T_SRV ns_t_srv
++#define T_ATMA ns_t_atma
++#define T_NAPTR ns_t_naptr
++#define T_A6 ns_t_a6
++#define T_TSIG ns_t_tsig
++#define T_IXFR ns_t_ixfr
++#define T_AXFR ns_t_axfr
++#define T_MAILB ns_t_mailb
++#define T_MAILA ns_t_maila
++#define T_ANY ns_t_any
++
++#define C_IN ns_c_in
++#define C_CHAOS ns_c_chaos
++#define C_HS ns_c_hs
++/* BIND_UPDATE */
++#define C_NONE ns_c_none
++#define C_ANY ns_c_any
++
++#define GETSHORT NS_GET16
++#define GETLONG NS_GET32
++#define PUTSHORT NS_PUT16
++#define PUTLONG NS_PUT32
++
++#endif /* _ARPA_NAMESER_COMPAT_ */
+Index: android-tools-4.2.2+git20130218/core/adbd/backup_service.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/backup_service.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,155 @@
++/*
++ * Copyright (C) 2011 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <unistd.h>
++#include <stdio.h>
++
++#include "sysdeps.h"
++
++#define TRACE_TAG TRACE_ADB
++#include "adb.h"
++
++typedef struct {
++ pid_t pid;
++ int fd;
++} backup_harvest_params;
++
++// socketpair but do *not* mark as close_on_exec
++static int backup_socketpair(int sv[2]) {
++ int rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv );
++ if (rc < 0)
++ return -1;
++
++ return 0;
++}
++
++// harvest the child process then close the read end of the socketpair
++static void* backup_child_waiter(void* args) {
++ int status;
++ backup_harvest_params* params = (backup_harvest_params*) args;
++
++ waitpid(params->pid, &status, 0);
++ adb_close(params->fd);
++ free(params);
++ return NULL;
++}
++
++/* returns the data socket passing the backup data here for forwarding */
++int backup_service(BackupOperation op, char* args) {
++ pid_t pid;
++ int s[2];
++ char* operation;
++ int socketnum;
++
++ // Command string and choice of stdin/stdout for the pipe depend on our invocation
++ if (op == BACKUP) {
++ operation = "backup";
++ socketnum = STDOUT_FILENO;
++ } else {
++ operation = "restore";
++ socketnum = STDIN_FILENO;
++ }
++
++ D("backup_service(%s, %s)\n", operation, args);
++
++ // set up the pipe from the subprocess to here
++ // parent will read s[0]; child will write s[1]
++ if (backup_socketpair(s)) {
++ D("can't create backup/restore socketpair\n");
++ fprintf(stderr, "unable to create backup/restore socketpair\n");
++ return -1;
++ }
++
++ D("Backup/restore socket pair: (send=%d, receive=%d)\n", s[1], s[0]);
++ close_on_exec(s[0]); // only the side we hold on to
++
++ // spin off the child process to run the backup command
++ pid = fork();
++ if (pid < 0) {
++ // failure
++ D("can't fork for %s\n", operation);
++ fprintf(stderr, "unable to fork for %s\n", operation);
++ adb_close(s[0]);
++ adb_close(s[1]);
++ return -1;
++ }
++
++ // Great, we're off and running.
++ if (pid == 0) {
++ // child -- actually run the backup here
++ char* p;
++ int argc;
++ char portnum[16];
++ char** bu_args;
++
++ // fixed args: [0] is 'bu', [1] is the port number, [2] is the 'operation' string
++ argc = 3;
++ for (p = (char*)args; p && *p; ) {
++ argc++;
++ while (*p && *p != ':') p++;
++ if (*p == ':') p++;
++ }
++
++ bu_args = (char**) alloca(argc*sizeof(char*) + 1);
++
++ // run through again to build the argv array
++ argc = 0;
++ bu_args[argc++] = "bu";
++ snprintf(portnum, sizeof(portnum), "%d", s[1]);
++ bu_args[argc++] = portnum;
++ bu_args[argc++] = operation;
++ for (p = (char*)args; p && *p; ) {
++ bu_args[argc++] = p;
++ while (*p && *p != ':') p++;
++ if (*p == ':') {
++ *p = 0;
++ p++;
++ }
++ }
++ bu_args[argc] = NULL;
++
++ // Close the half of the socket that we don't care about, route 'bu's console
++ // to the output socket, and off we go
++ adb_close(s[0]);
++
++ // off we go
++ execvp("/system/bin/bu", (char * const *)bu_args);
++ // oops error - close up shop and go home
++ fprintf(stderr, "Unable to exec 'bu', bailing\n");
++ exit(-1);
++ } else {
++ adb_thread_t t;
++ backup_harvest_params* params;
++
++ // parent, i.e. adbd -- close the sending half of the socket
++ D("fork() returned pid %d\n", pid);
++ adb_close(s[1]);
++
++ // spin a thread to harvest the child process
++ params = (backup_harvest_params*) malloc(sizeof(backup_harvest_params));
++ params->pid = pid;
++ params->fd = s[0];
++ if (adb_thread_create(&t, backup_child_waiter, params)) {
++ adb_close(s[0]);
++ free(params);
++ D("Unable to create child harvester\n");
++ return -1;
++ }
++ }
++
++ // we'll be reading from s[0] as the data is sent by the child process
++ return s[0];
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/base64.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/base64.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,340 @@
++/* $NetBSD: base64.c,v 1.8 2002/11/11 01:15:17 thorpej Exp $ */
++
++/*
++ * Copyright (c) 1996 by Internet Software Consortium.
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
++ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
++ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
++ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
++ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
++ * SOFTWARE.
++ */
++
++/*
++ * Portions Copyright (c) 1995 by International Business Machines, Inc.
++ *
++ * International Business Machines, Inc. (hereinafter called IBM) grants
++ * permission under its copyrights to use, copy, modify, and distribute this
++ * Software with or without fee, provided that the above copyright notice and
++ * all paragraphs of this notice appear in all copies, and that the name of IBM
++ * not be used in connection with the marketing of any product incorporating
++ * the Software or modifications thereof, without specific, written prior
++ * permission.
++ *
++ * To the extent it has a right to do so, IBM grants an immunity from suit
++ * under its patents, if any, for the use, sale or manufacture of products to
++ * the extent that such products are used for performing Domain Name System
++ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
++ * granted for any product per se or for any other function of any product.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
++ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
++ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
++ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
++ */
++
++#include <sys/cdefs.h>
++#if defined(LIBC_SCCS) && !defined(lint)
++__RCSID("$NetBSD: base64.c,v 1.8 2002/11/11 01:15:17 thorpej Exp $");
++#endif /* LIBC_SCCS and not lint */
++
++#include <sys/types.h>
++#include <sys/param.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include "arpa_nameser.h"
++
++#include <assert.h>
++#include <ctype.h>
++#ifdef ANDROID_CHANGES
++#include "resolv_private.h"
++#else
++#include <resolv.h>
++#endif
++#include <stdio.h>
++
++#include <stdlib.h>
++#include <string.h>
++
++static const char Base64[] =
++ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
++static const char Pad64 = '=';
++
++/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
++ The following encoding technique is taken from RFC 1521 by Borenstein
++ and Freed. It is reproduced here in a slightly edited form for
++ convenience.
++
++ A 65-character subset of US-ASCII is used, enabling 6 bits to be
++ represented per printable character. (The extra 65th character, "=",
++ is used to signify a special processing function.)
++
++ The encoding process represents 24-bit groups of input bits as output
++ strings of 4 encoded characters. Proceeding from left to right, a
++ 24-bit input group is formed by concatenating 3 8-bit input groups.
++ These 24 bits are then treated as 4 concatenated 6-bit groups, each
++ of which is translated into a single digit in the base64 alphabet.
++
++ Each 6-bit group is used as an index into an array of 64 printable
++ characters. The character referenced by the index is placed in the
++ output string.
++
++ Table 1: The Base64 Alphabet
++
++ Value Encoding Value Encoding Value Encoding Value Encoding
++ 0 A 17 R 34 i 51 z
++ 1 B 18 S 35 j 52 0
++ 2 C 19 T 36 k 53 1
++ 3 D 20 U 37 l 54 2
++ 4 E 21 V 38 m 55 3
++ 5 F 22 W 39 n 56 4
++ 6 G 23 X 40 o 57 5
++ 7 H 24 Y 41 p 58 6
++ 8 I 25 Z 42 q 59 7
++ 9 J 26 a 43 r 60 8
++ 10 K 27 b 44 s 61 9
++ 11 L 28 c 45 t 62 +
++ 12 M 29 d 46 u 63 /
++ 13 N 30 e 47 v
++ 14 O 31 f 48 w (pad) =
++ 15 P 32 g 49 x
++ 16 Q 33 h 50 y
++
++ Special processing is performed if fewer than 24 bits are available
++ at the end of the data being encoded. A full encoding quantum is
++ always completed at the end of a quantity. When fewer than 24 input
++ bits are available in an input group, zero bits are added (on the
++ right) to form an integral number of 6-bit groups. Padding at the
++ end of the data is performed using the '=' character.
++
++ Since all base64 input is an integral number of octets, only the
++ -------------------------------------------------
++ following cases can arise:
++
++ (1) the final quantum of encoding input is an integral
++ multiple of 24 bits; here, the final unit of encoded
++ output will be an integral multiple of 4 characters
++ with no "=" padding,
++ (2) the final quantum of encoding input is exactly 8 bits;
++ here, the final unit of encoded output will be two
++ characters followed by two "=" padding characters, or
++ (3) the final quantum of encoding input is exactly 16 bits;
++ here, the final unit of encoded output will be three
++ characters followed by one "=" padding character.
++ */
++
++int
++b64_ntop(src, srclength, target, targsize)
++ u_char const *src;
++ size_t srclength;
++ char *target;
++ size_t targsize;
++{
++ size_t datalength = 0;
++ u_char input[3] = { 0, 0, 0 }; /* make compiler happy */
++ u_char output[4];
++ size_t i;
++
++ assert(src != NULL);
++ assert(target != NULL);
++
++ while (2 < srclength) {
++ input[0] = *src++;
++ input[1] = *src++;
++ input[2] = *src++;
++ srclength -= 3;
++
++ output[0] = (u_int32_t)input[0] >> 2;
++ output[1] = ((u_int32_t)(input[0] & 0x03) << 4) +
++ ((u_int32_t)input[1] >> 4);
++ output[2] = ((u_int32_t)(input[1] & 0x0f) << 2) +
++ ((u_int32_t)input[2] >> 6);
++ output[3] = input[2] & 0x3f;
++ assert(output[0] < 64);
++ assert(output[1] < 64);
++ assert(output[2] < 64);
++ assert(output[3] < 64);
++
++ if (datalength + 4 > targsize)
++ return (-1);
++ target[datalength++] = Base64[output[0]];
++ target[datalength++] = Base64[output[1]];
++ target[datalength++] = Base64[output[2]];
++ target[datalength++] = Base64[output[3]];
++ }
++
++ /* Now we worry about padding. */
++ if (0 != srclength) {
++ /* Get what's left. */
++ input[0] = input[1] = input[2] = '\0';
++ for (i = 0; i < srclength; i++)
++ input[i] = *src++;
++
++ output[0] = (u_int32_t)input[0] >> 2;
++ output[1] = ((u_int32_t)(input[0] & 0x03) << 4) +
++ ((u_int32_t)input[1] >> 4);
++ output[2] = ((u_int32_t)(input[1] & 0x0f) << 2) +
++ ((u_int32_t)input[2] >> 6);
++ assert(output[0] < 64);
++ assert(output[1] < 64);
++ assert(output[2] < 64);
++
++ if (datalength + 4 > targsize)
++ return (-1);
++ target[datalength++] = Base64[output[0]];
++ target[datalength++] = Base64[output[1]];
++ if (srclength == 1)
++ target[datalength++] = Pad64;
++ else
++ target[datalength++] = Base64[output[2]];
++ target[datalength++] = Pad64;
++ }
++ if (datalength >= targsize)
++ return (-1);
++ target[datalength] = '\0'; /* Returned value doesn't count \0. */
++ return (datalength);
++}
++
++/* skips all whitespace anywhere.
++ converts characters, four at a time, starting at (or after)
++ src from base - 64 numbers into three 8 bit bytes in the target area.
++ it returns the number of data bytes stored at the target, or -1 on error.
++ */
++
++int
++b64_pton(src, target, targsize)
++ char const *src;
++ u_char *target;
++ size_t targsize;
++{
++ size_t tarindex;
++ int state, ch;
++ char *pos;
++
++ assert(src != NULL);
++ assert(target != NULL);
++
++ state = 0;
++ tarindex = 0;
++
++ while ((ch = (u_char) *src++) != '\0') {
++ if (isspace(ch)) /* Skip whitespace anywhere. */
++ continue;
++
++ if (ch == Pad64)
++ break;
++
++ pos = strchr(Base64, ch);
++ if (pos == 0) /* A non-base64 character. */
++ return (-1);
++
++ switch (state) {
++ case 0:
++ if (target) {
++ if (tarindex >= targsize)
++ return (-1);
++ target[tarindex] = (pos - Base64) << 2;
++ }
++ state = 1;
++ break;
++ case 1:
++ if (target) {
++ if (tarindex + 1 >= targsize)
++ return (-1);
++ target[tarindex] |=
++ (u_int32_t)(pos - Base64) >> 4;
++ target[tarindex+1] = ((pos - Base64) & 0x0f)
++ << 4 ;
++ }
++ tarindex++;
++ state = 2;
++ break;
++ case 2:
++ if (target) {
++ if (tarindex + 1 >= targsize)
++ return (-1);
++ target[tarindex] |=
++ (u_int32_t)(pos - Base64) >> 2;
++ target[tarindex+1] = ((pos - Base64) & 0x03)
++ << 6;
++ }
++ tarindex++;
++ state = 3;
++ break;
++ case 3:
++ if (target) {
++ if (tarindex >= targsize)
++ return (-1);
++ target[tarindex] |= (pos - Base64);
++ }
++ tarindex++;
++ state = 0;
++ break;
++ default:
++ abort();
++ }
++ }
++
++ /*
++ * We are done decoding Base-64 chars. Let's see if we ended
++ * on a byte boundary, and/or with erroneous trailing characters.
++ */
++
++ if (ch == Pad64) { /* We got a pad char. */
++ ch = *src++; /* Skip it, get next. */
++ switch (state) {
++ case 0: /* Invalid = in first position */
++ case 1: /* Invalid = in second position */
++ return (-1);
++
++ case 2: /* Valid, means one byte of info */
++ /* Skip any number of spaces. */
++ for (; ch != '\0'; ch = (u_char) *src++)
++ if (!isspace(ch))
++ break;
++ /* Make sure there is another trailing = sign. */
++ if (ch != Pad64)
++ return (-1);
++ ch = *src++; /* Skip the = */
++ /* Fall through to "single trailing =" case. */
++ /* FALLTHROUGH */
++
++ case 3: /* Valid, means two bytes of info */
++ /*
++ * We know this char is an =. Is there anything but
++ * whitespace after it?
++ */
++ for (; ch != '\0'; ch = (u_char) *src++)
++ if (!isspace(ch))
++ return (-1);
++
++ /*
++ * Now make sure for cases 2 and 3 that the "extra"
++ * bits that slopped past the last full byte were
++ * zeros. If we don't check them, they become a
++ * subliminal channel.
++ */
++ if (target && target[tarindex] != 0)
++ return (-1);
++ }
++ } else {
++ /*
++ * We ended by seeing the end of the string. Make sure we
++ * have no partial bytes lying around.
++ */
++ if (state != 0)
++ return (-1);
++ }
++
++ return (tarindex);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/commandline.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/commandline.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,1743 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <limits.h>
++#include <stdarg.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <ctype.h>
++#include <assert.h>
++
++#include "sysdeps.h"
++
++#ifdef HAVE_TERMIO_H
++#include <termios.h>
++#endif
++
++#define TRACE_TAG TRACE_ADB
++#include "adb.h"
++#include "adb_client.h"
++#include "file_sync_service.h"
++
++static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
++
++void get_my_path(char *s, size_t maxLen);
++int find_sync_dirs(const char *srcarg,
++ char **android_srcdir_out, char **data_srcdir_out);
++int install_app(transport_type transport, char* serial, int argc, char** argv);
++int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
++
++static const char *gProductOutPath = NULL;
++extern int gListenAll;
++
++static char *product_file(const char *extra)
++{
++ int n;
++ char *x;
++
++ if (gProductOutPath == NULL) {
++ fprintf(stderr, "adb: Product directory not specified; "
++ "use -p or define ANDROID_PRODUCT_OUT\n");
++ exit(1);
++ }
++
++ n = strlen(gProductOutPath) + strlen(extra) + 2;
++ x = malloc(n);
++ if (x == 0) {
++ fprintf(stderr, "adb: Out of memory (product_file())\n");
++ exit(1);
++ }
++
++ snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
++ return x;
++}
++
++void version(FILE * out) {
++ fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
++ ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
++}
++
++void help()
++{
++ version(stderr);
++
++ fprintf(stderr,
++ "\n"
++ " -a - directs adb to listen on all interfaces for a connection\n"
++ " -d - directs command to the only connected USB device\n"
++ " returns an error if more than one USB device is present.\n"
++ " -e - directs command to the only running emulator.\n"
++ " returns an error if more than one emulator is running.\n"
++ " -s <specific device> - directs command to the device or emulator with the given\n"
++ " serial number or qualifier. Overrides ANDROID_SERIAL\n"
++ " environment variable.\n"
++ " -p <product name or path> - simple product name like 'sooner', or\n"
++ " a relative/absolute path to a product\n"
++ " out directory like 'out/target/product/sooner'.\n"
++ " If -p is not specified, the ANDROID_PRODUCT_OUT\n"
++ " environment variable is used, which must\n"
++ " be an absolute path.\n"
++ " -H - Name of adb server host (default: localhost)\n"
++ " -P - Port of adb server (default: 5037)\n"
++ " devices [-l] - list all connected devices\n"
++ " ('-l' will also list device qualifiers)\n"
++ " connect <host>[:<port>] - connect to a device via TCP/IP\n"
++ " Port 5555 is used by default if no port number is specified.\n"
++ " disconnect [<host>[:<port>]] - disconnect from a TCP/IP device.\n"
++ " Port 5555 is used by default if no port number is specified.\n"
++ " Using this command with no additional arguments\n"
++ " will disconnect from all connected TCP/IP devices.\n"
++ "\n"
++ "device commands:\n"
++ " adb push <local> <remote> - copy file/dir to device\n"
++ " adb pull <remote> [<local>] - copy file/dir from device\n"
++ " adb sync [ <directory> ] - copy host->device only if changed\n"
++ " (-l means list but don't copy)\n"
++ " (see 'adb help all')\n"
++ " adb shell - run remote shell interactively\n"
++ " adb shell <command> - run remote shell command\n"
++ " adb emu <command> - run emulator console command\n"
++ " adb logcat [ <filter-spec> ] - View device log\n"
++ " adb forward --list - list all forward socket connections.\n"
++ " the format is a list of lines with the following format:\n"
++ " <serial> \" \" <local> \" \" <remote> \"\\n\"\n"
++ " adb forward <local> <remote> - forward socket connections\n"
++ " forward specs are one of: \n"
++ " tcp:<port>\n"
++ " localabstract:<unix domain socket name>\n"
++ " localreserved:<unix domain socket name>\n"
++ " localfilesystem:<unix domain socket name>\n"
++ " dev:<character device name>\n"
++ " jdwp:<process pid> (remote only)\n"
++ " adb forward --no-rebind <local> <remote>\n"
++ " - same as 'adb forward <local> <remote>' but fails\n"
++ " if <local> is already forwarded\n"
++ " adb forward --remove <local> - remove a specific forward socket connection\n"
++ " adb forward --remove-all - remove all forward socket connections\n"
++ " adb jdwp - list PIDs of processes hosting a JDWP transport\n"
++ " adb install [-l] [-r] [-s] [--algo <algorithm name> --key <hex-encoded key> --iv <hex-encoded iv>] <file>\n"
++ " - push this package file to the device and install it\n"
++ " ('-l' means forward-lock the app)\n"
++ " ('-r' means reinstall the app, keeping its data)\n"
++ " ('-s' means install on SD card instead of internal storage)\n"
++ " ('--algo', '--key', and '--iv' mean the file is encrypted already)\n"
++ " adb uninstall [-k] <package> - remove this app package from the device\n"
++ " ('-k' means keep the data and cache directories)\n"
++ " adb bugreport - return all information from the device\n"
++ " that should be included in a bug report.\n"
++ "\n"
++ " adb backup [-f <file>] [-apk|-noapk] [-shared|-noshared] [-all] [-system|-nosystem] [<packages...>]\n"
++ " - write an archive of the device's data to <file>.\n"
++ " If no -f option is supplied then the data is written\n"
++ " to \"backup.ab\" in the current directory.\n"
++ " (-apk|-noapk enable/disable backup of the .apks themselves\n"
++ " in the archive; the default is noapk.)\n"
++ " (-shared|-noshared enable/disable backup of the device's\n"
++ " shared storage / SD card contents; the default is noshared.)\n"
++ " (-all means to back up all installed applications)\n"
++ " (-system|-nosystem toggles whether -all automatically includes\n"
++ " system applications; the default is to include system apps)\n"
++ " (<packages...> is the list of applications to be backed up. If\n"
++ " the -all or -shared flags are passed, then the package\n"
++ " list is optional. Applications explicitly given on the\n"
++ " command line will be included even if -nosystem would\n"
++ " ordinarily cause them to be omitted.)\n"
++ "\n"
++ " adb restore <file> - restore device contents from the <file> backup archive\n"
++ "\n"
++ " adb help - show this help message\n"
++ " adb version - show version num\n"
++ "\n"
++ "scripting:\n"
++ " adb wait-for-device - block until device is online\n"
++ " adb start-server - ensure that there is a server running\n"
++ " adb kill-server - kill the server if it is running\n"
++ " adb get-state - prints: offline | bootloader | device\n"
++ " adb get-serialno - prints: <serial-number>\n"
++ " adb get-devpath - prints: <device-path>\n"
++ " adb status-window - continuously print device status for a specified device\n"
++ " adb remount - remounts the /system partition on the device read-write\n"
++ " adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
++ " adb reboot-bootloader - reboots the device into the bootloader\n"
++ " adb root - restarts the adbd daemon with root permissions\n"
++ " adb usb - restarts the adbd daemon listening on USB\n"
++ " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port"
++ "\n"
++ "networking:\n"
++ " adb ppp <tty> [parameters] - Run PPP over USB.\n"
++ " Note: you should not automatically start a PPP connection.\n"
++ " <tty> refers to the tty for PPP stream. Eg. dev:/dev/omap_csmi_tty1\n"
++ " [parameters] - Eg. defaultroute debug dump local notty usepeerdns\n"
++ "\n"
++ "adb sync notes: adb sync [ <directory> ]\n"
++ " <localdir> can be interpreted in several ways:\n"
++ "\n"
++ " - If <directory> is not specified, both /system and /data partitions will be updated.\n"
++ "\n"
++ " - If it is \"system\" or \"data\", only the corresponding partition\n"
++ " is updated.\n"
++ "\n"
++ "environmental variables:\n"
++ " ADB_TRACE - Print debug information. A comma separated list of the following values\n"
++ " 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n"
++ " ANDROID_SERIAL - The serial number to connect to. -s takes priority over this if given.\n"
++ " ANDROID_LOG_TAGS - When used with the logcat option, only these debug tags are printed.\n"
++ );
++}
++
++int usage()
++{
++ help();
++ return 1;
++}
++
++#ifdef HAVE_TERMIO_H
++static struct termios tio_save;
++
++static void stdin_raw_init(int fd)
++{
++ struct termios tio;
++
++ if(tcgetattr(fd, &tio)) return;
++ if(tcgetattr(fd, &tio_save)) return;
++
++ tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
++
++ /* no timeout but request at least one character per read */
++ tio.c_cc[VTIME] = 0;
++ tio.c_cc[VMIN] = 1;
++
++ tcsetattr(fd, TCSANOW, &tio);
++ tcflush(fd, TCIFLUSH);
++}
++
++static void stdin_raw_restore(int fd)
++{
++ tcsetattr(fd, TCSANOW, &tio_save);
++ tcflush(fd, TCIFLUSH);
++}
++#endif
++
++static void read_and_dump(int fd)
++{
++ char buf[4096];
++ int len;
++
++ while(fd >= 0) {
++ D("read_and_dump(): pre adb_read(fd=%d)\n", fd);
++ len = adb_read(fd, buf, 4096);
++ D("read_and_dump(): post adb_read(fd=%d): len=%d\n", fd, len);
++ if(len == 0) {
++ break;
++ }
++
++ if(len < 0) {
++ if(errno == EINTR) continue;
++ break;
++ }
++ fwrite(buf, 1, len, stdout);
++ fflush(stdout);
++ }
++}
++
++static void copy_to_file(int inFd, int outFd) {
++ const size_t BUFSIZE = 32 * 1024;
++ char* buf = (char*) malloc(BUFSIZE);
++ int len;
++ long total = 0;
++
++ D("copy_to_file(%d -> %d)\n", inFd, outFd);
++ for (;;) {
++ len = adb_read(inFd, buf, BUFSIZE);
++ if (len == 0) {
++ D("copy_to_file() : read 0 bytes; exiting\n");
++ break;
++ }
++ if (len < 0) {
++ if (errno == EINTR) {
++ D("copy_to_file() : EINTR, retrying\n");
++ continue;
++ }
++ D("copy_to_file() : error %d\n", errno);
++ break;
++ }
++ adb_write(outFd, buf, len);
++ total += len;
++ }
++ D("copy_to_file() finished after %lu bytes\n", total);
++ free(buf);
++}
++
++static void *stdin_read_thread(void *x)
++{
++ int fd, fdi;
++ unsigned char buf[1024];
++ int r, n;
++ int state = 0;
++
++ int *fds = (int*) x;
++ fd = fds[0];
++ fdi = fds[1];
++ free(fds);
++
++ for(;;) {
++ /* fdi is really the client's stdin, so use read, not adb_read here */
++ D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
++ r = unix_read(fdi, buf, 1024);
++ D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
++ if(r == 0) break;
++ if(r < 0) {
++ if(errno == EINTR) continue;
++ break;
++ }
++ for(n = 0; n < r; n++){
++ switch(buf[n]) {
++ case '\n':
++ state = 1;
++ break;
++ case '\r':
++ state = 1;
++ break;
++ case '~':
++ if(state == 1) state++;
++ break;
++ case '.':
++ if(state == 2) {
++ fprintf(stderr,"\n* disconnect *\n");
++#ifdef HAVE_TERMIO_H
++ stdin_raw_restore(fdi);
++#endif
++ exit(0);
++ }
++ default:
++ state = 0;
++ }
++ }
++ r = adb_write(fd, buf, r);
++ if(r <= 0) {
++ break;
++ }
++ }
++ return 0;
++}
++
++int interactive_shell(void)
++{
++ adb_thread_t thr;
++ int fdi, fd;
++ int *fds;
++
++ fd = adb_connect("shell:");
++ if(fd < 0) {
++ fprintf(stderr,"error: %s\n", adb_error());
++ return 1;
++ }
++ fdi = 0; //dup(0);
++
++ fds = malloc(sizeof(int) * 2);
++ fds[0] = fd;
++ fds[1] = fdi;
++
++#ifdef HAVE_TERMIO_H
++ stdin_raw_init(fdi);
++#endif
++ adb_thread_create(&thr, stdin_read_thread, fds);
++ read_and_dump(fd);
++#ifdef HAVE_TERMIO_H
++ stdin_raw_restore(fdi);
++#endif
++ return 0;
++}
++
++
++static void format_host_command(char* buffer, size_t buflen, const char* command, transport_type ttype, const char* serial)
++{
++ if (serial) {
++ snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
++ } else {
++ const char* prefix = "host";
++ if (ttype == kTransportUsb)
++ prefix = "host-usb";
++ else if (ttype == kTransportLocal)
++ prefix = "host-local";
++
++ snprintf(buffer, buflen, "%s:%s", prefix, command);
++ }
++}
++
++int adb_download_buffer(const char *service, const void* data, int sz,
++ unsigned progress)
++{
++ char buf[4096];
++ unsigned total;
++ int fd;
++ const unsigned char *ptr;
++
++ sprintf(buf,"%s:%d", service, sz);
++ fd = adb_connect(buf);
++ if(fd < 0) {
++ fprintf(stderr,"error: %s\n", adb_error());
++ return -1;
++ }
++
++ int opt = CHUNK_SIZE;
++ opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt));
++
++ total = sz;
++ ptr = data;
++
++ if(progress) {
++ char *x = strrchr(service, ':');
++ if(x) service = x + 1;
++ }
++
++ while(sz > 0) {
++ unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz;
++ if(writex(fd, ptr, xfer)) {
++ adb_status(fd);
++ fprintf(stderr,"* failed to write data '%s' *\n", adb_error());
++ return -1;
++ }
++ sz -= xfer;
++ ptr += xfer;
++ if(progress) {
++ printf("sending: '%s' %4d%% \r", service, (int)(100LL - ((100LL * sz) / (total))));
++ fflush(stdout);
++ }
++ }
++ if(progress) {
++ printf("\n");
++ }
++
++ if(readx(fd, buf, 4)){
++ fprintf(stderr,"* error reading response *\n");
++ adb_close(fd);
++ return -1;
++ }
++ if(memcmp(buf, "OKAY", 4)) {
++ buf[4] = 0;
++ fprintf(stderr,"* error response '%s' *\n", buf);
++ adb_close(fd);
++ return -1;
++ }
++
++ adb_close(fd);
++ return 0;
++}
++
++
++int adb_download(const char *service, const char *fn, unsigned progress)
++{
++ void *data;
++ unsigned sz;
++
++ data = load_file(fn, &sz);
++ if(data == 0) {
++ fprintf(stderr,"* cannot read '%s' *\n", service);
++ return -1;
++ }
++
++ int status = adb_download_buffer(service, data, sz, progress);
++ free(data);
++ return status;
++}
++
++static void status_window(transport_type ttype, const char* serial)
++{
++ char command[4096];
++ char *state = 0;
++ char *laststate = 0;
++
++ /* silence stderr */
++#ifdef _WIN32
++ /* XXX: TODO */
++#else
++ int fd;
++ fd = unix_open("/dev/null", O_WRONLY);
++ dup2(fd, 2);
++ adb_close(fd);
++#endif
++
++ format_host_command(command, sizeof command, "get-state", ttype, serial);
++
++ for(;;) {
++ adb_sleep_ms(250);
++
++ if(state) {
++ free(state);
++ state = 0;
++ }
++
++ state = adb_query(command);
++
++ if(state) {
++ if(laststate && !strcmp(state,laststate)){
++ continue;
++ } else {
++ if(laststate) free(laststate);
++ laststate = strdup(state);
++ }
++ }
++
++ printf("%c[2J%c[2H", 27, 27);
++ printf("Android Debug Bridge\n");
++ printf("State: %s\n", state ? state : "offline");
++ fflush(stdout);
++ }
++}
++
++/** duplicate string and quote all \ " ( ) chars + space character. */
++static char *
++dupAndQuote(const char *s)
++{
++ const char *ts;
++ size_t alloc_len;
++ char *ret;
++ char *dest;
++
++ ts = s;
++
++ alloc_len = 0;
++
++ for( ;*ts != '\0'; ts++) {
++ alloc_len++;
++ if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
++ alloc_len++;
++ }
++ }
++
++ ret = (char *)malloc(alloc_len + 1);
++
++ ts = s;
++ dest = ret;
++
++ for ( ;*ts != '\0'; ts++) {
++ if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
++ *dest++ = '\\';
++ }
++
++ *dest++ = *ts;
++ }
++
++ *dest++ = '\0';
++
++ return ret;
++}
++
++/**
++ * Run ppp in "notty" mode against a resource listed as the first parameter
++ * eg:
++ *
++ * ppp dev:/dev/omap_csmi_tty0 <ppp options>
++ *
++ */
++int ppp(int argc, char **argv)
++{
++#ifdef HAVE_WIN32_PROC
++ fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
++ return -1;
++#else
++ char *adb_service_name;
++ pid_t pid;
++ int fd;
++
++ if (argc < 2) {
++ fprintf(stderr, "usage: adb %s <adb service name> [ppp opts]\n",
++ argv[0]);
++
++ return 1;
++ }
++
++ adb_service_name = argv[1];
++
++ fd = adb_connect(adb_service_name);
++
++ if(fd < 0) {
++ fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n",
++ adb_service_name, adb_error());
++ return 1;
++ }
++
++ pid = fork();
++
++ if (pid < 0) {
++ perror("from fork()");
++ return 1;
++ } else if (pid == 0) {
++ int err;
++ int i;
++ const char **ppp_args;
++
++ // copy args
++ ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
++ ppp_args[0] = "pppd";
++ for (i = 2 ; i < argc ; i++) {
++ //argv[2] and beyond become ppp_args[1] and beyond
++ ppp_args[i - 1] = argv[i];
++ }
++ ppp_args[i-1] = NULL;
++
++ // child side
++
++ dup2(fd, STDIN_FILENO);
++ dup2(fd, STDOUT_FILENO);
++ adb_close(STDERR_FILENO);
++ adb_close(fd);
++
++ err = execvp("pppd", (char * const *)ppp_args);
++
++ if (err < 0) {
++ perror("execing pppd");
++ }
++ exit(-1);
++ } else {
++ // parent side
++
++ adb_close(fd);
++ return 0;
++ }
++#endif /* !HAVE_WIN32_PROC */
++}
++
++static int send_shellcommand(transport_type transport, char* serial, char* buf)
++{
++ int fd, ret;
++
++ for(;;) {
++ fd = adb_connect(buf);
++ if(fd >= 0)
++ break;
++ fprintf(stderr,"- waiting for device -\n");
++ adb_sleep_ms(1000);
++ do_cmd(transport, serial, "wait-for-device", 0);
++ }
++
++ read_and_dump(fd);
++ ret = adb_close(fd);
++ if (ret)
++ perror("close");
++
++ return ret;
++}
++
++static int logcat(transport_type transport, char* serial, int argc, char **argv)
++{
++ char buf[4096];
++
++ char *log_tags;
++ char *quoted_log_tags;
++
++ log_tags = getenv("ANDROID_LOG_TAGS");
++ quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
++
++ snprintf(buf, sizeof(buf),
++ "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
++ quoted_log_tags);
++
++ free(quoted_log_tags);
++
++ if (!strcmp(argv[0],"longcat")) {
++ strncat(buf, " -v long", sizeof(buf)-1);
++ }
++
++ argc -= 1;
++ argv += 1;
++ while(argc-- > 0) {
++ char *quoted;
++
++ quoted = dupAndQuote (*argv++);
++
++ strncat(buf, " ", sizeof(buf)-1);
++ strncat(buf, quoted, sizeof(buf)-1);
++ free(quoted);
++ }
++
++ send_shellcommand(transport, serial, buf);
++ return 0;
++}
++
++static int mkdirs(char *path)
++{
++ int ret;
++ char *x = path + 1;
++
++ for(;;) {
++ x = adb_dirstart(x);
++ if(x == 0) return 0;
++ *x = 0;
++ ret = adb_mkdir(path, 0775);
++ *x = OS_PATH_SEPARATOR;
++ if((ret < 0) && (errno != EEXIST)) {
++ return ret;
++ }
++ x++;
++ }
++ return 0;
++}
++
++static int backup(int argc, char** argv) {
++ char buf[4096];
++ char default_name[32];
++ const char* filename = strcpy(default_name, "./backup.ab");
++ int fd, outFd;
++ int i, j;
++
++ /* find, extract, and use any -f argument */
++ for (i = 1; i < argc; i++) {
++ if (!strcmp("-f", argv[i])) {
++ if (i == argc-1) {
++ fprintf(stderr, "adb: -f passed with no filename\n");
++ return usage();
++ }
++ filename = argv[i+1];
++ for (j = i+2; j <= argc; ) {
++ argv[i++] = argv[j++];
++ }
++ argc -= 2;
++ argv[argc] = NULL;
++ }
++ }
++
++ /* bare "adb backup" or "adb backup -f filename" are not valid invocations */
++ if (argc < 2) return usage();
++
++ adb_unlink(filename);
++ mkdirs((char *)filename);
++ outFd = adb_creat(filename, 0640);
++ if (outFd < 0) {
++ fprintf(stderr, "adb: unable to open file %s\n", filename);
++ return -1;
++ }
++
++ snprintf(buf, sizeof(buf), "backup");
++ for (argc--, argv++; argc; argc--, argv++) {
++ strncat(buf, ":", sizeof(buf) - strlen(buf) - 1);
++ strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1);
++ }
++
++ D("backup. filename=%s buf=%s\n", filename, buf);
++ fd = adb_connect(buf);
++ if (fd < 0) {
++ fprintf(stderr, "adb: unable to connect for backup\n");
++ adb_close(outFd);
++ return -1;
++ }
++
++ printf("Now unlock your device and confirm the backup operation.\n");
++ copy_to_file(fd, outFd);
++
++ adb_close(fd);
++ adb_close(outFd);
++ return 0;
++}
++
++static int restore(int argc, char** argv) {
++ const char* filename;
++ int fd, tarFd;
++
++ if (argc != 2) return usage();
++
++ filename = argv[1];
++ tarFd = adb_open(filename, O_RDONLY);
++ if (tarFd < 0) {
++ fprintf(stderr, "adb: unable to open file %s\n", filename);
++ return -1;
++ }
++
++ fd = adb_connect("restore:");
++ if (fd < 0) {
++ fprintf(stderr, "adb: unable to connect for backup\n");
++ adb_close(tarFd);
++ return -1;
++ }
++
++ printf("Now unlock your device and confirm the restore operation.\n");
++ copy_to_file(tarFd, fd);
++
++ adb_close(fd);
++ adb_close(tarFd);
++ return 0;
++}
++
++#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
++static int top_works(const char *top)
++{
++ if (top != NULL && adb_is_absolute_host_path(top)) {
++ char path_buf[PATH_MAX];
++ snprintf(path_buf, sizeof(path_buf),
++ "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
++ return access(path_buf, F_OK) == 0;
++ }
++ return 0;
++}
++
++static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
++{
++ strcpy(path_buf, indir);
++ while (1) {
++ if (top_works(path_buf)) {
++ return path_buf;
++ }
++ char *s = adb_dirstop(path_buf);
++ if (s != NULL) {
++ *s = '\0';
++ } else {
++ path_buf[0] = '\0';
++ return NULL;
++ }
++ }
++}
++
++static char *find_top(char path_buf[PATH_MAX])
++{
++ char *top = getenv("ANDROID_BUILD_TOP");
++ if (top != NULL && top[0] != '\0') {
++ if (!top_works(top)) {
++ fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
++ return NULL;
++ }
++ } else {
++ top = getenv("TOP");
++ if (top != NULL && top[0] != '\0') {
++ if (!top_works(top)) {
++ fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
++ return NULL;
++ }
++ } else {
++ top = NULL;
++ }
++ }
++
++ if (top != NULL) {
++ /* The environment pointed to a top directory that works.
++ */
++ strcpy(path_buf, top);
++ return path_buf;
++ }
++
++ /* The environment didn't help. Walk up the tree from the CWD
++ * to see if we can find the top.
++ */
++ char dir[PATH_MAX];
++ top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
++ if (top == NULL) {
++ /* If the CWD isn't under a good-looking top, see if the
++ * executable is.
++ */
++ get_my_path(dir, PATH_MAX);
++ top = find_top_from(dir, path_buf);
++ }
++ return top;
++}
++
++/* <hint> may be:
++ * - A simple product name
++ * e.g., "sooner"
++TODO: debug? sooner-debug, sooner:debug?
++ * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
++ * e.g., "out/target/product/sooner"
++ * - An absolute path to the PRODUCT_OUT dir
++ * e.g., "/src/device/out/target/product/sooner"
++ *
++ * Given <hint>, try to construct an absolute path to the
++ * ANDROID_PRODUCT_OUT dir.
++ */
++static const char *find_product_out_path(const char *hint)
++{
++ static char path_buf[PATH_MAX];
++
++ if (hint == NULL || hint[0] == '\0') {
++ return NULL;
++ }
++
++ /* If it's already absolute, don't bother doing any work.
++ */
++ if (adb_is_absolute_host_path(hint)) {
++ strcpy(path_buf, hint);
++ return path_buf;
++ }
++
++ /* If there are any slashes in it, assume it's a relative path;
++ * make it absolute.
++ */
++ if (adb_dirstart(hint) != NULL) {
++ if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
++ fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
++ return NULL;
++ }
++ if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
++ fprintf(stderr, "adb: Couldn't assemble path\n");
++ return NULL;
++ }
++ strcat(path_buf, OS_PATH_SEPARATOR_STR);
++ strcat(path_buf, hint);
++ return path_buf;
++ }
++
++ /* It's a string without any slashes. Try to do something with it.
++ *
++ * Try to find the root of the build tree, and build a PRODUCT_OUT
++ * path from there.
++ */
++ char top_buf[PATH_MAX];
++ const char *top = find_top(top_buf);
++ if (top == NULL) {
++ fprintf(stderr, "adb: Couldn't find top of build tree\n");
++ return NULL;
++ }
++//TODO: if we have a way to indicate debug, look in out/debug/target/...
++ snprintf(path_buf, sizeof(path_buf),
++ "%s" OS_PATH_SEPARATOR_STR
++ "out" OS_PATH_SEPARATOR_STR
++ "target" OS_PATH_SEPARATOR_STR
++ "product" OS_PATH_SEPARATOR_STR
++ "%s", top_buf, hint);
++ if (access(path_buf, F_OK) < 0) {
++ fprintf(stderr, "adb: Couldn't find a product dir "
++ "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
++ return NULL;
++ }
++ return path_buf;
++}
++
++int adb_commandline(int argc, char **argv)
++{
++ char buf[4096];
++ int no_daemon = 0;
++ int is_daemon = 0;
++ int is_server = 0;
++ int persist = 0;
++ int r;
++ int quote;
++ transport_type ttype = kTransportAny;
++ char* serial = NULL;
++ char* server_port_str = NULL;
++
++ /* If defined, this should be an absolute path to
++ * the directory containing all of the various system images
++ * for a particular product. If not defined, and the adb
++ * command requires this information, then the user must
++ * specify the path using "-p".
++ */
++ gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
++ if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
++ gProductOutPath = NULL;
++ }
++ // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
++
++ serial = getenv("ANDROID_SERIAL");
++
++ /* Validate and assign the server port */
++ server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
++ int server_port = DEFAULT_ADB_PORT;
++ if (server_port_str && strlen(server_port_str) > 0) {
++ server_port = (int) strtol(server_port_str, NULL, 0);
++ if (server_port <= 0 || server_port > 65535) {
++ fprintf(stderr,
++ "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number less than 65535. Got \"%s\"\n",
++ server_port_str);
++ return usage();
++ }
++ }
++
++ /* modifiers and flags */
++ while(argc > 0) {
++ if(!strcmp(argv[0],"server")) {
++ is_server = 1;
++ } else if(!strcmp(argv[0],"nodaemon")) {
++ no_daemon = 1;
++ } else if (!strcmp(argv[0], "fork-server")) {
++ /* this is a special flag used only when the ADB client launches the ADB Server */
++ is_daemon = 1;
++ } else if(!strcmp(argv[0],"persist")) {
++ persist = 1;
++ } else if(!strncmp(argv[0], "-p", 2)) {
++ const char *product = NULL;
++ if (argv[0][2] == '\0') {
++ if (argc < 2) return usage();
++ product = argv[1];
++ argc--;
++ argv++;
++ } else {
++ product = argv[0] + 2;
++ }
++ gProductOutPath = find_product_out_path(product);
++ if (gProductOutPath == NULL) {
++ fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
++ product);
++ return usage();
++ }
++ } else if (argv[0][0]=='-' && argv[0][1]=='s') {
++ if (isdigit(argv[0][2])) {
++ serial = argv[0] + 2;
++ } else {
++ if(argc < 2 || argv[0][2] != '\0') return usage();
++ serial = argv[1];
++ argc--;
++ argv++;
++ }
++ } else if (!strcmp(argv[0],"-d")) {
++ ttype = kTransportUsb;
++ } else if (!strcmp(argv[0],"-e")) {
++ ttype = kTransportLocal;
++ } else if (!strcmp(argv[0],"-a")) {
++ gListenAll = 1;
++ } else if(!strncmp(argv[0], "-H", 2)) {
++ const char *hostname = NULL;
++ if (argv[0][2] == '\0') {
++ if (argc < 2) return usage();
++ hostname = argv[1];
++ argc--;
++ argv++;
++ } else {
++ hostname = argv[0] + 2;
++ }
++ adb_set_tcp_name(hostname);
++
++ } else if(!strncmp(argv[0], "-P", 2)) {
++ if (argv[0][2] == '\0') {
++ if (argc < 2) return usage();
++ server_port_str = argv[1];
++ argc--;
++ argv++;
++ } else {
++ server_port_str = argv[0] + 2;
++ }
++ if (strlen(server_port_str) > 0) {
++ server_port = (int) strtol(server_port_str, NULL, 0);
++ if (server_port <= 0 || server_port > 65535) {
++ fprintf(stderr,
++ "adb: port number must be a positive number less than 65536. Got \"%s\"\n",
++ server_port_str);
++ return usage();
++ }
++ } else {
++ fprintf(stderr,
++ "adb: port number must be a positive number less than 65536. Got empty string.\n");
++ return usage();
++ }
++ } else {
++ /* out of recognized modifiers and flags */
++ break;
++ }
++ argc--;
++ argv++;
++ }
++
++ adb_set_transport(ttype, serial);
++ adb_set_tcp_specifics(server_port);
++
++ if (is_server) {
++ if (no_daemon || is_daemon) {
++ r = adb_main(is_daemon, server_port);
++ } else {
++ r = launch_server(server_port);
++ }
++ if(r) {
++ fprintf(stderr,"* could not start server *\n");
++ }
++ return r;
++ }
++
++top:
++ if(argc == 0) {
++ return usage();
++ }
++
++ /* adb_connect() commands */
++
++ if(!strcmp(argv[0], "devices")) {
++ char *tmp;
++ char *listopt;
++ if (argc < 2)
++ listopt = "";
++ else if (argc == 2 && !strcmp(argv[1], "-l"))
++ listopt = argv[1];
++ else {
++ fprintf(stderr, "Usage: adb devices [-l]\n");
++ return 1;
++ }
++ snprintf(buf, sizeof buf, "host:%s%s", argv[0], listopt);
++ tmp = adb_query(buf);
++ if(tmp) {
++ printf("List of devices attached \n");
++ printf("%s\n", tmp);
++ return 0;
++ } else {
++ return 1;
++ }
++ }
++
++ if(!strcmp(argv[0], "connect")) {
++ char *tmp;
++ if (argc != 2) {
++ fprintf(stderr, "Usage: adb connect <host>[:<port>]\n");
++ return 1;
++ }
++ snprintf(buf, sizeof buf, "host:connect:%s", argv[1]);
++ tmp = adb_query(buf);
++ if(tmp) {
++ printf("%s\n", tmp);
++ return 0;
++ } else {
++ return 1;
++ }
++ }
++
++ if(!strcmp(argv[0], "disconnect")) {
++ char *tmp;
++ if (argc > 2) {
++ fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n");
++ return 1;
++ }
++ if (argc == 2) {
++ snprintf(buf, sizeof buf, "host:disconnect:%s", argv[1]);
++ } else {
++ snprintf(buf, sizeof buf, "host:disconnect:");
++ }
++ tmp = adb_query(buf);
++ if(tmp) {
++ printf("%s\n", tmp);
++ return 0;
++ } else {
++ return 1;
++ }
++ }
++
++ if (!strcmp(argv[0], "emu")) {
++ return adb_send_emulator_command(argc, argv);
++ }
++
++ if(!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
++ int r;
++ int fd;
++
++ char h = (argv[0][0] == 'h');
++
++ if (h) {
++ printf("\x1b[41;33m");
++ fflush(stdout);
++ }
++
++ if(argc < 2) {
++ D("starting interactive shell\n");
++ r = interactive_shell();
++ if (h) {
++ printf("\x1b[0m");
++ fflush(stdout);
++ }
++ return r;
++ }
++
++ snprintf(buf, sizeof buf, "shell:%s", argv[1]);
++ argc -= 2;
++ argv += 2;
++ while(argc-- > 0) {
++ strcat(buf, " ");
++
++ /* quote empty strings and strings with spaces */
++ quote = (**argv == 0 || strchr(*argv, ' '));
++ if (quote)
++ strcat(buf, "\"");
++ strcat(buf, *argv++);
++ if (quote)
++ strcat(buf, "\"");
++ }
++
++ for(;;) {
++ D("interactive shell loop. buff=%s\n", buf);
++ fd = adb_connect(buf);
++ if(fd >= 0) {
++ D("about to read_and_dump(fd=%d)\n", fd);
++ read_and_dump(fd);
++ D("read_and_dump() done.\n");
++ adb_close(fd);
++ r = 0;
++ } else {
++ fprintf(stderr,"error: %s\n", adb_error());
++ r = -1;
++ }
++
++ if(persist) {
++ fprintf(stderr,"\n- waiting for device -\n");
++ adb_sleep_ms(1000);
++ do_cmd(ttype, serial, "wait-for-device", 0);
++ } else {
++ if (h) {
++ printf("\x1b[0m");
++ fflush(stdout);
++ }
++ D("interactive shell loop. return r=%d\n", r);
++ return r;
++ }
++ }
++ }
++
++ if(!strcmp(argv[0], "kill-server")) {
++ int fd;
++ fd = _adb_connect("host:kill");
++ if(fd == -1) {
++ fprintf(stderr,"* server not running *\n");
++ return 1;
++ }
++ return 0;
++ }
++
++ if(!strcmp(argv[0], "sideload")) {
++ if(argc != 2) return usage();
++ if(adb_download("sideload", argv[1], 1)) {
++ return 1;
++ } else {
++ return 0;
++ }
++ }
++
++ if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
++ || !strcmp(argv[0], "reboot-bootloader")
++ || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
++ || !strcmp(argv[0], "root")) {
++ char command[100];
++ if (!strcmp(argv[0], "reboot-bootloader"))
++ snprintf(command, sizeof(command), "reboot:bootloader");
++ else if (argc > 1)
++ snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
++ else
++ snprintf(command, sizeof(command), "%s:", argv[0]);
++ int fd = adb_connect(command);
++ if(fd >= 0) {
++ read_and_dump(fd);
++ adb_close(fd);
++ return 0;
++ }
++ fprintf(stderr,"error: %s\n", adb_error());
++ return 1;
++ }
++
++ if(!strcmp(argv[0], "bugreport")) {
++ if (argc != 1) return usage();
++ do_cmd(ttype, serial, "shell", "bugreport", 0);
++ return 0;
++ }
++
++ /* adb_command() wrapper commands */
++
++ if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
++ char* service = argv[0];
++ if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
++ if (ttype == kTransportUsb) {
++ service = "wait-for-usb";
++ } else if (ttype == kTransportLocal) {
++ service = "wait-for-local";
++ } else {
++ service = "wait-for-any";
++ }
++ }
++
++ format_host_command(buf, sizeof buf, service, ttype, serial);
++
++ if (adb_command(buf)) {
++ D("failure: %s *\n",adb_error());
++ fprintf(stderr,"error: %s\n", adb_error());
++ return 1;
++ }
++
++ /* Allow a command to be run after wait-for-device,
++ * e.g. 'adb wait-for-device shell'.
++ */
++ if(argc > 1) {
++ argc--;
++ argv++;
++ goto top;
++ }
++ return 0;
++ }
++
++ if(!strcmp(argv[0], "forward")) {
++ char host_prefix[64];
++ char remove = 0;
++ char remove_all = 0;
++ char list = 0;
++ char no_rebind = 0;
++
++ // Parse options here.
++ while (argc > 1 && argv[1][0] == '-') {
++ if (!strcmp(argv[1], "--list"))
++ list = 1;
++ else if (!strcmp(argv[1], "--remove"))
++ remove = 1;
++ else if (!strcmp(argv[1], "--remove-all"))
++ remove_all = 1;
++ else if (!strcmp(argv[1], "--no-rebind"))
++ no_rebind = 1;
++ else {
++ return usage();
++ }
++ argc--;
++ argv++;
++ }
++
++ // Ensure we can only use one option at a time.
++ if (list + remove + remove_all + no_rebind > 1) {
++ return usage();
++ }
++
++ // Determine the <host-prefix> for this command.
++ if (serial) {
++ snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
++ serial);
++ } else if (ttype == kTransportUsb) {
++ snprintf(host_prefix, sizeof host_prefix, "host-usb");
++ } else if (ttype == kTransportLocal) {
++ snprintf(host_prefix, sizeof host_prefix, "host-local");
++ } else {
++ snprintf(host_prefix, sizeof host_prefix, "host");
++ }
++
++ // Implement forward --list
++ if (list) {
++ if (argc != 1)
++ return usage();
++ snprintf(buf, sizeof buf, "%s:list-forward", host_prefix);
++ char* forwards = adb_query(buf);
++ if (forwards == NULL) {
++ fprintf(stderr, "error: %s\n", adb_error());
++ return 1;
++ }
++ printf("%s", forwards);
++ free(forwards);
++ return 0;
++ }
++
++ // Implement forward --remove-all
++ else if (remove_all) {
++ if (argc != 1)
++ return usage();
++ snprintf(buf, sizeof buf, "%s:killforward-all", host_prefix);
++ }
++
++ // Implement forward --remove <local>
++ else if (remove) {
++ if (argc != 2)
++ return usage();
++ snprintf(buf, sizeof buf, "%s:killforward:%s", host_prefix, argv[1]);
++ }
++ // Or implement one of:
++ // forward <local> <remote>
++ // forward --no-rebind <local> <remote>
++ else
++ {
++ if (argc != 3)
++ return usage();
++ const char* command = no_rebind ? "forward:norebind:" : "forward";
++ snprintf(buf, sizeof buf, "%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]);
++ }
++
++ if(adb_command(buf)) {
++ fprintf(stderr,"error: %s\n", adb_error());
++ return 1;
++ }
++ return 0;
++ }
++
++ /* do_sync_*() commands */
++
++ if(!strcmp(argv[0], "ls")) {
++ if(argc != 2) return usage();
++ return do_sync_ls(argv[1]);
++ }
++
++ if(!strcmp(argv[0], "push")) {
++ if(argc != 3) return usage();
++ return do_sync_push(argv[1], argv[2], 0 /* no verify APK */);
++ }
++
++ if(!strcmp(argv[0], "pull")) {
++ if (argc == 2) {
++ return do_sync_pull(argv[1], ".");
++ } else if (argc == 3) {
++ return do_sync_pull(argv[1], argv[2]);
++ } else {
++ return usage();
++ }
++ }
++
++ if(!strcmp(argv[0], "install")) {
++ if (argc < 2) return usage();
++ return install_app(ttype, serial, argc, argv);
++ }
++
++ if(!strcmp(argv[0], "uninstall")) {
++ if (argc < 2) return usage();
++ return uninstall_app(ttype, serial, argc, argv);
++ }
++
++ if(!strcmp(argv[0], "sync")) {
++ char *srcarg, *android_srcpath, *data_srcpath;
++ int listonly = 0;
++
++ int ret;
++ if(argc < 2) {
++ /* No local path was specified. */
++ srcarg = NULL;
++ } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
++ listonly = 1;
++ if (argc == 3) {
++ srcarg = argv[2];
++ } else {
++ srcarg = NULL;
++ }
++ } else if(argc == 2) {
++ /* A local path or "android"/"data" arg was specified. */
++ srcarg = argv[1];
++ } else {
++ return usage();
++ }
++ ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
++ if(ret != 0) return usage();
++
++ if(android_srcpath != NULL)
++ ret = do_sync_sync(android_srcpath, "/system", listonly);
++ if(ret == 0 && data_srcpath != NULL)
++ ret = do_sync_sync(data_srcpath, "/data", listonly);
++
++ free(android_srcpath);
++ free(data_srcpath);
++ return ret;
++ }
++
++ /* passthrough commands */
++
++ if(!strcmp(argv[0],"get-state") ||
++ !strcmp(argv[0],"get-serialno") ||
++ !strcmp(argv[0],"get-devpath"))
++ {
++ char *tmp;
++
++ format_host_command(buf, sizeof buf, argv[0], ttype, serial);
++ tmp = adb_query(buf);
++ if(tmp) {
++ printf("%s\n", tmp);
++ return 0;
++ } else {
++ return 1;
++ }
++ }
++
++ /* other commands */
++
++ if(!strcmp(argv[0],"status-window")) {
++ status_window(ttype, serial);
++ return 0;
++ }
++
++ if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) {
++ return logcat(ttype, serial, argc, argv);
++ }
++
++ if(!strcmp(argv[0],"ppp")) {
++ return ppp(argc, argv);
++ }
++
++ if (!strcmp(argv[0], "start-server")) {
++ return adb_connect("host:start-server");
++ }
++
++ if (!strcmp(argv[0], "backup")) {
++ return backup(argc, argv);
++ }
++
++ if (!strcmp(argv[0], "restore")) {
++ return restore(argc, argv);
++ }
++
++ if (!strcmp(argv[0], "jdwp")) {
++ int fd = adb_connect("jdwp");
++ if (fd >= 0) {
++ read_and_dump(fd);
++ adb_close(fd);
++ return 0;
++ } else {
++ fprintf(stderr, "error: %s\n", adb_error());
++ return -1;
++ }
++ }
++
++ /* "adb /?" is a common idiom under Windows */
++ if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
++ help();
++ return 0;
++ }
++
++ if(!strcmp(argv[0], "version")) {
++ version(stdout);
++ return 0;
++ }
++
++ usage();
++ return 1;
++}
++
++static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
++{
++ char *argv[16];
++ int argc;
++ va_list ap;
++
++ va_start(ap, cmd);
++ argc = 0;
++
++ if (serial) {
++ argv[argc++] = "-s";
++ argv[argc++] = serial;
++ } else if (ttype == kTransportUsb) {
++ argv[argc++] = "-d";
++ } else if (ttype == kTransportLocal) {
++ argv[argc++] = "-e";
++ }
++
++ argv[argc++] = cmd;
++ while((argv[argc] = va_arg(ap, char*)) != 0) argc++;
++ va_end(ap);
++
++#if 0
++ int n;
++ fprintf(stderr,"argc = %d\n",argc);
++ for(n = 0; n < argc; n++) {
++ fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
++ }
++#endif
++
++ return adb_commandline(argc, argv);
++}
++
++int find_sync_dirs(const char *srcarg,
++ char **android_srcdir_out, char **data_srcdir_out)
++{
++ char *android_srcdir, *data_srcdir;
++
++ if(srcarg == NULL) {
++ android_srcdir = product_file("system");
++ data_srcdir = product_file("data");
++ } else {
++ /* srcarg may be "data", "system" or NULL.
++ * if srcarg is NULL, then both data and system are synced
++ */
++ if(strcmp(srcarg, "system") == 0) {
++ android_srcdir = product_file("system");
++ data_srcdir = NULL;
++ } else if(strcmp(srcarg, "data") == 0) {
++ android_srcdir = NULL;
++ data_srcdir = product_file("data");
++ } else {
++ /* It's not "system" or "data".
++ */
++ return 1;
++ }
++ }
++
++ if(android_srcdir_out != NULL)
++ *android_srcdir_out = android_srcdir;
++ else
++ free(android_srcdir);
++
++ if(data_srcdir_out != NULL)
++ *data_srcdir_out = data_srcdir;
++ else
++ free(data_srcdir);
++
++ return 0;
++}
++
++static int pm_command(transport_type transport, char* serial,
++ int argc, char** argv)
++{
++ char buf[4096];
++
++ snprintf(buf, sizeof(buf), "shell:pm");
++
++ while(argc-- > 0) {
++ char *quoted;
++
++ quoted = dupAndQuote(*argv++);
++
++ strncat(buf, " ", sizeof(buf)-1);
++ strncat(buf, quoted, sizeof(buf)-1);
++ free(quoted);
++ }
++
++ send_shellcommand(transport, serial, buf);
++ return 0;
++}
++
++int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
++{
++ /* if the user choose the -k option, we refuse to do it until devices are
++ out with the option to uninstall the remaining data somehow (adb/ui) */
++ if (argc == 3 && strcmp(argv[1], "-k") == 0)
++ {
++ printf(
++ "The -k option uninstalls the application while retaining the data/cache.\n"
++ "At the moment, there is no way to remove the remaining data.\n"
++ "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
++ "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
++ return -1;
++ }
++
++ /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
++ return pm_command(transport, serial, argc, argv);
++}
++
++static int delete_file(transport_type transport, char* serial, char* filename)
++{
++ char buf[4096];
++ char* quoted;
++
++ snprintf(buf, sizeof(buf), "shell:rm ");
++ quoted = dupAndQuote(filename);
++ strncat(buf, quoted, sizeof(buf)-1);
++ free(quoted);
++
++ send_shellcommand(transport, serial, buf);
++ return 0;
++}
++
++static const char* get_basename(const char* filename)
++{
++ const char* basename = adb_dirstop(filename);
++ if (basename) {
++ basename++;
++ return basename;
++ } else {
++ return filename;
++ }
++}
++
++static int check_file(const char* filename)
++{
++ struct stat st;
++
++ if (filename == NULL) {
++ return 0;
++ }
++
++ if (stat(filename, &st) != 0) {
++ fprintf(stderr, "can't find '%s' to install\n", filename);
++ return 1;
++ }
++
++ if (!S_ISREG(st.st_mode)) {
++ fprintf(stderr, "can't install '%s' because it's not a file\n", filename);
++ return 1;
++ }
++
++ return 0;
++}
++
++int install_app(transport_type transport, char* serial, int argc, char** argv)
++{
++ static const char *const DATA_DEST = "/data/local/tmp/%s";
++ static const char *const SD_DEST = "/sdcard/tmp/%s";
++ const char* where = DATA_DEST;
++ char apk_dest[PATH_MAX];
++ char verification_dest[PATH_MAX];
++ char* apk_file;
++ char* verification_file = NULL;
++ int file_arg = -1;
++ int err;
++ int i;
++ int verify_apk = 1;
++
++ for (i = 1; i < argc; i++) {
++ if (*argv[i] != '-') {
++ file_arg = i;
++ break;
++ } else if (!strcmp(argv[i], "-i")) {
++ // Skip the installer package name.
++ i++;
++ } else if (!strcmp(argv[i], "-s")) {
++ where = SD_DEST;
++ } else if (!strcmp(argv[i], "--algo")) {
++ verify_apk = 0;
++ i++;
++ } else if (!strcmp(argv[i], "--iv")) {
++ verify_apk = 0;
++ i++;
++ } else if (!strcmp(argv[i], "--key")) {
++ verify_apk = 0;
++ i++;
++ }
++ }
++
++ if (file_arg < 0) {
++ fprintf(stderr, "can't find filename in arguments\n");
++ return 1;
++ } else if (file_arg + 2 < argc) {
++ fprintf(stderr, "too many files specified; only takes APK file and verifier file\n");
++ return 1;
++ }
++
++ apk_file = argv[file_arg];
++
++ if (file_arg != argc - 1) {
++ verification_file = argv[file_arg + 1];
++ }
++
++ if (check_file(apk_file) || check_file(verification_file)) {
++ return 1;
++ }
++
++ snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
++ if (verification_file != NULL) {
++ snprintf(verification_dest, sizeof(verification_dest), where, get_basename(verification_file));
++
++ if (!strcmp(apk_dest, verification_dest)) {
++ fprintf(stderr, "APK and verification file can't have the same name\n");
++ return 1;
++ }
++ }
++
++ err = do_sync_push(apk_file, apk_dest, verify_apk);
++ if (err) {
++ goto cleanup_apk;
++ } else {
++ argv[file_arg] = apk_dest; /* destination name, not source location */
++ }
++
++ if (verification_file != NULL) {
++ err = do_sync_push(verification_file, verification_dest, 0 /* no verify APK */);
++ if (err) {
++ goto cleanup_apk;
++ } else {
++ argv[file_arg + 1] = verification_dest; /* destination name, not source location */
++ }
++ }
++
++ pm_command(transport, serial, argc, argv);
++
++cleanup_apk:
++ if (verification_file != NULL) {
++ delete_file(transport, serial, verification_dest);
++ }
++
++ delete_file(transport, serial, apk_dest);
++
++ return err;
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/console.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/console.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,45 @@
++#include "sysdeps.h"
++#include "adb.h"
++#include "adb_client.h"
++#include <stdio.h>
++
++static int connect_to_console(void)
++{
++ int fd, port;
++
++ port = adb_get_emulator_console_port();
++ if (port < 0) {
++ if (port == -2)
++ fprintf(stderr, "error: more than one emulator detected. use -s option\n");
++ else
++ fprintf(stderr, "error: no emulator detected\n");
++ return -1;
++ }
++ fd = socket_loopback_client( port, SOCK_STREAM );
++ if (fd < 0) {
++ fprintf(stderr, "error: could not connect to TCP port %d\n", port);
++ return -1;
++ }
++ return fd;
++}
++
++
++int adb_send_emulator_command(int argc, char** argv)
++{
++ int fd, nn;
++
++ fd = connect_to_console();
++ if (fd < 0)
++ return 1;
++
++#define QUIT "quit\n"
++
++ for (nn = 1; nn < argc; nn++) {
++ adb_write( fd, argv[nn], strlen(argv[nn]) );
++ adb_write( fd, (nn == argc-1) ? "\n" : " ", 1 );
++ }
++ adb_write( fd, QUIT, sizeof(QUIT)-1 );
++ adb_close(fd);
++
++ return 0;
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/fdevent.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/fdevent.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,695 @@
++/* http://frotznet.googlecode.com/svn/trunk/utils/fdevent.c
++**
++** Copyright 2006, Brian Swetland <swetland@frotz.net>
++**
++** Licensed under the Apache License, Version 2.0 (the "License");
++** you may not use this file except in compliance with the License.
++** You may obtain a copy of the License at
++**
++** http://www.apache.org/licenses/LICENSE-2.0
++**
++** Unless required by applicable law or agreed to in writing, software
++** distributed under the License is distributed on an "AS IS" BASIS,
++** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++** See the License for the specific language governing permissions and
++** limitations under the License.
++*/
++
++#include <sys/ioctl.h>
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++#include <errno.h>
++
++#include <fcntl.h>
++
++#include <stdarg.h>
++#include <stddef.h>
++
++#include "fdevent.h"
++#include "transport.h"
++#include "sysdeps.h"
++
++
++/* !!! Do not enable DEBUG for the adb that will run as the server:
++** both stdout and stderr are used to communicate between the client
++** and server. Any extra output will cause failures.
++*/
++#define DEBUG 0 /* non-0 will break adb server */
++
++// This socket is used when a subproc shell service exists.
++// It wakes up the fdevent_loop() and cause the correct handling
++// of the shell's pseudo-tty master. I.e. force close it.
++int SHELL_EXIT_NOTIFY_FD = -1;
++
++static void fatal(const char *fn, const char *fmt, ...)
++{
++ va_list ap;
++ va_start(ap, fmt);
++ fprintf(stderr, "%s:", fn);
++ vfprintf(stderr, fmt, ap);
++ va_end(ap);
++ abort();
++}
++
++#define FATAL(x...) fatal(__FUNCTION__, x)
++
++#if DEBUG
++#define D(...) \
++ do { \
++ adb_mutex_lock(&D_lock); \
++ int save_errno = errno; \
++ fprintf(stderr, "%s::%s():", __FILE__, __FUNCTION__); \
++ errno = save_errno; \
++ fprintf(stderr, __VA_ARGS__); \
++ adb_mutex_unlock(&D_lock); \
++ errno = save_errno; \
++ } while(0)
++static void dump_fde(fdevent *fde, const char *info)
++{
++ adb_mutex_lock(&D_lock);
++ fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
++ fde->state & FDE_READ ? 'R' : ' ',
++ fde->state & FDE_WRITE ? 'W' : ' ',
++ fde->state & FDE_ERROR ? 'E' : ' ',
++ info);
++ adb_mutex_unlock(&D_lock);
++}
++#else
++#define D(...) ((void)0)
++#define dump_fde(fde, info) do { } while(0)
++#endif
++
++#define FDE_EVENTMASK 0x00ff
++#define FDE_STATEMASK 0xff00
++
++#define FDE_ACTIVE 0x0100
++#define FDE_PENDING 0x0200
++#define FDE_CREATED 0x0400
++
++static void fdevent_plist_enqueue(fdevent *node);
++static void fdevent_plist_remove(fdevent *node);
++static fdevent *fdevent_plist_dequeue(void);
++static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata);
++
++static fdevent list_pending = {
++ .next = &list_pending,
++ .prev = &list_pending,
++};
++
++static fdevent **fd_table = 0;
++static int fd_table_max = 0;
++
++#ifdef CRAPTASTIC
++//HAVE_EPOLL
++
++#include <sys/epoll.h>
++
++static int epoll_fd = -1;
++
++static void fdevent_init()
++{
++ /* XXX: what's a good size for the passed in hint? */
++ epoll_fd = epoll_create(256);
++
++ if(epoll_fd < 0) {
++ perror("epoll_create() failed");
++ exit(1);
++ }
++
++ /* mark for close-on-exec */
++ fcntl(epoll_fd, F_SETFD, FD_CLOEXEC);
++}
++
++static void fdevent_connect(fdevent *fde)
++{
++ struct epoll_event ev;
++
++ memset(&ev, 0, sizeof(ev));
++ ev.events = 0;
++ ev.data.ptr = fde;
++
++#if 0
++ if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
++ perror("epoll_ctl() failed\n");
++ exit(1);
++ }
++#endif
++}
++
++static void fdevent_disconnect(fdevent *fde)
++{
++ struct epoll_event ev;
++
++ memset(&ev, 0, sizeof(ev));
++ ev.events = 0;
++ ev.data.ptr = fde;
++
++ /* technically we only need to delete if we
++ ** were actively monitoring events, but let's
++ ** be aggressive and do it anyway, just in case
++ ** something's out of sync
++ */
++ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev);
++}
++
++static void fdevent_update(fdevent *fde, unsigned events)
++{
++ struct epoll_event ev;
++ int active;
++
++ active = (fde->state & FDE_EVENTMASK) != 0;
++
++ memset(&ev, 0, sizeof(ev));
++ ev.events = 0;
++ ev.data.ptr = fde;
++
++ if(events & FDE_READ) ev.events |= EPOLLIN;
++ if(events & FDE_WRITE) ev.events |= EPOLLOUT;
++ if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP);
++
++ fde->state = (fde->state & FDE_STATEMASK) | events;
++
++ if(active) {
++ /* we're already active. if we're changing to *no*
++ ** events being monitored, we need to delete, otherwise
++ ** we need to just modify
++ */
++ if(ev.events) {
++ if(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fde->fd, &ev)) {
++ perror("epoll_ctl() failed\n");
++ exit(1);
++ }
++ } else {
++ if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev)) {
++ perror("epoll_ctl() failed\n");
++ exit(1);
++ }
++ }
++ } else {
++ /* we're not active. if we're watching events, we need
++ ** to add, otherwise we can just do nothing
++ */
++ if(ev.events) {
++ if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
++ perror("epoll_ctl() failed\n");
++ exit(1);
++ }
++ }
++ }
++}
++
++static void fdevent_process()
++{
++ struct epoll_event events[256];
++ fdevent *fde;
++ int i, n;
++
++ n = epoll_wait(epoll_fd, events, 256, -1);
++
++ if(n < 0) {
++ if(errno == EINTR) return;
++ perror("epoll_wait");
++ exit(1);
++ }
++
++ for(i = 0; i < n; i++) {
++ struct epoll_event *ev = events + i;
++ fde = ev->data.ptr;
++
++ if(ev->events & EPOLLIN) {
++ fde->events |= FDE_READ;
++ }
++ if(ev->events & EPOLLOUT) {
++ fde->events |= FDE_WRITE;
++ }
++ if(ev->events & (EPOLLERR | EPOLLHUP)) {
++ fde->events |= FDE_ERROR;
++ }
++ if(fde->events) {
++ if(fde->state & FDE_PENDING) continue;
++ fde->state |= FDE_PENDING;
++ fdevent_plist_enqueue(fde);
++ }
++ }
++}
++
++#else /* USE_SELECT */
++
++#ifdef HAVE_WINSOCK
++#include <winsock2.h>
++#else
++#include <sys/select.h>
++#endif
++
++static fd_set read_fds;
++static fd_set write_fds;
++static fd_set error_fds;
++
++static int select_n = 0;
++
++static void fdevent_init(void)
++{
++ FD_ZERO(&read_fds);
++ FD_ZERO(&write_fds);
++ FD_ZERO(&error_fds);
++}
++
++static void fdevent_connect(fdevent *fde)
++{
++ if(fde->fd >= select_n) {
++ select_n = fde->fd + 1;
++ }
++}
++
++static void fdevent_disconnect(fdevent *fde)
++{
++ int i, n;
++
++ FD_CLR(fde->fd, &read_fds);
++ FD_CLR(fde->fd, &write_fds);
++ FD_CLR(fde->fd, &error_fds);
++
++ for(n = 0, i = 0; i < select_n; i++) {
++ if(fd_table[i] != 0) n = i;
++ }
++ select_n = n + 1;
++}
++
++static void fdevent_update(fdevent *fde, unsigned events)
++{
++ if(events & FDE_READ) {
++ FD_SET(fde->fd, &read_fds);
++ } else {
++ FD_CLR(fde->fd, &read_fds);
++ }
++ if(events & FDE_WRITE) {
++ FD_SET(fde->fd, &write_fds);
++ } else {
++ FD_CLR(fde->fd, &write_fds);
++ }
++ if(events & FDE_ERROR) {
++ FD_SET(fde->fd, &error_fds);
++ } else {
++ FD_CLR(fde->fd, &error_fds);
++ }
++
++ fde->state = (fde->state & FDE_STATEMASK) | events;
++}
++
++/* Looks at fd_table[] for bad FDs and sets bit in fds.
++** Returns the number of bad FDs.
++*/
++static int fdevent_fd_check(fd_set *fds)
++{
++ int i, n = 0;
++ fdevent *fde;
++
++ for(i = 0; i < select_n; i++) {
++ fde = fd_table[i];
++ if(fde == 0) continue;
++ if(fcntl(i, F_GETFL, NULL) < 0) {
++ FD_SET(i, fds);
++ n++;
++ // fde->state |= FDE_DONT_CLOSE;
++
++ }
++ }
++ return n;
++}
++
++#if !DEBUG
++static inline void dump_all_fds(const char *extra_msg) {}
++#else
++static void dump_all_fds(const char *extra_msg)
++{
++int i;
++ fdevent *fde;
++ // per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank
++ char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff;
++ size_t max_chars = FD_SETSIZE * 6 + 1;
++ int printed_out;
++#define SAFE_SPRINTF(...) \
++ do { \
++ printed_out = snprintf(pb, max_chars, __VA_ARGS__); \
++ if (printed_out <= 0) { \
++ D("... snprintf failed.\n"); \
++ return; \
++ } \
++ if (max_chars < (unsigned int)printed_out) { \
++ D("... snprintf out of space.\n"); \
++ return; \
++ } \
++ pb += printed_out; \
++ max_chars -= printed_out; \
++ } while(0)
++
++ for(i = 0; i < select_n; i++) {
++ fde = fd_table[i];
++ SAFE_SPRINTF("%d", i);
++ if(fde == 0) {
++ SAFE_SPRINTF("? ");
++ continue;
++ }
++ if(fcntl(i, F_GETFL, NULL) < 0) {
++ SAFE_SPRINTF("b");
++ }
++ SAFE_SPRINTF(" ");
++ }
++ D("%s fd_table[]->fd = {%s}\n", extra_msg, msg_buff);
++}
++#endif
++
++static void fdevent_process()
++{
++ int i, n;
++ fdevent *fde;
++ unsigned events;
++ fd_set rfd, wfd, efd;
++
++ memcpy(&rfd, &read_fds, sizeof(fd_set));
++ memcpy(&wfd, &write_fds, sizeof(fd_set));
++ memcpy(&efd, &error_fds, sizeof(fd_set));
++
++ dump_all_fds("pre select()");
++
++ n = select(select_n, &rfd, &wfd, &efd, NULL);
++ int saved_errno = errno;
++ D("select() returned n=%d, errno=%d\n", n, n<0?saved_errno:0);
++
++ dump_all_fds("post select()");
++
++ if(n < 0) {
++ switch(saved_errno) {
++ case EINTR: return;
++ case EBADF:
++ // Can't trust the FD sets after an error.
++ FD_ZERO(&wfd);
++ FD_ZERO(&efd);
++ FD_ZERO(&rfd);
++ break;
++ default:
++ D("Unexpected select() error=%d\n", saved_errno);
++ return;
++ }
++ }
++ if(n <= 0) {
++ // We fake a read, as the rest of the code assumes
++ // that errors will be detected at that point.
++ n = fdevent_fd_check(&rfd);
++ }
++
++ for(i = 0; (i < select_n) && (n > 0); i++) {
++ events = 0;
++ if(FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; }
++ if(FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; }
++ if(FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; }
++
++ if(events) {
++ fde = fd_table[i];
++ if(fde == 0)
++ FATAL("missing fde for fd %d\n", i);
++
++ fde->events |= events;
++
++ D("got events fde->fd=%d events=%04x, state=%04x\n",
++ fde->fd, fde->events, fde->state);
++ if(fde->state & FDE_PENDING) continue;
++ fde->state |= FDE_PENDING;
++ fdevent_plist_enqueue(fde);
++ }
++ }
++}
++
++#endif
++
++static void fdevent_register(fdevent *fde)
++{
++ if(fde->fd < 0) {
++ FATAL("bogus negative fd (%d)\n", fde->fd);
++ }
++
++ if(fde->fd >= fd_table_max) {
++ int oldmax = fd_table_max;
++ if(fde->fd > 32000) {
++ FATAL("bogus huuuuge fd (%d)\n", fde->fd);
++ }
++ if(fd_table_max == 0) {
++ fdevent_init();
++ fd_table_max = 256;
++ }
++ while(fd_table_max <= fde->fd) {
++ fd_table_max *= 2;
++ }
++ fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
++ if(fd_table == 0) {
++ FATAL("could not expand fd_table to %d entries\n", fd_table_max);
++ }
++ memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
++ }
++
++ fd_table[fde->fd] = fde;
++}
++
++static void fdevent_unregister(fdevent *fde)
++{
++ if((fde->fd < 0) || (fde->fd >= fd_table_max)) {
++ FATAL("fd out of range (%d)\n", fde->fd);
++ }
++
++ if(fd_table[fde->fd] != fde) {
++ FATAL("fd_table out of sync [%d]\n", fde->fd);
++ }
++
++ fd_table[fde->fd] = 0;
++
++ if(!(fde->state & FDE_DONT_CLOSE)) {
++ dump_fde(fde, "close");
++ adb_close(fde->fd);
++ }
++}
++
++static void fdevent_plist_enqueue(fdevent *node)
++{
++ fdevent *list = &list_pending;
++
++ node->next = list;
++ node->prev = list->prev;
++ node->prev->next = node;
++ list->prev = node;
++}
++
++static void fdevent_plist_remove(fdevent *node)
++{
++ node->prev->next = node->next;
++ node->next->prev = node->prev;
++ node->next = 0;
++ node->prev = 0;
++}
++
++static fdevent *fdevent_plist_dequeue(void)
++{
++ fdevent *list = &list_pending;
++ fdevent *node = list->next;
++
++ if(node == list) return 0;
++
++ list->next = node->next;
++ list->next->prev = list;
++ node->next = 0;
++ node->prev = 0;
++
++ return node;
++}
++
++static void fdevent_call_fdfunc(fdevent* fde)
++{
++ unsigned events = fde->events;
++ fde->events = 0;
++ if(!(fde->state & FDE_PENDING)) return;
++ fde->state &= (~FDE_PENDING);
++ dump_fde(fde, "callback");
++ fde->func(fde->fd, events, fde->arg);
++}
++
++static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata)
++{
++
++ D("subproc handling on fd=%d ev=%04x\n", fd, ev);
++
++ // Hook oneself back into the fde's suitable for select() on read.
++ if((fd < 0) || (fd >= fd_table_max)) {
++ FATAL("fd %d out of range for fd_table \n", fd);
++ }
++ fdevent *fde = fd_table[fd];
++ fdevent_add(fde, FDE_READ);
++
++ if(ev & FDE_READ){
++ int subproc_fd;
++
++ if(readx(fd, &subproc_fd, sizeof(subproc_fd))) {
++ FATAL("Failed to read the subproc's fd from fd=%d\n", fd);
++ }
++ if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) {
++ D("subproc_fd %d out of range 0, fd_table_max=%d\n",
++ subproc_fd, fd_table_max);
++ return;
++ }
++ fdevent *subproc_fde = fd_table[subproc_fd];
++ if(!subproc_fde) {
++ D("subproc_fd %d cleared from fd_table\n", subproc_fd);
++ return;
++ }
++ if(subproc_fde->fd != subproc_fd) {
++ // Already reallocated?
++ D("subproc_fd %d != fd_table[].fd %d\n", subproc_fd, subproc_fde->fd);
++ return;
++ }
++
++ subproc_fde->force_eof = 1;
++
++ int rcount = 0;
++ ioctl(subproc_fd, FIONREAD, &rcount);
++ D("subproc with fd=%d has rcount=%d err=%d\n",
++ subproc_fd, rcount, errno);
++
++ if(rcount) {
++ // If there is data left, it will show up in the select().
++ // This works because there is no other thread reading that
++ // data when in this fd_func().
++ return;
++ }
++
++ D("subproc_fde.state=%04x\n", subproc_fde->state);
++ subproc_fde->events |= FDE_READ;
++ if(subproc_fde->state & FDE_PENDING) {
++ return;
++ }
++ subproc_fde->state |= FDE_PENDING;
++ fdevent_call_fdfunc(subproc_fde);
++ }
++}
++
++fdevent *fdevent_create(int fd, fd_func func, void *arg)
++{
++ fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
++ if(fde == 0) return 0;
++ fdevent_install(fde, fd, func, arg);
++ fde->state |= FDE_CREATED;
++ return fde;
++}
++
++void fdevent_destroy(fdevent *fde)
++{
++ if(fde == 0) return;
++ if(!(fde->state & FDE_CREATED)) {
++ FATAL("fde %p not created by fdevent_create()\n", fde);
++ }
++ fdevent_remove(fde);
++}
++
++void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
++{
++ memset(fde, 0, sizeof(fdevent));
++ fde->state = FDE_ACTIVE;
++ fde->fd = fd;
++ fde->force_eof = 0;
++ fde->func = func;
++ fde->arg = arg;
++
++#ifndef HAVE_WINSOCK
++ fcntl(fd, F_SETFL, O_NONBLOCK);
++#endif
++ fdevent_register(fde);
++ dump_fde(fde, "connect");
++ fdevent_connect(fde);
++ fde->state |= FDE_ACTIVE;
++}
++
++void fdevent_remove(fdevent *fde)
++{
++ if(fde->state & FDE_PENDING) {
++ fdevent_plist_remove(fde);
++ }
++
++ if(fde->state & FDE_ACTIVE) {
++ fdevent_disconnect(fde);
++ dump_fde(fde, "disconnect");
++ fdevent_unregister(fde);
++ }
++
++ fde->state = 0;
++ fde->events = 0;
++}
++
++
++void fdevent_set(fdevent *fde, unsigned events)
++{
++ events &= FDE_EVENTMASK;
++
++ if((fde->state & FDE_EVENTMASK) == events) return;
++
++ if(fde->state & FDE_ACTIVE) {
++ fdevent_update(fde, events);
++ dump_fde(fde, "update");
++ }
++
++ fde->state = (fde->state & FDE_STATEMASK) | events;
++
++ if(fde->state & FDE_PENDING) {
++ /* if we're pending, make sure
++ ** we don't signal an event that
++ ** is no longer wanted.
++ */
++ fde->events &= (~events);
++ if(fde->events == 0) {
++ fdevent_plist_remove(fde);
++ fde->state &= (~FDE_PENDING);
++ }
++ }
++}
++
++void fdevent_add(fdevent *fde, unsigned events)
++{
++ fdevent_set(
++ fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
++}
++
++void fdevent_del(fdevent *fde, unsigned events)
++{
++ fdevent_set(
++ fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
++}
++
++void fdevent_subproc_setup()
++{
++ int s[2];
++
++ if(adb_socketpair(s)) {
++ FATAL("cannot create shell-exit socket-pair\n");
++ }
++ SHELL_EXIT_NOTIFY_FD = s[0];
++ fdevent *fde;
++ fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
++ if(!fde)
++ FATAL("cannot create fdevent for shell-exit handler\n");
++ fdevent_add(fde, FDE_READ);
++}
++
++void fdevent_loop()
++{
++ fdevent *fde;
++ fdevent_subproc_setup();
++
++ for(;;) {
++ D("--- ---- waiting for events\n");
++
++ fdevent_process();
++
++ while((fde = fdevent_plist_dequeue())) {
++ fdevent_call_fdfunc(fde);
++ }
++ }
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/fdevent.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/fdevent.h 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,83 @@
++/*
++ * Copyright (C) 2006 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef __FDEVENT_H
++#define __FDEVENT_H
++
++#include <stdint.h> /* for int64_t */
++
++/* events that may be observed */
++#define FDE_READ 0x0001
++#define FDE_WRITE 0x0002
++#define FDE_ERROR 0x0004
++#define FDE_TIMEOUT 0x0008
++
++/* features that may be set (via the events set/add/del interface) */
++#define FDE_DONT_CLOSE 0x0080
++
++typedef struct fdevent fdevent;
++
++typedef void (*fd_func)(int fd, unsigned events, void *userdata);
++
++/* Allocate and initialize a new fdevent object
++ * Note: use FD_TIMER as 'fd' to create a fd-less object
++ * (used to implement timers).
++*/
++fdevent *fdevent_create(int fd, fd_func func, void *arg);
++
++/* Uninitialize and deallocate an fdevent object that was
++** created by fdevent_create()
++*/
++void fdevent_destroy(fdevent *fde);
++
++/* Initialize an fdevent object that was externally allocated
++*/
++void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg);
++
++/* Uninitialize an fdevent object that was initialized by
++** fdevent_install()
++*/
++void fdevent_remove(fdevent *item);
++
++/* Change which events should cause notifications
++*/
++void fdevent_set(fdevent *fde, unsigned events);
++void fdevent_add(fdevent *fde, unsigned events);
++void fdevent_del(fdevent *fde, unsigned events);
++
++void fdevent_set_timeout(fdevent *fde, int64_t timeout_ms);
++
++/* loop forever, handling events.
++*/
++void fdevent_loop();
++
++struct fdevent
++{
++ fdevent *next;
++ fdevent *prev;
++
++ int fd;
++ int force_eof;
++
++ unsigned short state;
++ unsigned short events;
++
++ fd_func func;
++ void *arg;
++};
++
++
++#endif
+Index: android-tools-4.2.2+git20130218/core/adbd/file_sync_client.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/file_sync_client.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,1024 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/stat.h>
++#include <sys/time.h>
++#include <time.h>
++#include <dirent.h>
++#include <limits.h>
++#include <sys/types.h>
++#include <zipfile/zipfile.h>
++
++#include "sysdeps.h"
++#include "adb.h"
++#include "adb_client.h"
++#include "file_sync_service.h"
++
++
++static unsigned total_bytes;
++static long long start_time;
++
++static long long NOW()
++{
++ struct timeval tv;
++ gettimeofday(&tv, 0);
++ return ((long long) tv.tv_usec) +
++ 1000000LL * ((long long) tv.tv_sec);
++}
++
++static void BEGIN()
++{
++ total_bytes = 0;
++ start_time = NOW();
++}
++
++static void END()
++{
++ long long t = NOW() - start_time;
++ if(total_bytes == 0) return;
++
++ if (t == 0) /* prevent division by 0 :-) */
++ t = 1000000;
++
++ fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n",
++ ((((long long) total_bytes) * 1000000LL) / t) / 1024LL,
++ (long long) total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
++}
++
++void sync_quit(int fd)
++{
++ syncmsg msg;
++
++ msg.req.id = ID_QUIT;
++ msg.req.namelen = 0;
++
++ writex(fd, &msg.req, sizeof(msg.req));
++}
++
++typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
++
++int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie)
++{
++ syncmsg msg;
++ char buf[257];
++ int len;
++
++ len = strlen(path);
++ if(len > 1024) goto fail;
++
++ msg.req.id = ID_LIST;
++ msg.req.namelen = htoll(len);
++
++ if(writex(fd, &msg.req, sizeof(msg.req)) ||
++ writex(fd, path, len)) {
++ goto fail;
++ }
++
++ for(;;) {
++ if(readx(fd, &msg.dent, sizeof(msg.dent))) break;
++ if(msg.dent.id == ID_DONE) return 0;
++ if(msg.dent.id != ID_DENT) break;
++
++ len = ltohl(msg.dent.namelen);
++ if(len > 256) break;
++
++ if(readx(fd, buf, len)) break;
++ buf[len] = 0;
++
++ func(ltohl(msg.dent.mode),
++ ltohl(msg.dent.size),
++ ltohl(msg.dent.time),
++ buf, cookie);
++ }
++
++fail:
++ adb_close(fd);
++ return -1;
++}
++
++typedef struct syncsendbuf syncsendbuf;
++
++struct syncsendbuf {
++ unsigned id;
++ unsigned size;
++ char data[SYNC_DATA_MAX];
++};
++
++static syncsendbuf send_buffer;
++
++int sync_readtime(int fd, const char *path, unsigned *timestamp)
++{
++ syncmsg msg;
++ int len = strlen(path);
++
++ msg.req.id = ID_STAT;
++ msg.req.namelen = htoll(len);
++
++ if(writex(fd, &msg.req, sizeof(msg.req)) ||
++ writex(fd, path, len)) {
++ return -1;
++ }
++
++ if(readx(fd, &msg.stat, sizeof(msg.stat))) {
++ return -1;
++ }
++
++ if(msg.stat.id != ID_STAT) {
++ return -1;
++ }
++
++ *timestamp = ltohl(msg.stat.time);
++ return 0;
++}
++
++static int sync_start_readtime(int fd, const char *path)
++{
++ syncmsg msg;
++ int len = strlen(path);
++
++ msg.req.id = ID_STAT;
++ msg.req.namelen = htoll(len);
++
++ if(writex(fd, &msg.req, sizeof(msg.req)) ||
++ writex(fd, path, len)) {
++ return -1;
++ }
++
++ return 0;
++}
++
++static int sync_finish_readtime(int fd, unsigned int *timestamp,
++ unsigned int *mode, unsigned int *size)
++{
++ syncmsg msg;
++
++ if(readx(fd, &msg.stat, sizeof(msg.stat)))
++ return -1;
++
++ if(msg.stat.id != ID_STAT)
++ return -1;
++
++ *timestamp = ltohl(msg.stat.time);
++ *mode = ltohl(msg.stat.mode);
++ *size = ltohl(msg.stat.size);
++
++ return 0;
++}
++
++int sync_readmode(int fd, const char *path, unsigned *mode)
++{
++ syncmsg msg;
++ int len = strlen(path);
++
++ msg.req.id = ID_STAT;
++ msg.req.namelen = htoll(len);
++
++ if(writex(fd, &msg.req, sizeof(msg.req)) ||
++ writex(fd, path, len)) {
++ return -1;
++ }
++
++ if(readx(fd, &msg.stat, sizeof(msg.stat))) {
++ return -1;
++ }
++
++ if(msg.stat.id != ID_STAT) {
++ return -1;
++ }
++
++ *mode = ltohl(msg.stat.mode);
++ return 0;
++}
++
++static int write_data_file(int fd, const char *path, syncsendbuf *sbuf)
++{
++ int lfd, err = 0;
++
++ lfd = adb_open(path, O_RDONLY);
++ if(lfd < 0) {
++ fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
++ return -1;
++ }
++
++ sbuf->id = ID_DATA;
++ for(;;) {
++ int ret;
++
++ ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX);
++ if(!ret)
++ break;
++
++ if(ret < 0) {
++ if(errno == EINTR)
++ continue;
++ fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
++ break;
++ }
++
++ sbuf->size = htoll(ret);
++ if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){
++ err = -1;
++ break;
++ }
++ total_bytes += ret;
++ }
++
++ adb_close(lfd);
++ return err;
++}
++
++static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf)
++{
++ int err = 0;
++ int total = 0;
++
++ sbuf->id = ID_DATA;
++ while (total < size) {
++ int count = size - total;
++ if (count > SYNC_DATA_MAX) {
++ count = SYNC_DATA_MAX;
++ }
++
++ memcpy(sbuf->data, &file_buffer[total], count);
++ sbuf->size = htoll(count);
++ if(writex(fd, sbuf, sizeof(unsigned) * 2 + count)){
++ err = -1;
++ break;
++ }
++ total += count;
++ total_bytes += count;
++ }
++
++ return err;
++}
++
++#ifdef HAVE_SYMLINKS
++static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
++{
++ int len, ret;
++
++ len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
++ if(len < 0) {
++ fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
++ return -1;
++ }
++ sbuf->data[len] = '\0';
++
++ sbuf->size = htoll(len + 1);
++ sbuf->id = ID_DATA;
++
++ ret = writex(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
++ if(ret)
++ return -1;
++
++ total_bytes += len + 1;
++
++ return 0;
++}
++#endif
++
++static int sync_send(int fd, const char *lpath, const char *rpath,
++ unsigned mtime, mode_t mode, int verifyApk)
++{
++ syncmsg msg;
++ int len, r;
++ syncsendbuf *sbuf = &send_buffer;
++ char* file_buffer = NULL;
++ int size = 0;
++ char tmp[64];
++
++ len = strlen(rpath);
++ if(len > 1024) goto fail;
++
++ snprintf(tmp, sizeof(tmp), ",%d", mode);
++ r = strlen(tmp);
++
++ if (verifyApk) {
++ int lfd;
++ zipfile_t zip;
++ zipentry_t entry;
++ int amt;
++
++ // if we are transferring an APK file, then sanity check to make sure
++ // we have a real zip file that contains an AndroidManifest.xml
++ // this requires that we read the entire file into memory.
++ lfd = adb_open(lpath, O_RDONLY);
++ if(lfd < 0) {
++ fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
++ return -1;
++ }
++
++ size = adb_lseek(lfd, 0, SEEK_END);
++ if (size == -1 || -1 == adb_lseek(lfd, 0, SEEK_SET)) {
++ fprintf(stderr, "error seeking in file '%s'\n", lpath);
++ adb_close(lfd);
++ return 1;
++ }
++
++ file_buffer = (char *)malloc(size);
++ if (file_buffer == NULL) {
++ fprintf(stderr, "could not allocate buffer for '%s'\n",
++ lpath);
++ adb_close(lfd);
++ return 1;
++ }
++ amt = adb_read(lfd, file_buffer, size);
++ if (amt != size) {
++ fprintf(stderr, "error reading from file: '%s'\n", lpath);
++ adb_close(lfd);
++ free(file_buffer);
++ return 1;
++ }
++
++ adb_close(lfd);
++
++ zip = init_zipfile(file_buffer, size);
++ if (zip == NULL) {
++ fprintf(stderr, "file '%s' is not a valid zip file\n",
++ lpath);
++ free(file_buffer);
++ return 1;
++ }
++
++ entry = lookup_zipentry(zip, "AndroidManifest.xml");
++ release_zipfile(zip);
++ if (entry == NULL) {
++ fprintf(stderr, "file '%s' does not contain AndroidManifest.xml\n",
++ lpath);
++ free(file_buffer);
++ return 1;
++ }
++ }
++
++ msg.req.id = ID_SEND;
++ msg.req.namelen = htoll(len + r);
++
++ if(writex(fd, &msg.req, sizeof(msg.req)) ||
++ writex(fd, rpath, len) || writex(fd, tmp, r)) {
++ free(file_buffer);
++ goto fail;
++ }
++
++ if (file_buffer) {
++ write_data_buffer(fd, file_buffer, size, sbuf);
++ free(file_buffer);
++ } else if (S_ISREG(mode))
++ write_data_file(fd, lpath, sbuf);
++#ifdef HAVE_SYMLINKS
++ else if (S_ISLNK(mode))
++ write_data_link(fd, lpath, sbuf);
++#endif
++ else
++ goto fail;
++
++ msg.data.id = ID_DONE;
++ msg.data.size = htoll(mtime);
++ if(writex(fd, &msg.data, sizeof(msg.data)))
++ goto fail;
++
++ if(readx(fd, &msg.status, sizeof(msg.status)))
++ return -1;
++
++ if(msg.status.id != ID_OKAY) {
++ if(msg.status.id == ID_FAIL) {
++ len = ltohl(msg.status.msglen);
++ if(len > 256) len = 256;
++ if(readx(fd, sbuf->data, len)) {
++ return -1;
++ }
++ sbuf->data[len] = 0;
++ } else
++ strcpy(sbuf->data, "unknown reason");
++
++ fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
++ return -1;
++ }
++
++ return 0;
++
++fail:
++ fprintf(stderr,"protocol failure\n");
++ adb_close(fd);
++ return -1;
++}
++
++static int mkdirs(char *name)
++{
++ int ret;
++ char *x = name + 1;
++
++ for(;;) {
++ x = adb_dirstart(x);
++ if(x == 0) return 0;
++ *x = 0;
++ ret = adb_mkdir(name, 0775);
++ *x = OS_PATH_SEPARATOR;
++ if((ret < 0) && (errno != EEXIST)) {
++ return ret;
++ }
++ x++;
++ }
++ return 0;
++}
++
++int sync_recv(int fd, const char *rpath, const char *lpath)
++{
++ syncmsg msg;
++ int len;
++ int lfd = -1;
++ char *buffer = send_buffer.data;
++ unsigned id;
++
++ len = strlen(rpath);
++ if(len > 1024) return -1;
++
++ msg.req.id = ID_RECV;
++ msg.req.namelen = htoll(len);
++ if(writex(fd, &msg.req, sizeof(msg.req)) ||
++ writex(fd, rpath, len)) {
++ return -1;
++ }
++
++ if(readx(fd, &msg.data, sizeof(msg.data))) {
++ return -1;
++ }
++ id = msg.data.id;
++
++ if((id == ID_DATA) || (id == ID_DONE)) {
++ adb_unlink(lpath);
++ mkdirs((char *)lpath);
++ lfd = adb_creat(lpath, 0644);
++ if(lfd < 0) {
++ fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
++ return -1;
++ }
++ goto handle_data;
++ } else {
++ goto remote_error;
++ }
++
++ for(;;) {
++ if(readx(fd, &msg.data, sizeof(msg.data))) {
++ return -1;
++ }
++ id = msg.data.id;
++
++ handle_data:
++ len = ltohl(msg.data.size);
++ if(id == ID_DONE) break;
++ if(id != ID_DATA) goto remote_error;
++ if(len > SYNC_DATA_MAX) {
++ fprintf(stderr,"data overrun\n");
++ adb_close(lfd);
++ return -1;
++ }
++
++ if(readx(fd, buffer, len)) {
++ adb_close(lfd);
++ return -1;
++ }
++
++ if(writex(lfd, buffer, len)) {
++ fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
++ adb_close(lfd);
++ return -1;
++ }
++
++ total_bytes += len;
++ }
++
++ adb_close(lfd);
++ return 0;
++
++remote_error:
++ adb_close(lfd);
++ adb_unlink(lpath);
++
++ if(id == ID_FAIL) {
++ len = ltohl(msg.data.size);
++ if(len > 256) len = 256;
++ if(readx(fd, buffer, len)) {
++ return -1;
++ }
++ buffer[len] = 0;
++ } else {
++ memcpy(buffer, &id, 4);
++ buffer[4] = 0;
++// strcpy(buffer,"unknown reason");
++ }
++ fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
++ return 0;
++}
++
++
++
++/* --- */
++
++
++static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
++ const char *name, void *cookie)
++{
++ printf("%08x %08x %08x %s\n", mode, size, time, name);
++}
++
++int do_sync_ls(const char *path)
++{
++ int fd = adb_connect("sync:");
++ if(fd < 0) {
++ fprintf(stderr,"error: %s\n", adb_error());
++ return 1;
++ }
++
++ if(sync_ls(fd, path, do_sync_ls_cb, 0)) {
++ return 1;
++ } else {
++ sync_quit(fd);
++ return 0;
++ }
++}
++
++typedef struct copyinfo copyinfo;
++
++struct copyinfo
++{
++ copyinfo *next;
++ const char *src;
++ const char *dst;
++ unsigned int time;
++ unsigned int mode;
++ unsigned int size;
++ int flag;
++ //char data[0];
++};
++
++copyinfo *mkcopyinfo(const char *spath, const char *dpath,
++ const char *name, int isdir)
++{
++ int slen = strlen(spath);
++ int dlen = strlen(dpath);
++ int nlen = strlen(name);
++ int ssize = slen + nlen + 2;
++ int dsize = dlen + nlen + 2;
++
++ copyinfo *ci = malloc(sizeof(copyinfo) + ssize + dsize);
++ if(ci == 0) {
++ fprintf(stderr,"out of memory\n");
++ abort();
++ }
++
++ ci->next = 0;
++ ci->time = 0;
++ ci->mode = 0;
++ ci->size = 0;
++ ci->flag = 0;
++ ci->src = (const char*)(ci + 1);
++ ci->dst = ci->src + ssize;
++ snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
++ snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
++
++// fprintf(stderr,"mkcopyinfo('%s','%s')\n", ci->src, ci->dst);
++ return ci;
++}
++
++
++static int local_build_list(copyinfo **filelist,
++ const char *lpath, const char *rpath)
++{
++ DIR *d;
++ struct dirent *de;
++ struct stat st;
++ copyinfo *dirlist = 0;
++ copyinfo *ci, *next;
++
++// fprintf(stderr,"local_build_list('%s','%s')\n", lpath, rpath);
++
++ d = opendir(lpath);
++ if(d == 0) {
++ fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
++ return -1;
++ }
++
++ while((de = readdir(d))) {
++ char stat_path[PATH_MAX];
++ char *name = de->d_name;
++
++ if(name[0] == '.') {
++ if(name[1] == 0) continue;
++ if((name[1] == '.') && (name[2] == 0)) continue;
++ }
++
++ /*
++ * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
++ * always returns DT_UNKNOWN, so we just use stat() for all cases.
++ */
++ if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
++ continue;
++ strcpy(stat_path, lpath);
++ strcat(stat_path, de->d_name);
++ stat(stat_path, &st);
++
++ if (S_ISDIR(st.st_mode)) {
++ ci = mkcopyinfo(lpath, rpath, name, 1);
++ ci->next = dirlist;
++ dirlist = ci;
++ } else {
++ ci = mkcopyinfo(lpath, rpath, name, 0);
++ if(lstat(ci->src, &st)) {
++ fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
++ closedir(d);
++
++ return -1;
++ }
++ if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
++ fprintf(stderr, "skipping special file '%s'\n", ci->src);
++ free(ci);
++ } else {
++ ci->time = st.st_mtime;
++ ci->mode = st.st_mode;
++ ci->size = st.st_size;
++ ci->next = *filelist;
++ *filelist = ci;
++ }
++ }
++ }
++
++ closedir(d);
++
++ for(ci = dirlist; ci != 0; ci = next) {
++ next = ci->next;
++ local_build_list(filelist, ci->src, ci->dst);
++ free(ci);
++ }
++
++ return 0;
++}
++
++
++static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, int checktimestamps, int listonly)
++{
++ copyinfo *filelist = 0;
++ copyinfo *ci, *next;
++ int pushed = 0;
++ int skipped = 0;
++
++ if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
++ if(lpath[strlen(lpath) - 1] != '/') {
++ int tmplen = strlen(lpath)+2;
++ char *tmp = malloc(tmplen);
++ if(tmp == 0) return -1;
++ snprintf(tmp, tmplen, "%s/",lpath);
++ lpath = tmp;
++ }
++ if(rpath[strlen(rpath) - 1] != '/') {
++ int tmplen = strlen(rpath)+2;
++ char *tmp = malloc(tmplen);
++ if(tmp == 0) return -1;
++ snprintf(tmp, tmplen, "%s/",rpath);
++ rpath = tmp;
++ }
++
++ if(local_build_list(&filelist, lpath, rpath)) {
++ return -1;
++ }
++
++ if(checktimestamps){
++ for(ci = filelist; ci != 0; ci = ci->next) {
++ if(sync_start_readtime(fd, ci->dst)) {
++ return 1;
++ }
++ }
++ for(ci = filelist; ci != 0; ci = ci->next) {
++ unsigned int timestamp, mode, size;
++ if(sync_finish_readtime(fd, ×tamp, &mode, &size))
++ return 1;
++ if(size == ci->size) {
++ /* for links, we cannot update the atime/mtime */
++ if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
++ (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
++ ci->flag = 1;
++ }
++ }
++ }
++ for(ci = filelist; ci != 0; ci = next) {
++ next = ci->next;
++ if(ci->flag == 0) {
++ fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
++ if(!listonly &&
++ sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */)){
++ return 1;
++ }
++ pushed++;
++ } else {
++ skipped++;
++ }
++ free(ci);
++ }
++
++ fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
++ pushed, (pushed == 1) ? "" : "s",
++ skipped, (skipped == 1) ? "" : "s");
++
++ return 0;
++}
++
++
++int do_sync_push(const char *lpath, const char *rpath, int verifyApk)
++{
++ struct stat st;
++ unsigned mode;
++ int fd;
++
++ fd = adb_connect("sync:");
++ if(fd < 0) {
++ fprintf(stderr,"error: %s\n", adb_error());
++ return 1;
++ }
++
++ if(stat(lpath, &st)) {
++ fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
++ sync_quit(fd);
++ return 1;
++ }
++
++ if(S_ISDIR(st.st_mode)) {
++ BEGIN();
++ if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
++ return 1;
++ } else {
++ END();
++ sync_quit(fd);
++ }
++ } else {
++ if(sync_readmode(fd, rpath, &mode)) {
++ return 1;
++ }
++ if((mode != 0) && S_ISDIR(mode)) {
++ /* if we're copying a local file to a remote directory,
++ ** we *really* want to copy to remotedir + "/" + localfilename
++ */
++ const char *name = adb_dirstop(lpath);
++ if(name == 0) {
++ name = lpath;
++ } else {
++ name++;
++ }
++ int tmplen = strlen(name) + strlen(rpath) + 2;
++ char *tmp = malloc(strlen(name) + strlen(rpath) + 2);
++ if(tmp == 0) return 1;
++ snprintf(tmp, tmplen, "%s/%s", rpath, name);
++ rpath = tmp;
++ }
++ BEGIN();
++ if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk)) {
++ return 1;
++ } else {
++ END();
++ sync_quit(fd);
++ return 0;
++ }
++ }
++
++ return 0;
++}
++
++
++typedef struct {
++ copyinfo **filelist;
++ copyinfo **dirlist;
++ const char *rpath;
++ const char *lpath;
++} sync_ls_build_list_cb_args;
++
++void
++sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
++ const char *name, void *cookie)
++{
++ sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
++ copyinfo *ci;
++
++ if (S_ISDIR(mode)) {
++ copyinfo **dirlist = args->dirlist;
++
++ /* Don't try recursing down "." or ".." */
++ if (name[0] == '.') {
++ if (name[1] == '\0') return;
++ if ((name[1] == '.') && (name[2] == '\0')) return;
++ }
++
++ ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
++ ci->next = *dirlist;
++ *dirlist = ci;
++ } else if (S_ISREG(mode) || S_ISLNK(mode)) {
++ copyinfo **filelist = args->filelist;
++
++ ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
++ ci->time = time;
++ ci->mode = mode;
++ ci->size = size;
++ ci->next = *filelist;
++ *filelist = ci;
++ } else {
++ fprintf(stderr, "skipping special file '%s'\n", name);
++ }
++}
++
++static int remote_build_list(int syncfd, copyinfo **filelist,
++ const char *rpath, const char *lpath)
++{
++ copyinfo *dirlist = NULL;
++ sync_ls_build_list_cb_args args;
++
++ args.filelist = filelist;
++ args.dirlist = &dirlist;
++ args.rpath = rpath;
++ args.lpath = lpath;
++
++ /* Put the files/dirs in rpath on the lists. */
++ if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
++ return 1;
++ }
++
++ /* Recurse into each directory we found. */
++ while (dirlist != NULL) {
++ copyinfo *next = dirlist->next;
++ if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
++ return 1;
++ }
++ free(dirlist);
++ dirlist = next;
++ }
++
++ return 0;
++}
++
++static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
++ int checktimestamps)
++{
++ copyinfo *filelist = 0;
++ copyinfo *ci, *next;
++ int pulled = 0;
++ int skipped = 0;
++
++ /* Make sure that both directory paths end in a slash. */
++ if (rpath[0] == 0 || lpath[0] == 0) return -1;
++ if (rpath[strlen(rpath) - 1] != '/') {
++ int tmplen = strlen(rpath) + 2;
++ char *tmp = malloc(tmplen);
++ if (tmp == 0) return -1;
++ snprintf(tmp, tmplen, "%s/", rpath);
++ rpath = tmp;
++ }
++ if (lpath[strlen(lpath) - 1] != '/') {
++ int tmplen = strlen(lpath) + 2;
++ char *tmp = malloc(tmplen);
++ if (tmp == 0) return -1;
++ snprintf(tmp, tmplen, "%s/", lpath);
++ lpath = tmp;
++ }
++
++ fprintf(stderr, "pull: building file list...\n");
++ /* Recursively build the list of files to copy. */
++ if (remote_build_list(fd, &filelist, rpath, lpath)) {
++ return -1;
++ }
++
++#if 0
++ if (checktimestamps) {
++ for (ci = filelist; ci != 0; ci = ci->next) {
++ if (sync_start_readtime(fd, ci->dst)) {
++ return 1;
++ }
++ }
++ for (ci = filelist; ci != 0; ci = ci->next) {
++ unsigned int timestamp, mode, size;
++ if (sync_finish_readtime(fd, ×tamp, &mode, &size))
++ return 1;
++ if (size == ci->size) {
++ /* for links, we cannot update the atime/mtime */
++ if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
++ (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
++ ci->flag = 1;
++ }
++ }
++ }
++#endif
++ for (ci = filelist; ci != 0; ci = next) {
++ next = ci->next;
++ if (ci->flag == 0) {
++ fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
++ if (sync_recv(fd, ci->src, ci->dst)) {
++ return 1;
++ }
++ pulled++;
++ } else {
++ skipped++;
++ }
++ free(ci);
++ }
++
++ fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
++ pulled, (pulled == 1) ? "" : "s",
++ skipped, (skipped == 1) ? "" : "s");
++
++ return 0;
++}
++
++int do_sync_pull(const char *rpath, const char *lpath)
++{
++ unsigned mode;
++ struct stat st;
++
++ int fd;
++
++ fd = adb_connect("sync:");
++ if(fd < 0) {
++ fprintf(stderr,"error: %s\n", adb_error());
++ return 1;
++ }
++
++ if(sync_readmode(fd, rpath, &mode)) {
++ return 1;
++ }
++ if(mode == 0) {
++ fprintf(stderr,"remote object '%s' does not exist\n", rpath);
++ return 1;
++ }
++
++ if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
++ if(stat(lpath, &st) == 0) {
++ if(S_ISDIR(st.st_mode)) {
++ /* if we're copying a remote file to a local directory,
++ ** we *really* want to copy to localdir + "/" + remotefilename
++ */
++ const char *name = adb_dirstop(rpath);
++ if(name == 0) {
++ name = rpath;
++ } else {
++ name++;
++ }
++ int tmplen = strlen(name) + strlen(lpath) + 2;
++ char *tmp = malloc(tmplen);
++ if(tmp == 0) return 1;
++ snprintf(tmp, tmplen, "%s/%s", lpath, name);
++ lpath = tmp;
++ }
++ }
++ BEGIN();
++ if(sync_recv(fd, rpath, lpath)) {
++ return 1;
++ } else {
++ END();
++ sync_quit(fd);
++ return 0;
++ }
++ } else if(S_ISDIR(mode)) {
++ BEGIN();
++ if (copy_remote_dir_local(fd, rpath, lpath, 0)) {
++ return 1;
++ } else {
++ END();
++ sync_quit(fd);
++ return 0;
++ }
++ } else {
++ fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
++ return 1;
++ }
++}
++
++int do_sync_sync(const char *lpath, const char *rpath, int listonly)
++{
++ fprintf(stderr,"syncing %s...\n",rpath);
++
++ int fd = adb_connect("sync:");
++ if(fd < 0) {
++ fprintf(stderr,"error: %s\n", adb_error());
++ return 1;
++ }
++
++ BEGIN();
++ if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
++ return 1;
++ } else {
++ END();
++ sync_quit(fd);
++ return 0;
++ }
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/file_sync_service.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/file_sync_service.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,414 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++
++#include <sys/stat.h>
++#include <sys/types.h>
++#include <dirent.h>
++#include <utime.h>
++
++#include <errno.h>
++
++#include "sysdeps.h"
++
++#define TRACE_TAG TRACE_SYNC
++#include "adb.h"
++#include "file_sync_service.h"
++
++static int mkdirs(char *name)
++{
++ int ret;
++ char *x = name + 1;
++
++ if(name[0] != '/') return -1;
++
++ for(;;) {
++ x = adb_dirstart(x);
++ if(x == 0) return 0;
++ *x = 0;
++ ret = adb_mkdir(name, 0775);
++ if((ret < 0) && (errno != EEXIST)) {
++ D("mkdir(\"%s\") -> %s\n", name, strerror(errno));
++ *x = '/';
++ return ret;
++ }
++ *x++ = '/';
++ }
++ return 0;
++}
++
++static int do_stat(int s, const char *path)
++{
++ syncmsg msg;
++ struct stat st;
++
++ msg.stat.id = ID_STAT;
++
++ if(lstat(path, &st)) {
++ msg.stat.mode = 0;
++ msg.stat.size = 0;
++ msg.stat.time = 0;
++ } else {
++ msg.stat.mode = htoll(st.st_mode);
++ msg.stat.size = htoll(st.st_size);
++ msg.stat.time = htoll(st.st_mtime);
++ }
++
++ return writex(s, &msg.stat, sizeof(msg.stat));
++}
++
++static int do_list(int s, const char *path)
++{
++ DIR *d;
++ struct dirent *de;
++ struct stat st;
++ syncmsg msg;
++ int len;
++
++ char tmp[1024 + 256 + 1];
++ char *fname;
++
++ len = strlen(path);
++ memcpy(tmp, path, len);
++ tmp[len] = '/';
++ fname = tmp + len + 1;
++
++ msg.dent.id = ID_DENT;
++
++ d = opendir(path);
++ if(d == 0) goto done;
++
++ while((de = readdir(d))) {
++ int len = strlen(de->d_name);
++
++ /* not supposed to be possible, but
++ if it does happen, let's not buffer overrun */
++ if(len > 256) continue;
++
++ strcpy(fname, de->d_name);
++ if(lstat(tmp, &st) == 0) {
++ msg.dent.mode = htoll(st.st_mode);
++ msg.dent.size = htoll(st.st_size);
++ msg.dent.time = htoll(st.st_mtime);
++ msg.dent.namelen = htoll(len);
++
++ if(writex(s, &msg.dent, sizeof(msg.dent)) ||
++ writex(s, de->d_name, len)) {
++ return -1;
++ }
++ }
++ }
++
++ closedir(d);
++
++done:
++ msg.dent.id = ID_DONE;
++ msg.dent.mode = 0;
++ msg.dent.size = 0;
++ msg.dent.time = 0;
++ msg.dent.namelen = 0;
++ return writex(s, &msg.dent, sizeof(msg.dent));
++}
++
++static int fail_message(int s, const char *reason)
++{
++ syncmsg msg;
++ int len = strlen(reason);
++
++ D("sync: failure: %s\n", reason);
++
++ msg.data.id = ID_FAIL;
++ msg.data.size = htoll(len);
++ if(writex(s, &msg.data, sizeof(msg.data)) ||
++ writex(s, reason, len)) {
++ return -1;
++ } else {
++ return 0;
++ }
++}
++
++static int fail_errno(int s)
++{
++ return fail_message(s, strerror(errno));
++}
++
++static int handle_send_file(int s, char *path, mode_t mode, char *buffer)
++{
++ syncmsg msg;
++ unsigned int timestamp = 0;
++ int fd;
++
++ fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
++ if(fd < 0 && errno == ENOENT) {
++ mkdirs(path);
++ fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
++ }
++ if(fd < 0 && errno == EEXIST) {
++ fd = adb_open_mode(path, O_WRONLY, mode);
++ }
++ if(fd < 0) {
++ if(fail_errno(s))
++ return -1;
++ fd = -1;
++ }
++
++ for(;;) {
++ unsigned int len;
++
++ if(readx(s, &msg.data, sizeof(msg.data)))
++ goto fail;
++
++ if(msg.data.id != ID_DATA) {
++ if(msg.data.id == ID_DONE) {
++ timestamp = ltohl(msg.data.size);
++ break;
++ }
++ fail_message(s, "invalid data message");
++ goto fail;
++ }
++ len = ltohl(msg.data.size);
++ if(len > SYNC_DATA_MAX) {
++ fail_message(s, "oversize data message");
++ goto fail;
++ }
++ if(readx(s, buffer, len))
++ goto fail;
++
++ if(fd < 0)
++ continue;
++ if(writex(fd, buffer, len)) {
++ int saved_errno = errno;
++ adb_close(fd);
++ adb_unlink(path);
++ fd = -1;
++ errno = saved_errno;
++ if(fail_errno(s)) return -1;
++ }
++ }
++
++ if(fd >= 0) {
++ struct utimbuf u;
++ adb_close(fd);
++ u.actime = timestamp;
++ u.modtime = timestamp;
++ utime(path, &u);
++
++ msg.status.id = ID_OKAY;
++ msg.status.msglen = 0;
++ if(writex(s, &msg.status, sizeof(msg.status)))
++ return -1;
++ }
++ return 0;
++
++fail:
++ if(fd >= 0)
++ adb_close(fd);
++ adb_unlink(path);
++ return -1;
++}
++
++#ifdef HAVE_SYMLINKS
++static int handle_send_link(int s, char *path, char *buffer)
++{
++ syncmsg msg;
++ unsigned int len;
++ int ret;
++
++ if(readx(s, &msg.data, sizeof(msg.data)))
++ return -1;
++
++ if(msg.data.id != ID_DATA) {
++ fail_message(s, "invalid data message: expected ID_DATA");
++ return -1;
++ }
++
++ len = ltohl(msg.data.size);
++ if(len > SYNC_DATA_MAX) {
++ fail_message(s, "oversize data message");
++ return -1;
++ }
++ if(readx(s, buffer, len))
++ return -1;
++
++ ret = symlink(buffer, path);
++ if(ret && errno == ENOENT) {
++ mkdirs(path);
++ ret = symlink(buffer, path);
++ }
++ if(ret) {
++ fail_errno(s);
++ return -1;
++ }
++
++ if(readx(s, &msg.data, sizeof(msg.data)))
++ return -1;
++
++ if(msg.data.id == ID_DONE) {
++ msg.status.id = ID_OKAY;
++ msg.status.msglen = 0;
++ if(writex(s, &msg.status, sizeof(msg.status)))
++ return -1;
++ } else {
++ fail_message(s, "invalid data message: expected ID_DONE");
++ return -1;
++ }
++
++ return 0;
++}
++#endif /* HAVE_SYMLINKS */
++
++static int do_send(int s, char *path, char *buffer)
++{
++ char *tmp;
++ mode_t mode;
++ int is_link, ret;
++
++ tmp = strrchr(path,',');
++ if(tmp) {
++ *tmp = 0;
++ errno = 0;
++ mode = strtoul(tmp + 1, NULL, 0);
++#ifndef HAVE_SYMLINKS
++ is_link = 0;
++#else
++ is_link = S_ISLNK(mode);
++#endif
++ mode &= 0777;
++ }
++ if(!tmp || errno) {
++ mode = 0644;
++ is_link = 0;
++ }
++
++ adb_unlink(path);
++
++
++#ifdef HAVE_SYMLINKS
++ if(is_link)
++ ret = handle_send_link(s, path, buffer);
++ else {
++#else
++ {
++#endif
++ /* copy user permission bits to "group" and "other" permissions */
++ mode |= ((mode >> 3) & 0070);
++ mode |= ((mode >> 3) & 0007);
++
++ ret = handle_send_file(s, path, mode, buffer);
++ }
++
++ return ret;
++}
++
++static int do_recv(int s, const char *path, char *buffer)
++{
++ syncmsg msg;
++ int fd, r;
++
++ fd = adb_open(path, O_RDONLY);
++ if(fd < 0) {
++ if(fail_errno(s)) return -1;
++ return 0;
++ }
++
++ msg.data.id = ID_DATA;
++ for(;;) {
++ r = adb_read(fd, buffer, SYNC_DATA_MAX);
++ if(r <= 0) {
++ if(r == 0) break;
++ if(errno == EINTR) continue;
++ r = fail_errno(s);
++ adb_close(fd);
++ return r;
++ }
++ msg.data.size = htoll(r);
++ if(writex(s, &msg.data, sizeof(msg.data)) ||
++ writex(s, buffer, r)) {
++ adb_close(fd);
++ return -1;
++ }
++ }
++
++ adb_close(fd);
++
++ msg.data.id = ID_DONE;
++ msg.data.size = 0;
++ if(writex(s, &msg.data, sizeof(msg.data))) {
++ return -1;
++ }
++
++ return 0;
++}
++
++void file_sync_service(int fd, void *cookie)
++{
++ syncmsg msg;
++ char name[1025];
++ unsigned namelen;
++
++ char *buffer = malloc(SYNC_DATA_MAX);
++ if(buffer == 0) goto fail;
++
++ for(;;) {
++ D("sync: waiting for command\n");
++
++ if(readx(fd, &msg.req, sizeof(msg.req))) {
++ fail_message(fd, "command read failure");
++ break;
++ }
++ namelen = ltohl(msg.req.namelen);
++ if(namelen > 1024) {
++ fail_message(fd, "invalid namelen");
++ break;
++ }
++ if(readx(fd, name, namelen)) {
++ fail_message(fd, "filename read failure");
++ break;
++ }
++ name[namelen] = 0;
++
++ msg.req.namelen = 0;
++ D("sync: '%s' '%s'\n", (char*) &msg.req, name);
++
++ switch(msg.req.id) {
++ case ID_STAT:
++ if(do_stat(fd, name)) goto fail;
++ break;
++ case ID_LIST:
++ if(do_list(fd, name)) goto fail;
++ break;
++ case ID_SEND:
++ if(do_send(fd, name, buffer)) goto fail;
++ break;
++ case ID_RECV:
++ if(do_recv(fd, name, buffer)) goto fail;
++ break;
++ case ID_QUIT:
++ goto fail;
++ default:
++ fail_message(fd, "unknown command");
++ goto fail;
++ }
++ }
++
++fail:
++ if(buffer != 0) free(buffer);
++ D("sync: done\n");
++ adb_close(fd);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/file_sync_service.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/file_sync_service.h 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,87 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef _FILE_SYNC_SERVICE_H_
++#define _FILE_SYNC_SERVICE_H_
++
++#ifdef HAVE_BIG_ENDIAN
++static inline unsigned __swap_uint32(unsigned x)
++{
++ return (((x) & 0xFF000000) >> 24)
++ | (((x) & 0x00FF0000) >> 8)
++ | (((x) & 0x0000FF00) << 8)
++ | (((x) & 0x000000FF) << 24);
++}
++#define htoll(x) __swap_uint32(x)
++#define ltohl(x) __swap_uint32(x)
++#define MKID(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24))
++#else
++#define htoll(x) (x)
++#define ltohl(x) (x)
++#define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
++#endif
++
++#define ID_STAT MKID('S','T','A','T')
++#define ID_LIST MKID('L','I','S','T')
++#define ID_ULNK MKID('U','L','N','K')
++#define ID_SEND MKID('S','E','N','D')
++#define ID_RECV MKID('R','E','C','V')
++#define ID_DENT MKID('D','E','N','T')
++#define ID_DONE MKID('D','O','N','E')
++#define ID_DATA MKID('D','A','T','A')
++#define ID_OKAY MKID('O','K','A','Y')
++#define ID_FAIL MKID('F','A','I','L')
++#define ID_QUIT MKID('Q','U','I','T')
++
++typedef union {
++ unsigned id;
++ struct {
++ unsigned id;
++ unsigned namelen;
++ } req;
++ struct {
++ unsigned id;
++ unsigned mode;
++ unsigned size;
++ unsigned time;
++ } stat;
++ struct {
++ unsigned id;
++ unsigned mode;
++ unsigned size;
++ unsigned time;
++ unsigned namelen;
++ } dent;
++ struct {
++ unsigned id;
++ unsigned size;
++ } data;
++ struct {
++ unsigned id;
++ unsigned msglen;
++ } status;
++} syncmsg;
++
++
++void file_sync_service(int fd, void *cookie);
++int do_sync_ls(const char *path);
++int do_sync_push(const char *lpath, const char *rpath, int verifyApk);
++int do_sync_sync(const char *lpath, const char *rpath, int listonly);
++int do_sync_pull(const char *rpath, const char *lpath);
++
++#define SYNC_DATA_MAX (64*1024)
++
++#endif
+Index: android-tools-4.2.2+git20130218/core/adbd/framebuffer_service.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/framebuffer_service.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,180 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <unistd.h>
++#include <string.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/wait.h>
++
++#include "fdevent.h"
++#include "adb.h"
++
++#include <linux/fb.h>
++#include <sys/ioctl.h>
++#include <sys/mman.h>
++
++/* TODO:
++** - sync with vsync to avoid tearing
++*/
++/* This version number defines the format of the fbinfo struct.
++ It must match versioning in ddms where this data is consumed. */
++#define DDMS_RAWIMAGE_VERSION 1
++struct fbinfo {
++ unsigned int version;
++ unsigned int bpp;
++ unsigned int size;
++ unsigned int width;
++ unsigned int height;
++ unsigned int red_offset;
++ unsigned int red_length;
++ unsigned int blue_offset;
++ unsigned int blue_length;
++ unsigned int green_offset;
++ unsigned int green_length;
++ unsigned int alpha_offset;
++ unsigned int alpha_length;
++} __attribute__((packed));
++
++void framebuffer_service(int fd, void *cookie)
++{
++ struct fbinfo fbinfo;
++ unsigned int i;
++ char buf[640];
++ int fd_screencap;
++ int w, h, f;
++ int fds[2];
++
++ if (pipe(fds) < 0) goto done;
++
++ pid_t pid = fork();
++ if (pid < 0) goto done;
++
++ if (pid == 0) {
++ dup2(fds[1], STDOUT_FILENO);
++ close(fds[0]);
++ close(fds[1]);
++ const char* command = "screencap";
++ const char *args[2] = {command, NULL};
++ execvp(command, (char**)args);
++ exit(1);
++ }
++
++ fd_screencap = fds[0];
++
++ /* read w, h & format */
++ if(readx(fd_screencap, &w, 4)) goto done;
++ if(readx(fd_screencap, &h, 4)) goto done;
++ if(readx(fd_screencap, &f, 4)) goto done;
++
++ fbinfo.version = DDMS_RAWIMAGE_VERSION;
++ /* see hardware/hardware.h */
++ switch (f) {
++ case 1: /* RGBA_8888 */
++ fbinfo.bpp = 32;
++ fbinfo.size = w * h * 4;
++ fbinfo.width = w;
++ fbinfo.height = h;
++ fbinfo.red_offset = 0;
++ fbinfo.red_length = 8;
++ fbinfo.green_offset = 8;
++ fbinfo.green_length = 8;
++ fbinfo.blue_offset = 16;
++ fbinfo.blue_length = 8;
++ fbinfo.alpha_offset = 24;
++ fbinfo.alpha_length = 8;
++ break;
++ case 2: /* RGBX_8888 */
++ fbinfo.bpp = 32;
++ fbinfo.size = w * h * 4;
++ fbinfo.width = w;
++ fbinfo.height = h;
++ fbinfo.red_offset = 0;
++ fbinfo.red_length = 8;
++ fbinfo.green_offset = 8;
++ fbinfo.green_length = 8;
++ fbinfo.blue_offset = 16;
++ fbinfo.blue_length = 8;
++ fbinfo.alpha_offset = 24;
++ fbinfo.alpha_length = 0;
++ break;
++ case 3: /* RGB_888 */
++ fbinfo.bpp = 24;
++ fbinfo.size = w * h * 3;
++ fbinfo.width = w;
++ fbinfo.height = h;
++ fbinfo.red_offset = 0;
++ fbinfo.red_length = 8;
++ fbinfo.green_offset = 8;
++ fbinfo.green_length = 8;
++ fbinfo.blue_offset = 16;
++ fbinfo.blue_length = 8;
++ fbinfo.alpha_offset = 24;
++ fbinfo.alpha_length = 0;
++ break;
++ case 4: /* RGB_565 */
++ fbinfo.bpp = 16;
++ fbinfo.size = w * h * 2;
++ fbinfo.width = w;
++ fbinfo.height = h;
++ fbinfo.red_offset = 11;
++ fbinfo.red_length = 5;
++ fbinfo.green_offset = 5;
++ fbinfo.green_length = 6;
++ fbinfo.blue_offset = 0;
++ fbinfo.blue_length = 5;
++ fbinfo.alpha_offset = 0;
++ fbinfo.alpha_length = 0;
++ break;
++ case 5: /* BGRA_8888 */
++ fbinfo.bpp = 32;
++ fbinfo.size = w * h * 4;
++ fbinfo.width = w;
++ fbinfo.height = h;
++ fbinfo.red_offset = 16;
++ fbinfo.red_length = 8;
++ fbinfo.green_offset = 8;
++ fbinfo.green_length = 8;
++ fbinfo.blue_offset = 0;
++ fbinfo.blue_length = 8;
++ fbinfo.alpha_offset = 24;
++ fbinfo.alpha_length = 8;
++ break;
++ default:
++ goto done;
++ }
++
++ /* write header */
++ if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done;
++
++ /* write data */
++ for(i = 0; i < fbinfo.size; i += sizeof(buf)) {
++ if(readx(fd_screencap, buf, sizeof(buf))) goto done;
++ if(writex(fd, buf, sizeof(buf))) goto done;
++ }
++ if(readx(fd_screencap, buf, fbinfo.size % sizeof(buf))) goto done;
++ if(writex(fd, buf, fbinfo.size % sizeof(buf))) goto done;
++
++done:
++ TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
++
++ close(fds[0]);
++ close(fds[1]);
++ close(fd);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/get_my_path_darwin.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/get_my_path_darwin.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#import <Carbon/Carbon.h>
++#include <unistd.h>
++
++void get_my_path(char *s, size_t maxLen)
++{
++ ProcessSerialNumber psn;
++ GetCurrentProcess(&psn);
++ CFDictionaryRef dict;
++ dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
++ CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
++ CFSTR("CFBundleExecutable"));
++ CFStringGetCString(value, s, maxLen, kCFStringEncodingUTF8);
++}
++
+Index: android-tools-4.2.2+git20130218/core/adbd/get_my_path_freebsd.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/get_my_path_freebsd.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,36 @@
++/*
++ * Copyright (C) 2009 bsdroid project
++ * Alexey Tarasov <tarasov@dodologics.com>
++ *
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <sys/types.h>
++#include <unistd.h>
++#include <limits.h>
++#include <stdio.h>
++
++void
++get_my_path(char *exe, size_t maxLen)
++{
++ char proc[64];
++
++ snprintf(proc, sizeof(proc), "/proc/%d/file", getpid());
++
++ int err = readlink(proc, exe, maxLen - 1);
++
++ exe[err > 0 ? err : 0] = '\0';
++}
++
+Index: android-tools-4.2.2+git20130218/core/adbd/get_my_path_linux.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/get_my_path_linux.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,33 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <sys/types.h>
++#include <unistd.h>
++#include <limits.h>
++#include <stdio.h>
++
++void get_my_path(char *exe, size_t maxLen)
++{
++ char proc[64];
++ snprintf(proc, sizeof proc, "/proc/%d/exe", getpid());
++ int err = readlink(proc, exe, maxLen - 1);
++ if(err > 0) {
++ exe[err] = '\0';
++ } else {
++ exe[0] = '\0';
++ }
++}
++
+Index: android-tools-4.2.2+git20130218/core/adbd/get_my_path_windows.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/get_my_path_windows.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,34 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <limits.h>
++#include <assert.h>
++#include <windows.h>
++
++void get_my_path(char *exe, size_t maxLen)
++{
++ char *r;
++
++ /* XXX: should be GetModuleFileNameA */
++ if (GetModuleFileName(NULL, exe, maxLen) > 0) {
++ r = strrchr(exe, '\\');
++ if (r != NULL)
++ *r = '\0';
++ } else {
++ exe[0] = '\0';
++ }
++}
++
+Index: android-tools-4.2.2+git20130218/core/adbd/jdwp_service.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/jdwp_service.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,735 @@
++/* implement the "debug-ports" and "track-debug-ports" device services */
++#include "sysdeps.h"
++#define TRACE_TAG TRACE_JDWP
++#include "adb.h"
++#include <errno.h>
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++
++/* here's how these things work.
++
++ when adbd starts, it creates a unix server socket
++ named @vm-debug-control (@ is a shortcut for "first byte is zero"
++ to use the private namespace instead of the file system)
++
++ when a new JDWP daemon thread starts in a new VM process, it creates
++ a connection to @vm-debug-control to announce its availability.
++
++
++ JDWP thread @vm-debug-control
++ | |
++ |-------------------------------> |
++ | hello I'm in process <pid> |
++ | |
++ | |
++
++ the connection is kept alive. it will be closed automatically if
++ the JDWP process terminates (this allows adbd to detect dead
++ processes).
++
++ adbd thus maintains a list of "active" JDWP processes. it can send
++ its content to clients through the "device:debug-ports" service,
++ or even updates through the "device:track-debug-ports" service.
++
++ when a debugger wants to connect, it simply runs the command
++ equivalent to "adb forward tcp:<hostport> jdwp:<pid>"
++
++ "jdwp:<pid>" is a new forward destination format used to target
++ a given JDWP process on the device. when sutch a request arrives,
++ adbd does the following:
++
++ - first, it calls socketpair() to create a pair of equivalent
++ sockets.
++
++ - it attaches the first socket in the pair to a local socket
++ which is itself attached to the transport's remote socket:
++
++
++ - it sends the file descriptor of the second socket directly
++ to the JDWP process with the help of sendmsg()
++
++
++ JDWP thread @vm-debug-control
++ | |
++ | <----------------------|
++ | OK, try this file descriptor |
++ | |
++ | |
++
++ then, the JDWP thread uses this new socket descriptor as its
++ pass-through connection to the debugger (and receives the
++ JDWP-Handshake message, answers to it, etc...)
++
++ this gives the following graphics:
++ ____________________________________
++ | |
++ | ADB Server (host) |
++ | |
++ Debugger <---> LocalSocket <----> RemoteSocket |
++ | ^^ |
++ |___________________________||_______|
++ ||
++ Transport ||
++ (TCP for emulator - USB for device) ||
++ ||
++ ___________________________||_______
++ | || |
++ | ADBD (device) || |
++ | VV |
++ JDWP <======> LocalSocket <----> RemoteSocket |
++ | |
++ |____________________________________|
++
++ due to the way adb works, this doesn't need a special socket
++ type or fancy handling of socket termination if either the debugger
++ or the JDWP process closes the connection.
++
++ THIS IS THE SIMPLEST IMPLEMENTATION I COULD FIND, IF YOU HAPPEN
++ TO HAVE A BETTER IDEA, LET ME KNOW - Digit
++
++**********************************************************************/
++
++/** JDWP PID List Support Code
++ ** for each JDWP process, we record its pid and its connected socket
++ **/
++
++#define MAX_OUT_FDS 4
++
++#if !ADB_HOST
++
++#include <sys/socket.h>
++#include <sys/un.h>
++
++typedef struct JdwpProcess JdwpProcess;
++struct JdwpProcess {
++ JdwpProcess* next;
++ JdwpProcess* prev;
++ int pid;
++ int socket;
++ fdevent* fde;
++
++ char in_buff[4]; /* input character to read PID */
++ int in_len; /* number from JDWP process */
++
++ int out_fds[MAX_OUT_FDS]; /* output array of file descriptors */
++ int out_count; /* to send to the JDWP process */
++};
++
++static JdwpProcess _jdwp_list;
++
++static int
++jdwp_process_list( char* buffer, int bufferlen )
++{
++ char* end = buffer + bufferlen;
++ char* p = buffer;
++ JdwpProcess* proc = _jdwp_list.next;
++
++ for ( ; proc != &_jdwp_list; proc = proc->next ) {
++ int len;
++
++ /* skip transient connections */
++ if (proc->pid < 0)
++ continue;
++
++ len = snprintf(p, end-p, "%d\n", proc->pid);
++ if (p + len >= end)
++ break;
++ p += len;
++ }
++ p[0] = 0;
++ return (p - buffer);
++}
++
++
++static int
++jdwp_process_list_msg( char* buffer, int bufferlen )
++{
++ char head[5];
++ int len = jdwp_process_list( buffer+4, bufferlen-4 );
++ snprintf(head, sizeof head, "%04x", len);
++ memcpy(buffer, head, 4);
++ return len + 4;
++}
++
++
++static void jdwp_process_list_updated(void);
++
++static void
++jdwp_process_free( JdwpProcess* proc )
++{
++ if (proc) {
++ int n;
++
++ proc->prev->next = proc->next;
++ proc->next->prev = proc->prev;
++
++ if (proc->socket >= 0) {
++ adb_shutdown(proc->socket);
++ adb_close(proc->socket);
++ proc->socket = -1;
++ }
++
++ if (proc->fde != NULL) {
++ fdevent_destroy(proc->fde);
++ proc->fde = NULL;
++ }
++ proc->pid = -1;
++
++ for (n = 0; n < proc->out_count; n++) {
++ adb_close(proc->out_fds[n]);
++ }
++ proc->out_count = 0;
++
++ free(proc);
++
++ jdwp_process_list_updated();
++ }
++}
++
++
++static void jdwp_process_event(int, unsigned, void*); /* forward */
++
++
++static JdwpProcess*
++jdwp_process_alloc( int socket )
++{
++ JdwpProcess* proc = calloc(1,sizeof(*proc));
++
++ if (proc == NULL) {
++ D("not enough memory to create new JDWP process\n");
++ return NULL;
++ }
++
++ proc->socket = socket;
++ proc->pid = -1;
++ proc->next = proc;
++ proc->prev = proc;
++
++ proc->fde = fdevent_create( socket, jdwp_process_event, proc );
++ if (proc->fde == NULL) {
++ D("could not create fdevent for new JDWP process\n" );
++ free(proc);
++ return NULL;
++ }
++
++ proc->fde->state |= FDE_DONT_CLOSE;
++ proc->in_len = 0;
++ proc->out_count = 0;
++
++ /* append to list */
++ proc->next = &_jdwp_list;
++ proc->prev = proc->next->prev;
++
++ proc->prev->next = proc;
++ proc->next->prev = proc;
++
++ /* start by waiting for the PID */
++ fdevent_add(proc->fde, FDE_READ);
++
++ return proc;
++}
++
++
++static void
++jdwp_process_event( int socket, unsigned events, void* _proc )
++{
++ JdwpProcess* proc = _proc;
++
++ if (events & FDE_READ) {
++ if (proc->pid < 0) {
++ /* read the PID as a 4-hexchar string */
++ char* p = proc->in_buff + proc->in_len;
++ int size = 4 - proc->in_len;
++ char temp[5];
++ while (size > 0) {
++ int len = recv( socket, p, size, 0 );
++ if (len < 0) {
++ if (errno == EINTR)
++ continue;
++ if (errno == EAGAIN)
++ return;
++ /* this can fail here if the JDWP process crashes very fast */
++ D("weird unknown JDWP process failure: %s\n",
++ strerror(errno));
++
++ goto CloseProcess;
++ }
++ if (len == 0) { /* end of stream ? */
++ D("weird end-of-stream from unknown JDWP process\n");
++ goto CloseProcess;
++ }
++ p += len;
++ proc->in_len += len;
++ size -= len;
++ }
++ /* we have read 4 characters, now decode the pid */
++ memcpy(temp, proc->in_buff, 4);
++ temp[4] = 0;
++
++ if (sscanf( temp, "%04x", &proc->pid ) != 1) {
++ D("could not decode JDWP %p PID number: '%s'\n", proc, temp);
++ goto CloseProcess;
++ }
++
++ /* all is well, keep reading to detect connection closure */
++ D("Adding pid %d to jdwp process list\n", proc->pid);
++ jdwp_process_list_updated();
++ }
++ else
++ {
++ /* the pid was read, if we get there it's probably because the connection
++ * was closed (e.g. the JDWP process exited or crashed) */
++ char buf[32];
++
++ for (;;) {
++ int len = recv(socket, buf, sizeof(buf), 0);
++
++ if (len <= 0) {
++ if (len < 0 && errno == EINTR)
++ continue;
++ if (len < 0 && errno == EAGAIN)
++ return;
++ else {
++ D("terminating JDWP %d connection: %s\n", proc->pid,
++ strerror(errno));
++ break;
++ }
++ }
++ else {
++ D( "ignoring unexpected JDWP %d control socket activity (%d bytes)\n",
++ proc->pid, len );
++ }
++ }
++
++ CloseProcess:
++ if (proc->pid >= 0)
++ D( "remove pid %d to jdwp process list\n", proc->pid );
++ jdwp_process_free(proc);
++ return;
++ }
++ }
++
++ if (events & FDE_WRITE) {
++ D("trying to write to JDWP pid controli (count=%d first=%d) %d\n",
++ proc->pid, proc->out_count, proc->out_fds[0]);
++ if (proc->out_count > 0) {
++ int fd = proc->out_fds[0];
++ int n, ret;
++ struct cmsghdr* cmsg;
++ struct msghdr msg;
++ struct iovec iov;
++ char dummy = '!';
++ char buffer[sizeof(struct cmsghdr) + sizeof(int)];
++ int flags;
++
++ iov.iov_base = &dummy;
++ iov.iov_len = 1;
++ msg.msg_name = NULL;
++ msg.msg_namelen = 0;
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++ msg.msg_flags = 0;
++ msg.msg_control = buffer;
++ msg.msg_controllen = sizeof(buffer);
++
++ cmsg = CMSG_FIRSTHDR(&msg);
++ cmsg->cmsg_len = msg.msg_controllen;
++ cmsg->cmsg_level = SOL_SOCKET;
++ cmsg->cmsg_type = SCM_RIGHTS;
++ ((int*)CMSG_DATA(cmsg))[0] = fd;
++
++ flags = fcntl(proc->socket,F_GETFL,0);
++
++ if (flags == -1) {
++ D("failed to get cntl flags for socket %d: %s\n",
++ proc->pid, strerror(errno));
++ goto CloseProcess;
++
++ }
++
++ if (fcntl(proc->socket, F_SETFL, flags & ~O_NONBLOCK) == -1) {
++ D("failed to remove O_NONBLOCK flag for socket %d: %s\n",
++ proc->pid, strerror(errno));
++ goto CloseProcess;
++ }
++
++ for (;;) {
++ ret = sendmsg(proc->socket, &msg, 0);
++ if (ret >= 0) {
++ adb_close(fd);
++ break;
++ }
++ if (errno == EINTR)
++ continue;
++ D("sending new file descriptor to JDWP %d failed: %s\n",
++ proc->pid, strerror(errno));
++ goto CloseProcess;
++ }
++
++ D("sent file descriptor %d to JDWP process %d\n",
++ fd, proc->pid);
++
++ for (n = 1; n < proc->out_count; n++)
++ proc->out_fds[n-1] = proc->out_fds[n];
++
++ if (fcntl(proc->socket, F_SETFL, flags) == -1) {
++ D("failed to set O_NONBLOCK flag for socket %d: %s\n",
++ proc->pid, strerror(errno));
++ goto CloseProcess;
++ }
++
++ if (--proc->out_count == 0)
++ fdevent_del( proc->fde, FDE_WRITE );
++ }
++&nb