diff options
73 files changed, 2703 insertions, 1349 deletions
@@ -302,8 +302,10 @@ void handle_packet(apacket *p, atransport *t) { asocket *s; - D("handle_packet() %d\n", p->msg.command); - + 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){ @@ -680,9 +682,11 @@ void start_device_log(void) 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 @@ -873,7 +877,7 @@ int adb_main(int is_daemon, int server_port) // don't run as root if ro.secure is set... secure = 1; - // ... except we allow running as root in userdebug builds if the + // ... 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) { @@ -1104,7 +1108,7 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r type = kTransportAny; } else if (!strncmp(service, "transport:", strlen("transport:"))) { service += strlen("transport:"); - serial = strdup(service); + serial = service; } transport = acquire_one_transport(CS_ANY, type, serial, &error_string); @@ -1264,8 +1268,8 @@ int recovery_mode = 0; int main(int argc, char **argv) { - adb_trace_init(); #if ADB_HOST + adb_trace_init(); adb_sysdeps_init(); return adb_commandline(argc - 1, argv + 1); #else diff --git a/adb/commandline.c b/adb/commandline.c index dcba83b..b0c2b80 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -104,7 +104,7 @@ void help() " 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 ocmmand with no additional arguments\n" + " Using this command with no additional arguments\n" " will disconnect from all connected TCP/IP devices.\n" "\n" "device commands:\n" @@ -683,6 +683,7 @@ 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; @@ -719,7 +720,9 @@ int adb_commandline(int argc, char **argv) /* modifiers and flags */ while(argc > 0) { - if(!strcmp(argv[0],"nodaemon")) { + 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 */ @@ -766,7 +769,7 @@ int adb_commandline(int argc, char **argv) adb_set_transport(ttype, serial); adb_set_tcp_specifics(server_port); - if ((argc > 0) && (!strcmp(argv[0],"server"))) { + if (is_server) { if (no_daemon || is_daemon) { r = adb_main(is_daemon, server_port); } else { @@ -838,12 +841,24 @@ top: return adb_send_emulator_command(argc, argv); } - if(!strcmp(argv[0], "shell")) { + 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) { - return interactive_shell(); + r = interactive_shell(); + if (h) { + printf("\x1b[0m"); + fflush(stdout); + } + return r; } snprintf(buf, sizeof buf, "shell:%s", argv[1]); @@ -877,6 +892,10 @@ top: adb_sleep_ms(1000); do_cmd(ttype, serial, "wait-for-device", 0); } else { + if (h) { + printf("\x1b[0m"); + fflush(stdout); + } return r; } } diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c index da25ae8..5c7a26f 100644 --- a/adb/file_sync_client.c +++ b/adb/file_sync_client.c @@ -57,9 +57,9 @@ static void END() if (t == 0) /* prevent division by 0 :-) */ t = 1000000; - fprintf(stderr,"%lld KB/s (%d bytes in %lld.%03llds)\n", + fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n", ((((long long) total_bytes) * 1000000LL) / t) / 1024LL, - total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL); + (long long) total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL); } void sync_quit(int fd) diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h index 11ea06b..e402e06 100644 --- a/adb/file_sync_service.h +++ b/adb/file_sync_service.h @@ -17,7 +17,7 @@ #ifndef _FILE_SYNC_SERVICE_H_ #define _FILE_SYNC_SERVICE_H_ -#ifdef __ppc__ +#ifdef HAVE_BIG_ENDIAN static inline unsigned __swap_uint32(unsigned x) { return (((x) & 0xFF000000) >> 24) diff --git a/adb/jdwp_service.c b/adb/jdwp_service.c index 0c26f7b..cd62b55 100644 --- a/adb/jdwp_service.c +++ b/adb/jdwp_service.c @@ -5,6 +5,7 @@ #include <errno.h> #include <stdio.h> #include <string.h> +#include <unistd.h> /* here's how these things work. @@ -320,6 +321,7 @@ jdwp_process_event( int socket, unsigned events, void* _proc ) struct iovec iov; char dummy = '!'; char buffer[sizeof(struct cmsghdr) + sizeof(int)]; + int flags; iov.iov_base = &dummy; iov.iov_len = 1; @@ -337,10 +339,27 @@ jdwp_process_event( int socket, unsigned events, void* _proc ) 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) + if (ret >= 0) { + adb_close(fd); break; + } if (errno == EINTR) continue; D("sending new file descriptor to JDWP %d failed: %s\n", @@ -354,6 +373,12 @@ jdwp_process_event( int socket, unsigned events, void* _proc ) 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 ); } @@ -474,6 +499,7 @@ jdwp_control_init( JdwpControl* control, /* only wait for incoming connections */ fdevent_add(control->fde, FDE_READ); + close_on_exec(s); D("jdwp control socket started (%d)\n", control->listen_socket); return 0; diff --git a/adb/services.c b/adb/services.c index 487c7d3..c22ce17 100644 --- a/adb/services.c +++ b/adb/services.c @@ -309,6 +309,7 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1 dup2(pts, 1); dup2(pts, 2); + adb_close(pts); adb_close(ptm); execl(cmd, cmd, arg0, arg1, NULL); diff --git a/adb/sockets.c b/adb/sockets.c index 9f1b598..f0357d6 100644 --- a/adb/sockets.c +++ b/adb/sockets.c @@ -65,8 +65,11 @@ asocket *find_local_socket(unsigned id) asocket *result = NULL; adb_mutex_lock(&socket_list_lock); - for(s = local_socket_list.next; s != &local_socket_list && !result; s = s->next) { - if(s->id == id) result = s; + for (s = local_socket_list.next; s != &local_socket_list; s = s->next) { + if (s->id == id) { + result = s; + break; + } } adb_mutex_unlock(&socket_list_lock); @@ -218,10 +221,12 @@ static void local_socket_close_locked(asocket *s) if(s->peer) { s->peer->peer = 0; // tweak to avoid deadlock - if (s->peer->close == local_socket_close) + if (s->peer->close == local_socket_close) { local_socket_close_locked(s->peer); - else + } else { s->peer->close(s->peer); + } + s->peer = 0; } /* If we are already closing, or if there are no @@ -366,7 +371,7 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s) asocket *create_local_socket(int fd) { asocket *s = calloc(1, sizeof(asocket)); - if(s == 0) fatal("cannot allocate socket"); + if (s == NULL) fatal("cannot allocate socket"); install_local_socket(s); s->fd = fd; s->enqueue = local_socket_enqueue; @@ -482,7 +487,7 @@ asocket *create_remote_socket(unsigned id, atransport *t) asocket *s = calloc(1, sizeof(aremotesocket)); adisconnect* dis = &((aremotesocket*)s)->disconnect; - if(s == 0) fatal("cannot allocate socket"); + if (s == NULL) fatal("cannot allocate socket"); s->id = id; s->enqueue = remote_socket_enqueue; s->ready = remote_socket_ready; @@ -566,6 +571,32 @@ unsigned unhex(unsigned char *s, int len) return n; } +/* skip_host_serial return the position in a string + skipping over the 'serial' parameter in the ADB protocol, + where parameter string may be a host:port string containing + the protocol delimiter (colon). */ +char *skip_host_serial(char *service) { + char *first_colon, *serial_end; + + first_colon = strchr(service, ':'); + if (!first_colon) { + /* No colon in service string. */ + return NULL; + } + serial_end = first_colon; + if (isdigit(serial_end[1])) { + serial_end++; + while ((*serial_end) && isdigit(*serial_end)) { + serial_end++; + } + if ((*serial_end) != ':') { + // Something other than numbers was found, reset the end. + serial_end = first_colon; + } + } + return serial_end; +} + static int smart_socket_enqueue(asocket *s, apacket *p) { unsigned len; @@ -621,8 +652,8 @@ static int smart_socket_enqueue(asocket *s, apacket *p) char* serial_end; service += strlen("host-serial:"); - // serial number should follow "host:" - serial_end = strchr(service, ':'); + // serial number should follow "host:" and could be a host:port string. + serial_end = skip_host_serial(service); if (serial_end) { *serial_end = 0; // terminate string serial = service; @@ -753,6 +784,7 @@ static void smart_socket_close(asocket *s) if(s->peer) { s->peer->peer = 0; s->peer->close(s->peer); + s->peer = 0; } free(s); } @@ -761,8 +793,7 @@ asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act)) { D("Creating smart socket \n"); asocket *s = calloc(1, sizeof(asocket)); - if(s == 0) fatal("cannot allocate socket"); - s->id = 0; + if (s == NULL) fatal("cannot allocate socket"); s->enqueue = smart_socket_enqueue; s->ready = smart_socket_ready; s->close = smart_socket_close; diff --git a/adb/sysdeps.h b/adb/sysdeps.h index 6372649..74f4ed1 100644 --- a/adb/sysdeps.h +++ b/adb/sysdeps.h @@ -387,7 +387,13 @@ static __inline__ int adb_creat(const char* path, int mode) static __inline__ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) { - return accept( serverfd, addr, addrlen ); + int fd; + + fd = accept(serverfd, addr, addrlen); + if (fd >= 0) + close_on_exec(fd); + + return fd; } #undef accept diff --git a/adb/transport.c b/adb/transport.c index 62bdfdb..2baf340 100644 --- a/adb/transport.c +++ b/adb/transport.c @@ -79,7 +79,7 @@ run_transport_disconnects(atransport* t) { adisconnect* dis = t->disconnects.next; - D("run_transport_disconnects: %p (%s)\n", t, t->serial ? t->serial : "unknown" ); + D("%s: run_transport_disconnects\n", t->serial); while (dis != &t->disconnects) { adisconnect* next = dis->next; dis->func( dis->opaque, t ); @@ -87,75 +87,91 @@ run_transport_disconnects(atransport* t) } } +#if ADB_TRACE +static void +dump_packet(const char* name, const char* func, apacket* p) +{ + unsigned command = p->msg.command; + int len = p->msg.data_length; + char cmd[9]; + char arg0[12], arg1[12]; + int n; + + for (n = 0; n < 4; n++) { + int b = (command >> (n*8)) & 255; + if (b < 32 || b >= 127) + break; + cmd[n] = (char)b; + } + if (n == 4) { + cmd[4] = 0; + } else { + /* There is some non-ASCII name in the command, so dump + * the hexadecimal value instead */ + snprintf(cmd, sizeof cmd, "%08x", command); + } + + if (p->msg.arg0 < 256U) + snprintf(arg0, sizeof arg0, "%d", p->msg.arg0); + else + snprintf(arg0, sizeof arg0, "0x%x", p->msg.arg0); + + if (p->msg.arg1 < 256U) + snprintf(arg1, sizeof arg1, "%d", p->msg.arg1); + else + snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1); + + D("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ", + name, func, cmd, arg0, arg1, len); + dump_hex(p->data, len); +} +#endif /* ADB_TRACE */ + static int -read_packet(int fd, apacket** ppacket) +read_packet(int fd, const char* name, apacket** ppacket) { char *p = (char*)ppacket; /* really read a packet address */ int r; int len = sizeof(*ppacket); + char buff[8]; + if (!name) { + snprintf(buff, sizeof buff, "fd=%d", fd); + name = buff; + } while(len > 0) { r = adb_read(fd, p, len); if(r > 0) { len -= r; p += r; } else { - D("read_packet: %d error %d %d\n", fd, r, errno); + D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno)); if((r < 0) && (errno == EINTR)) continue; return -1; } } #if ADB_TRACE - if (ADB_TRACING) - { - unsigned command = (*ppacket)->msg.command; - int len = (*ppacket)->msg.data_length; - char cmd[5]; - int n; - - for (n = 0; n < 4; n++) { - int b = (command >> (n*8)) & 255; - if (b >= 32 && b < 127) - cmd[n] = (char)b; - else - cmd[n] = '.'; - } - cmd[4] = 0; - - D("read_packet: %d ok: [%08x %s] %08x %08x (%d) ", - fd, command, cmd, (*ppacket)->msg.arg0, (*ppacket)->msg.arg1, len); - dump_hex((*ppacket)->data, len); + if (ADB_TRACING) { + dump_packet(name, "from remote", *ppacket); } #endif return 0; } static int -write_packet(int fd, apacket** ppacket) +write_packet(int fd, const char* name, apacket** ppacket) { char *p = (char*) ppacket; /* we really write the packet address */ int r, len = sizeof(ppacket); + char buff[8]; + if (!name) { + snprintf(buff, sizeof buff, "fd=%d", fd); + name = buff; + } #if ADB_TRACE - if (ADB_TRACING) - { - unsigned command = (*ppacket)->msg.command; - int len = (*ppacket)->msg.data_length; - char cmd[5]; - int n; - - for (n = 0; n < 4; n++) { - int b = (command >> (n*8)) & 255; - if (b >= 32 && b < 127) - cmd[n] = (char)b; - else - cmd[n] = '.'; - } - cmd[4] = 0; - - D("write_packet: %d [%08x %s] %08x %08x (%d) ", - fd, command, cmd, (*ppacket)->msg.arg0, (*ppacket)->msg.arg1, len); - dump_hex((*ppacket)->data, len); + if (ADB_TRACING) { + dump_packet(name, "to remote", *ppacket); } #endif len = sizeof(ppacket); @@ -165,7 +181,7 @@ write_packet(int fd, apacket** ppacket) len -= r; p += r; } else { - D("write_packet: %d error %d %d\n", fd, r, errno); + D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno)); if((r < 0) && (errno == EINTR)) continue; return -1; } @@ -175,10 +191,11 @@ write_packet(int fd, apacket** ppacket) static void transport_socket_events(int fd, unsigned events, void *_t) { + atransport *t = _t; if(events & FDE_READ){ apacket *p = 0; - if(read_packet(fd, &p)){ - D("failed to read packet from transport socket on fd %d\n", fd); + if(read_packet(fd, t->serial, &p)){ + D("%s: failed to read packet from transport socket on fd %d\n", t->serial, fd); } else { handle_packet(p, (atransport *) _t); } @@ -208,7 +225,7 @@ void send_packet(apacket *p, atransport *t) D("Transport is null \n"); } - if(write_packet(t->transport_socket, &p)){ + if(write_packet(t->transport_socket, t->serial, &p)){ fatal_errno("cannot enqueue packet on transport socket"); } } @@ -231,52 +248,51 @@ static void *output_thread(void *_t) atransport *t = _t; apacket *p; - D("from_remote: starting thread for transport %p, on fd %d\n", t, t->fd ); - - D("from_remote: transport %p SYNC online (%d)\n", t, t->sync_token + 1); + D("%s: starting transport output thread on fd %d, SYNC online (%d)\n", + t->serial, t->fd, t->sync_token + 1); p = get_apacket(); p->msg.command = A_SYNC; p->msg.arg0 = 1; p->msg.arg1 = ++(t->sync_token); p->msg.magic = A_SYNC ^ 0xffffffff; - if(write_packet(t->fd, &p)) { + if(write_packet(t->fd, t->serial, &p)) { put_apacket(p); - D("from_remote: failed to write SYNC apacket to transport %p", t); + D("%s: failed to write SYNC packet\n", t->serial); goto oops; } - D("from_remote: data pump for transport %p\n", t); + D("%s: data pump started\n", t->serial); for(;;) { p = get_apacket(); if(t->read_from_remote(p, t) == 0){ - D("from_remote: received remote packet, sending to transport %p\n", - t); - if(write_packet(t->fd, &p)){ + D("%s: received remote packet, sending to transport\n", + t->serial); + if(write_packet(t->fd, t->serial, &p)){ put_apacket(p); - D("from_remote: failed to write apacket to transport %p", t); + D("%s: failed to write apacket to transport\n", t->serial); goto oops; } } else { - D("from_remote: remote read failed for transport %p\n", p); + D("%s: remote read failed for transport\n", t->serial); put_apacket(p); break; } } - D("from_remote: SYNC offline for transport %p\n", t); + D("%s: SYNC offline for transport\n", t->serial); p = get_apacket(); p->msg.command = A_SYNC; p->msg.arg0 = 0; p->msg.arg1 = 0; p->msg.magic = A_SYNC ^ 0xffffffff; - if(write_packet(t->fd, &p)) { + if(write_packet(t->fd, t->serial, &p)) { put_apacket(p); - D("from_remote: failed to write SYNC apacket to transport %p", t); + D("%s: failed to write SYNC apacket to transport", t->serial); } oops: - D("from_remote: thread is exiting for transport %p\n", t); + D("%s: transport output thread is exiting\n", t->serial); kick_transport(t); transport_unref(t); return 0; @@ -288,35 +304,35 @@ static void *input_thread(void *_t) apacket *p; int active = 0; - D("to_remote: starting input_thread for %p, reading from fd %d\n", - t, t->fd); + D("%s: starting transport input thread, reading from fd %d\n", + t->serial, t->fd); for(;;){ - if(read_packet(t->fd, &p)) { - D("to_remote: failed to read apacket from transport %p on fd %d\n", - t, t->fd ); + if(read_packet(t->fd, t->serial, &p)) { + D("%s: failed to read apacket from transport on fd %d\n", + t->serial, t->fd ); break; } if(p->msg.command == A_SYNC){ if(p->msg.arg0 == 0) { - D("to_remote: transport %p SYNC offline\n", t); + D("%s: transport SYNC offline\n", t->serial); put_apacket(p); break; } else { if(p->msg.arg1 == t->sync_token) { - D("to_remote: transport %p SYNC online\n", t); + D("%s: transport SYNC online\n", t->serial); active = 1; } else { - D("to_remote: trandport %p ignoring SYNC %d != %d\n", - t, p->msg.arg1, t->sync_token); + D("%s: transport ignoring SYNC %d != %d\n", + t->serial, p->msg.arg1, t->sync_token); } } } else { if(active) { - D("to_remote: transport %p got packet, sending to remote\n", t); + D("%s: transport got packet, sending to remote\n", t->serial); t->write_to_remote(p, t); } else { - D("to_remote: transport %p ignoring packet while offline\n", t); + D("%s: transport ignoring packet while offline\n", t->serial); } } @@ -327,7 +343,7 @@ static void *input_thread(void *_t) // while a client socket is still active. close_all_sockets(t); - D("to_remote: thread is exiting for transport %p, fd %d\n", t, t->fd); + D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd); kick_transport(t); transport_unref(t); return 0; @@ -508,7 +524,7 @@ transport_read_action(int fd, struct tmsg* m) p += r; } else { if((r < 0) && (errno == EINTR)) continue; - D("transport_read_action: on fd %d, error %d: %s\n", + D("transport_read_action: on fd %d, error %d: %s\n", fd, errno, strerror(errno)); return -1; } @@ -530,7 +546,7 @@ transport_write_action(int fd, struct tmsg* m) p += r; } else { if((r < 0) && (errno == EINTR)) continue; - D("transport_write_action: on fd %d, error %d: %s\n", + D("transport_write_action: on fd %d, error %d: %s\n", fd, errno, strerror(errno)); return -1; } @@ -557,7 +573,7 @@ static void transport_registration_func(int _fd, unsigned ev, void *data) t = m.transport; if(m.action == 0){ - D("transport: %p removing and free'ing %d\n", t, t->transport_socket); + D("transport: %s removing and free'ing %d\n", t->serial, t->transport_socket); /* IMPORTANT: the remove closes one half of the ** socket pair. The close closes the other half. @@ -593,12 +609,11 @@ static void transport_registration_func(int _fd, unsigned ev, void *data) fatal_errno("cannot open transport socketpair"); } - D("transport: %p (%d,%d) starting\n", t, s[0], s[1]); + D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]); t->transport_socket = s[0]; t->fd = s[1]; - D("transport: %p install %d\n", t, t->transport_socket ); fdevent_install(&(t->transport_fde), t->transport_socket, transport_socket_events, @@ -653,7 +668,7 @@ static void register_transport(atransport *transport) tmsg m; m.transport = transport; m.action = 1; - D("transport: %p registered\n", transport); + D("transport: %s registered\n", transport->serial); if(transport_write_action(transport_registration_send, &m)) { fatal_errno("cannot write transport registration socket\n"); } @@ -664,7 +679,7 @@ static void remove_transport(atransport *transport) tmsg m; m.transport = transport; m.action = 0; - D("transport: %p removed\n", transport); + D("transport: %s removed\n", transport->serial); if(transport_write_action(transport_registration_send, &m)) { fatal_errno("cannot write transport registration socket\n"); } @@ -674,15 +689,16 @@ static void remove_transport(atransport *transport) static void transport_unref_locked(atransport *t) { t->ref_count--; - D("transport: %p R- (ref=%d)\n", t, t->ref_count); if (t->ref_count == 0) { - D("transport: %p kicking and closing\n", t); + D("transport: %s unref (kicking and closing)\n", t->serial); if (!t->kicked) { t->kicked = 1; t->kick(t); } t->close(t); remove_transport(t); + } else { + D("transport: %s unref (count=%d)\n", t->serial, t->ref_count); } } @@ -857,7 +873,13 @@ void close_usb_devices() void register_socket_transport(int s, const char *serial, int port, int local) { atransport *t = calloc(1, sizeof(atransport)); - D("transport: %p init'ing for socket %d, on port %d\n", t, s, port); + char buff[32]; + + if (!serial) { + snprintf(buff, sizeof buff, "T-%p", t); + serial = buff; + } + D("transport: %s init'ing for socket %d, on port %d\n", serial, s, port); if ( init_socket_transport(t, s, port, local) < 0 ) { adb_close(s); free(t); @@ -961,21 +983,26 @@ int readx(int fd, void *ptr, size_t len) #if ADB_TRACE int len0 = len; #endif - D("readx: %d %p %d\n", fd, ptr, (int)len); + D("readx: fd=%d wanted=%d\n", fd, (int)len); while(len > 0) { r = adb_read(fd, p, len); if(r > 0) { len -= r; p += r; } else { - D("readx: %d %d %s\n", fd, r, strerror(errno)); - if((r < 0) && (errno == EINTR)) continue; + if (r < 0) { + D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno)); + if (errno == EINTR) + continue; + } else { + D("readx: fd=%d disconnected\n", fd); + } return -1; } } #if ADB_TRACE - D("readx: %d ok: ", fd); + D("readx: fd=%d wanted=%d got=%d\n", fd, len0, len0 - len); dump_hex( ptr, len0 ); #endif return 0; @@ -987,7 +1014,7 @@ int writex(int fd, const void *ptr, size_t len) int r; #if ADB_TRACE - D("writex: %d %p %d: ", fd, ptr, (int)len); + D("writex: fd=%d len=%d: ", fd, (int)len); dump_hex( ptr, len ); #endif while(len > 0) { @@ -996,13 +1023,16 @@ int writex(int fd, const void *ptr, size_t len) len -= r; p += r; } else { - D("writex: %d %d %s\n", fd, r, strerror(errno)); - if((r < 0) && (errno == EINTR)) continue; + if (r < 0) { + D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno)); + if (errno == EINTR) + continue; + } else { + D("writex: fd=%d disconnected\n", fd); + } return -1; } } - - D("writex: %d ok\n", fd); return 0; } diff --git a/adb/transport_local.c b/adb/transport_local.c index 8dfc98d..4431ba7 100644 --- a/adb/transport_local.c +++ b/adb/transport_local.c @@ -25,7 +25,7 @@ #define TRACE_TAG TRACE_TRANSPORT #include "adb.h" -#ifdef __ppc__ +#ifdef HAVE_BIG_ENDIAN #define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) static inline void fix_endians(apacket *p) { @@ -61,7 +61,7 @@ static int remote_read(apacket *p, atransport *t) fix_endians(p); -#if 0 && defined __ppc__ +#if 0 && defined HAVE_BIG_ENDIAN D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic); #endif @@ -89,7 +89,7 @@ static int remote_write(apacket *p, atransport *t) fix_endians(p); -#if 0 && defined __ppc__ +#if 0 && defined HAVE_BIG_ENDIAN D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic); #endif diff --git a/adb/transport_usb.c b/adb/transport_usb.c index 2584163..ee6b637 100644 --- a/adb/transport_usb.c +++ b/adb/transport_usb.c @@ -27,8 +27,7 @@ #include "usb_vendors.h" #endif -/* XXX better define? */ -#ifdef __ppc__ +#ifdef HAVE_BIG_ENDIAN #define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) static inline void fix_endians(apacket *p) { diff --git a/adb/usb_linux.c b/adb/usb_linux.c index bb86813..cd61083 100644 --- a/adb/usb_linux.c +++ b/adb/usb_linux.c @@ -149,7 +149,7 @@ static void find_usb_device(const char *base, // DBGX("[ scanning %s ]\n", busname); while((de = readdir(devdir))) { - unsigned char devdesc[256]; + unsigned char devdesc[4096]; unsigned char* bufptr = devdesc; unsigned char* bufend; struct usb_device_descriptor* device; @@ -191,9 +191,8 @@ static void find_usb_device(const char *base, continue; } - vid = __le16_to_cpu(device->idVendor); - pid = __le16_to_cpu(device->idProduct); - pid = devdesc[10] | (devdesc[11] << 8); + vid = device->idVendor; + pid = device->idProduct; DBGX("[ %s is V:%04x P:%04x ]\n", devname, vid, pid); // should have config descriptor next @@ -617,7 +616,7 @@ static void register_device(const char *dev_name, ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE; ctrl.bRequest = USB_REQ_GET_DESCRIPTOR; ctrl.wValue = (USB_DT_STRING << 8) | serial_index; - ctrl.wIndex = languages[i]; + ctrl.wIndex = __le16_to_cpu(languages[i]); ctrl.wLength = sizeof(buffer); ctrl.data = buffer; @@ -627,7 +626,7 @@ static void register_device(const char *dev_name, // skip first word, and copy the rest to the serial string, changing shorts to bytes. result /= 2; for (i = 1; i < result; i++) - serial[i - 1] = buffer[i]; + serial[i - 1] = __le16_to_cpu(buffer[i]); serial[i - 1] = 0; break; } diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c index cbc2464..e0c6a47 100644 --- a/adb/usb_vendors.c +++ b/adb/usb_vendors.c @@ -69,6 +69,8 @@ #define VENDOR_ID_PANTECH 0x10A9 // Qualcomm's USB Vendor ID #define VENDOR_ID_QUALCOMM 0x05c6 +// On-The-Go-Video's USB Vendor ID +#define VENDOR_ID_OTGV 0x2257 // NEC's USB Vendor ID #define VENDOR_ID_NEC 0x0409 // Panasonic Mobile Communication's USB Vendor ID @@ -83,6 +85,24 @@ #define VENDOR_ID_ASUS 0x0b05 // Philips's USB Vendor ID #define VENDOR_ID_PHILIPS 0x0471 +// Texas Instruments's USB Vendor ID +#define VENDOR_ID_TI 0x0451 +// Funai's USB Vendor ID +#define VENDOR_ID_FUNAI 0x0F1C +// Gigabyte's USB Vendor ID +#define VENDOR_ID_GIGABYTE 0x0414 +// IRiver's USB Vendor ID +#define VENDOR_ID_IRIVER 0x2420 +// Compal's USB Vendor ID +#define VENDOR_ID_COMPAL 0x1219 +// T & A Mobile Phones' USB Vendor ID +#define VENDOR_ID_T_AND_A 0x1BBB +// LenovoMobile's USB Vendor ID +#define VENDOR_ID_LENOVOMOBILE 0x2006 +// Lenovo's USB Vendor ID +#define VENDOR_ID_LENOVO 0x17EF +// Vizio's USB Vendor ID +#define VENDOR_ID_VIZIO 0xE040 /** built-in vendor list */ @@ -104,6 +124,7 @@ int builtInVendorIds[] = { VENDOR_ID_KYOCERA, VENDOR_ID_PANTECH, VENDOR_ID_QUALCOMM, + VENDOR_ID_OTGV, VENDOR_ID_NEC, VENDOR_ID_PMC, VENDOR_ID_TOSHIBA, @@ -111,6 +132,15 @@ int builtInVendorIds[] = { VENDOR_ID_KT_TECH, VENDOR_ID_ASUS, VENDOR_ID_PHILIPS, + VENDOR_ID_TI, + VENDOR_ID_FUNAI, + VENDOR_ID_GIGABYTE, + VENDOR_ID_IRIVER, + VENDOR_ID_COMPAL, + VENDOR_ID_T_AND_A, + VENDOR_ID_LENOVOMOBILE, + VENDOR_ID_LENOVO, + VENDOR_ID_VIZIO, }; #define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0])) @@ -172,7 +202,7 @@ void usb_vendors_init(void) /* builds the path to the adb vendor id file. returns 0 if success */ int build_path(char* buff, size_t len, const char* format, const char* home) { - if (snprintf(buff, len, format, home, ANDROID_PATH, ANDROID_ADB_INI) >= len) { + if (snprintf(buff, len, format, home, ANDROID_PATH, ANDROID_ADB_INI) >= (signed)len) { return 1; } diff --git a/adb/usb_vendors.h b/adb/usb_vendors.h index 43790b9..cee23a1 100644 --- a/adb/usb_vendors.h +++ b/adb/usb_vendors.h @@ -22,4 +22,4 @@ extern unsigned vendorIdCount; void usb_vendors_init(void); -#endif
\ No newline at end of file +#endif diff --git a/debuggerd/debuggerd.c.orig b/debuggerd/debuggerd.c.orig deleted file mode 100644 index 0b3d9ba..0000000 --- a/debuggerd/debuggerd.c.orig +++ /dev/null @@ -1,911 +0,0 @@ -/* system/debuggerd/debuggerd.c -** -** Copyright 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. -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <signal.h> -#include <pthread.h> -#include <stdarg.h> -#include <fcntl.h> -#include <sys/types.h> -#include <dirent.h> - -#include <sys/ptrace.h> -#include <sys/wait.h> -#include <sys/exec_elf.h> -#include <sys/stat.h> - -#include <cutils/sockets.h> -#include <cutils/logd.h> -#include <cutils/sockets.h> -#include <cutils/properties.h> - -#include <linux/input.h> - -#include <private/android_filesystem_config.h> - -#include "utility.h" - -#ifdef WITH_VFP -#ifdef WITH_VFP_D32 -#define NUM_VFP_REGS 32 -#else -#define NUM_VFP_REGS 16 -#endif -#endif - -/* Main entry point to get the backtrace from the crashing process */ -extern int unwind_backtrace_with_ptrace(int tfd, pid_t pid, mapinfo *map, - unsigned int sp_list[], - int *frame0_pc_sane, - bool at_fault); - -static int logsocket = -1; - -#define ANDROID_LOG_INFO 4 - -/* Log information onto the tombstone */ -void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...) -{ - char buf[512]; - - va_list ap; - va_start(ap, fmt); - - if (tfd >= 0) { - int len; - vsnprintf(buf, sizeof(buf), fmt, ap); - len = strlen(buf); - if(tfd >= 0) write(tfd, buf, len); - } - - if (!in_tombstone_only) - __android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap); -} - -#define LOG(fmt...) _LOG(-1, 0, fmt) -#if 0 -#define XLOG(fmt...) _LOG(-1, 0, fmt) -#else -#define XLOG(fmt...) do {} while(0) -#endif - -// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so -// 012345678901234567890123456789012345678901234567890123456789 -// 0 1 2 3 4 5 - -mapinfo *parse_maps_line(char *line) -{ - mapinfo *mi; - int len = strlen(line); - - if(len < 1) return 0; - line[--len] = 0; - - if(len < 50) return 0; - if(line[20] != 'x') return 0; - - mi = malloc(sizeof(mapinfo) + (len - 47)); - if(mi == 0) return 0; - - mi->start = strtoul(line, 0, 16); - mi->end = strtoul(line + 9, 0, 16); - /* To be filled in parse_elf_info if the mapped section starts with - * elf_header - */ - mi->exidx_start = mi->exidx_end = 0; - mi->symbols = 0; - mi->next = 0; - strcpy(mi->name, line + 49); - - return mi; -} - -void dump_build_info(int tfd) -{ - char fingerprint[PROPERTY_VALUE_MAX]; - - property_get("ro.build.fingerprint", fingerprint, "unknown"); - - _LOG(tfd, false, "Build fingerprint: '%s'\n", fingerprint); -} - - -void dump_stack_and_code(int tfd, int pid, mapinfo *map, - int unwind_depth, unsigned int sp_list[], - bool at_fault) -{ - unsigned int sp, pc, p, end, data; - struct pt_regs r; - int sp_depth; - bool only_in_tombstone = !at_fault; - char code_buffer[80]; - - if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return; - sp = r.ARM_sp; - pc = r.ARM_pc; - - _LOG(tfd, only_in_tombstone, "\ncode around pc:\n"); - - end = p = pc & ~3; - p -= 32; - end += 32; - - /* Dump the code around PC as: - * addr contents - * 00008d34 fffffcd0 4c0eb530 b0934a0e 1c05447c - * 00008d44 f7ff18a0 490ced94 68035860 d0012b00 - */ - while (p <= end) { - int i; - - sprintf(code_buffer, "%08x ", p); - for (i = 0; i < 4; i++) { - data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); - sprintf(code_buffer + strlen(code_buffer), "%08x ", data); - p += 4; - } - _LOG(tfd, only_in_tombstone, "%s\n", code_buffer); - } - - if ((unsigned) r.ARM_lr != pc) { - _LOG(tfd, only_in_tombstone, "\ncode around lr:\n"); - - end = p = r.ARM_lr & ~3; - p -= 32; - end += 32; - - /* Dump the code around LR as: - * addr contents - * 00008d34 fffffcd0 4c0eb530 b0934a0e 1c05447c - * 00008d44 f7ff18a0 490ced94 68035860 d0012b00 - */ - while (p <= end) { - int i; - - sprintf(code_buffer, "%08x ", p); - for (i = 0; i < 4; i++) { - data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); - sprintf(code_buffer + strlen(code_buffer), "%08x ", data); - p += 4; - } - _LOG(tfd, only_in_tombstone, "%s\n", code_buffer); - } - } - - p = sp - 64; - p &= ~3; - if (unwind_depth != 0) { - if (unwind_depth < STACK_CONTENT_DEPTH) { - end = sp_list[unwind_depth-1]; - } - else { - end = sp_list[STACK_CONTENT_DEPTH-1]; - } - } - else { - end = sp | 0x000000ff; - end += 0xff; - } - - _LOG(tfd, only_in_tombstone, "\nstack:\n"); - - /* If the crash is due to PC == 0, there will be two frames that - * have identical SP value. - */ - if (sp_list[0] == sp_list[1]) { - sp_depth = 1; - } - else { - sp_depth = 0; - } - - while (p <= end) { - char *prompt; - char level[16]; - data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); - if (p == sp_list[sp_depth]) { - sprintf(level, "#%02d", sp_depth++); - prompt = level; - } - else { - prompt = " "; - } - - /* Print the stack content in the log for the first 3 frames. For the - * rest only print them in the tombstone file. - */ - _LOG(tfd, (sp_depth > 2) || only_in_tombstone, - "%s %08x %08x %s\n", prompt, p, data, - map_to_name(map, data, "")); - p += 4; - } - /* print another 64-byte of stack data after the last frame */ - - end = p+64; - while (p <= end) { - data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); - _LOG(tfd, (sp_depth > 2) || only_in_tombstone, - " %08x %08x %s\n", p, data, - map_to_name(map, data, "")); - p += 4; - } -} - -void dump_pc_and_lr(int tfd, int pid, mapinfo *map, int unwound_level, - bool at_fault) -{ - struct pt_regs r; - - if(ptrace(PTRACE_GETREGS, pid, 0, &r)) { - _LOG(tfd, !at_fault, "tid %d not responding!\n", pid); - return; - } - - if (unwound_level == 0) { - _LOG(tfd, !at_fault, " #%02d pc %08x %s\n", 0, r.ARM_pc, - map_to_name(map, r.ARM_pc, "<unknown>")); - } - _LOG(tfd, !at_fault, " #%02d lr %08x %s\n", 1, r.ARM_lr, - map_to_name(map, r.ARM_lr, "<unknown>")); -} - -void dump_registers(int tfd, int pid, bool at_fault) -{ - struct pt_regs r; - bool only_in_tombstone = !at_fault; - - if(ptrace(PTRACE_GETREGS, pid, 0, &r)) { - _LOG(tfd, only_in_tombstone, - "cannot get registers: %s\n", strerror(errno)); - return; - } - - _LOG(tfd, only_in_tombstone, " r0 %08x r1 %08x r2 %08x r3 %08x\n", - r.ARM_r0, r.ARM_r1, r.ARM_r2, r.ARM_r3); - _LOG(tfd, only_in_tombstone, " r4 %08x r5 %08x r6 %08x r7 %08x\n", - r.ARM_r4, r.ARM_r5, r.ARM_r6, r.ARM_r7); - _LOG(tfd, only_in_tombstone, " r8 %08x r9 %08x 10 %08x fp %08x\n", - r.ARM_r8, r.ARM_r9, r.ARM_r10, r.ARM_fp); - _LOG(tfd, only_in_tombstone, - " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", - r.ARM_ip, r.ARM_sp, r.ARM_lr, r.ARM_pc, r.ARM_cpsr); - -#ifdef WITH_VFP - struct user_vfp vfp_regs; - int i; - - if(ptrace(PTRACE_GETVFPREGS, pid, 0, &vfp_regs)) { - _LOG(tfd, only_in_tombstone, - "cannot get registers: %s\n", strerror(errno)); - return; - } - - for (i = 0; i < NUM_VFP_REGS; i += 2) { - _LOG(tfd, only_in_tombstone, - " d%-2d %016llx d%-2d %016llx\n", - i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]); - } - _LOG(tfd, only_in_tombstone, " scr %08lx\n\n", vfp_regs.fpscr); -#endif -} - -const char *get_signame(int sig) -{ - switch(sig) { - case SIGILL: return "SIGILL"; - case SIGABRT: return "SIGABRT"; - case SIGBUS: return "SIGBUS"; - case SIGFPE: return "SIGFPE"; - case SIGSEGV: return "SIGSEGV"; - case SIGSTKFLT: return "SIGSTKFLT"; - default: return "?"; - } -} - -const char *get_sigcode(int signo, int code) -{ - switch (signo) { - case SIGILL: - switch (code) { - case ILL_ILLOPC: return "ILL_ILLOPC"; - case ILL_ILLOPN: return "ILL_ILLOPN"; - case ILL_ILLADR: return "ILL_ILLADR"; - case ILL_ILLTRP: return "ILL_ILLTRP"; - case ILL_PRVOPC: return "ILL_PRVOPC"; - case ILL_PRVREG: return "ILL_PRVREG"; - case ILL_COPROC: return "ILL_COPROC"; - case ILL_BADSTK: return "ILL_BADSTK"; - } - break; - case SIGBUS: - switch (code) { - case BUS_ADRALN: return "BUS_ADRALN"; - case BUS_ADRERR: return "BUS_ADRERR"; - case BUS_OBJERR: return "BUS_OBJERR"; - } - break; - case SIGFPE: - switch (code) { - case FPE_INTDIV: return "FPE_INTDIV"; - case FPE_INTOVF: return "FPE_INTOVF"; - case FPE_FLTDIV: return "FPE_FLTDIV"; - case FPE_FLTOVF: return "FPE_FLTOVF"; - case FPE_FLTUND: return "FPE_FLTUND"; - case FPE_FLTRES: return "FPE_FLTRES"; - case FPE_FLTINV: return "FPE_FLTINV"; - case FPE_FLTSUB: return "FPE_FLTSUB"; - } - break; - case SIGSEGV: - switch (code) { - case SEGV_MAPERR: return "SEGV_MAPERR"; - case SEGV_ACCERR: return "SEGV_ACCERR"; - } - break; - } - return "?"; -} - -void dump_fault_addr(int tfd, int pid, int sig) -{ - siginfo_t si; - - memset(&si, 0, sizeof(si)); - if(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)){ - _LOG(tfd, false, "cannot get siginfo: %s\n", strerror(errno)); - } else { - _LOG(tfd, false, "signal %d (%s), code %d (%s), fault addr %08x\n", - sig, get_signame(sig), - si.si_code, get_sigcode(sig, si.si_code), - si.si_addr); - } -} - -void dump_crash_banner(int tfd, unsigned pid, unsigned tid, int sig) -{ - char data[1024]; - char *x = 0; - FILE *fp; - - sprintf(data, "/proc/%d/cmdline", pid); - fp = fopen(data, "r"); - if(fp) { - x = fgets(data, 1024, fp); - fclose(fp); - } - - _LOG(tfd, false, - "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); - dump_build_info(tfd); - _LOG(tfd, false, "pid: %d, tid: %d >>> %s <<<\n", - pid, tid, x ? x : "UNKNOWN"); - - if(sig) dump_fault_addr(tfd, tid, sig); -} - -static void parse_elf_info(mapinfo *milist, pid_t pid) -{ - mapinfo *mi; - for (mi = milist; mi != NULL; mi = mi->next) { - Elf32_Ehdr ehdr; - - memset(&ehdr, 0, sizeof(Elf32_Ehdr)); - /* Read in sizeof(Elf32_Ehdr) worth of data from the beginning of - * mapped section. - */ - get_remote_struct(pid, (void *) (mi->start), &ehdr, - sizeof(Elf32_Ehdr)); - /* Check if it has the matching magic words */ - if (IS_ELF(ehdr)) { - Elf32_Phdr phdr; - Elf32_Phdr *ptr; - int i; - - ptr = (Elf32_Phdr *) (mi->start + ehdr.e_phoff); - for (i = 0; i < ehdr.e_phnum; i++) { - /* Parse the program header */ - get_remote_struct(pid, (char *) (ptr+i), &phdr, - sizeof(Elf32_Phdr)); - /* Found a EXIDX segment? */ - if (phdr.p_type == PT_ARM_EXIDX) { - mi->exidx_start = mi->start + phdr.p_offset; - mi->exidx_end = mi->exidx_start + phdr.p_filesz; - break; - } - } - - /* Try to load symbols from this file */ - mi->symbols = symbol_table_create(mi->name); - } - } -} - -void dump_crash_report(int tfd, unsigned pid, unsigned tid, bool at_fault) -{ - char data[1024]; - FILE *fp; - mapinfo *milist = 0; - unsigned int sp_list[STACK_CONTENT_DEPTH]; - int stack_depth; - int frame0_pc_sane = 1; - - if (!at_fault) { - _LOG(tfd, true, - "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n"); - _LOG(tfd, true, "pid: %d, tid: %d\n", pid, tid); - } - - dump_registers(tfd, tid, at_fault); - - /* Clear stack pointer records */ - memset(sp_list, 0, sizeof(sp_list)); - - sprintf(data, "/proc/%d/maps", pid); - fp = fopen(data, "r"); - if(fp) { - while(fgets(data, 1024, fp)) { - mapinfo *mi = parse_maps_line(data); - if(mi) { - mi->next = milist; - milist = mi; - } - } - fclose(fp); - } - - parse_elf_info(milist, tid); - - /* If stack unwinder fails, use the default solution to dump the stack - * content. - */ - stack_depth = unwind_backtrace_with_ptrace(tfd, tid, milist, sp_list, - &frame0_pc_sane, at_fault); - - /* The stack unwinder should at least unwind two levels of stack. If less - * level is seen we make sure at lease pc and lr are dumped. - */ - if (stack_depth < 2) { - dump_pc_and_lr(tfd, tid, milist, stack_depth, at_fault); - } - - dump_stack_and_code(tfd, tid, milist, stack_depth, sp_list, at_fault); - - while(milist) { - mapinfo *next = milist->next; - symbol_table_free(milist->symbols); - free(milist); - milist = next; - } -} - -#define MAX_TOMBSTONES 10 - -#define typecheck(x,y) { \ - typeof(x) __dummy1; \ - typeof(y) __dummy2; \ - (void)(&__dummy1 == &__dummy2); } - -#define TOMBSTONE_DIR "/data/tombstones" - -/* - * find_and_open_tombstone - find an available tombstone slot, if any, of the - * form tombstone_XX where XX is 00 to MAX_TOMBSTONES-1, inclusive. If no - * file is available, we reuse the least-recently-modified file. - */ -static int find_and_open_tombstone(void) -{ - unsigned long mtime = ULONG_MAX; - struct stat sb; - char path[128]; - int fd, i, oldest = 0; - - /* - * XXX: Our stat.st_mtime isn't time_t. If it changes, as it probably ought - * to, our logic breaks. This check will generate a warning if that happens. - */ - typecheck(mtime, sb.st_mtime); - - /* - * In a single wolf-like pass, find an available slot and, in case none - * exist, find and record the least-recently-modified file. - */ - for (i = 0; i < MAX_TOMBSTONES; i++) { - snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", i); - - if (!stat(path, &sb)) { - if (sb.st_mtime < mtime) { - oldest = i; - mtime = sb.st_mtime; - } - continue; - } - if (errno != ENOENT) - continue; - - fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0600); - if (fd < 0) - continue; /* raced ? */ - - fchown(fd, AID_SYSTEM, AID_SYSTEM); - return fd; - } - - /* we didn't find an available file, so we clobber the oldest one */ - snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", oldest); - fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600); - fchown(fd, AID_SYSTEM, AID_SYSTEM); - - return fd; -} - -/* Return true if some thread is not detached cleanly */ -static bool dump_sibling_thread_report(int tfd, unsigned pid, unsigned tid) -{ - char task_path[1024]; - - sprintf(task_path, "/proc/%d/task", pid); - DIR *d; - struct dirent *de; - int need_cleanup = 0; - - d = opendir(task_path); - /* Bail early if cannot open the task directory */ - if (d == NULL) { - XLOG("Cannot open /proc/%d/task\n", pid); - return false; - } - while ((de = readdir(d)) != NULL) { - unsigned new_tid; - /* Ignore "." and ".." */ - if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) - continue; - new_tid = atoi(de->d_name); - /* The main thread at fault has been handled individually */ - if (new_tid == tid) - continue; - - /* Skip this thread if cannot ptrace it */ - if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) - continue; - - dump_crash_report(tfd, pid, new_tid, false); - need_cleanup |= ptrace(PTRACE_DETACH, new_tid, 0, 0); - } - closedir(d); - return need_cleanup != 0; -} - -/* Return true if some thread is not detached cleanly */ -static bool engrave_tombstone(unsigned pid, unsigned tid, int debug_uid, - int signal) -{ - int fd; - bool need_cleanup = false; - - mkdir(TOMBSTONE_DIR, 0755); - chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM); - - fd = find_and_open_tombstone(); - if (fd < 0) - return need_cleanup; - - dump_crash_banner(fd, pid, tid, signal); - dump_crash_report(fd, pid, tid, true); - /* - * If the user has requested to attach gdb, don't collect the per-thread - * information as it increases the chance to lose track of the process. - */ - if ((signed)pid > debug_uid) { - need_cleanup = dump_sibling_thread_report(fd, pid, tid); - } - - close(fd); - return need_cleanup; -} - -static int -write_string(const char* file, const char* string) -{ - int len; - int fd; - ssize_t amt; - fd = open(file, O_RDWR); - len = strlen(string); - if (fd < 0) - return -errno; - amt = write(fd, string, len); - close(fd); - return amt >= 0 ? 0 : -errno; -} - -static -void init_debug_led(void) -{ - // trout leds - write_string("/sys/class/leds/red/brightness", "0"); - write_string("/sys/class/leds/green/brightness", "0"); - write_string("/sys/class/leds/blue/brightness", "0"); - write_string("/sys/class/leds/red/device/blink", "0"); - // sardine leds - write_string("/sys/class/leds/left/cadence", "0,0"); -} - -static -void enable_debug_led(void) -{ - // trout leds - write_string("/sys/class/leds/red/brightness", "255"); - // sardine leds - write_string("/sys/class/leds/left/cadence", "1,0"); -} - -static -void disable_debug_led(void) -{ - // trout leds - write_string("/sys/class/leds/red/brightness", "0"); - // sardine leds - write_string("/sys/class/leds/left/cadence", "0,0"); -} - -extern int init_getevent(); -extern void uninit_getevent(); -extern int get_event(struct input_event* event, int timeout); - -static void wait_for_user_action(unsigned tid, struct ucred* cr) -{ - (void)tid; - /* First log a helpful message */ - LOG( "********************************************************\n" - "* Process %d has been suspended while crashing. To\n" - "* attach gdbserver for a gdb connection on port 5039:\n" - "*\n" - "* adb shell gdbserver :5039 --attach %d &\n" - "*\n" - "* Press HOME key to let the process continue crashing.\n" - "********************************************************\n", - cr->pid, cr->pid); - - /* wait for HOME key (TODO: something useful for devices w/o HOME key) */ - if (init_getevent() == 0) { - int ms = 1200 / 10; - int dit = 1; - int dah = 3*dit; - int _ = -dit; - int ___ = 3*_; - int _______ = 7*_; - const signed char codes[] = { - dit,_,dit,_,dit,___,dah,_,dah,_,dah,___,dit,_,dit,_,dit,_______ - }; - size_t s = 0; - struct input_event e; - int home = 0; - init_debug_led(); - enable_debug_led(); - do { - int timeout = abs((int)(codes[s])) * ms; - int res = get_event(&e, timeout); - if (res == 0) { - if (e.type==EV_KEY && e.code==KEY_HOME && e.value==0) - home = 1; - } else if (res == 1) { - if (++s >= sizeof(codes)/sizeof(*codes)) - s = 0; - if (codes[s] > 0) { - enable_debug_led(); - } else { - disable_debug_led(); - } - } - } while (!home); - uninit_getevent(); - } - - /* don't forget to turn debug led off */ - disable_debug_led(); - - /* close filedescriptor */ - LOG("debuggerd resuming process %d", cr->pid); - } - -static void handle_crashing_process(int fd) -{ - char buf[64]; - struct stat s; - unsigned tid; - struct ucred cr; - int n, len, status; - int tid_attach_status = -1; - unsigned retry = 30; - bool need_cleanup = false; - - char value[PROPERTY_VALUE_MAX]; - property_get("debug.db.uid", value, "-1"); - int debug_uid = atoi(value); - - XLOG("handle_crashing_process(%d)\n", fd); - - len = sizeof(cr); - n = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len); - if(n != 0) { - LOG("cannot get credentials\n"); - goto done; - } - - XLOG("reading tid\n"); - fcntl(fd, F_SETFL, O_NONBLOCK); - while((n = read(fd, &tid, sizeof(unsigned))) != sizeof(unsigned)) { - if(errno == EINTR) continue; - if(errno == EWOULDBLOCK) { - if(retry-- > 0) { - usleep(100 * 1000); - continue; - } - LOG("timed out reading tid\n"); - goto done; - } - LOG("read failure? %s\n", strerror(errno)); - goto done; - } - - sprintf(buf,"/proc/%d/task/%d", cr.pid, tid); - if(stat(buf, &s)) { - LOG("tid %d does not exist in pid %d. ignoring debug request\n", - tid, cr.pid); - close(fd); - return; - } - - XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n", cr.pid, cr.uid, cr.gid, tid); - - tid_attach_status = ptrace(PTRACE_ATTACH, tid, 0, 0); - if(tid_attach_status < 0) { - LOG("ptrace attach failed: %s\n", strerror(errno)); - goto done; - } - - close(fd); - fd = -1; - - for(;;) { - n = waitpid(tid, &status, __WALL); - - if(n < 0) { - if(errno == EAGAIN) continue; - LOG("waitpid failed: %s\n", strerror(errno)); - goto done; - } - - XLOG("waitpid: n=%d status=%08x\n", n, status); - - if(WIFSTOPPED(status)){ - n = WSTOPSIG(status); - switch(n) { - case SIGSTOP: - XLOG("stopped -- continuing\n"); - n = ptrace(PTRACE_CONT, tid, 0, 0); - if(n) { - LOG("ptrace failed: %s\n", strerror(errno)); - goto done; - } - continue; - - case SIGILL: - case SIGABRT: - case SIGBUS: - case SIGFPE: - case SIGSEGV: - case SIGSTKFLT: { - XLOG("stopped -- fatal signal\n"); - need_cleanup = engrave_tombstone(cr.pid, tid, debug_uid, n); - kill(tid, SIGSTOP); - goto done; - } - - default: - XLOG("stopped -- unexpected signal\n"); - goto done; - } - } else { - XLOG("unexpected waitpid response\n"); - goto done; - } - } - -done: - XLOG("detaching\n"); - - /* stop the process so we can debug */ - kill(cr.pid, SIGSTOP); - - /* - * If a thread has been attached by ptrace, make sure it is detached - * successfully otherwise we will get a zombie. - */ - if (tid_attach_status == 0) { - int detach_status; - /* detach so we can attach gdbserver */ - detach_status = ptrace(PTRACE_DETACH, tid, 0, 0); - need_cleanup |= (detach_status != 0); - } - - /* - * if debug.db.uid is set, its value indicates if we should wait - * for user action for the crashing process. - * in this case, we log a message and turn the debug LED on - * waiting for a gdb connection (for instance) - */ - - if ((signed)cr.uid <= debug_uid) { - wait_for_user_action(tid, &cr); - } - - /* resume stopped process (so it can crash in peace) */ - kill(cr.pid, SIGCONT); - - if (need_cleanup) { - LOG("debuggerd committing suicide to free the zombie!\n"); - kill(getpid(), SIGKILL); - } - - if(fd != -1) close(fd); -} - -int main() -{ - int s; - struct sigaction act; - - logsocket = socket_local_client("logd", - ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM); - if(logsocket < 0) { - logsocket = -1; - } else { - fcntl(logsocket, F_SETFD, FD_CLOEXEC); - } - - act.sa_handler = SIG_DFL; - sigemptyset(&act.sa_mask); - sigaddset(&act.sa_mask,SIGCHLD); - act.sa_flags = SA_NOCLDWAIT; - sigaction(SIGCHLD, &act, 0); - - s = socket_local_server("android:debuggerd", - ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); - if(s < 0) return -1; - fcntl(s, F_SETFD, FD_CLOEXEC); - - LOG("debuggerd: " __DATE__ " " __TIME__ "\n"); - - for(;;) { - struct sockaddr addr; - socklen_t alen; - int fd; - - alen = sizeof(addr); - fd = accept(s, &addr, &alen); - if(fd < 0) continue; - - fcntl(fd, F_SETFD, FD_CLOEXEC); - - handle_crashing_process(fd); - } - return 0; -} diff --git a/debuggerd/symbol_table.c b/debuggerd/symbol_table.c index e76df33..fd008fe 100644 --- a/debuggerd/symbol_table.c +++ b/debuggerd/symbol_table.c @@ -94,17 +94,26 @@ struct symbol_table *symbol_table_create(const char *filename) table->name = strdup(filename); table->num_symbols = 0; - Elf32_Sym *dynsyms = (Elf32_Sym*)(base + shdr[dynsym_idx].sh_offset); - Elf32_Sym *syms = (Elf32_Sym*)(base + shdr[sym_idx].sh_offset); + Elf32_Sym *dynsyms = NULL; + Elf32_Sym *syms = NULL; + int dynnumsyms = 0; + int numsyms = 0; + char *dynstr = NULL; + char *str = NULL; - int dynnumsyms = shdr[dynsym_idx].sh_size / shdr[dynsym_idx].sh_entsize; - int numsyms = shdr[sym_idx].sh_size / shdr[sym_idx].sh_entsize; - - int dynstr_idx = shdr[dynsym_idx].sh_link; - int str_idx = shdr[sym_idx].sh_link; + if (dynsym_idx != -1) { + dynsyms = (Elf32_Sym*)(base + shdr[dynsym_idx].sh_offset); + dynnumsyms = shdr[dynsym_idx].sh_size / shdr[dynsym_idx].sh_entsize; + int dynstr_idx = shdr[dynsym_idx].sh_link; + dynstr = base + shdr[dynstr_idx].sh_offset; + } - char *dynstr = base + shdr[dynstr_idx].sh_offset; - char *str = base + shdr[str_idx].sh_offset; + if (sym_idx != -1) { + syms = (Elf32_Sym*)(base + shdr[sym_idx].sh_offset); + numsyms = shdr[sym_idx].sh_size / shdr[sym_idx].sh_entsize; + int str_idx = shdr[sym_idx].sh_link; + str = base + shdr[str_idx].sh_offset; + } int symbol_count = 0; int dynsymbol_count = 0; @@ -134,7 +143,7 @@ struct symbol_table *symbol_table_create(const char *filename) } // Now, create an entry in our symbol table structure for each symbol... - table->num_symbols += symbol_count + dynsymbol_count;; + table->num_symbols += symbol_count + dynsymbol_count; table->symbols = malloc(table->num_symbols * sizeof(struct symbol)); if(!table->symbols) { free(table); diff --git a/debuggerd/x86/unwind.c b/debuggerd/x86/unwind.c index 8f84e01..0a7f04c 100644 --- a/debuggerd/x86/unwind.c +++ b/debuggerd/x86/unwind.c @@ -24,7 +24,6 @@ int unwind_backtrace_with_ptrace_x86(int tfd, pid_t pid, mapinfo *map, //ebp==0, it indicates that the stack is poped to the bottom or there is no stack at all. while (ebp) { - _LOG(tfd, !at_fault, "#0%d ",stack_level); mi = pc_to_mapinfo(map, eip, &rel_pc); /* See if we can determine what symbol this stack frame resides in */ @@ -32,9 +31,11 @@ int unwind_backtrace_with_ptrace_x86(int tfd, pid_t pid, mapinfo *map, sym = symbol_table_lookup(mi->symbols, rel_pc); } if (sym) { - _LOG(tfd, !at_fault, " eip: %08x %s (%s)\n", eip, mi ? mi->name : "", sym->name); + _LOG(tfd, !at_fault, " #%02d eip: %08x %s (%s)\n", + stack_level, eip, mi ? mi->name : "", sym->name); } else { - _LOG(tfd, !at_fault, " eip: %08x %s\n", eip, mi ? mi->name : ""); + _LOG(tfd, !at_fault, " #%02d eip: %08x %s\n", + stack_level, eip, mi ? mi->name : ""); } stack_level++; @@ -49,7 +50,6 @@ int unwind_backtrace_with_ptrace_x86(int tfd, pid_t pid, mapinfo *map, if (ebp) _LOG(tfd, !at_fault, "stack: \n"); while (ebp) { - _LOG(tfd, !at_fault, "#0%d \n",stack_level); stack_ptr = cur_sp; while((int)(ebp - stack_ptr) >= 0) { stack_content = ptrace(PTRACE_PEEKTEXT, pid, (void*)stack_ptr, NULL); @@ -60,10 +60,11 @@ int unwind_backtrace_with_ptrace_x86(int tfd, pid_t pid, mapinfo *map, sym = symbol_table_lookup(mi->symbols, rel_pc); } if (sym) { - _LOG(tfd, !at_fault, " %08x %08x %s (%s)\n", - stack_ptr, stack_content, mi ? mi->name : "", sym->name); + _LOG(tfd, !at_fault, " #%02d %08x %08x %s (%s)\n", + stack_level, stack_ptr, stack_content, mi ? mi->name : "", sym->name); } else { - _LOG(tfd, !at_fault, " %08x %08x %s\n", stack_ptr, stack_content, mi ? mi->name : ""); + _LOG(tfd, !at_fault, " #%02d %08x %08x %s\n", + stack_level, stack_ptr, stack_content, mi ? mi->name : ""); } stack_ptr = stack_ptr + 4; diff --git a/fastboot/engine.c b/fastboot/engine.c index 8ba202c..48073ee 100644 --- a/fastboot/engine.c +++ b/fastboot/engine.c @@ -97,14 +97,20 @@ static Action *queue_action(unsigned op, const char *fmt, ...) { Action *a; va_list ap; + size_t cmdsize; a = calloc(1, sizeof(Action)); if (a == 0) die("out of memory"); va_start(ap, fmt); - vsprintf(a->cmd, fmt, ap); + cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap); va_end(ap); + if (cmdsize >= sizeof(a->cmd)) { + free(a); + die("Command length (%d) exceeds maximum size (%d)", cmdsize, sizeof(a->cmd)); + } + if (action_last) { action_last->next = a; } else { diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c index f3bfbeba..14048a1 100644 --- a/fastboot/fastboot.c +++ b/fastboot/fastboot.c @@ -223,6 +223,7 @@ void usage(void) " boot <kernel> [ <ramdisk> ] download and boot kernel\n" " flash:raw boot <kernel> [ <ramdisk> ] create bootimage and flash it\n" " devices list all connected devices\n" + " continue continue with autoboot\n" " reboot reboot device normally\n" " reboot-bootloader reboot device into bootloader\n" "\n" diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c index 78b7b98..1ba87e6 100644 --- a/fastboot/usb_linux.c +++ b/fastboot/usb_linux.c @@ -61,6 +61,11 @@ #define DBG1(x...) #endif +/* The max bulk size for linux is 16384 which is defined + * in drivers/usb/core/devio.c. + */ +#define MAX_USBFS_BULK_SIZE (16 * 1024) + struct usb_handle { char fname[64]; @@ -289,7 +294,7 @@ int usb_write(usb_handle *h, const void *_data, int len) while(len > 0) { int xfer; - xfer = (len > 4096) ? 4096 : len; + xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len; bulk.ep = h->ep_out; bulk.len = xfer; @@ -323,7 +328,7 @@ int usb_read(usb_handle *h, void *_data, int len) } while(len > 0) { - int xfer = (len > 4096) ? 4096 : len; + int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len; bulk.ep = h->ep_in; bulk.len = xfer; diff --git a/fastboot/usb_windows.c b/fastboot/usb_windows.c index 54008a4..1050293 100644 --- a/fastboot/usb_windows.c +++ b/fastboot/usb_windows.c @@ -42,6 +42,7 @@ #define DBG(x...) #endif +#define MAX_USBFS_BULK_SIZE (1024 * 1024) /** Structure usb_handle describes our connection to the usb device via AdbWinApi.dll. This structure is returned from usb_open() routine and @@ -160,7 +161,7 @@ int usb_write(usb_handle* handle, const void* data, int len) { if (NULL != handle) { // Perform write while(len > 0) { - int xfer = (len > 4096) ? 4096 : len; + int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len; ret = AdbWriteEndpointSync(handle->adb_write_pipe, (void*)data, (unsigned long)xfer, @@ -200,7 +201,7 @@ int usb_read(usb_handle *handle, void* data, int len) { DBG("usb_read %d\n", len); if (NULL != handle) { while (1) { - int xfer = (len > 4096) ? 4096 : len; + int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len; ret = AdbReadEndpointSync(handle->adb_read_pipe, (void*)data, diff --git a/include/arch/darwin-x86/AndroidConfig.h b/include/arch/darwin-x86/AndroidConfig.h index 2bb44c6..9914bd5 100644 --- a/include/arch/darwin-x86/AndroidConfig.h +++ b/include/arch/darwin-x86/AndroidConfig.h @@ -300,4 +300,12 @@ */ #define HAVE_PRINTF_ZD 1 +/* + * We need to open binary files using O_BINARY on Windows. + * Most systems lack (and actually don't need) this flag. + */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + #endif /*_ANDROID_CONFIG_H*/ diff --git a/include/arch/freebsd-x86/AndroidConfig.h b/include/arch/freebsd-x86/AndroidConfig.h index 992b689..ed5af59 100644 --- a/include/arch/freebsd-x86/AndroidConfig.h +++ b/include/arch/freebsd-x86/AndroidConfig.h @@ -358,4 +358,12 @@ */ #define HAVE_PRINTF_ZD 1 +/* + * We need to open binary files using O_BINARY on Windows. + * Most systems lack (and actually don't need) this flag. + */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + #endif /*_ANDROID_CONFIG_H*/ diff --git a/include/arch/linux-arm/AndroidConfig.h b/include/arch/linux-arm/AndroidConfig.h index 5b7ccee..c70618d 100644 --- a/include/arch/linux-arm/AndroidConfig.h +++ b/include/arch/linux-arm/AndroidConfig.h @@ -354,4 +354,12 @@ */ #define HAVE_PRINTF_ZD 1 +/* + * We need to open binary files using O_BINARY on Windows. + * Most systems lack (and actually don't need) this flag. + */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + #endif /* _ANDROID_CONFIG_H */ diff --git a/include/arch/linux-ppc/AndroidConfig.h b/include/arch/linux-ppc/AndroidConfig.h new file mode 100644 index 0000000..91af629 --- /dev/null +++ b/include/arch/linux-ppc/AndroidConfig.h @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2010 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. + */ + +/* + * Android config -- "Linux". Used for desktop ppc Linux. + */ +#ifndef _ANDROID_CONFIG_H +#define _ANDROID_CONFIG_H + +/* + * =========================================================================== + * !!! IMPORTANT !!! + * =========================================================================== + * + * This file is included by ALL C/C++ source files. Don't put anything in + * here unless you are absolutely certain it can't go anywhere else. + * + * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//" + * comments. + */ + +/* + * Threading model. Choose one: + * + * HAVE_PTHREADS - use the pthreads library. + * HAVE_WIN32_THREADS - use Win32 thread primitives. + * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX + */ +#define HAVE_PTHREADS + +/* + * Do we have the futex syscall? + */ + +#define HAVE_FUTEX + +/* + * Process creation model. Choose one: + * + * HAVE_FORKEXEC - use fork() and exec() + * HAVE_WIN32_PROC - use CreateProcess() + */ +#define HAVE_FORKEXEC + +/* + * Process out-of-memory adjustment. Set if running on Linux, + * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory + * badness adjustment. + */ +#define HAVE_OOM_ADJ + +/* + * IPC model. Choose one: + * + * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget). + * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap). + * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping). + * HAVE_ANDROID_IPC - use Android versions (?, mmap). + */ +#define HAVE_SYSV_IPC + +/* + * Memory-mapping model. Choose one: + * + * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h + * HAVE_WIN32_FILEMAP - use Win32 filemaps + */ +#define HAVE_POSIX_FILEMAP + +/* + * Define this if you have <termio.h> + */ +#define HAVE_TERMIO_H + +/* + * Define this if you have <sys/sendfile.h> + */ +#define HAVE_SYS_SENDFILE_H 1 + +/* + * Define this if you build against MSVCRT.DLL + */ +/* #define HAVE_MS_C_RUNTIME */ + +/* + * Define this if you have sys/uio.h + */ +#define HAVE_SYS_UIO_H + +/* + * Define this if your platforms implements symbolic links + * in its filesystems + */ +#define HAVE_SYMLINKS + +/* + * Define this if we have localtime_r(). + */ +#define HAVE_LOCALTIME_R + +/* + * Define this if we have gethostbyname_r(). + */ +#define HAVE_GETHOSTBYNAME_R + +/* + * Define this if we have ioctl(). + */ +#define HAVE_IOCTL + +/* + * Define this if we want to use WinSock. + */ +/* #define HAVE_WINSOCK */ + +/* + * Define this if have clock_gettime() and friends + * + * Desktop Linux has this in librt, but it's broken in goobuntu, yielding + * mildly or wildly inaccurate results. + */ +/*#define HAVE_POSIX_CLOCKS*/ + +/* + * Define this if we have pthread_cond_timedwait_monotonic() and + * clock_gettime(CLOCK_MONOTONIC). + */ +/* #define HAVE_TIMEDWAIT_MONOTONIC */ + +/* + * Define this if we have linux style epoll() + */ +#define HAVE_EPOLL + +/* + * Endianness of the target machine. Choose one: + * + * HAVE_ENDIAN_H -- have endian.h header we can include. + * HAVE_LITTLE_ENDIAN -- we are little endian. + * HAVE_BIG_ENDIAN -- we are big endian. + */ +#define HAVE_ENDIAN_H +#define HAVE_BIG_ENDIAN + +/* + * We need to choose between 32-bit and 64-bit off_t. All of our code should + * agree on the same size. For desktop systems, use 64-bit values, + * because some of our libraries (e.g. wxWidgets) expect to be built that way. + */ +#define _FILE_OFFSET_BITS 64 +#define _LARGEFILE_SOURCE 1 + +/* + * Defined if we have the backtrace() call for retrieving a stack trace. + * Needed for CallStack to operate; if not defined, CallStack is + * non-functional. + */ +#define HAVE_BACKTRACE 1 + +/* + * Defined if we have the dladdr() call for retrieving the symbol associated + * with a memory address. If not defined, stack crawls will not have symbolic + * information. + */ +#define HAVE_DLADDR 1 + +/* + * Defined if we have the cxxabi.h header for demangling C++ symbols. If + * not defined, stack crawls will be displayed with raw mangled symbols + */ +#define HAVE_CXXABI 0 + +/* + * Defined if we have the gettid() system call. + */ +/* #define HAVE_GETTID */ + +/* + * Defined if we have the sched_setscheduler() call + */ +#define HAVE_SCHED_SETSCHEDULER + +/* + * Add any extra platform-specific defines here. + */ + +/* + * Define if we have <malloc.h> header + */ +#define HAVE_MALLOC_H + +/* + * Define if we have Linux-style non-filesystem Unix Domain Sockets + */ + +/* + * What CPU architecture does this platform use? + */ +#define ARCH_PPC + + +/* + * Define if we have Linux's inotify in <sys/inotify.h>. + */ +/*#define HAVE_INOTIFY 1*/ + +/* + * Define if we have madvise() in <sys/mman.h> + */ +#define HAVE_MADVISE 1 + +/* + * Define if tm struct has tm_gmtoff field + */ +#define HAVE_TM_GMTOFF 1 + +/* + * Define if dirent struct has d_type field + */ +#define HAVE_DIRENT_D_TYPE 1 + +/* + * Define if libc includes Android system properties implementation. + */ +/* #define HAVE_LIBC_SYSTEM_PROPERTIES */ + +/* + * Define if system provides a system property server (should be + * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES). + */ +#define HAVE_SYSTEM_PROPERTY_SERVER + +/* + * sprintf() format string for shared library naming. + */ +#define OS_SHARED_LIB_FORMAT_STR "lib%s.so" + +/* + * type for the third argument to mincore(). + */ +#define MINCORE_POINTER_TYPE unsigned char * + +/* + * Do we have the sigaction flag SA_NOCLDWAIT? + */ +#define HAVE_SA_NOCLDWAIT + +/* + * The default path separator for the platform + */ +#define OS_PATH_SEPARATOR '/' + +/* + * Is the filesystem case sensitive? + */ +#define OS_CASE_SENSITIVE + +/* + * Define if <sys/socket.h> exists. + */ +#define HAVE_SYS_SOCKET_H 1 + +/* + * Define if the strlcpy() function exists on the system. + */ +/* #define HAVE_STRLCPY 1 */ + +/* + * Define if the open_memstream() function exists on the system. + */ +#define HAVE_OPEN_MEMSTREAM 1 + +/* + * Define if the BSD funopen() function exists on the system. + */ +/* #define HAVE_FUNOPEN 1 */ + +/* + * Define if prctl() exists + */ +#define HAVE_PRCTL 1 + +/* + * Define if writev() exists + */ +#define HAVE_WRITEV 1 + +/* + * Define if <stdint.h> exists. + */ +#define HAVE_STDINT_H 1 + +/* + * Define if <stdbool.h> exists. + */ +#define HAVE_STDBOOL_H 1 + +/* + * Define if <sched.h> exists. + */ +#define HAVE_SCHED_H 1 + +/* + * Define if pread() exists + */ +#define HAVE_PREAD 1 + +/* + * We need to open binary files using O_BINARY on Windows. + * Most systems lack (and actually don't need) this flag. + */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#endif /*_ANDROID_CONFIG_H*/ diff --git a/include/arch/linux-sh/AndroidConfig.h b/include/arch/linux-sh/AndroidConfig.h index 0dd7b3b..622ca50 100644 --- a/include/arch/linux-sh/AndroidConfig.h +++ b/include/arch/linux-sh/AndroidConfig.h @@ -361,4 +361,12 @@ */ #define HAVE_PRINTF_ZD 1 +/* + * We need to open binary files using O_BINARY on Windows. + * Most systems lack (and actually don't need) this flag. + */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + #endif /* _ANDROID_CONFIG_H */ diff --git a/include/arch/linux-x86/AndroidConfig.h b/include/arch/linux-x86/AndroidConfig.h index 24f6ccc..26dcf1f 100644 --- a/include/arch/linux-x86/AndroidConfig.h +++ b/include/arch/linux-x86/AndroidConfig.h @@ -328,4 +328,12 @@ */ #define HAVE_PRINTF_ZD 1 +/* + * We need to open binary files using O_BINARY on Windows. + * Most systems lack (and actually don't need) this flag. + */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + #endif /*_ANDROID_CONFIG_H*/ diff --git a/include/arch/target_linux-x86/AndroidConfig.h b/include/arch/target_linux-x86/AndroidConfig.h index d6ce3f2..9b357d9 100644 --- a/include/arch/target_linux-x86/AndroidConfig.h +++ b/include/arch/target_linux-x86/AndroidConfig.h @@ -345,4 +345,12 @@ */ #define HAVE_PRINTF_ZD 1 +/* + * We need to open binary files using O_BINARY on Windows. + * Most systems lack (and actually don't need) this flag. + */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + #endif /* _ANDROID_CONFIG_H */ diff --git a/include/arch/windows/AndroidConfig.h b/include/arch/windows/AndroidConfig.h index f0bf56f..17c84c7 100644 --- a/include/arch/windows/AndroidConfig.h +++ b/include/arch/windows/AndroidConfig.h @@ -333,4 +333,10 @@ */ /* #define HAVE_PRINTF_ZD 1 */ +/* + * We need to open binary files using O_BINARY on Windows. + * We don't define it on Windows since it is part of the io headers. + */ +/* #define O_BINARY 0 */ + #endif /*_ANDROID_CONFIG_H*/ diff --git a/include/cutils/bitops.h b/include/cutils/bitops.h new file mode 100644 index 0000000..1b3b762 --- /dev/null +++ b/include/cutils/bitops.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef __CUTILS_BITOPS_H +#define __CUTILS_BITOPS_H + +#include <sys/cdefs.h> + +__BEGIN_DECLS + +static inline int popcount(unsigned int x) +{ + return __builtin_popcount(x); +} + +static inline int popcountl(unsigned long x) +{ + return __builtin_popcountl(x); +} + +static inline int popcountll(unsigned long long x) +{ + return __builtin_popcountll(x); +} + +__END_DECLS + +#endif /* __CUTILS_BITOPS_H */ diff --git a/include/cutils/log.h b/include/cutils/log.h index dd47c35..f602017 100644 --- a/include/cutils/log.h +++ b/include/cutils/log.h @@ -291,11 +291,11 @@ extern "C" { */ #define LOG_ALWAYS_FATAL_IF(cond, ...) \ ( (CONDITION(cond)) \ - ? ((void)android_printAssert(#cond, LOG_TAG, __VA_ARGS__)) \ + ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \ : (void)0 ) #define LOG_ALWAYS_FATAL(...) \ - ( ((void)android_printAssert(NULL, LOG_TAG, __VA_ARGS__)) ) + ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) ) /* * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that @@ -308,7 +308,7 @@ extern "C" { #else -#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, __VA_ARGS__) +#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__) #define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__) #endif @@ -317,7 +317,7 @@ extern "C" { * Assertion that generates a log message when the assertion fails. * Stripped out of release builds. Uses the current LOG_TAG. */ -#define LOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), __VA_ARGS__) +#define LOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__) //#define LOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond) // --------------------------------------------------------------------- @@ -403,8 +403,24 @@ typedef enum { #define android_vprintLog(prio, cond, tag, fmt...) \ __android_log_vprint(prio, tag, fmt) +/* XXX Macros to work around syntax errors in places where format string + * arg is not passed to LOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF + * (happens only in debug builds). + */ + +/* Returns 2nd arg. Used to substitute default value if caller's vararg list + * is empty. + */ +#define __android_second(dummy, second, ...) second + +/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise + * returns nothing. + */ +#define __android_rest(first, ...) , ## __VA_ARGS__ + #define android_printAssert(cond, tag, fmt...) \ - __android_log_assert(cond, tag, fmt) + __android_log_assert(cond, tag, \ + __android_second(0, ## fmt, NULL) __android_rest(fmt)) #define android_writeLog(prio, tag, text) \ __android_log_write(prio, tag, text) @@ -413,7 +429,7 @@ typedef enum { __android_log_bwrite(tag, payload, len) #define android_btWriteLog(tag, type, payload, len) \ __android_log_btwrite(tag, type, payload, len) - + // TODO: remove these prototypes and their users #define android_testLog(prio, tag) (1) #define android_writevLog(vec,num) do{}while(0) diff --git a/include/cutils/qtaguid.h b/include/cutils/qtaguid.h new file mode 100644 index 0000000..e6d61e6 --- /dev/null +++ b/include/cutils/qtaguid.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#ifndef __CUTILS_QTAGUID_H +#define __CUTILS_QTAGUID_H + +#include <stdint.h> +#include <sys/types.h> +#include <unistd.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Set tags (and owning UIDs) for network sockets. +*/ +extern int qtaguid_tagSocket(int sockfd, int tag, uid_t uid); + +/* + * Untag a network socket before closing. +*/ +extern int qtaguid_untagSocket(int sockfd); + +#ifdef __cplusplus +} +#endif + +#endif /* __CUTILS_QTAG_UID_H */ diff --git a/include/cutils/str_parms.h b/include/cutils/str_parms.h new file mode 100644 index 0000000..247c996 --- /dev/null +++ b/include/cutils/str_parms.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#ifndef __CUTILS_STR_PARMS_H +#define __CUTILS_STR_PARMS_H + +#include <stdint.h> + +struct str_parms; + +struct str_parms *str_parms_create(void); +struct str_parms *str_parms_create_str(const char *_string); +void str_parms_destroy(struct str_parms *str_parms); + +void str_parms_del(struct str_parms *str_parms, const char *key); + +int str_parms_add_str(struct str_parms *str_parms, const char *key, + const char *value); +int str_parms_add_int(struct str_parms *str_parms, const char *key, int value); + +int str_parms_add_float(struct str_parms *str_parms, const char *key, + float value); + +int str_parms_get_str(struct str_parms *str_parms, const char *key, + char *out_val, int len); +int str_parms_get_int(struct str_parms *str_parms, const char *key, + int *out_val); +int str_parms_get_float(struct str_parms *str_parms, const char *key, + float *out_val); + +char *str_parms_to_str(struct str_parms *str_parms); + +/* debug */ +void str_parms_dump(struct str_parms *str_parms); + +#endif /* __CUTILS_STR_PARMS_H */ diff --git a/include/cutils/uevent.h b/include/cutils/uevent.h new file mode 100644 index 0000000..587149c --- /dev/null +++ b/include/cutils/uevent.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef __CUTILS_UEVENT_H +#define __CUTILS_UEVENT_H + +#include <sys/socket.h> + +#ifdef __cplusplus +extern "C" { +#endif + +ssize_t uevent_checked_recv(int socket, void *buffer, size_t length); + +#ifdef __cplusplus +} +#endif + +#endif /* __CUTILS_UEVENT_H */ diff --git a/include/netutils/dhcp.h b/include/netutils/dhcp.h new file mode 100644 index 0000000..96798c5 --- /dev/null +++ b/include/netutils/dhcp.h @@ -0,0 +1,40 @@ +/* + * Copyright 2010, 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 _NETUTILS_DHCP_H_ +#define _NETUTILS_DHCP_H_ + +#include <sys/cdefs.h> +#include <arpa/inet.h> + +__BEGIN_DECLS + +extern int do_dhcp(char *iname); +extern int dhcp_do_request(const char *ifname, + in_addr_t *ipaddr, + in_addr_t *gateway, + in_addr_t *mask, + in_addr_t *dns1, + in_addr_t *dns2, + in_addr_t *server, + uint32_t *lease); +extern int dhcp_stop(const char *ifname); +extern int dhcp_release_lease(const char *ifname); +extern char *dhcp_get_errmsg(); + +__END_DECLS + +#endif /* _NETUTILS_DHCP_H_ */ diff --git a/include/netutils/ifc.h b/include/netutils/ifc.h new file mode 100644 index 0000000..e245262 --- /dev/null +++ b/include/netutils/ifc.h @@ -0,0 +1,64 @@ +/* + * Copyright 2008, 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 _NETUTILS_IFC_H_ +#define _NETUTILS_IFC_H_ + +#include <sys/cdefs.h> +#include <arpa/inet.h> + +__BEGIN_DECLS + +extern int ifc_init(void); +extern void ifc_close(void); + +extern int ifc_get_ifindex(const char *name, int *if_indexp); +extern int ifc_get_hwaddr(const char *name, void *ptr); + +extern int ifc_up(const char *name); +extern int ifc_down(const char *name); + +extern int ifc_enable(const char *ifname); +extern int ifc_disable(const char *ifname); + +extern int ifc_reset_connections(const char *ifname); + +extern int ifc_set_addr(const char *name, in_addr_t addr); +extern int ifc_set_mask(const char *name, in_addr_t mask); +extern int ifc_set_hwaddr(const char *name, const void *ptr); + +/* This function is deprecated. Use ifc_add_route instead. */ +extern int ifc_add_host_route(const char *name, in_addr_t addr); +extern int ifc_remove_host_routes(const char *name); +extern int ifc_get_default_route(const char *ifname); +/* This function is deprecated. Use ifc_add_route instead */ +extern int ifc_set_default_route(const char *ifname, in_addr_t gateway); +/* This function is deprecated. Use ifc_add_route instead */ +extern int ifc_create_default_route(const char *name, in_addr_t addr); +extern int ifc_remove_default_route(const char *ifname); +extern int ifc_add_route(const char *name, const char *addr, int prefix_length, + const char *gw); + +extern int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, + in_addr_t *flags); + +extern int ifc_configure(const char *ifname, in_addr_t address, + in_addr_t netmask, in_addr_t gateway, + in_addr_t dns1, in_addr_t dns2); + +__END_DECLS + +#endif /* _NETUTILS_IFC_H_ */ diff --git a/include/pixelflinger/pixelflinger.h b/include/pixelflinger/pixelflinger.h index dca0b90..8a2b442 100644 --- a/include/pixelflinger/pixelflinger.h +++ b/include/pixelflinger/pixelflinger.h @@ -315,7 +315,7 @@ extern "C" { ssize_t gglInit(GGLContext** context); ssize_t gglUninit(GGLContext* context); -GGLint gglBitBlti( +GGLint gglBitBlit( GGLContext* c, int tmu, GGLint crop[4], diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h index 844ad02..4d19f17 100644 --- a/include/private/android_filesystem_config.h +++ b/include/private/android_filesystem_config.h @@ -52,6 +52,8 @@ #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_DRMIO 1020 /* DRM IO server */ #define AID_GPS 1021 /* GPS daemon */ #define AID_UNUSED1 1022 /* deprecated, DO NOT USE */ #define AID_RFU1 1023 /* RFU */ @@ -98,6 +100,8 @@ static const struct android_id_info android_ids[] = { { "adb", AID_ADB, }, { "install", AID_INSTALL, }, { "media", AID_MEDIA, }, + { "drm", AID_DRM, }, + { "drmio", AID_DRMIO, }, { "nfc", AID_NFC, }, { "shell", AID_SHELL, }, { "cache", AID_CACHE, }, diff --git a/include/system/audio.h b/include/system/audio.h new file mode 100644 index 0000000..8f2ac0c --- /dev/null +++ b/include/system/audio.h @@ -0,0 +1,393 @@ +/* + * 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. + */ + + +#ifndef ANDROID_AUDIO_CORE_H +#define ANDROID_AUDIO_CORE_H + +#include <stdbool.h> +#include <stdint.h> +#include <sys/cdefs.h> +#include <sys/types.h> + +#include <cutils/bitops.h> + +__BEGIN_DECLS + +/* The enums were moved here mostly from + * frameworks/base/include/media/AudioSystem.h + */ + +typedef int audio_io_handle_t; + +/* Audio stream types */ +typedef enum { + AUDIO_STREAM_DEFAULT = -1, + AUDIO_STREAM_VOICE_CALL = 0, + AUDIO_STREAM_SYSTEM = 1, + AUDIO_STREAM_RING = 2, + AUDIO_STREAM_MUSIC = 3, + AUDIO_STREAM_ALARM = 4, + AUDIO_STREAM_NOTIFICATION = 5, + AUDIO_STREAM_BLUETOOTH_SCO = 6, + AUDIO_STREAM_ENFORCED_AUDIBLE = 7, /* Sounds that cannot be muted by user and must be routed to speaker */ + AUDIO_STREAM_DTMF = 8, + AUDIO_STREAM_TTS = 9, + + AUDIO_STREAM_CNT, + AUDIO_STREAM_MAX = AUDIO_STREAM_CNT - 1, +} audio_stream_type_t; + +/* Do not change these values without updating their counterparts + * in media/java/android/media/MediaRecorder.java! + */ +typedef enum { + AUDIO_SOURCE_DEFAULT = 0, + AUDIO_SOURCE_MIC = 1, + AUDIO_SOURCE_VOICE_UPLINK = 2, + AUDIO_SOURCE_VOICE_DOWNLINK = 3, + AUDIO_SOURCE_VOICE_CALL = 4, + AUDIO_SOURCE_CAMCORDER = 5, + AUDIO_SOURCE_VOICE_RECOGNITION = 6, + AUDIO_SOURCE_VOICE_COMMUNICATION = 7, + + AUDIO_SOURCE_CNT, + AUDIO_SOURCE_MAX = AUDIO_SOURCE_CNT - 1, +} audio_source_t; + +/* special audio session values + * (XXX: should this be living in the audio effects land?) + */ +typedef enum { + /* session for effects attached to a particular output stream + * (value must be less than 0) + */ + AUDIO_SESSION_OUTPUT_STAGE = -1, + + /* session for effects applied to output mix. These effects can + * be moved by audio policy manager to another output stream + * (value must be 0) + */ + AUDIO_SESSION_OUTPUT_MIX = 0, +} audio_session_t; + +/* Audio sub formats (see enum audio_format). */ + +/* PCM sub formats */ +typedef enum { + AUDIO_FORMAT_PCM_SUB_16_BIT = 0x1, /* DO NOT CHANGE */ + AUDIO_FORMAT_PCM_SUB_8_BIT = 0x2, /* DO NOT CHANGE */ +} audio_format_pcm_sub_fmt_t; + +/* MP3 sub format field definition : can use 11 LSBs in the same way as MP3 + * frame header to specify bit rate, stereo mode, version... + */ +typedef enum { + AUDIO_FORMAT_MP3_SUB_NONE = 0x0, +} audio_format_mp3_sub_fmt_t; + +/* AMR NB/WB sub format field definition: specify frame block interleaving, + * bandwidth efficient or octet aligned, encoding mode for recording... + */ +typedef enum { + AUDIO_FORMAT_AMR_SUB_NONE = 0x0, +} audio_format_amr_sub_fmt_t; + +/* AAC sub format field definition: specify profile or bitrate for recording... */ +typedef enum { + AUDIO_FORMAT_AAC_SUB_NONE = 0x0, +} audio_format_aac_sub_fmt_t; + +/* VORBIS sub format field definition: specify quality for recording... */ +typedef enum { + AUDIO_FORMAT_VORBIS_SUB_NONE = 0x0, +} audio_format_vorbis_sub_fmt_t; + +/* Audio format consists in a main format field (upper 8 bits) and a sub format + * field (lower 24 bits). + * + * The main format indicates the main codec type. The sub format field + * indicates options and parameters for each format. The sub format is mainly + * used for record to indicate for instance the requested bitrate or profile. + * It can also be used for certain formats to give informations not present in + * the encoded audio stream (e.g. octet alignement for AMR). + */ +typedef enum { + AUDIO_FORMAT_INVALID = 0xFFFFFFFFUL, + AUDIO_FORMAT_DEFAULT = 0, + AUDIO_FORMAT_PCM = 0x00000000UL, /* DO NOT CHANGE */ + AUDIO_FORMAT_MP3 = 0x01000000UL, + AUDIO_FORMAT_AMR_NB = 0x02000000UL, + AUDIO_FORMAT_AMR_WB = 0x03000000UL, + AUDIO_FORMAT_AAC = 0x04000000UL, + AUDIO_FORMAT_HE_AAC_V1 = 0x05000000UL, + AUDIO_FORMAT_HE_AAC_V2 = 0x06000000UL, + AUDIO_FORMAT_VORBIS = 0x07000000UL, + AUDIO_FORMAT_MAIN_MASK = 0xFF000000UL, + AUDIO_FORMAT_SUB_MASK = 0x00FFFFFFUL, + + /* Aliases */ + AUDIO_FORMAT_PCM_16_BIT = (AUDIO_FORMAT_PCM | + AUDIO_FORMAT_PCM_SUB_16_BIT), + AUDIO_FORMAT_PCM_8_BIT = (AUDIO_FORMAT_PCM | + AUDIO_FORMAT_PCM_SUB_8_BIT), +} audio_format_t; + +/* Channel mask definitions must be kept in sync with JAVA values in + * frameworks/base/media/java/android/media/AudioFormat.java */ +typedef enum { + /* output channels */ + AUDIO_CHANNEL_OUT_FRONT_LEFT = 0x4, + AUDIO_CHANNEL_OUT_FRONT_RIGHT = 0x8, + AUDIO_CHANNEL_OUT_FRONT_CENTER = 0x10, + AUDIO_CHANNEL_OUT_LOW_FREQUENCY = 0x20, + AUDIO_CHANNEL_OUT_BACK_LEFT = 0x40, + AUDIO_CHANNEL_OUT_BACK_RIGHT = 0x80, + AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100, + AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200, + AUDIO_CHANNEL_OUT_BACK_CENTER = 0x400, + + AUDIO_CHANNEL_OUT_MONO = AUDIO_CHANNEL_OUT_FRONT_LEFT, + AUDIO_CHANNEL_OUT_STEREO = (AUDIO_CHANNEL_OUT_FRONT_LEFT | + AUDIO_CHANNEL_OUT_FRONT_RIGHT), + AUDIO_CHANNEL_OUT_QUAD = (AUDIO_CHANNEL_OUT_FRONT_LEFT | + AUDIO_CHANNEL_OUT_FRONT_RIGHT | + AUDIO_CHANNEL_OUT_BACK_LEFT | + AUDIO_CHANNEL_OUT_BACK_RIGHT), + AUDIO_CHANNEL_OUT_SURROUND = (AUDIO_CHANNEL_OUT_FRONT_LEFT | + AUDIO_CHANNEL_OUT_FRONT_RIGHT | + AUDIO_CHANNEL_OUT_FRONT_CENTER | + AUDIO_CHANNEL_OUT_BACK_CENTER), + AUDIO_CHANNEL_OUT_5POINT1 = (AUDIO_CHANNEL_OUT_FRONT_LEFT | + AUDIO_CHANNEL_OUT_FRONT_RIGHT | + AUDIO_CHANNEL_OUT_FRONT_CENTER | + AUDIO_CHANNEL_OUT_LOW_FREQUENCY | + AUDIO_CHANNEL_OUT_BACK_LEFT | + AUDIO_CHANNEL_OUT_BACK_RIGHT), + AUDIO_CHANNEL_OUT_7POINT1 = (AUDIO_CHANNEL_OUT_FRONT_LEFT | + AUDIO_CHANNEL_OUT_FRONT_RIGHT | + AUDIO_CHANNEL_OUT_FRONT_CENTER | + AUDIO_CHANNEL_OUT_LOW_FREQUENCY | + AUDIO_CHANNEL_OUT_BACK_LEFT | + AUDIO_CHANNEL_OUT_BACK_RIGHT | + AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER | + AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER), + AUDIO_CHANNEL_OUT_ALL = (AUDIO_CHANNEL_OUT_FRONT_LEFT | + AUDIO_CHANNEL_OUT_FRONT_RIGHT | + AUDIO_CHANNEL_OUT_FRONT_CENTER | + AUDIO_CHANNEL_OUT_LOW_FREQUENCY | + AUDIO_CHANNEL_OUT_BACK_LEFT | + AUDIO_CHANNEL_OUT_BACK_RIGHT | + AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER | + AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | + AUDIO_CHANNEL_OUT_BACK_CENTER), + + /* input channels */ + AUDIO_CHANNEL_IN_LEFT = 0x4, + AUDIO_CHANNEL_IN_RIGHT = 0x8, + AUDIO_CHANNEL_IN_FRONT = 0x10, + AUDIO_CHANNEL_IN_BACK = 0x20, + AUDIO_CHANNEL_IN_LEFT_PROCESSED = 0x40, + AUDIO_CHANNEL_IN_RIGHT_PROCESSED = 0x80, + AUDIO_CHANNEL_IN_FRONT_PROCESSED = 0x100, + AUDIO_CHANNEL_IN_BACK_PROCESSED = 0x200, + AUDIO_CHANNEL_IN_PRESSURE = 0x400, + AUDIO_CHANNEL_IN_X_AXIS = 0x800, + AUDIO_CHANNEL_IN_Y_AXIS = 0x1000, + AUDIO_CHANNEL_IN_Z_AXIS = 0x2000, + AUDIO_CHANNEL_IN_VOICE_UPLINK = 0x4000, + AUDIO_CHANNEL_IN_VOICE_DNLINK = 0x8000, + + AUDIO_CHANNEL_IN_MONO = AUDIO_CHANNEL_IN_FRONT, + AUDIO_CHANNEL_IN_STEREO = (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT), + AUDIO_CHANNEL_IN_ALL = (AUDIO_CHANNEL_IN_LEFT | + AUDIO_CHANNEL_IN_RIGHT | + AUDIO_CHANNEL_IN_FRONT | + AUDIO_CHANNEL_IN_BACK| + AUDIO_CHANNEL_IN_LEFT_PROCESSED | + AUDIO_CHANNEL_IN_RIGHT_PROCESSED | + AUDIO_CHANNEL_IN_FRONT_PROCESSED | + AUDIO_CHANNEL_IN_BACK_PROCESSED| + AUDIO_CHANNEL_IN_PRESSURE | + AUDIO_CHANNEL_IN_X_AXIS | + AUDIO_CHANNEL_IN_Y_AXIS | + AUDIO_CHANNEL_IN_Z_AXIS | + AUDIO_CHANNEL_IN_VOICE_UPLINK | + AUDIO_CHANNEL_IN_VOICE_DNLINK), +} audio_channels_t; + +typedef enum { + AUDIO_MODE_INVALID = -2, + AUDIO_MODE_CURRENT = -1, + AUDIO_MODE_NORMAL = 0, + AUDIO_MODE_RINGTONE = 1, + AUDIO_MODE_IN_CALL = 2, + AUDIO_MODE_IN_COMMUNICATION = 3, + + AUDIO_MODE_CNT, + AUDIO_MODE_MAX = AUDIO_MODE_CNT - 1, +} audio_mode_t; + +typedef enum { + AUDIO_IN_ACOUSTICS_AGC_ENABLE = 0x0001, + AUDIO_IN_ACOUSTICS_AGC_DISABLE = 0, + AUDIO_IN_ACOUSTICS_NS_ENABLE = 0x0002, + AUDIO_IN_ACOUSTICS_NS_DISABLE = 0, + AUDIO_IN_ACOUSTICS_TX_IIR_ENABLE = 0x0004, + AUDIO_IN_ACOUSTICS_TX_DISABLE = 0, +} audio_in_acoustics_t; + +typedef enum { + /* output devices */ + AUDIO_DEVICE_OUT_EARPIECE = 0x1, + AUDIO_DEVICE_OUT_SPEAKER = 0x2, + AUDIO_DEVICE_OUT_WIRED_HEADSET = 0x4, + AUDIO_DEVICE_OUT_WIRED_HEADPHONE = 0x8, + AUDIO_DEVICE_OUT_BLUETOOTH_SCO = 0x10, + AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20, + AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40, + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP = 0x80, + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100, + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200, + AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400, + AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800, + AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000, + AUDIO_DEVICE_OUT_DEFAULT = 0x8000, + AUDIO_DEVICE_OUT_ALL = (AUDIO_DEVICE_OUT_EARPIECE | + AUDIO_DEVICE_OUT_SPEAKER | + AUDIO_DEVICE_OUT_WIRED_HEADSET | + AUDIO_DEVICE_OUT_WIRED_HEADPHONE | + AUDIO_DEVICE_OUT_BLUETOOTH_SCO | + AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET | + AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT | + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | + AUDIO_DEVICE_OUT_AUX_DIGITAL | + AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET | + AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET | + AUDIO_DEVICE_OUT_DEFAULT), + AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER), + AUDIO_DEVICE_OUT_ALL_SCO = (AUDIO_DEVICE_OUT_BLUETOOTH_SCO | + AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET | + AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT), + + /* input devices */ + AUDIO_DEVICE_IN_COMMUNICATION = 0x10000, + AUDIO_DEVICE_IN_AMBIENT = 0x20000, + AUDIO_DEVICE_IN_BUILTIN_MIC = 0x40000, + AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000, + AUDIO_DEVICE_IN_WIRED_HEADSET = 0x100000, + AUDIO_DEVICE_IN_AUX_DIGITAL = 0x200000, + AUDIO_DEVICE_IN_VOICE_CALL = 0x400000, + AUDIO_DEVICE_IN_BACK_MIC = 0x800000, + AUDIO_DEVICE_IN_DEFAULT = 0x80000000, + + AUDIO_DEVICE_IN_ALL = (AUDIO_DEVICE_IN_COMMUNICATION | + AUDIO_DEVICE_IN_AMBIENT | + AUDIO_DEVICE_IN_BUILTIN_MIC | + AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET | + AUDIO_DEVICE_IN_WIRED_HEADSET | + AUDIO_DEVICE_IN_AUX_DIGITAL | + AUDIO_DEVICE_IN_VOICE_CALL | + AUDIO_DEVICE_IN_BACK_MIC | + AUDIO_DEVICE_IN_DEFAULT), + AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, +} audio_devices_t; + +static inline bool audio_is_output_device(audio_devices_t device) +{ + if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL) == 0)) + return true; + else + return false; +} + +static inline bool audio_is_input_device(audio_devices_t device) +{ + if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_IN_ALL) == 0)) + return true; + else + return false; +} + +static inline bool audio_is_a2dp_device(audio_devices_t device) +{ + if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_A2DP)) + return true; + else + return false; +} + +static inline bool audio_is_bluetooth_sco_device(audio_devices_t device) +{ + if ((popcount(device) == 1) && (device & (AUDIO_DEVICE_OUT_ALL_SCO | + AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET))) + return true; + else + return false; +} + +static inline bool audio_is_input_channel(uint32_t channel) +{ + if ((channel & ~AUDIO_CHANNEL_IN_ALL) == 0) + return true; + else + return false; +} + +static inline bool audio_is_output_channel(uint32_t channel) +{ + if ((channel & ~AUDIO_CHANNEL_OUT_ALL) == 0) + return true; + else + return false; +} + +static inline bool audio_is_valid_format(uint32_t format) +{ + switch (format & AUDIO_FORMAT_MAIN_MASK) { + case AUDIO_FORMAT_PCM: + case AUDIO_FORMAT_MP3: + case AUDIO_FORMAT_AMR_NB: + case AUDIO_FORMAT_AMR_WB: + case AUDIO_FORMAT_AAC: + case AUDIO_FORMAT_HE_AAC_V1: + case AUDIO_FORMAT_HE_AAC_V2: + case AUDIO_FORMAT_VORBIS: + return true; + default: + return false; + } +} + +static inline bool audio_is_linear_pcm(uint32_t format) +{ + switch (format) { + case AUDIO_FORMAT_PCM_16_BIT: + case AUDIO_FORMAT_PCM_8_BIT: + return true; + default: + return false; + } +} + + +__END_DECLS + +#endif // ANDROID_AUDIO_CORE_H diff --git a/include/sysutils/SocketClient.h b/include/sysutils/SocketClient.h index e7fb177..d6bb7d5 100644 --- a/include/sysutils/SocketClient.h +++ b/include/sysutils/SocketClient.h @@ -19,6 +19,10 @@ class SocketClient { /* Peer group ID */ gid_t mGid; + /* Reference count (starts at 1) */ + pthread_mutex_t mRefCountMutex; + int mRefCount; + public: SocketClient(int sock); virtual ~SocketClient() {} @@ -28,8 +32,19 @@ public: uid_t getUid() const { return mUid; } gid_t getGid() const { return mGid; } + // Send null-terminated C strings: int sendMsg(int code, const char *msg, bool addErrno); int sendMsg(const char *msg); + + // Sending binary data: + int sendData(const void *data, int len); + + // Optional reference counting. Reference count starts at 1. If + // it's decremented to 0, it deletes itself. + // SocketListener creates a SocketClient (at refcount 1) and calls + // decRef() when it's done with the client. + void incRef(); + bool decRef(); // returns true at 0 (but note: SocketClient already deleted) }; typedef android::List<SocketClient *> SocketClientCollection; diff --git a/include/sysutils/SocketListener.h b/include/sysutils/SocketListener.h index c7edfeb..6592b01 100644 --- a/include/sysutils/SocketListener.h +++ b/include/sysutils/SocketListener.h @@ -30,7 +30,7 @@ class SocketListener { pthread_t mThread; public: - SocketListener(const char *socketNames, bool listen); + SocketListener(const char *socketName, bool listen); SocketListener(int socketFd, bool listen); virtual ~SocketListener(); diff --git a/init/devices.c b/init/devices.c index e73efdf..eb5d84e 100644 --- a/init/devices.c +++ b/init/devices.c @@ -33,6 +33,8 @@ #include <asm/page.h> #include <sys/wait.h> +#include <cutils/uevent.h> + #include "devices.h" #include "util.h" #include "log.h" @@ -589,35 +591,9 @@ static void handle_firmware_event(struct uevent *uevent) #define UEVENT_MSG_LEN 1024 void handle_device_fd() { - for(;;) { - char msg[UEVENT_MSG_LEN+2]; - char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; - struct iovec iov = {msg, sizeof(msg)}; - struct sockaddr_nl snl; - struct msghdr hdr = {&snl, sizeof(snl), &iov, 1, cred_msg, sizeof(cred_msg), 0}; - - ssize_t n = recvmsg(device_fd, &hdr, 0); - if (n <= 0) { - break; - } - - if ((snl.nl_groups != 1) || (snl.nl_pid != 0)) { - /* ignoring non-kernel netlink multicast message */ - continue; - } - - struct cmsghdr * cmsg = CMSG_FIRSTHDR(&hdr); - if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { - /* no sender credentials received, ignore message */ - continue; - } - - struct ucred * cred = (struct ucred *)CMSG_DATA(cmsg); - if (cred->uid != 0) { - /* message from non-root user, ignore */ - continue; - } - + char msg[UEVENT_MSG_LEN+2]; + int n; + while ((n = uevent_checked_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) { if(n >= UEVENT_MSG_LEN) /* overflow -- discard */ continue; diff --git a/init/init.c b/init/init.c index 75ffb5c..f2a1d27 100755 --- a/init/init.c +++ b/init/init.c @@ -646,6 +646,8 @@ static int bootchart_init_action(int nargs, char **args) } else { NOTICE("bootcharting ignored\n"); } + + return 0; } #endif diff --git a/init/init_parser.c b/init/init_parser.c index d136c28..fafd732 100644 --- a/init/init_parser.c +++ b/init/init_parser.c @@ -187,7 +187,7 @@ static void parse_config(const char *fn, char *s) nargs = 0; state.filename = fn; - state.line = 1; + state.line = 0; state.ptr = s; state.nexttoken = 0; state.parse_line = parse_line_no_op; @@ -197,6 +197,7 @@ static void parse_config(const char *fn, char *s) state.parse_line(&state, 0, 0); return; case T_NEWLINE: + state.line++; if (nargs) { int kw = lookup_keyword(args[0]); if (kw_is(kw, SECTION)) { diff --git a/init/parser.c b/init/parser.c index 2f36ac7..3c2ec00 100644 --- a/init/parser.c +++ b/init/parser.c @@ -83,7 +83,6 @@ int next_token(struct parse_state *state) state->ptr = x; return T_EOF; case '\n': - state->line++; x++; state->ptr = x; return T_NEWLINE; @@ -94,9 +93,13 @@ int next_token(struct parse_state *state) continue; case '#': while (*x && (*x != '\n')) x++; - state->line++; - state->ptr = x; - return T_NEWLINE; + if (*x == '\n') { + state->ptr = x+1; + return T_NEWLINE; + } else { + state->ptr = x; + return T_EOF; + } default: goto text; } diff --git a/init/util.c b/init/util.c index 377754b..d8ec88e 100644..100755 --- a/init/util.c +++ b/init/util.c @@ -439,8 +439,9 @@ void get_hardware_name(char *hardware, unsigned int *revision) if (x) { x += 2; n = 0; - while (*x && !isspace(*x)) { - hardware[n++] = tolower(*x); + while (*x && *x != '\n') { + if (!isspace(*x)) + hardware[n++] = tolower(*x); x++; if (n == 31) break; } diff --git a/libcutils/Android.mk b/libcutils/Android.mk index 3dc3d69..03e6e9a 100644 --- a/libcutils/Android.mk +++ b/libcutils/Android.mk @@ -46,7 +46,8 @@ commonSources := \ properties.c \ threads.c \ sched_policy.c \ - iosched_policy.c + iosched_policy.c \ + str_parms.c commonHostSources := \ ashmem-host.c @@ -109,7 +110,7 @@ else #!sim # ======================================================== include $(CLEAR_VARS) LOCAL_MODULE := libcutils -LOCAL_SRC_FILES := $(commonSources) ashmem-dev.c mq.c +LOCAL_SRC_FILES := $(commonSources) ashmem-dev.c mq.c uevent.c qtaguid.c ifeq ($(TARGET_ARCH),arm) LOCAL_SRC_FILES += arch-arm/memset32.S diff --git a/libcutils/qtaguid.c b/libcutils/qtaguid.c new file mode 100644 index 0000000..218a21f --- /dev/null +++ b/libcutils/qtaguid.c @@ -0,0 +1,67 @@ +/* libcutils/qtaguid.c +** +** Copyright 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. +*/ + +#define LOG_TAG "qtaguid" + +#include <cutils/qtaguid.h> +#include <cutils/log.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +extern int qtaguid_tagSocket(int sockfd, int tag, uid_t uid) { + char lineBuf[128]; + int fd, cnt = 0, res = 0; + uint64_t kTag = (uint64_t)tag << 32; + snprintf(lineBuf, sizeof(lineBuf), "t %d %llu %d", sockfd, kTag, uid); + + LOGI("Tagging socket %d with tag %llx(%d) for uid %d", sockfd, kTag, tag, uid); + fd = open("/proc/net/xt_qtaguid/ctrl", O_WRONLY); + if (fd < 0) { + return -errno; + } + + cnt = write(fd, lineBuf, strlen(lineBuf)); + if (cnt < 0) { + res = -errno; + } + + close(fd); + return res; +} + +extern int qtaguid_untagSocket(int sockfd) { + char lineBuf[128]; + int fd, cnt = 0, res = 0; + snprintf(lineBuf, sizeof(lineBuf), "u %d", sockfd); + + LOGI("Untagging socket %d", sockfd); + fd = open("/proc/net/xt_qtaguid/ctrl", O_WRONLY); + if (fd < 0) { + return -errno; + } + + cnt = write(fd, lineBuf, strlen(lineBuf)); + if (cnt < 0) { + res = -errno; + } + + close(fd); + return res; +} diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c new file mode 100644 index 0000000..dfa1f73 --- /dev/null +++ b/libcutils/str_parms.c @@ -0,0 +1,329 @@ +/* + * 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. + */ + +#define LOG_TAG "str_params" +//#define LOG_NDEBUG 0 + +#define _GNU_SOURCE 1 +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <cutils/hashmap.h> +#include <cutils/log.h> +#include <cutils/memory.h> + +#include <cutils/str_parms.h> + +struct str_parms { + Hashmap *map; +}; + + +static bool str_eq(void *key_a, void *key_b) +{ + return !strcmp((const char *)key_a, (const char *)key_b); +} + +/* use djb hash unless we find it inadequate */ +static int str_hash_fn(void *str) +{ + uint32_t hash = 5381; + char *p; + + for (p = str; p && *p; p++) + hash = ((hash << 5) + hash) + *p; + return (int)hash; +} + +struct str_parms *str_parms_create(void) +{ + struct str_parms *str_parms; + + str_parms = calloc(1, sizeof(struct str_parms)); + if (!str_parms) + return NULL; + + str_parms->map = hashmapCreate(5, str_hash_fn, str_eq); + if (!str_parms->map) + goto err; + + return str_parms; + +err: + free(str_parms); + return NULL; +} + +static bool remove_pair(void *key, void *value, void *context) +{ + struct str_parms *str_parms = context; + + hashmapRemove(str_parms->map, key); + free(key); + free(value); + return true; +} + +void str_parms_destroy(struct str_parms *str_parms) +{ + hashmapForEach(str_parms->map, remove_pair, str_parms); + hashmapFree(str_parms->map); + free(str_parms); +} + +struct str_parms *str_parms_create_str(const char *_string) +{ + struct str_parms *str_parms; + char *str; + char *kvpair; + char *tmpstr; + int items = 0; + + str_parms = str_parms_create(); + if (!str_parms) + goto err_create_str_parms; + + str = strdup(_string); + if (!str) + goto err_strdup; + + LOGV("%s: source string == '%s'\n", __func__, _string); + + kvpair = strtok_r(str, ";", &tmpstr); + while (kvpair && *kvpair) { + char *eq = strchr(kvpair, '='); /* would love strchrnul */ + char *value; + char *key; + void *old_val; + + if (eq == kvpair) + goto next_pair; + + if (eq) { + key = strndup(kvpair, eq - kvpair); + if (*(++eq)) + value = strdup(eq); + else + value = strdup(""); + } else { + key = strdup(kvpair); + value = strdup(""); + } + + /* if we replaced a value, free it */ + old_val = hashmapPut(str_parms->map, key, value); + if (old_val) + free(old_val); + + items++; +next_pair: + kvpair = strtok_r(NULL, ";", &tmpstr); + } + + if (!items) + LOGV("%s: no items found in string\n", __func__); + + free(str); + + return str_parms; + +err_strdup: + str_parms_destroy(str_parms); +err_create_str_parms: + return NULL; +} + +void str_parms_del(struct str_parms *str_parms, const char *key) +{ + hashmapRemove(str_parms->map, (void *)key); +} + +int str_parms_add_str(struct str_parms *str_parms, const char *key, + const char *value) +{ + void *old_val; + char *tmp; + + tmp = strdup(value); + old_val = hashmapPut(str_parms->map, (void *)key, tmp); + + if (old_val) { + free(old_val); + } else if (errno == ENOMEM) { + free(tmp); + return -ENOMEM; + } + return 0; +} + +int str_parms_add_int(struct str_parms *str_parms, const char *key, int value) +{ + char val_str[12]; + int ret; + + ret = snprintf(val_str, sizeof(val_str), "%d", value); + if (ret < 0) + return -EINVAL; + + ret = str_parms_add_str(str_parms, key, val_str); + return ret; +} + +int str_parms_add_float(struct str_parms *str_parms, const char *key, + float value) +{ + char val_str[23]; + int ret; + + ret = snprintf(val_str, sizeof(val_str), "%.10f", value); + if (ret < 0) + return -EINVAL; + + ret = str_parms_add_str(str_parms, key, val_str); + return ret; +} + +int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val, + int len) +{ + char *value; + + value = hashmapGet(str_parms->map, (void *)key); + if (value) + return strlcpy(val, value, len); + + return -ENOENT; +} + +int str_parms_get_int(struct str_parms *str_parms, const char *key, int *val) +{ + char *value; + char *end; + + value = hashmapGet(str_parms->map, (void *)key); + if (!value) + return -ENOENT; + + *val = (int)strtol(value, &end, 0); + if (*value != '\0' && *end == '\0') + return 0; + + return -EINVAL; +} + +int str_parms_get_float(struct str_parms *str_parms, const char *key, + float *val) +{ + float out; + char *value; + char *end; + + value = hashmapGet(str_parms->map, (void *)key); + if (!value) + return -ENOENT; + + out = strtof(value, &end); + if (*value != '\0' && *end == '\0') + return 0; + + return -EINVAL; +} + +static bool combine_strings(void *key, void *value, void *context) +{ + char **old_str = context; + char *new_str; + int ret; + + ret = asprintf(&new_str, "%s%s%s=%s", + *old_str ? *old_str : "", + *old_str ? ";" : "", + (char *)key, + (char *)value); + if (*old_str) + free(*old_str); + + if (ret >= 0) { + *old_str = new_str; + return true; + } + + *old_str = NULL; + return false; +} + +char *str_parms_to_str(struct str_parms *str_parms) +{ + char *str = NULL; + + if (hashmapSize(str_parms->map) > 0) + hashmapForEach(str_parms->map, combine_strings, &str); + else + str = strdup(""); + return str; +} + +static bool dump_entry(void *key, void *value, void *context) +{ + LOGI("key: '%s' value: '%s'\n", (char *)key, (char *)value); + return true; +} + +void str_parms_dump(struct str_parms *str_parms) +{ + hashmapForEach(str_parms->map, dump_entry, str_parms); +} + +#ifdef TEST_STR_PARMS +static void test_str_parms_str(const char *str) +{ + struct str_parms *str_parms; + char *out_str; + int ret; + + str_parms = str_parms_create_str(str); + str_parms_dump(str_parms); + out_str = str_parms_to_str(str_parms); + str_parms_destroy(str_parms); + LOGI("%s: '%s' stringified is '%s'", __func__, str, out_str); + free(out_str); +} + +int main(void) +{ + struct str_parms *str_parms; + + test_str_parms_str(""); + test_str_parms_str(";"); + test_str_parms_str("="); + test_str_parms_str("=;"); + test_str_parms_str("=bar"); + test_str_parms_str("=bar;"); + test_str_parms_str("foo="); + test_str_parms_str("foo=;"); + test_str_parms_str("foo=bar"); + test_str_parms_str("foo=bar;"); + test_str_parms_str("foo=bar;baz"); + test_str_parms_str("foo=bar;baz="); + test_str_parms_str("foo=bar;baz=bat"); + test_str_parms_str("foo=bar;baz=bat;"); + + return 0; +} +#endif diff --git a/libcutils/uevent.c b/libcutils/uevent.c new file mode 100644 index 0000000..3533c00 --- /dev/null +++ b/libcutils/uevent.c @@ -0,0 +1,70 @@ +/* + * 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 <cutils/uevent.h> + +#include <errno.h> +#include <strings.h> + +#include <linux/netlink.h> + +/** + * Like recv(), but checks that messages actually originate from the kernel. + */ +ssize_t uevent_checked_recv(int socket, void *buffer, size_t length) { + struct iovec iov = { buffer, length }; + struct sockaddr_nl addr; + char control[CMSG_SPACE(sizeof(struct ucred))]; + struct msghdr hdr = { + &addr, + sizeof(addr), + &iov, + 1, + control, + sizeof(control), + 0, + }; + + ssize_t n = recvmsg(socket, &hdr, 0); + if (n <= 0) { + return n; + } + + if (addr.nl_groups == 0 || addr.nl_pid != 0) { + /* ignoring non-kernel or unicast netlink message */ + goto out; + } + + struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr); + if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { + /* ignoring netlink message with no sender credentials */ + goto out; + } + + struct ucred *cred = (struct ucred *)CMSG_DATA(cmsg); + if (cred->uid != 0) { + /* ignoring netlink message from non-root user */ + goto out; + } + + return n; + +out: + /* clear residual potentially malicious data */ + bzero(buffer, length); + errno = EIO; + return -1; +} diff --git a/libdiskconfig/Android.mk b/libdiskconfig/Android.mk index 1d0ecb4..714606a 100644 --- a/libdiskconfig/Android.mk +++ b/libdiskconfig/Android.mk @@ -3,17 +3,27 @@ include $(CLEAR_VARS) ifneq ($(TARGET_SIMULATOR),true) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ +commonSources := \ diskconfig.c \ diskutils.c \ write_lst.c \ config_mbr.c +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(commonSources) LOCAL_MODULE := libdiskconfig +LOCAL_MODULE_TAGS := optional LOCAL_SYSTEM_SHARED_LIBRARIES := libcutils liblog libc - include $(BUILD_SHARED_LIBRARY) +ifeq ($(HOST_OS),linux) +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(commonSources) +LOCAL_MODULE := libdiskconfig_host +LOCAL_MODULE_TAGS := optional +LOCAL_SYSTEM_SHARED_LIBRARIES := libcutils +LOCAL_CFLAGS := -O2 -g -W -Wall -Werror -D_LARGEFILE64_SOURCE +include $(BUILD_HOST_STATIC_LIBRARY) +endif # HOST_OS == linux + endif # ! TARGET_SIMULATOR diff --git a/liblog/logd_write.c b/liblog/logd_write.c index 9923bba..a0a753b 100644 --- a/liblog/logd_write.c +++ b/liblog/logd_write.c @@ -56,7 +56,7 @@ static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1 }; * the simulator rather than a desktop tool and want to use the device. */ static enum { - kLogUninitialized, kLogNotAvailable, kLogAvailable + kLogUninitialized, kLogNotAvailable, kLogAvailable } g_log_status = kLogUninitialized; int __android_log_dev_available(void) { @@ -189,7 +189,7 @@ int __android_log_buf_write(int bufID, int prio, const char *tag, const char *ms int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap) { - char buf[LOG_BUF_SIZE]; + char buf[LOG_BUF_SIZE]; vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); @@ -223,12 +223,23 @@ int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fm void __android_log_assert(const char *cond, const char *tag, const char *fmt, ...) { - va_list ap; - char buf[LOG_BUF_SIZE]; + char buf[LOG_BUF_SIZE]; - va_start(ap, fmt); - vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); - va_end(ap); + if (fmt) { + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); + va_end(ap); + } else { + /* Msg not provided, log condition. N.B. Do not use cond directly as + * format string as it could contain spurious '%' syntax (e.g. + * "%d" in "blocks%devs == 0"). + */ + if (cond) + snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond); + else + strcpy(buf, "Unspecified assertion failed"); + } __android_log_write(ANDROID_LOG_FATAL, tag, buf); diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c index dc71bab..064eb0c 100644 --- a/libnetutils/dhcp_utils.c +++ b/libnetutils/dhcp_utils.c @@ -116,6 +116,14 @@ static void fill_ip_info(const char *interface, } } +static const char *ipaddr_to_string(in_addr_t addr) +{ + struct in_addr in_addr; + + in_addr.s_addr = addr; + return inet_ntoa(in_addr); +} + /* * Start the dhcp client daemon, and wait for it to finish * configuring the interface. @@ -172,7 +180,13 @@ int dhcp_do_request(const char *interface, return -1; } if (strcmp(prop_value, "ok") == 0) { + char dns_prop_name[PROPERTY_KEY_MAX]; fill_ip_info(interface, ipaddr, gateway, mask, dns1, dns2, server, lease); + /* copy the dhcp.XXX.dns properties to net.XXX.dns */ + snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", interface); + property_set(dns_prop_name, *dns1 ? ipaddr_to_string(*dns1) : ""); + snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", interface); + property_set(dns_prop_name, *dns2 ? ipaddr_to_string(*dns2) : ""); return 0; } else { snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value); @@ -286,4 +300,4 @@ int dhcp_do_request_renew(const char *interface, snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value); return -1; } -}
\ No newline at end of file +} diff --git a/libnetutils/dhcpclient.c b/libnetutils/dhcpclient.c index 6755ba1..ff00432 100644 --- a/libnetutils/dhcpclient.c +++ b/libnetutils/dhcpclient.c @@ -36,8 +36,8 @@ #include <dirent.h> +#include <netutils/ifc.h> #include "dhcpmsg.h" -#include "ifc_utils.h" #include "packet.h" #define VERBOSE 2 @@ -85,16 +85,12 @@ int fatal(const char *reason) // exit(1); } -const char *ipaddr(uint32_t addr) +const char *ipaddr(in_addr_t addr) { - static char buf[32]; - - sprintf(buf,"%d.%d.%d.%d", - addr & 255, - ((addr >> 8) & 255), - ((addr >> 16) & 255), - (addr >> 24)); - return buf; + struct in_addr in_addr; + + in_addr.s_addr = addr; + return inet_ntoa(in_addr); } typedef struct dhcp_info dhcp_info; @@ -128,31 +124,11 @@ void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *mask, *lease = last_good_info.lease; } -static int ifc_configure(const char *ifname, dhcp_info *info) +static int dhcp_configure(const char *ifname, dhcp_info *info) { - char dns_prop_name[PROPERTY_KEY_MAX]; - - if (ifc_set_addr(ifname, info->ipaddr)) { - printerr("failed to set ipaddr %s: %s\n", ipaddr(info->ipaddr), strerror(errno)); - return -1; - } - if (ifc_set_mask(ifname, info->netmask)) { - printerr("failed to set netmask %s: %s\n", ipaddr(info->netmask), strerror(errno)); - return -1; - } - if (ifc_create_default_route(ifname, info->gateway)) { - printerr("failed to set default route %s: %s\n", ipaddr(info->gateway), strerror(errno)); - return -1; - } - - snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", ifname); - property_set(dns_prop_name, info->dns1 ? ipaddr(info->dns1) : ""); - snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", ifname); - property_set(dns_prop_name, info->dns2 ? ipaddr(info->dns2) : ""); - last_good_info = *info; - - return 0; + return ifc_configure(ifname, info->ipaddr, info->netmask, info->gateway, + info->dns1, info->dns2); } static const char *dhcp_type_to_name(uint32_t type) @@ -449,7 +425,7 @@ int dhcp_init_ifc(const char *ifname) printerr("timed out\n"); if ( info.type == DHCPOFFER ) { printerr("no acknowledgement from DHCP server\nconfiguring %s with offered parameters\n", ifname); - return ifc_configure(ifname, &info); + return dhcp_configure(ifname, &info); } errno = ETIME; close(s); @@ -530,7 +506,7 @@ int dhcp_init_ifc(const char *ifname) if (info.type == DHCPACK) { printerr("configuring %s\n", ifname); close(s); - return ifc_configure(ifname, &info); + return dhcp_configure(ifname, &info); } else if (info.type == DHCPNAK) { printerr("configuration request denied\n"); close(s); diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c index bde336f..0ca5fe6 100644 --- a/libnetutils/ifc_utils.c +++ b/libnetutils/ifc_utils.c @@ -27,8 +27,12 @@ #include <arpa/inet.h> #include <linux/if.h> +#include <linux/if_ether.h> +#include <linux/if_arp.h> #include <linux/sockios.h> #include <linux/route.h> +#include <linux/ipv6_route.h> +#include <netdb.h> #include <linux/wireless.h> #ifdef ANDROID @@ -43,9 +47,10 @@ #endif static int ifc_ctl_sock = -1; +static int ifc_ctl_sock6 = -1; void printerr(char *fmt, ...); -static const char *ipaddr_to_string(uint32_t addr) +static const char *ipaddr_to_string(in_addr_t addr) { struct in_addr in_addr; @@ -64,6 +69,17 @@ int ifc_init(void) return ifc_ctl_sock < 0 ? -1 : 0; } +int ifc_init6(void) +{ + if (ifc_ctl_sock6 == -1) { + ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM, 0); + if (ifc_ctl_sock6 < 0) { + printerr("socket() failed: %s\n", strerror(errno)); + } + } + return ifc_ctl_sock6 < 0 ? -1 : 0; +} + void ifc_close(void) { if (ifc_ctl_sock != -1) { @@ -72,6 +88,14 @@ void ifc_close(void) } } +void ifc_close6(void) +{ + if (ifc_ctl_sock6 != -1) { + (void)close(ifc_ctl_sock6); + ifc_ctl_sock6 = -1; + } +} + static void ifc_init_ifr(const char *name, struct ifreq *ifr) { memset(ifr, 0, sizeof(struct ifreq)); @@ -88,7 +112,7 @@ int ifc_get_hwaddr(const char *name, void *ptr) r = ioctl(ifc_ctl_sock, SIOCGIFHWADDR, &ifr); if(r < 0) return -1; - memcpy(ptr, &ifr.ifr_hwaddr.sa_data, 6); + memcpy(ptr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); return 0; } @@ -143,6 +167,17 @@ int ifc_set_addr(const char *name, in_addr_t addr) return ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr); } +int ifc_set_hwaddr(const char *name, const void *ptr) +{ + int r; + struct ifreq ifr; + ifc_init_ifr(name, &ifr); + + ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; + memcpy(&ifr.ifr_hwaddr.sa_data, ptr, ETH_ALEN); + return ioctl(ifc_ctl_sock, SIOCSIFHWADDR, &ifr); +} + int ifc_set_mask(const char *name, in_addr_t mask) { struct ifreq ifr; @@ -185,45 +220,80 @@ int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *f return 0; } - -int ifc_create_default_route(const char *name, in_addr_t addr) +in_addr_t get_ipv4_netmask(int prefix_length) { - struct rtentry rt; + in_addr_t mask = 0; - memset(&rt, 0, sizeof(rt)); - - rt.rt_dst.sa_family = AF_INET; - rt.rt_flags = RTF_UP | RTF_GATEWAY; - rt.rt_dev = (void*) name; - init_sockaddr_in(&rt.rt_genmask, 0); - init_sockaddr_in(&rt.rt_gateway, addr); - - return ioctl(ifc_ctl_sock, SIOCADDRT, &rt); + mask = ~mask << (32 - prefix_length); + mask = htonl(mask); + + return mask; } -int ifc_add_host_route(const char *name, in_addr_t addr) +int ifc_add_ipv4_route(const char *ifname, struct in_addr dst, int prefix_length, + struct in_addr gw) { struct rtentry rt; int result; + in_addr_t netmask; memset(&rt, 0, sizeof(rt)); - + rt.rt_dst.sa_family = AF_INET; - rt.rt_flags = RTF_UP | RTF_HOST; - rt.rt_dev = (void*) name; - init_sockaddr_in(&rt.rt_dst, addr); - init_sockaddr_in(&rt.rt_genmask, 0); - init_sockaddr_in(&rt.rt_gateway, 0); - + rt.rt_dev = (void*) ifname; + + netmask = get_ipv4_netmask(prefix_length); + init_sockaddr_in(&rt.rt_genmask, netmask); + init_sockaddr_in(&rt.rt_dst, dst.s_addr); + rt.rt_flags = RTF_UP; + + if (prefix_length == 32) { + rt.rt_flags |= RTF_HOST; + } + + if (gw.s_addr != 0) { + rt.rt_flags |= RTF_GATEWAY; + init_sockaddr_in(&rt.rt_gateway, gw.s_addr); + } + ifc_init(); + + if (ifc_ctl_sock < 0) { + return -errno; + } + result = ioctl(ifc_ctl_sock, SIOCADDRT, &rt); - if (result < 0 && errno == EEXIST) { - result = 0; + if (result < 0) { + if (errno == EEXIST) { + result = 0; + } else { + result = -errno; + } } ifc_close(); return result; } +int ifc_create_default_route(const char *name, in_addr_t gw) +{ + struct in_addr in_dst, in_gw; + + in_dst.s_addr = 0; + in_gw.s_addr = gw; + + return ifc_add_ipv4_route(name, in_dst, 0, in_gw); +} + +int ifc_add_host_route(const char *name, in_addr_t dst) +{ + struct in_addr in_dst, in_gw; + + in_dst.s_addr = dst; + in_gw.s_addr = 0; + + return ifc_add_ipv4_route(name, in_dst, 32, in_gw); +} + int ifc_enable(const char *ifname) { int result; @@ -429,10 +499,119 @@ ifc_configure(const char *ifname, ifc_close(); - snprintf(dns_prop_name, sizeof(dns_prop_name), "dhcp.%s.dns1", ifname); + snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", ifname); property_set(dns_prop_name, dns1 ? ipaddr_to_string(dns1) : ""); - snprintf(dns_prop_name, sizeof(dns_prop_name), "dhcp.%s.dns2", ifname); + snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", ifname); property_set(dns_prop_name, dns2 ? ipaddr_to_string(dns2) : ""); return 0; } + +int ifc_add_ipv6_route(const char *ifname, struct in6_addr dst, int prefix_length, + struct in6_addr gw) +{ + struct in6_rtmsg rtmsg; + int result; + int ifindex; + + memset(&rtmsg, 0, sizeof(rtmsg)); + + ifindex = if_nametoindex(ifname); + if (ifindex == 0) { + printerr("if_nametoindex() failed: interface %s\n", ifname); + return -ENXIO; + } + + rtmsg.rtmsg_ifindex = ifindex; + rtmsg.rtmsg_dst = dst; + rtmsg.rtmsg_dst_len = prefix_length; + rtmsg.rtmsg_flags = RTF_UP; + + if (prefix_length == 128) { + rtmsg.rtmsg_flags |= RTF_HOST; + } + + if (memcmp(&gw, &in6addr_any, sizeof(in6addr_any))) { + rtmsg.rtmsg_flags |= RTF_GATEWAY; + rtmsg.rtmsg_gateway = gw; + } + + ifc_init6(); + + if (ifc_ctl_sock6 < 0) { + return -errno; + } + + result = ioctl(ifc_ctl_sock6, SIOCADDRT, &rtmsg); + if (result < 0) { + if (errno == EEXIST) { + result = 0; + } else { + result = -errno; + } + } + ifc_close6(); + return result; +} + +int ifc_add_route(const char *ifname, const char *dst, int prefix_length, + const char *gw) +{ + int ret = 0; + struct sockaddr_in ipv4_dst, ipv4_gw; + struct sockaddr_in6 ipv6_dst, ipv6_gw; + struct addrinfo hints, *addr_ai, *gw_ai; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_flags = AI_NUMERICHOST; + + ret = getaddrinfo(dst, NULL, &hints, &addr_ai); + + if (ret != 0) { + printerr("getaddrinfo failed: invalid address %s\n", dst); + return -EINVAL; + } + + if (gw == NULL) { + if (addr_ai->ai_family == AF_INET6) { + gw = "::"; + } else if (addr_ai->ai_family == AF_INET) { + gw = "0.0.0.0"; + } + } + + ret = getaddrinfo(gw, NULL, &hints, &gw_ai); + if (ret != 0) { + printerr("getaddrinfo failed: invalid gateway %s\n", gw); + freeaddrinfo(addr_ai); + return -EINVAL; + } + + if (addr_ai->ai_family != gw_ai->ai_family) { + printerr("ifc_add_route: different address families: %s and %s\n", dst, gw); + freeaddrinfo(addr_ai); + freeaddrinfo(gw_ai); + return -EINVAL; + } + + if (addr_ai->ai_family == AF_INET6) { + memcpy(&ipv6_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in6)); + memcpy(&ipv6_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in6)); + ret = ifc_add_ipv6_route(ifname, ipv6_dst.sin6_addr, prefix_length, + ipv6_gw.sin6_addr); + } else if (addr_ai->ai_family == AF_INET) { + memcpy(&ipv4_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in)); + memcpy(&ipv4_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in)); + ret = ifc_add_ipv4_route(ifname, ipv4_dst.sin_addr, prefix_length, + ipv4_gw.sin_addr); + } else { + printerr("ifc_add_route: getaddrinfo returned un supported address family %d\n", + addr_ai->ai_family); + ret = -EAFNOSUPPORT; + } + + freeaddrinfo(addr_ai); + freeaddrinfo(gw_ai); + return ret; +} diff --git a/libnetutils/ifc_utils.h b/libnetutils/ifc_utils.h deleted file mode 100644 index 49b8747..0000000 --- a/libnetutils/ifc_utils.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2008, 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 _IFC_UTILS_H_ -#define _IFC_UTILS_H_ - -int ifc_init(void); - -int ifc_get_ifindex(const char *name, int *if_indexp); -int ifc_get_hwaddr(const char *name, void *ptr); - -int ifc_up(const char *name); -int ifc_down(const char *name); - -int ifc_set_addr(const char *name, unsigned addr); -int ifc_set_mask(const char *name, unsigned mask); - -int ifc_create_default_route(const char *name, unsigned addr); - -int ifc_get_info(const char *name, unsigned *addr, unsigned *mask, unsigned *flags); - -#endif diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp index c2ba647..86c1f42 100644 --- a/libsysutils/src/NetlinkEvent.cpp +++ b/libsysutils/src/NetlinkEvent.cpp @@ -93,13 +93,11 @@ bool NetlinkEvent::decode(char *buffer, int size) { } const char *NetlinkEvent::findParam(const char *paramName) { - int i; - - for (i = 0; i < NL_PARAMS_MAX; i++) { - if (!mParams[i]) - break; - if (!strncmp(mParams[i], paramName, strlen(paramName))) - return &mParams[i][strlen(paramName) + 1]; + size_t len = strlen(paramName); + for (int i = 0; mParams[i] && i < NL_PARAMS_MAX; ++i) { + const char *ptr = mParams[i] + len; + if (!strncmp(mParams[i], paramName, len) && *ptr == '=') + return ++ptr; } SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName); diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp index 8e5f154..90ca52e 100644 --- a/libsysutils/src/SocketClient.cpp +++ b/libsysutils/src/SocketClient.cpp @@ -15,8 +15,10 @@ SocketClient::SocketClient(int socket) , mPid(-1) , mUid(-1) , mGid(-1) + , mRefCount(1) { pthread_mutex_init(&mWriteMutex, NULL); + pthread_mutex_init(&mRefCountMutex, NULL); struct ucred creds; socklen_t szCreds = sizeof(creds); @@ -32,14 +34,24 @@ SocketClient::SocketClient(int socket) int SocketClient::sendMsg(int code, const char *msg, bool addErrno) { char *buf; + const char* arg; + const char* fmt; + char tmp[1]; + int len; if (addErrno) { - buf = (char *) alloca(strlen(msg) + strlen(strerror(errno)) + 8); - sprintf(buf, "%.3d %s (%s)", code, msg, strerror(errno)); + fmt = "%.3d %s (%s)"; + arg = strerror(errno); } else { - buf = (char *) alloca(strlen(msg) + strlen("XXX ")); - sprintf(buf, "%.3d %s", code, msg); + fmt = "%.3d %s"; + arg = NULL; } + /* Measure length of required buffer */ + len = snprintf(tmp, sizeof tmp, fmt, code, msg, arg); + /* Allocate in the stack, then write to it */ + buf = (char*)alloca(len+1); + snprintf(buf, len+1, fmt, code, msg, arg); + /* Send the zero-terminated message */ return sendMsg(buf); } @@ -50,25 +62,65 @@ int SocketClient::sendMsg(const char *msg) { } // Send the message including null character + if (sendData(msg, strlen(msg) + 1) != 0) { + SLOGW("Unable to send msg '%s'", msg); + return -1; + } + return 0; +} + +int SocketClient::sendData(const void* data, int len) { int rc = 0; - const char *p = msg; - int brtw = strlen(msg) + 1; + const char *p = (const char*) data; + int brtw = len; + + if (len == 0) { + return 0; + } pthread_mutex_lock(&mWriteMutex); - while(brtw) { - if ((rc = write(mSocket,p, brtw)) < 0) { - SLOGW("Unable to send msg '%s' (%s)", msg, strerror(errno)); - pthread_mutex_unlock(&mWriteMutex); - return -1; - } else if (!rc) { + while (brtw > 0) { + rc = write(mSocket, p, brtw); + if (rc > 0) { + p += rc; + brtw -= rc; + continue; + } + + if (rc < 0 && errno == EINTR) + continue; + + pthread_mutex_unlock(&mWriteMutex); + if (rc == 0) { SLOGW("0 length write :("); errno = EIO; - pthread_mutex_unlock(&mWriteMutex); - return -1; + } else { + SLOGW("write error (%s)", strerror(errno)); } - p += rc; - brtw -= rc; + return -1; } pthread_mutex_unlock(&mWriteMutex); return 0; } + +void SocketClient::incRef() { + pthread_mutex_lock(&mRefCountMutex); + mRefCount++; + pthread_mutex_unlock(&mRefCountMutex); +} + +bool SocketClient::decRef() { + bool deleteSelf = false; + pthread_mutex_lock(&mRefCountMutex); + mRefCount--; + if (mRefCount == 0) { + deleteSelf = true; + } else if (mRefCount < 0) { + SLOGE("SocketClient refcount went negative!"); + } + pthread_mutex_unlock(&mRefCountMutex); + if (deleteSelf) { + delete this; + } + return deleteSelf; +} diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp index 1bc06db..fcad624 100644 --- a/libsysutils/src/SocketListener.cpp +++ b/libsysutils/src/SocketListener.cpp @@ -54,8 +54,8 @@ SocketListener::~SocketListener() { close(mCtrlPipe[1]); } SocketClientCollection::iterator it; - for (it = mClients->begin(); it != mClients->end(); ++it) { - delete (*it); + for (it = mClients->begin(); it != mClients->end();) { + (*it)->decRef(); it = mClients->erase(it); } delete mClients; @@ -96,8 +96,10 @@ int SocketListener::startListener() { int SocketListener::stopListener() { char c = 0; + int rc; - if (write(mCtrlPipe[1], &c, 1) != 1) { + rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1)); + if (rc != 1) { SLOGE("Error writing to control pipe (%s)", strerror(errno)); return -1; } @@ -118,7 +120,7 @@ int SocketListener::stopListener() { } SocketClientCollection::iterator it; - for (it = mClients->begin(); it != mClients->end(); ++it) { + for (it = mClients->begin(); it != mClients->end();) { delete (*it); it = mClients->erase(it); } @@ -135,11 +137,13 @@ void *SocketListener::threadStart(void *obj) { void SocketListener::runListener() { + SocketClientCollection *pendingList = new SocketClientCollection(); + while(1) { SocketClientCollection::iterator it; fd_set read_fds; int rc = 0; - int max = 0; + int max = -1; FD_ZERO(&read_fds); @@ -154,13 +158,16 @@ void SocketListener::runListener() { pthread_mutex_lock(&mClientsLock); for (it = mClients->begin(); it != mClients->end(); ++it) { - FD_SET((*it)->getSocket(), &read_fds); - if ((*it)->getSocket() > max) - max = (*it)->getSocket(); + int fd = (*it)->getSocket(); + FD_SET(fd, &read_fds); + if (fd > max) + max = fd; } pthread_mutex_unlock(&mClientsLock); if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { + if (errno == EINTR) + continue; SLOGE("select failed (%s)", strerror(errno)); sleep(1); continue; @@ -171,10 +178,14 @@ void SocketListener::runListener() { break; if (mListen && FD_ISSET(mSock, &read_fds)) { struct sockaddr addr; - socklen_t alen = sizeof(addr); + socklen_t alen; int c; - if ((c = accept(mSock, &addr, &alen)) < 0) { + do { + alen = sizeof(addr); + c = accept(mSock, &addr, &alen); + } while (c < 0 && errno == EINTR); + if (c < 0) { SLOGE("accept failed (%s)", strerror(errno)); sleep(1); continue; @@ -184,27 +195,46 @@ void SocketListener::runListener() { pthread_mutex_unlock(&mClientsLock); } - do { - pthread_mutex_lock(&mClientsLock); - for (it = mClients->begin(); it != mClients->end(); ++it) { - int fd = (*it)->getSocket(); - if (FD_ISSET(fd, &read_fds)) { - pthread_mutex_unlock(&mClientsLock); - if (!onDataAvailable(*it)) { - close(fd); - pthread_mutex_lock(&mClientsLock); - delete *it; - it = mClients->erase(it); - pthread_mutex_unlock(&mClientsLock); + /* Add all active clients to the pending list first */ + pendingList->clear(); + pthread_mutex_lock(&mClientsLock); + for (it = mClients->begin(); it != mClients->end(); ++it) { + int fd = (*it)->getSocket(); + if (FD_ISSET(fd, &read_fds)) { + pendingList->push_back(*it); + } + } + pthread_mutex_unlock(&mClientsLock); + + /* Process the pending list, since it is owned by the thread, + * there is no need to lock it */ + while (!pendingList->empty()) { + /* Pop the first item from the list */ + it = pendingList->begin(); + SocketClient* c = *it; + pendingList->erase(it); + /* Process it, if false is returned and our sockets are + * connection-based, remove and destroy it */ + if (!onDataAvailable(c) && mListen) { + /* Remove the client from our array */ + pthread_mutex_lock(&mClientsLock); + for (it = mClients->begin(); it != mClients->end(); ++it) { + if (*it == c) { + mClients->erase(it); + break; } - FD_CLR(fd, &read_fds); - pthread_mutex_lock(&mClientsLock); - continue; + } + pthread_mutex_unlock(&mClientsLock); + /* Destroy the client */ + int socket = c->getSocket(); + if (c->decRef()) { + // Note: 'c' is deleted memory at this point. + close(socket); } } - pthread_mutex_unlock(&mClientsLock); - } while (0); + } } + delete pendingList; } void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) { diff --git a/netcfg/netcfg.c b/netcfg/netcfg.c index fc9cf48..9cd883a 100644 --- a/netcfg/netcfg.c +++ b/netcfg/netcfg.c @@ -19,17 +19,13 @@ #include <stdlib.h> #include <errno.h> #include <dirent.h> +#include <netinet/ether.h> + +#include <netutils/ifc.h> +#include <netutils/dhcp.h> static int verbose = 0; -int ifc_init(); -void ifc_close(); -int ifc_up(char *iname); -int ifc_down(char *iname); -int ifc_remove_host_routes(char *iname); -int ifc_remove_default_route(char *iname); -int ifc_get_info(const char *name, unsigned *addr, unsigned *mask, unsigned *flags); -int do_dhcp(char *iname); void die(const char *reason) { @@ -37,16 +33,12 @@ void die(const char *reason) exit(1); } -const char *ipaddr(unsigned addr) +const char *ipaddr(in_addr_t addr) { - static char buf[32]; - - sprintf(buf,"%d.%d.%d.%d", - addr & 255, - ((addr >> 8) & 255), - ((addr >> 16) & 255), - (addr >> 24)); - return buf; + struct in_addr in_addr; + + in_addr.s_addr = addr; + return inet_ntoa(in_addr); } void usage(void) @@ -86,6 +78,15 @@ int dump_interfaces(void) return 0; } +int set_hwaddr(const char *name, const char *asc) { + struct ether_addr *addr = ether_aton(asc); + if (!addr) { + printf("Failed to parse '%s'\n", asc); + return -1; + } + return ifc_set_hwaddr(name, addr->ether_addr_octet); +} + struct { const char *name; @@ -97,6 +98,7 @@ struct { "down", 1, ifc_down }, { "flhosts", 1, ifc_remove_host_routes }, { "deldefault", 1, ifc_remove_default_route }, + { "hwaddr", 2, set_hwaddr }, { 0, 0, 0 }, }; diff --git a/nexus/DhcpClient.cpp b/nexus/DhcpClient.cpp index a5654d2..713059d 100644 --- a/nexus/DhcpClient.cpp +++ b/nexus/DhcpClient.cpp @@ -27,35 +27,15 @@ #include <sysutils/ServiceManager.h> +#include <netutils/ifc.h> +#include <netutils/dhcp.h> + #include "DhcpClient.h" #include "DhcpState.h" #include "DhcpListener.h" #include "IDhcpEventHandlers.h" #include "Controller.h" -extern "C" { -int ifc_disable(const char *ifname); -int ifc_add_host_route(const char *ifname, uint32_t addr); -int ifc_remove_host_routes(const char *ifname); -int ifc_set_default_route(const char *ifname, uint32_t gateway); -int ifc_get_default_route(const char *ifname); -int ifc_remove_default_route(const char *ifname); -int ifc_reset_connections(const char *ifname); -int ifc_configure(const char *ifname, in_addr_t ipaddr, in_addr_t netmask, in_addr_t gateway, in_addr_t dns1, in_addr_t dns2); - -int dhcp_do_request(const char *ifname, - in_addr_t *ipaddr, - in_addr_t *gateway, - in_addr_t *mask, - in_addr_t *dns1, - in_addr_t *dns2, - in_addr_t *server, - uint32_t *lease); -int dhcp_stop(const char *ifname); -int dhcp_release_lease(const char *ifname); -char *dhcp_get_errmsg(); -} - DhcpClient::DhcpClient(IDhcpEventHandlers *handlers) : mState(DhcpState::INIT), mHandlers(handlers) { mServiceManager = new ServiceManager(); diff --git a/patch.txt b/patch.txt new file mode 100644 index 0000000..258965d --- /dev/null +++ b/patch.txt @@ -0,0 +1,16 @@ +diff --git a/init/util.c b/init/util.c +index 4d98cc2..0667593 100755 +--- a/init/util.c ++++ b/init/util.c +@@ -657,8 +657,9 @@ static void get_hardware_name(void) + if (x) { + x += 2; + n = 0; +- while (*x && !isspace(*x)) { +- hardware[n++] = tolower(*x); ++ while (*x && *x != '\n') { ++ if (!isspace(*x)) ++ hardware[n++] = tolower(*x); + x++; + if (n == 31) break; + } diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 6d6012e..1a9e06f 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -7,7 +7,7 @@ copy_from := \ etc/dbus.conf \ etc/hosts -ifeq ($(TARGET_PRODUCT),generic) +ifeq ($(TARGET_PRODUCT),full) copy_from += etc/vold.fstab endif diff --git a/rootdir/etc/init.goldfish.sh b/rootdir/etc/init.goldfish.sh index 5ff0a3a..cfa2c82 100755 --- a/rootdir/etc/init.goldfish.sh +++ b/rootdir/etc/init.goldfish.sh @@ -45,3 +45,13 @@ esac # this line doesn't really do anything useful. however without it the # previous setprop doesn't seem to apply for some really odd reason setprop ro.qemu.init.completed 1 + +# set up the second interface (for inter-emulator connections) +# if required +my_ip=`getprop net.shared_net_ip` +case "$my_ip" in + "") + ;; + *) ifconfig eth1 "$my_ip" netmask 255.255.255.0 up + ;; +esac diff --git a/rootdir/etc/ueventd.goldfish.rc b/rootdir/etc/ueventd.goldfish.rc index e69de29..f4262fb 100644 --- a/rootdir/etc/ueventd.goldfish.rc +++ b/rootdir/etc/ueventd.goldfish.rc @@ -0,0 +1,2 @@ +/dev/qemu_trace 0666 system system +/dev/qemu_pipe 0666 system system diff --git a/rootdir/init.rc b/rootdir/init.rc index 8227273..f6e0196 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -166,6 +166,11 @@ on post-fs chown system system /data/dalvik-cache chmod 0771 /data/dalvik-cache + # create resource-cache and double-check the perms + mkdir /data/resource-cache 0771 system system + chown system system /data/resource-cache + chmod 0771 /data/resource-cache + # create the lost+found directories, so as to enforce our permissions mkdir /data/lost+found 0770 mkdir /cache/lost+found 0770 @@ -176,6 +181,11 @@ on post-fs chown root root /cache/lost+found chmod 0770 /cache/lost+found + # create data/drm directory + mkdir /data/drm 0774 drm drm + chown drm drm /data/drm + chmod 0774 /data/drm + on boot # basic network init ifup lo @@ -315,6 +325,7 @@ service vold /system/bin/vold service netd /system/bin/netd socket netd stream 0660 root system + socket dnsproxyd stream 0660 root inet service debuggerd /system/bin/debuggerd @@ -331,6 +342,13 @@ service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-sys onrestart restart media onrestart restart netd +service drm /system/bin/drmserver + user drm + group system root inet + +service drmio /system/bin/drmioserver + user drmio + service media /system/bin/mediaserver user media group system audio camera graphics inet net_bt net_bt_admin net_raw diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc index 254a1cf..d475c44 100644 --- a/rootdir/ueventd.rc +++ b/rootdir/ueventd.rc @@ -64,8 +64,6 @@ /dev/snd/dsp1 0660 system audio /dev/snd/mixer 0660 system audio /dev/smd0 0640 radio radio -/dev/qemu_trace 0666 system system -/dev/qemu_pipe 0666 system system /dev/qmi 0640 radio radio /dev/qmi0 0640 radio radio /dev/qmi1 0640 radio radio diff --git a/sh/Android.mk b/sh/Android.mk index b5e5c38..dcd13d8 100644 --- a/sh/Android.mk +++ b/sh/Android.mk @@ -29,7 +29,8 @@ LOCAL_SRC_FILES:= \ bltin/echo.c \ init.c -LOCAL_MODULE:= sh +LOCAL_MODULE:= ash +LOCAL_MODULE_TAGS:= shell_ash LOCAL_CFLAGS += -DSHELL -DWITH_LINENOISE @@ -51,3 +52,19 @@ make_ash_files: sh ./mkinit.sh $(PRIVATE_SRC_FILES) include $(BUILD_EXECUTABLE) + + +# create /system/bin/sh symlink to $(TARGET_SHELL) +# not the optimal place for this, but a fitting one + +OUTSYSTEMBINSH := $(TARGET_OUT)/bin/sh +LOCAL_MODULE := systembinsh +$(OUTSYSTEMBINSH): | $(TARGET_SHELL) +$(OUTSYSTEMBINSH): LOCAL_MODULE := $(LOCAL_MODULE) +$(OUTSYSTEMBINSH): + @echo "Symlink: $@ -> $(TARGET_SHELL)" + @rm -rf $@ + $(hide) ln -sf $(TARGET_SHELL) $@ + +ALL_DEFAULT_INSTALLED_MODULES += $(OUTSYSTEMBINSH) +ALL_MODULES.$(LOCAL_MODULE).INSTALLED += $(OUTSYSTEMBINSH) diff --git a/toolbox/chmod.c b/toolbox/chmod.c index 31a53bf..2a524e9 100644 --- a/toolbox/chmod.c +++ b/toolbox/chmod.c @@ -4,17 +4,74 @@ #include <sys/types.h> #include <dirent.h> #include <errno.h> +#include <sys/limits.h> +#include <sys/stat.h> #include <unistd.h> #include <time.h> +void recurse_chmod(char* path, int mode) +{ + struct dirent *dp; + DIR *dir = opendir(path); + if (dir == NULL) { + // not a directory, carry on + return; + } + char *subpath = malloc(sizeof(char)*PATH_MAX); + int pathlen = strlen(path); + + while ((dp = readdir(dir)) != NULL) { + if (strcmp(dp->d_name, ".") == 0 || + strcmp(dp->d_name, "..") == 0) continue; + + if (strlen(dp->d_name) + pathlen + 2/*NUL and slash*/ > PATH_MAX) { + fprintf(stderr, "Invalid path specified: too long\n"); + exit(1); + } + + strcpy(subpath, path); + strcat(subpath, "/"); + strcat(subpath, dp->d_name); + + if (chmod(subpath, mode) < 0) { + fprintf(stderr, "Unable to chmod %s: %s\n", subpath, strerror(errno)); + exit(1); + } + + recurse_chmod(subpath, mode); + } + free(subpath); + closedir(dir); +} + +static int usage() +{ + fprintf(stderr, "Usage: chmod [OPTION] <MODE> <FILE>\n"); + fprintf(stderr, " -R, --recursive change files and directories recursively\n"); + fprintf(stderr, " --help display this help and exit\n"); + + return 10; +} + int chmod_main(int argc, char **argv) { int i; - if (argc < 3) { - fprintf(stderr, "Usage: chmod <MODE> <FILE>\n"); - return 10; + if (argc < 3 || strcmp(argv[1], "--help") == 0) { + return usage(); + } + + int recursive = (strcmp(argv[1], "-R") == 0 || + strcmp(argv[1], "--recursive") == 0) ? 1 : 0; + + if (recursive && argc < 4) { + return usage(); + } + + if (recursive) { + argc--; + argv++; } int mode = 0; @@ -29,11 +86,15 @@ int chmod_main(int argc, char **argv) } s++; } + for (i = 2; i < argc; i++) { if (chmod(argv[i], mode) < 0) { fprintf(stderr, "Unable to chmod %s: %s\n", argv[i], strerror(errno)); return 10; } + if (recursive) { + recurse_chmod(argv[i], mode); + } } return 0; } diff --git a/toolbox/insmod.c b/toolbox/insmod.c index 44b9847..756a64b 100644 --- a/toolbox/insmod.c +++ b/toolbox/insmod.c @@ -77,7 +77,6 @@ int insmod_main(int argc, char **argv) memcpy(ptr, argv[i], len); ptr += len; *ptr++ = ' '; - *ptr++ = '\0'; } *(ptr - 1) = '\0'; } diff --git a/toolbox/ls.c b/toolbox/ls.c index 8799514..59ba35e 100644 --- a/toolbox/ls.c +++ b/toolbox/ls.c @@ -13,6 +13,130 @@ #include <grp.h> #include <linux/kdev_t.h> +#include <limits.h> + +// dynamic arrays +typedef struct { + int count; + int capacity; + void** items; +} dynarray_t; + +#define DYNARRAY_INITIALIZER { 0, 0, NULL } + +static void dynarray_init( dynarray_t *a ) +{ + a->count = a->capacity = 0; + a->items = NULL; +} + +static void dynarray_reserve_more( dynarray_t *a, int count ) +{ + int old_cap = a->capacity; + int new_cap = old_cap; + const int max_cap = INT_MAX/sizeof(void*); + void** new_items; + int new_count = a->count + count; + + if (count <= 0) + return; + + if (count > max_cap - a->count) + abort(); + + new_count = a->count + count; + + while (new_cap < new_count) { + old_cap = new_cap; + new_cap += (new_cap >> 2) + 4; + if (new_cap < old_cap || new_cap > max_cap) { + new_cap = max_cap; + } + } + new_items = realloc(a->items, new_cap*sizeof(void*)); + if (new_items == NULL) + abort(); + + a->items = new_items; + a->capacity = new_cap; +} + +static void dynarray_append( dynarray_t *a, void* item ) +{ + if (a->count >= a->capacity) + dynarray_reserve_more(a, 1); + + a->items[a->count++] = item; +} + +static void dynarray_done( dynarray_t *a ) +{ + free(a->items); + a->items = NULL; + a->count = a->capacity = 0; +} + +#define DYNARRAY_FOREACH_TYPE(_array,_item_type,_item,_stmnt) \ + do { \ + int _nn_##__LINE__ = 0; \ + for (;_nn_##__LINE__ < (_array)->count; ++ _nn_##__LINE__) { \ + _item_type _item = (_item_type)(_array)->items[_nn_##__LINE__]; \ + _stmnt; \ + } \ + } while (0) + +#define DYNARRAY_FOREACH(_array,_item,_stmnt) \ + DYNARRAY_FOREACH_TYPE(_array,void *,_item,_stmnt) + +// string arrays + +typedef dynarray_t strlist_t; + +#define STRLIST_INITIALIZER DYNARRAY_INITIALIZER + +#define STRLIST_FOREACH(_list,_string,_stmnt) \ + DYNARRAY_FOREACH_TYPE(_list,char *,_string,_stmnt) + +static void strlist_init( strlist_t *list ) +{ + dynarray_init(list); +} + +static void strlist_append_b( strlist_t *list, const void* str, size_t slen ) +{ + char *copy = malloc(slen+1); + memcpy(copy, str, slen); + copy[slen] = '\0'; + dynarray_append(list, copy); +} + +static void strlist_append_dup( strlist_t *list, const char *str) +{ + strlist_append_b(list, str, strlen(str)); +} + +static void strlist_done( strlist_t *list ) +{ + STRLIST_FOREACH(list, string, free(string)); + dynarray_done(list); +} + +static int strlist_compare_strings(const void* a, const void* b) +{ + const char *sa = *(const char **)a; + const char *sb = *(const char **)b; + return strcmp(sa, sb); +} + +static void strlist_sort( strlist_t *list ) +{ + if (list->count > 0) { + qsort(list->items, + (size_t)list->count, + sizeof(void*), + strlist_compare_strings); + } +} // bits for flags argument #define LIST_LONG (1 << 0) @@ -20,6 +144,7 @@ #define LIST_RECURSIVE (1 << 2) #define LIST_DIRECTORIES (1 << 3) #define LIST_SIZE (1 << 4) +#define LIST_CLASSIFY (1 << 6) // fwd static int listpath(const char *name, int flags); @@ -129,7 +254,27 @@ static int listfile_size(const char *path, const char *filename, int flags) } /* blocks are 512 bytes, we want output to be KB */ - printf("%lld %s\n", s.st_blocks / 2, filename); + if ((flags & LIST_SIZE) != 0) { + printf("%lld ", s.st_blocks / 2); + } + + if ((flags & LIST_CLASSIFY) != 0) { + char filetype = mode2kind(s.st_mode); + if (filetype != 'l') { + printf("%c ", filetype); + } else { + struct stat link_dest; + if (!stat(path, &link_dest)) { + printf("l%c ", mode2kind(link_dest.st_mode)); + } else { + fprintf(stderr, "stat '%s' failed: %s\n", path, strerror(errno)); + printf("l? "); + } + } + } + + printf("%s\n", filename); + return 0; } @@ -206,7 +351,7 @@ static int listfile_long(const char *path, int flags) static int listfile(const char *dirname, const char *filename, int flags) { - if ((flags & (LIST_LONG | LIST_SIZE)) == 0) { + if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY)) == 0) { printf("%s\n", filename); return 0; } @@ -233,7 +378,8 @@ static int listdir(const char *name, int flags) char tmp[4096]; DIR *d; struct dirent *de; - + strlist_t files = STRLIST_INITIALIZER; + d = opendir(name); if(d == 0) { fprintf(stderr, "opendir failed, %s\n", strerror(errno)); @@ -248,10 +394,16 @@ static int listdir(const char *name, int flags) if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue; if(de->d_name[0] == '.' && (flags & LIST_ALL) == 0) continue; - listfile(name, de->d_name, flags); + strlist_append_dup(&files, de->d_name); } + strlist_sort(&files); + STRLIST_FOREACH(&files, filename, listfile(name, filename, flags)); + strlist_done(&files); + if (flags & LIST_RECURSIVE) { + strlist_t subdirs = STRLIST_INITIALIZER; + rewinddir(d); while ((de = readdir(d)) != 0) { @@ -284,10 +436,15 @@ static int listdir(const char *name, int flags) } if (S_ISDIR(s.st_mode)) { - printf("\n%s:\n", tmp); - listdir(tmp, flags); + strlist_append_dup(&subdirs, tmp); } } + strlist_sort(&subdirs); + STRLIST_FOREACH(&subdirs, path, { + printf("\n%s:\n", path); + listdir(path, flags); + }); + strlist_done(&subdirs); } closedir(d); @@ -331,27 +488,41 @@ int ls_main(int argc, char **argv) if(argc > 1) { int i; int err = 0; + strlist_t files = STRLIST_INITIALIZER; for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "-l")) { - flags |= LIST_LONG; - } else if (!strcmp(argv[i], "-s")) { - flags |= LIST_SIZE; - } else if (!strcmp(argv[i], "-a")) { - flags |= LIST_ALL; - } else if (!strcmp(argv[i], "-R")) { - flags |= LIST_RECURSIVE; - } else if (!strcmp(argv[i], "-d")) { - flags |= LIST_DIRECTORIES; - } else { - listed++; - if(listpath(argv[i], flags) != 0) { - err = EXIT_FAILURE; + if (argv[i][0] == '-') { + /* an option ? */ + const char *arg = argv[i]+1; + while (arg[0]) { + switch (arg[0]) { + case 'l': flags |= LIST_LONG; break; + case 's': flags |= LIST_SIZE; break; + case 'R': flags |= LIST_RECURSIVE; break; + case 'd': flags |= LIST_DIRECTORIES; break; + case 'a': flags |= LIST_ALL; break; + case 'F': flags |= LIST_CLASSIFY; break; + default: + fprintf(stderr, "%s: Unknown option '-%c'. Aborting.\n", "ls", arg[0]); + exit(1); + } + arg++; } + } else { + /* not an option ? */ + strlist_append_dup(&files, argv[i]); } } - if (listed > 0) return err; + if (files.count > 0) { + STRLIST_FOREACH(&files, path, { + if (listpath(path, flags) != 0) { + err = EXIT_FAILURE; + } + }); + strlist_done(&files); + return err; + } } // list working directory if no files or directories were specified diff --git a/toolbox/mkdir.c b/toolbox/mkdir.c index 121adab..656970a 100644 --- a/toolbox/mkdir.c +++ b/toolbox/mkdir.c @@ -2,10 +2,14 @@ #include <unistd.h> #include <string.h> #include <errno.h> +#include <sys/limits.h> +#include <sys/stat.h> static int usage() { - fprintf(stderr,"mkdir <target>\n"); + fprintf(stderr,"mkdir [OPTION] <target>\n"); + fprintf(stderr," --help display usage and exit\n"); + fprintf(stderr," -p, --parents create parent directories as needed\n"); return -1; } @@ -13,15 +17,60 @@ int mkdir_main(int argc, char *argv[]) { int symbolic = 0; int ret; - if(argc < 2) return usage(); + if(argc < 2 || strcmp(argv[1], "--help") == 0) { + return usage(); + } + + int recursive = (strcmp(argv[1], "-p") == 0 || + strcmp(argv[1], "--parents") == 0) ? 1 : 0; + + if(recursive && argc < 3) { + // -p specified without a path + return usage(); + } + + if(recursive) { + argc--; + argv++; + } + + char currpath[PATH_MAX], *pathpiece; + struct stat st; while(argc > 1) { argc--; argv++; - ret = mkdir(argv[0], 0777); - if(ret < 0) { - fprintf(stderr, "mkdir failed for %s, %s\n", argv[0], strerror(errno)); - return ret; + if(recursive) { + // reset path + strcpy(currpath, ""); + // create the pieces of the path along the way + pathpiece = strtok(argv[0], "/"); + if(argv[0][0] == '/') { + // prepend / if needed + strcat(currpath, "/"); + } + while(pathpiece != NULL) { + if(strlen(currpath) + strlen(pathpiece) + 2/*NUL and slash*/ > PATH_MAX) { + fprintf(stderr, "Invalid path specified: too long\n"); + return 1; + } + strcat(currpath, pathpiece); + strcat(currpath, "/"); + if(stat(currpath, &st) != 0) { + ret = mkdir(currpath, 0777); + if(ret < 0) { + fprintf(stderr, "mkdir failed for %s, %s\n", currpath, strerror(errno)); + return ret; + } + } + pathpiece = strtok(NULL, "/"); + } + } else { + ret = mkdir(argv[0], 0777); + if(ret < 0) { + fprintf(stderr, "mkdir failed for %s, %s\n", argv[0], strerror(errno)); + return ret; + } } } diff --git a/toolbox/route.c b/toolbox/route.c index 107e48a..3e10014 100644 --- a/toolbox/route.c +++ b/toolbox/route.c @@ -80,14 +80,24 @@ int route_main(int argc, char *argv[]) /* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */ if (argc > 7 && !strcmp(argv[2], "-net") && - !strcmp(argv[4], "netmask") && !strcmp(argv[6], "gw")) { - rt.rt_flags = RTF_UP | RTF_GATEWAY; - if (set_address(argv[3], &rt.rt_dst) && - set_address(argv[5], &rt.rt_genmask) && - set_address(argv[7], &rt.rt_gateway)) { - errno = 0; + !strcmp(argv[4], "netmask")) { + if (!strcmp(argv[6], "gw")) { + rt.rt_flags = RTF_UP | RTF_GATEWAY; + if (set_address(argv[3], &rt.rt_dst) && + set_address(argv[5], &rt.rt_genmask) && + set_address(argv[7], &rt.rt_gateway)) { + errno = 0; + } + goto apply; + } else if (!strcmp(argv[6], "dev")) { + rt.rt_flags = RTF_UP; + rt.rt_dev = argv[7]; + if (set_address(argv[3], &rt.rt_dst) && + set_address(argv[5], &rt.rt_genmask)) { + errno = 0; + } + goto apply; } - goto apply; } } |