diff options
55 files changed, 1339 insertions, 543 deletions
diff --git a/adb/Android.mk b/adb/Android.mk index c8606cf..9725478 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -53,10 +53,13 @@ LOCAL_SRC_FILES := \ $(USB_SRCS) \ shlist.c \ utils.c \ + usb_vendors.c \ ifneq ($(USE_SYSDEPS_WIN32),) LOCAL_SRC_FILES += sysdeps_win32.c +else + LOCAL_SRC_FILES += fdevent.c endif LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter @@ -98,6 +101,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ adb.c \ + fdevent.c \ transport.c \ transport_local.c \ transport_usb.c \ @@ -29,6 +29,8 @@ #if !ADB_HOST #include <private/android_filesystem_config.h> +#else +#include "usb_vendors.h" #endif @@ -818,19 +820,6 @@ int adb_main(int is_daemon) #if !ADB_HOST int secure = 0; char value[PROPERTY_VALUE_MAX]; - - // prevent the OOM killer from killing us - char text[64]; - snprintf(text, sizeof text, "/proc/%d/oom_adj", (int)getpid()); - int fd = adb_open(text, O_WRONLY); - if (fd >= 0) { - // -17 should make us immune to OOM - snprintf(text, sizeof text, "%d", -17); - adb_write(fd, text, strlen(text)); - adb_close(fd); - } else { - D("adb: unable to open %s\n", text); - } #endif atexit(adb_cleanup); @@ -846,6 +835,7 @@ int adb_main(int is_daemon) #if ADB_HOST HOST = 1; + usb_vendors_init(); usb_init(); local_init(); @@ -929,6 +919,9 @@ int adb_main(int is_daemon) fdevent_loop(); usb_cleanup(); +#if ADB_HOST + usb_vendors_cleanup(); +#endif return 0; } @@ -375,7 +375,9 @@ int usb_close(usb_handle *h); void usb_kick(usb_handle *h); /* used for USB device detection */ +#if ADB_HOST int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol); +#endif unsigned host_to_le32(unsigned n); int adb_commandline(int argc, char **argv); diff --git a/libcutils/fdevent.c b/adb/fdevent.c index 4cf46fa..c179b20 100644 --- a/libcutils/fdevent.c +++ b/adb/fdevent.c @@ -26,7 +26,7 @@ #include <stdarg.h> #include <stddef.h> -#include <cutils/fdevent.h> +#include "fdevent.h" #define TRACE(x...) fprintf(stderr,x) @@ -87,7 +87,7 @@ static void fdevent_init() { /* XXX: what's a good size for the passed in hint? */ epoll_fd = epoll_create(256); - + if(epoll_fd < 0) { perror("epoll_create() failed"); exit(1); @@ -105,7 +105,7 @@ static void fdevent_connect(fdevent *fde) ev.events = 0; ev.data.ptr = fde; -#if 0 +#if 0 if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) { perror("epoll_ctl() failed\n"); exit(1); @@ -116,7 +116,7 @@ static void fdevent_connect(fdevent *fde) static void fdevent_disconnect(fdevent *fde) { struct epoll_event ev; - + memset(&ev, 0, sizeof(ev)); ev.events = 0; ev.data.ptr = fde; @@ -133,9 +133,9 @@ static void fdevent_update(fdevent *fde, unsigned events) { struct epoll_event ev; int active; - + active = (fde->state & FDE_EVENTMASK) != 0; - + memset(&ev, 0, sizeof(ev)); ev.events = 0; ev.data.ptr = fde; @@ -241,7 +241,7 @@ static void fdevent_connect(fdevent *fde) static void fdevent_disconnect(fdevent *fde) { int i, n; - + FD_CLR(fde->fd, &read_fds); FD_CLR(fde->fd, &write_fds); FD_CLR(fde->fd, &error_fds); @@ -283,9 +283,9 @@ static void fdevent_process() memcpy(&rfd, &read_fds, sizeof(fd_set)); memcpy(&wfd, &write_fds, sizeof(fd_set)); memcpy(&efd, &error_fds, sizeof(fd_set)); - + n = select(select_n, &rfd, &wfd, &efd, 0); - + if(n < 0) { if(errno == EINTR) return; perror("select"); @@ -300,12 +300,12 @@ static void fdevent_process() if(events) { n--; - + fde = fd_table[i]; if(fde == 0) FATAL("missing fde for fd %d\n", i); fde->events |= events; - + if(fde->state & FDE_PENDING) continue; fde->state |= FDE_PENDING; fdevent_plist_enqueue(fde); @@ -320,7 +320,7 @@ static void fdevent_register(fdevent *fde) if(fde->fd < 0) { FATAL("bogus negative fd (%d)\n", fde->fd); } - + if(fde->fd >= fd_table_max) { int oldmax = fd_table_max; if(fde->fd > 32000) { @@ -383,9 +383,9 @@ static fdevent *fdevent_plist_dequeue(void) { fdevent *list = &list_pending; fdevent *node = list->next; - + if(node == list) return 0; - + list->next = node->next; list->next->prev = list; node->next = 0; @@ -449,9 +449,9 @@ void fdevent_remove(fdevent *fde) void fdevent_set(fdevent *fde, unsigned events) { events &= FDE_EVENTMASK; - + if((fde->state & FDE_EVENTMASK) == events) return; - + if(fde->state & FDE_ACTIVE) { fdevent_update(fde, events); dump_fde(fde, "update"); @@ -487,13 +487,13 @@ void fdevent_del(fdevent *fde, unsigned events) void fdevent_loop() { fdevent *fde; - + for(;;) { #if DEBUG fprintf(stderr,"--- ---- waiting for events\n"); #endif fdevent_process(); - + while((fde = fdevent_plist_dequeue())) { unsigned events = fde->events; fde->events = 0; diff --git a/include/cutils/fdevent.h b/adb/fdevent.h index 7a442d4..6b7e7ec 100644 --- a/include/cutils/fdevent.h +++ b/adb/fdevent.h @@ -17,10 +17,13 @@ #ifndef __FDEVENT_H #define __FDEVENT_H +#include <stdint.h> /* for int64_t */ + /* events that may be observed */ #define FDE_READ 0x0001 #define FDE_WRITE 0x0002 #define FDE_ERROR 0x0004 +#define FDE_TIMEOUT 0x0008 /* features that may be set (via the events set/add/del interface) */ #define FDE_DONT_CLOSE 0x0080 @@ -30,6 +33,8 @@ typedef struct fdevent fdevent; typedef void (*fd_func)(int fd, unsigned events, void *userdata); /* Allocate and initialize a new fdevent object + * Note: use FD_TIMER as 'fd' to create a fd-less object + * (used to implement timers). */ fdevent *fdevent_create(int fd, fd_func func, void *arg); @@ -53,6 +58,8 @@ void fdevent_set(fdevent *fde, unsigned events); void fdevent_add(fdevent *fde, unsigned events); void fdevent_del(fdevent *fde, unsigned events); +void fdevent_set_timeout(fdevent *fde, int64_t timeout_ms); + /* loop forever, handling events. */ void fdevent_loop(); @@ -65,7 +72,7 @@ struct fdevent int fd; unsigned short state; unsigned short events; - + fd_func func; void *arg; }; diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c index 4e6d385..0ebfe73 100644 --- a/adb/file_sync_client.c +++ b/adb/file_sync_client.c @@ -165,7 +165,7 @@ static int sync_start_readtime(int fd, const char *path) } static int sync_finish_readtime(int fd, unsigned int *timestamp, - unsigned int *mode, unsigned int *size) + unsigned int *mode, unsigned int *size) { syncmsg msg; @@ -908,12 +908,12 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, unsigned int timestamp, mode, size; if (sync_finish_readtime(fd, ×tamp, &mode, &size)) return 1; - if (size == ci->size) { + if (size == ci->size) { /* for links, we cannot update the atime/mtime */ if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) || - (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) + (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) ci->flag = 1; - } + } } } #endif diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.c index 0de0dd5..65cb20a 100644 --- a/adb/framebuffer_service.c +++ b/adb/framebuffer_service.c @@ -20,7 +20,7 @@ #include <string.h> #include <fcntl.h> -#include <cutils/fdevent.h> +#include "fdevent.h" #include "adb.h" #include <linux/fb.h> diff --git a/adb/protocol.txt b/adb/protocol.txt index d0f307c..398d042 100644 --- a/adb/protocol.txt +++ b/adb/protocol.txt @@ -23,7 +23,7 @@ implementation to be much more robust. --- protocol overview and basics --------------------------------------- - + The transport layer deals in "messages", which consist of a 24 byte header followed (optionally) by a payload. The header consists of 6 32 bit words which are sent across the wire in little endian format. @@ -52,7 +52,7 @@ The identifiers "local-id" and "remote-id" are always relative to the reversed. - + --- CONNECT(version, maxdata, "system-identity-string") ---------------- The CONNECT message establishes the presence of a remote system. @@ -114,7 +114,7 @@ is used to establish the connection). Nonetheless, the local-id MUST not change on later READY messages sent to the same stream. - + --- WRITE(0, remote-id, "data") ---------------------------------------- The WRITE message sends data to the recipient's stream identified by @@ -172,7 +172,7 @@ to send across the wire. #define A_WRTE 0x45545257 - + --- implementation details --------------------------------------------- The core of the bridge program will use three threads. One thread diff --git a/adb/services.c b/adb/services.c index 1de55e6..0a5edcf 100644 --- a/adb/services.c +++ b/adb/services.c @@ -244,6 +244,18 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1 cmd, strerror(errno), errno); exit(-1); } else { +#if !ADB_HOST + // set child's OOM adjustment to zero + char text[64]; + snprintf(text, sizeof text, "/proc/%d/oom_adj", pid); + int fd = adb_open(text, O_WRONLY); + if (fd >= 0) { + adb_write(fd, "0", 1); + adb_close(fd); + } else { + D("adb: unable to open %s\n", text); + } +#endif return ptm; } #endif /* !HAVE_WIN32_PROC */ diff --git a/adb/sysdeps.h b/adb/sysdeps.h index e5d17a8..389fbd2 100644 --- a/adb/sysdeps.h +++ b/adb/sysdeps.h @@ -67,16 +67,16 @@ typedef void (*win_thread_func_t)(void* arg); static __inline__ int adb_thread_create( adb_thread_t *thread, adb_thread_func_t func, void* arg) { - thread->tid = _beginthread( (win_thread_func_t)func, 0, arg ); - if (thread->tid == (unsigned)-1L) { - return -1; - } - return 0; + thread->tid = _beginthread( (win_thread_func_t)func, 0, arg ); + if (thread->tid == (unsigned)-1L) { + return -1; + } + return 0; } static __inline__ void close_on_exec(int fd) { - /* nothing really */ + /* nothing really */ } extern void disable_tcp_nagle(int fd); @@ -138,7 +138,7 @@ static __inline__ int unix_write(int fd, const void* buf, size_t len) static __inline__ int adb_open_mode(const char* path, int options, int mode) { - return adb_open(path, options); + return adb_open(path, options); } static __inline__ int unix_open(const char* path, int options,...) @@ -169,7 +169,7 @@ extern int socket_network_client(const char *host, int port, int type); extern int socket_loopback_server(int port, int type); extern int socket_inaddr_any_server(int port, int type); -/* normally provided by <cutils/fdevent.h> */ +/* normally provided by "fdevent.h" */ #define FDE_READ 0x0001 #define FDE_WRITE 0x0002 @@ -203,7 +203,7 @@ struct fdevent { static __inline__ void adb_sleep_ms( int mseconds ) { - Sleep( mseconds ); + Sleep( mseconds ); } extern int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen); @@ -252,7 +252,7 @@ static __inline__ int adb_is_absolute_host_path( const char* path ) #else /* !_WIN32 a.k.a. Unix */ -#include <cutils/fdevent.h> +#include "fdevent.h" #include <cutils/sockets.h> #include <cutils/properties.h> #include <cutils/misc.h> @@ -290,7 +290,7 @@ typedef pthread_mutex_t adb_mutex_t; static __inline__ void close_on_exec(int fd) { - fcntl( fd, F_SETFD, FD_CLOEXEC ); + fcntl( fd, F_SETFD, FD_CLOEXEC ); } static __inline__ int unix_open(const char* path, int options,...) @@ -312,7 +312,7 @@ static __inline__ int unix_open(const char* path, int options,...) static __inline__ int adb_open_mode( const char* pathname, int options, int mode ) { - return open( pathname, options, mode ); + return open( pathname, options, mode ); } @@ -368,11 +368,11 @@ static __inline__ int adb_creat(const char* path, int mode) { int fd = creat(path, mode); - if ( fd < 0 ) - return -1; + if ( fd < 0 ) + return -1; close_on_exec(fd); - return fd; + return fd; } #undef creat #define creat ___xxx_creat @@ -439,12 +439,12 @@ static __inline__ int adb_socketpair( int sv[2] ) static __inline__ void adb_sleep_ms( int mseconds ) { - usleep( mseconds*1000 ); + usleep( mseconds*1000 ); } static __inline__ int adb_mkdir(const char* path, int mode) { - return mkdir(path, mode); + return mkdir(path, mode); } #undef mkdir #define mkdir ___xxx_mkdir diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c index c2a9a98..a8e3bb9 100644 --- a/adb/sysdeps_win32.c +++ b/adb/sysdeps_win32.c @@ -739,12 +739,12 @@ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrle { FH serverfh = _fh_from_int(serverfd); FH fh; - + if ( !serverfh || serverfh->clazz != &_fh_socket_class ) { D( "adb_socket_accept: invalid fd %d\n", serverfd ); return -1; } - + fh = _fh_alloc( &_fh_socket_class ); if (!fh) { D( "adb_socket_accept: not enough memory to allocate accepted socket descriptor\n" ); @@ -757,7 +757,7 @@ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrle D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError() ); return -1; } - + snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name ); D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh) ); return _fh_to_int(fh); @@ -768,7 +768,7 @@ void disable_tcp_nagle(int fd) { FH fh = _fh_from_int(fd); int on; - + if ( !fh || fh->clazz != &_fh_socket_class ) return; @@ -1746,7 +1746,7 @@ void fdevent_loop() /** FILE EVENT HOOKS **/ - + static void _event_file_prepare( EventHook hook ) { if (hook->wanted & (FDE_READ|FDE_WRITE)) { diff --git a/adb/transport_usb.c b/adb/transport_usb.c index 01c4a7e..50ebff7 100644 --- a/adb/transport_usb.c +++ b/adb/transport_usb.c @@ -23,6 +23,10 @@ #define TRACE_TAG TRACE_TRANSPORT #include "adb.h" +#if ADB_HOST +#include "usb_vendors.h" +#endif + /* XXX better define? */ #ifdef __ppc__ #define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) @@ -125,23 +129,23 @@ void init_usb_transport(atransport *t, usb_handle *h) #endif } +#if ADB_HOST int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol) { - if (vid == VENDOR_ID_GOOGLE) { - /* might support adb */ - } else if (vid == VENDOR_ID_HTC) { - /* might support adb */ - } else { - /* not supported */ - return 0; - } - - /* class:vendor (0xff) subclass:android (0x42) proto:adb (0x01) */ - if(usb_class == 0xff) { - if((usb_subclass == 0x42) && (usb_protocol == 0x01)) { - return 1; + unsigned i; + for (i = 0; i < vendorIdCount; i++) { + if (vid == vendorIds[i]) { + /* class:vendor (0xff) subclass:android (0x42) proto:adb (0x01) */ + if(usb_class == 0xff) { + if((usb_subclass == 0x42) && (usb_protocol == 0x01)) { + return 1; + } + } + + return 0; } } return 0; } +#endif diff --git a/adb/usb_osx.c b/adb/usb_osx.c index 2d4c1a9..171a9fc 100644 --- a/adb/usb_osx.c +++ b/adb/usb_osx.c @@ -28,20 +28,15 @@ #define TRACE_TAG TRACE_USB #include "adb.h" +#include "usb_vendors.h" #define DBG D #define ADB_SUBCLASS 0x42 #define ADB_PROTOCOL 0x1 -int vendorIds[] = { - VENDOR_ID_GOOGLE, - VENDOR_ID_HTC, -}; -#define NUM_VENDORS (sizeof(vendorIds)/sizeof(vendorIds[0])) - static IONotificationPortRef notificationPort = 0; -static io_iterator_t notificationIterators[NUM_VENDORS]; +static io_iterator_t* notificationIterators; struct usb_handle { @@ -81,7 +76,7 @@ InitUSB() memset(notificationIterators, 0, sizeof(notificationIterators)); //* loop through all supported vendors - for (i = 0; i < NUM_VENDORS; i++) { + for (i = 0; i < vendorIdCount; i++) { //* Create our matching dictionary to find the Android device's //* adb interface //* IOServiceAddMatchingNotification consumes the reference, so we do @@ -374,7 +369,7 @@ void* RunLoopThread(void* unused) CFRunLoopRun(); currentRunLoop = 0; - for (i = 0; i < NUM_VENDORS; i++) { + for (i = 0; i < vendorIdCount; i++) { IOObjectRelease(notificationIterators[i]); } IONotificationPortDestroy(notificationPort); @@ -391,6 +386,9 @@ void usb_init() { adb_thread_t tid; + notificationIterators = (io_iterator_t*)malloc( + vendorIdCount * sizeof(io_iterator_t)); + adb_mutex_init(&start_lock, NULL); adb_cond_init(&start_cond, NULL); @@ -415,6 +413,11 @@ void usb_cleanup() close_usb_devices(); if (currentRunLoop) CFRunLoopStop(currentRunLoop); + + if (notificationIterators != NULL) { + free(notificationIterators); + notificationIterators = NULL; + } } int usb_write(usb_handle *handle, const void *buf, int len) diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c new file mode 100644 index 0000000..f949249 --- /dev/null +++ b/adb/usb_vendors.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2009 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 "usb_vendors.h" + +#include "sysdeps.h" +#include <stdio.h> +#include "adb.h" + +int* vendorIds = NULL; +unsigned vendorIdCount = 0; + +void usb_vendors_init(void) { + /* for now, only put the built-in VENDOR_ID_* */ + vendorIdCount = 2; + vendorIds = (int*)malloc(vendorIdCount * sizeof(int)); + vendorIds[0] = VENDOR_ID_GOOGLE; + vendorIds[1] = VENDOR_ID_HTC; +} + +void usb_vendors_cleanup(void) { + if (vendorIds != NULL) { + free(vendorIds); + vendorIds = NULL; + vendorIdCount = 0; + } +} diff --git a/adb/usb_vendors.h b/adb/usb_vendors.h new file mode 100644 index 0000000..43e5f99 --- /dev/null +++ b/adb/usb_vendors.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2009 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 __USB_VENDORS_H +#define __USB_VENDORS_H + +extern int* vendorIds; +extern unsigned vendorIdCount; + +void usb_vendors_init(void); +void usb_vendors_cleanup(void); + +#endif
\ No newline at end of file diff --git a/adb/usb_windows.c b/adb/usb_windows.c index 7ddaa0c..0951f67 100644 --- a/adb/usb_windows.c +++ b/adb/usb_windows.c @@ -446,7 +446,7 @@ int recognized_device(usb_handle* handle) { } void find_devices() { - usb_handle* handle = NULL; + usb_handle* handle = NULL; char entry_buffer[2048]; char interf_name[2048]; AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]); diff --git a/include/cutils/abort_socket.h b/include/cutils/abort_socket.h new file mode 100644 index 0000000..fbb1112 --- /dev/null +++ b/include/cutils/abort_socket.h @@ -0,0 +1,103 @@ +/* + * Copyright 2009, 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. + */ + +/* Helper to perform abortable blocking operations on a socket: + * asocket_connect() + * asocket_accept() + * asocket_read() + * asocket_write() + * These calls are similar to the regular syscalls, but can be aborted with: + * asocket_abort() + * + * Calling close() on a regular POSIX socket does not abort blocked syscalls on + * that socket in other threads. + * + * After calling asocket_abort() the socket cannot be reused. + * + * Call asocket_destory() *after* all threads have finished with the socket to + * finish closing the socket and free the asocket structure. + * + * The helper is implemented by setting the socket non-blocking to initiate + * syscalls connect(), accept(), read(), write(), then using a blocking poll() + * on both the primary socket and a local pipe. This makes the poll() abortable + * by writing a byte to the local pipe in asocket_abort(). + * + * asocket_create() sets the fd to non-blocking mode. It must not be changed to + * blocking mode. + * + * Using asocket will triple the number of file descriptors required per + * socket, due to the local pipe. It may be possible to use a global pipe per + * process rather than per socket, but we have not been able to come up with a + * race-free implementation yet. + * + * All functions except asocket_init() and asocket_destroy() are thread safe. + */ + +#include <stdlib.h> +#include <sys/socket.h> + +#ifndef __CUTILS_ABORT_SOCKET_H__ +#define __CUTILS_ABORT_SOCKET_H__ +#ifdef __cplusplus +extern "C" { +#endif + +struct asocket { + int fd; /* primary socket fd */ + int abort_fd[2]; /* pipe used to abort */ +}; + +/* Create an asocket from fd. + * Sets the socket to non-blocking mode. + * Returns NULL on error with errno set. + */ +struct asocket *asocket_init(int fd); + +/* Blocking socket I/O with timeout. + * Calling asocket_abort() from another thread will cause each of these + * functions to immediately return with value -1 and errno ECANCELED. + * timeout is in ms, use -1 to indicate no timeout. On timeout -1 is returned + * with errno ETIMEDOUT. + * EINTR is handled in-call. + * Other semantics are identical to the regular syscalls. + */ +int asocket_connect(struct asocket *s, const struct sockaddr *addr, + socklen_t addrlen, int timeout); + +int asocket_accept(struct asocket *s, struct sockaddr *addr, + socklen_t *addrlen, int timeout); + +int asocket_read(struct asocket *s, void *buf, size_t count, int timeout); + +int asocket_write(struct asocket *s, const void *buf, size_t count, + int timeout); + +/* Abort above calls and shutdown socket. + * Further I/O operations on this socket will immediately fail after this call. + * asocket_destroy() should be used to release resources once all threads + * have returned from blocking calls on the socket. + */ +void asocket_abort(struct asocket *s); + +/* Close socket and free asocket structure. + * Must not be called until all calls on this structure have completed. + */ +void asocket_destroy(struct asocket *s); + +#ifdef __cplusplus +} +#endif +#endif //__CUTILS_ABORT_SOCKET__H__ diff --git a/include/cutils/native_handle.h b/include/cutils/native_handle.h index 38ac11a..89d6b65 100644 --- a/include/cutils/native_handle.h +++ b/include/cutils/native_handle.h @@ -17,52 +17,57 @@ #ifndef NATIVE_HANDLE_H_ #define NATIVE_HANDLE_H_ -#include <sys/cdefs.h> - -__BEGIN_DECLS +#ifdef __cplusplus +extern "C" { +#endif typedef struct { - int version; /* sizeof(native_handle) */ + int version; /* sizeof(native_handle_t) */ int numFds; /* number of file-descriptors at &data[0] */ int numInts; /* number of ints at &data[numFds] */ int data[0]; /* numFds + numInts ints */ -} native_handle; +} native_handle_t; + +/* keep the old definition for backward source-compatibility */ +typedef native_handle_t native_handle; /* * native_handle_close * - * closes the file descriptors contained in this native_handle + * closes the file descriptors contained in this native_handle_t * * return 0 on success, or a negative error code on failure * */ -int native_handle_close(const native_handle* h); +int native_handle_close(const native_handle_t* h); /* * native_handle_create * - * creates a native_handle and initializes it. must be destroyed with + * creates a native_handle_t and initializes it. must be destroyed with * native_handle_delete(). * */ -native_handle* native_handle_create(int numFds, int numInts); +native_handle_t* native_handle_create(int numFds, int numInts); /* * native_handle_delete * - * frees a native_handle allocated with native_handle_create(). - * This ONLY frees the memory allocated for the native_handle, but doesn't + * frees a native_handle_t allocated with native_handle_create(). + * This ONLY frees the memory allocated for the native_handle_t, but doesn't * close the file descriptors; which can be achieved with native_handle_close(). * * return 0 on success, or a negative error code on failure * */ -int native_handle_delete(native_handle* h); +int native_handle_delete(native_handle_t* h); -__END_DECLS +#ifdef __cplusplus +} +#endif #endif /* NATIVE_HANDLE_H_ */ diff --git a/include/cutils/tztime.h b/include/cutils/tztime.h index 4af2ce4..cf103ca 100644 --- a/include/cutils/tztime.h +++ b/include/cutils/tztime.h @@ -32,6 +32,7 @@ void localtime_tz(const time_t * const timep, struct tm * tmp, const char* tz); struct strftime_locale { const char *mon[12]; /* short names */ const char *month[12]; /* long names */ + const char *standalone_month[12]; /* long standalone names */ const char *wday[7]; /* short names */ const char *weekday[7]; /* long names */ const char *X_fmt; diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h index a47f2e4..a4351ac 100644 --- a/include/private/android_filesystem_config.h +++ b/include/private/android_filesystem_config.h @@ -49,6 +49,7 @@ #define AID_MEDIA 1013 /* mediaserver process */ #define AID_DHCP 1014 /* dhcp client */ #define AID_SDCARD_RW 1015 /* external storage write access */ +#define AID_VPN 1016 /* vpn system */ #define AID_SHELL 2000 /* adb and debug shell user */ #define AID_CACHE 2001 /* cache access */ @@ -95,6 +96,7 @@ static struct android_id_info android_ids[] = { { "net_bt_admin", AID_NET_BT_ADMIN, }, { "net_bt", AID_NET_BT, }, { "sdcard_rw", AID_SDCARD_RW, }, + { "vpn", AID_VPN, }, { "inet", AID_INET, }, { "net_raw", AID_NET_RAW, }, { "misc", AID_MISC, }, @@ -170,6 +172,7 @@ static struct fs_path_config android_files[] = { { 06755, AID_ROOT, AID_ROOT, "system/xbin/librank" }, { 06755, AID_ROOT, AID_ROOT, "system/xbin/procrank" }, { 06755, AID_ROOT, AID_ROOT, "system/xbin/procmem" }, + { 06755, AID_ROOT, AID_ROOT, "system/xbin/tcpdump" }, { 00755, AID_ROOT, AID_SHELL, "system/bin/*" }, { 00755, AID_ROOT, AID_SHELL, "system/xbin/*" }, { 00750, AID_ROOT, AID_SHELL, "sbin/*" }, diff --git a/include/sysutils/FrameworkClient.h b/include/sysutils/FrameworkClient.h index 1eb112a..0ef0753 100644 --- a/include/sysutils/FrameworkClient.h +++ b/include/sysutils/FrameworkClient.h @@ -13,8 +13,8 @@ public: FrameworkClient(int sock); virtual ~FrameworkClient() {} - int sendMsg(char *msg); - int sendMsg(char *msg, char *data); + int sendMsg(const char *msg); + int sendMsg(const char *msg, const char *data); }; typedef android::List<FrameworkClient *> FrameworkClientCollection; diff --git a/include/sysutils/ServiceManager.h b/include/sysutils/ServiceManager.h new file mode 100644 index 0000000..c31dd8f --- /dev/null +++ b/include/sysutils/ServiceManager.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 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 _SERVICE_MANAGER_H +#define _SERVICE_MANAGER_H + +class ServiceManager { +public: + ServiceManager(); + virtual ~ServiceManager() {} + + int start(const char *name); + int stop(const char *name); + bool isRunning(const char *name); +}; + +#endif diff --git a/include/sysutils/SocketClient.h b/include/sysutils/SocketClient.h index cde64a5..469dd9d 100644 --- a/include/sysutils/SocketClient.h +++ b/include/sysutils/SocketClient.h @@ -15,8 +15,8 @@ public: int getSocket() { return mSocket; } - int sendMsg(int code, char *msg, bool addErrno); - int sendMsg(char *msg); + int sendMsg(int code, const char *msg, bool addErrno); + int sendMsg(const char *msg); }; typedef android::List<SocketClient *> SocketClientCollection; diff --git a/include/sysutils/SocketListener.h b/include/sysutils/SocketListener.h index 30d050d..68dcb8f 100644 --- a/include/sysutils/SocketListener.h +++ b/include/sysutils/SocketListener.h @@ -37,8 +37,8 @@ public: int startListener(); int stopListener(); - void sendBroadcast(int code, char *msg, bool addErrno); - void sendBroadcast(char *msg); + void sendBroadcast(int code, const char *msg, bool addErrno); + void sendBroadcast(const char *msg); protected: virtual bool onDataAvailable(SocketClient *c) = 0; diff --git a/init/builtins.c b/init/builtins.c index bcdfee1..93ce6e8 100644 --- a/init/builtins.c +++ b/init/builtins.c @@ -127,7 +127,7 @@ done: static void service_start_if_not_disabled(struct service *svc) { if (!(svc->flags & SVC_DISABLED)) { - service_start(svc); + service_start(svc, NULL); } } @@ -372,7 +372,7 @@ int do_start(int nargs, char **args) struct service *svc; svc = service_find_by_name(args[1]); if (svc) { - service_start(svc); + service_start(svc, NULL); } return 0; } @@ -393,7 +393,7 @@ int do_restart(int nargs, char **args) svc = service_find_by_name(args[1]); if (svc) { service_stop(svc); - service_start(svc); + service_start(svc, NULL); } return 0; } diff --git a/init/devices.c b/init/devices.c index 8aea772..300faab 100644 --- a/init/devices.c +++ b/init/devices.c @@ -131,9 +131,9 @@ static struct perms_ devperms[] = { { "/dev/qmi0", 0640, AID_RADIO, AID_RADIO, 0 }, { "/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 }, { "/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 }, - /* CDMA radio interface MUX */ { "/dev/ts0710mux", 0640, AID_RADIO, AID_RADIO, 1 }, + { "/dev/tun", 0640, AID_VPN , AID_VPN, 0 }, { NULL, 0, 0, 0, 0 }, }; diff --git a/init/init.c b/init/init.c index 283608c..8c2a058 100644 --- a/init/init.c +++ b/init/init.c @@ -156,7 +156,7 @@ static void publish_socket(const char *name, int fd) fcntl(fd, F_SETFD, 0); } -void service_start(struct service *svc) +void service_start(struct service *svc, const char *dynamic_args) { struct stat s; pid_t pid; @@ -192,6 +192,13 @@ void service_start(struct service *svc) return; } + if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) { + ERROR("service '%s' must be one-shot to use dynamic args, disabling\n", + svc->args[0]); + svc->flags |= SVC_DISABLED; + return; + } + NOTICE("starting '%s'\n", svc->name); pid = fork(); @@ -248,8 +255,27 @@ void service_start(struct service *svc) setuid(svc->uid); } - if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) { - ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno)); + if (!dynamic_args) { + if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) { + ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno)); + } + } else { + char *arg_ptrs[SVC_MAXARGS+1]; + int arg_idx = svc->nargs; + char *tmp = strdup(dynamic_args); + char *next = tmp; + char *bword; + + /* Copy the static arguments */ + memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *))); + + while((bword = strsep(&next, " "))) { + arg_ptrs[arg_idx++] = bword; + if (arg_idx == SVC_MAXARGS) + break; + } + arg_ptrs[arg_idx] = '\0'; + execve(svc->args[0], (char**) arg_ptrs, (char**) ENV); } _exit(127); } @@ -381,7 +407,7 @@ static void restart_service_if_needed(struct service *svc) if (next_start_time <= gettime()) { svc->flags &= (~SVC_RESTARTING); - service_start(svc); + service_start(svc, NULL); return; } @@ -407,13 +433,28 @@ static void sigchld_handler(int s) static void msg_start(const char *name) { - struct service *svc = service_find_by_name(name); + struct service *svc; + char *tmp = NULL; + char *args = NULL; + + if (!strchr(name, ':')) + svc = service_find_by_name(name); + else { + tmp = strdup(name); + args = strchr(tmp, ':'); + *args = '\0'; + args++; + + svc = service_find_by_name(tmp); + } if (svc) { - service_start(svc); + service_start(svc, args); } else { ERROR("no such service '%s'\n", name); } + if (tmp) + free(tmp); } static void msg_stop(const char *name) @@ -739,7 +780,7 @@ void handle_keychord(int fd) svc = service_find_by_keychord(id); if (svc) { INFO("starting service %s from keychord\n", svc->name); - service_start(svc); + service_start(svc, NULL); } else { ERROR("service for keychord %d not found\n", id); } diff --git a/init/init.h b/init/init.h index b93eb50..f306b7b 100644 --- a/init/init.h +++ b/init/init.h @@ -116,6 +116,8 @@ struct svcenvinfo { #define NR_SVC_SUPP_GIDS 6 /* six supplementary groups */ +#define SVC_MAXARGS 64 + struct service { /* list of all services */ struct listnode slist; @@ -160,7 +162,7 @@ void service_for_each_class(const char *classname, void service_for_each_flags(unsigned matchflags, void (*func)(struct service *svc)); void service_stop(struct service *svc); -void service_start(struct service *svc); +void service_start(struct service *svc, const char *dynamic_args); void property_changed(const char *name, const char *value); struct action *action_remove_queue_head(void); diff --git a/init/parser.c b/init/parser.c index 30fa3de..33c1a68 100644 --- a/init/parser.c +++ b/init/parser.c @@ -60,8 +60,6 @@ void DUMP(void) #endif } -#define MAXARGS 64 - #define T_EOF 0 #define T_TEXT 1 #define T_NEWLINE 2 @@ -357,7 +355,7 @@ void parse_new_section(struct parse_state *state, int kw, static void parse_config(const char *fn, char *s) { struct parse_state state; - char *args[MAXARGS]; + char *args[SVC_MAXARGS]; int nargs; nargs = 0; @@ -384,7 +382,7 @@ static void parse_config(const char *fn, char *s) } break; case T_TEXT: - if (nargs < MAXARGS) { + if (nargs < SVC_MAXARGS) { args[nargs++] = state.text; } break; diff --git a/libacc/FEATURES b/libacc/FEATURES index 3e80890..1a44415 100644 --- a/libacc/FEATURES +++ b/libacc/FEATURES @@ -56,7 +56,7 @@ Supported C language subset (read joint example 'otccex.c' to have - C Strings and C character constants are supported. Only '\n', '\"', '\'' and '\\' escapes are recognized. - - C Comments can be used (but no C++ comments). + - Both C comments ( /* */ ) and C++ comments ( // ... end-of-line ) can be used. - No error is displayed if an incorrect program is given. diff --git a/libacc/MODULE_LICENSE_BSD_LIKE b/libacc/MODULE_LICENSE_BSD_LIKE new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libacc/MODULE_LICENSE_BSD_LIKE diff --git a/libacc/acc.cpp b/libacc/acc.cpp index 50d90dd..04d45d5 100644 --- a/libacc/acc.cpp +++ b/libacc/acc.cpp @@ -1,4 +1,15 @@ /* + * Android "Almost" C Compiler. + * This is a compiler for a small subset of the C language, intended for use + * in scripting environments where speed and memory footprint are important. + * + * This code is based upon the "unobfuscated" version of the + * Obfuscated Tiny C compiler, and retains the + * original copyright notice and license from that compiler, see below. + * + */ + +/* Obfuscated Tiny C Compiler Copyright (C) 2001-2003 Fabrice Bellard @@ -23,6 +34,7 @@ #include <ctype.h> #include <dlfcn.h> #include <stdarg.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -31,11 +43,25 @@ #include <unistd.h> #endif +#if defined(__arm__) +#define DEFAULT_ARM_CODEGEN +#define PROVIDE_ARM_CODEGEN +#elif defined(__i386__) +#define DEFAULT_X86_CODEGEN +#define PROVIDE_X86_CODEGEN +#elif defined(__x86_64__) +#define DEFAULT_X64_CODEGEN +#define PROVIDE_X64_CODEGEN +#endif + + +#ifdef PROVIDE_ARM_CODEGEN #include "disassem.h" +#endif namespace acc { -class compiler { +class Compiler { class CodeBuf { char* ind; char* pProgramBase; @@ -63,16 +89,8 @@ class compiler { ind = pProgramBase; } - void o(int n) { - /* cannot use unsigned, so we must do a hack */ - while (n && n != -1) { - *ind++ = n; - n = n >> 8; - } - } - int o4(int n) { - int result = (int) ind; + intptr_t result = (intptr_t) ind; * (int*) ind = n; ind += 4; return result; @@ -85,41 +103,16 @@ class compiler { *ind++ = n; } - /* output a symbol and patch all calls to it */ - void gsym(int t) { - int n; - while (t) { - n = *(int *) t; /* next value */ - *(int *) t = ((int) ind) - t - 4; - t = n; - } - } - - /* psym is used to put an instruction with a data field which is a - reference to a symbol. It is in fact the same as oad ! */ - int psym(int n, int t) { - return oad(n, t); - } - - /* instruction + address */ - int oad(int n, int t) { - o(n); - *(int *) ind = t; - t = (int) ind; - ind = ind + 4; - return t; - } - inline void* getBase() { return (void*) pProgramBase; } - int getSize() { + intptr_t getSize() { return ind - pProgramBase; } - int getPC() { - return (int) ind; + intptr_t getPC() { + return (intptr_t) ind; } }; @@ -164,15 +157,14 @@ class compiler { virtual void storeEAX(int ea) = 0; - virtual void loadEAX(int ea) = 0; - - virtual void postIncrementOrDecrement(int n, int op) = 0; + virtual void loadEAX(int ea, bool isIncDec, int op) = 0; virtual int beginFunctionCallArguments() = 0; + virtual void storeEAToArg(int l) = 0; + virtual void endFunctionCallArguments(int a, int l) = 0; - virtual void storeEAToArg(int l) = 0; virtual int callForward(int symbol) = 0; @@ -180,14 +172,12 @@ class compiler { virtual void callIndirect(int l) = 0; - virtual void adjustStackAfterCall(int l) = 0; + virtual void adjustStackAfterCall(int l, bool isIndirect) = 0; virtual int disassemble(FILE* out) = 0; /* output a symbol and patch all calls to it */ - virtual void gsym(int t) { - pCodeBuf->gsym(t); - } + virtual void gsym(int t) = 0; virtual int finishCompile() { #if defined(__arm__) @@ -206,10 +196,6 @@ class compiler { virtual int jumpOffset() = 0; protected: - void o(int n) { - pCodeBuf->o(n); - } - /* * Output a byte. Handles all values, 0..ff. */ @@ -217,32 +203,23 @@ class compiler { pCodeBuf->ob(n); } - /* psym is used to put an instruction with a data field which is a - reference to a symbol. It is in fact the same as oad ! */ - int psym(int n, int t) { - return oad(n, t); - } - - /* instruction + address */ - int oad(int n, int t) { - return pCodeBuf->oad(n,t); + intptr_t o4(int data) { + return pCodeBuf->o4(data); } - int getBase() { - return (int) pCodeBuf->getBase(); + intptr_t getBase() { + return (intptr_t) pCodeBuf->getBase(); } - int getPC() { + intptr_t getPC() { return pCodeBuf->getPC(); } - - int o4(int data) { - return pCodeBuf->o4(data); - } private: CodeBuf* pCodeBuf; }; +#ifdef PROVIDE_ARM_CODEGEN + class ARMCodeGenerator : public CodeGenerator { public: ARMCodeGenerator() {} @@ -360,6 +337,12 @@ class compiler { case OP_MUL: o4(0x0E0000091); // mul r0,r1,r0 break; + case OP_DIV: + callRuntime(runtime_DIV); + break; + case OP_MOD: + callRuntime(runtime_MOD); + break; case OP_PLUS: o4(0xE0810000); // add r0,r1,r0 break; @@ -429,62 +412,90 @@ class compiler { virtual void leaEAX(int ea) { fprintf(stderr, "leaEAX(%d);\n", ea); - if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) { - error("Offset out of range: %08x", ea); - } - if (ea < 0) { - o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea + if (ea < LOCAL) { + // Local, fp relative + if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) { + error("Offset out of range: %08x", ea); + } + if (ea < 0) { + o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea + } else { + o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea + } } else { - o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea + // Global, absolute. + o4(0xE59F0000); // ldr r0, .L1 + o4(0xEA000000); // b .L99 + o4(ea); // .L1: .word 0 + // .L99: } - } virtual void storeEAX(int ea) { fprintf(stderr, "storeEAX(%d);\n", ea); - if (ea < -4095 || ea > 4095) { - error("Offset out of range: %08x", ea); - } - if (ea < 0) { - o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea] - } else { - o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea] + if (ea < LOCAL) { + // Local, fp relative + if (ea < -4095 || ea > 4095) { + error("Offset out of range: %08x", ea); + } + if (ea < 0) { + o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea] + } else { + o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea] + } + } else{ + // Global, absolute + o4(0xE59F1000); // ldr r1, .L1 + o4(0xEA000000); // b .L99 + o4(ea); // .L1: .word 0 + o4(0xE5810000); // .L99: str r0, [r1] } } - virtual void loadEAX(int ea) { - fprintf(stderr, "loadEAX(%d);\n", ea); - if (ea < -4095 || ea > 4095) { - error("Offset out of range: %08x", ea); - } - if (ea < 0) { - o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea] + virtual void loadEAX(int ea, bool isIncDec, int op) { + fprintf(stderr, "loadEAX(%d, %d, %d);\n", ea, isIncDec, op); + if (ea < LOCAL) { + // Local, fp relative + if (ea < -4095 || ea > 4095) { + error("Offset out of range: %08x", ea); + } + if (ea < 0) { + o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea] + } else { + o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea] + } } else { - o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea] + // Global, absolute + o4(0xE59F2000); // ldr r2, .L1 + o4(0xEA000000); // b .L99 + o4(ea); // .L1: .word ea + o4(0xE5920000); // .L99: ldr r0, [r2] } - } - virtual void postIncrementOrDecrement(int ea, int op) { - fprintf(stderr, "postIncrementOrDecrement(%d, %d);\n", ea, op); - /* R0 has the original value. - */ - switch (op) { - case OP_INCREMENT: - o4(0xE2801001); // add r1, r0, #1 - break; - case OP_DECREMENT: - o4(0xE2401001); // sub r1, r0, #1 - break; - default: - error("unknown opcode: %d", op); - } - if (ea < -4095 || ea > 4095) { - error("Offset out of range: %08x", ea); - } - if (ea < 0) { - o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea] - } else { - o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea] + if (isIncDec) { + switch (op) { + case OP_INCREMENT: + o4(0xE2801001); // add r1, r0, #1 + break; + case OP_DECREMENT: + o4(0xE2401001); // sub r1, r0, #1 + break; + default: + error("unknown opcode: %d", op); + } + if (ea < LOCAL) { + // Local, fp relative + // Don't need range check, was already checked above + if (ea < 0) { + o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea] + } else { + o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea] + } + } else{ + // Global, absolute + // r2 is already set up from before. + o4(0xE5821000); // str r1, [r2] + } } } @@ -493,6 +504,14 @@ class compiler { return o4(0xE24DDF00); // Placeholder } + virtual void storeEAToArg(int l) { + fprintf(stderr, "storeEAToArg(%d);\n", l); + if (l < 0 || l > 4096-4) { + error("l out of range for stack offset: 0x%08x", l); + } + o4(0xE58D0000 + l); // str r0, [sp, #4] + } + virtual void endFunctionCallArguments(int a, int l) { fprintf(stderr, "endFunctionCallArguments(0x%08x, %d);\n", a, l); if (l < 0 || l > 0x3FC) { @@ -506,14 +525,6 @@ class compiler { } } - virtual void storeEAToArg(int l) { - fprintf(stderr, "storeEAToArg(%d);\n", l); - if (l < 0 || l > 4096-4) { - error("l out of range for stack offset: 0x%08x", l); - } - o4(0xE58D0000 + l); // str r0, [sp, #4] - } - virtual int callForward(int symbol) { fprintf(stderr, "callForward(%d);\n", symbol); // Forward calls are always short (local) @@ -538,20 +549,27 @@ class compiler { virtual void callIndirect(int l) { fprintf(stderr, "callIndirect(%d);\n", l); - oad(0x2494ff, l); /* call *xxx(%esp) */ + int argCount = l >> 2; + int poppedArgs = argCount > 4 ? 4 : argCount; + int adjustedL = l - (poppedArgs << 2); + if (adjustedL < 0 || adjustedL > 4096-4) { + error("l out of range for stack offset: 0x%08x", l); + } + o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL] + o4(0xE12FFF3C); // blx r12 } - virtual void adjustStackAfterCall(int l) { - fprintf(stderr, "adjustStackAfterCall(%d);\n", l); - if (l < 0 || l > 0x3FC) { - error("L out of range for stack adjustment: 0x%08x", l); - } + virtual void adjustStackAfterCall(int l, bool isIndirect) { + fprintf(stderr, "adjustStackAfterCall(%d, %d);\n", l, isIndirect); int argCount = l >> 2; - if (argCount > 4) { - int remainingArgs = argCount - 4; - o4(0xE28DDF00 | remainingArgs); // add sp, sp, #0x3fc + int stackArgs = argCount > 4 ? argCount - 4 : 0; + int stackUse = stackArgs + (isIndirect ? 1 : 0); + if (stackUse) { + if (stackUse < 0 || stackUse > 255) { + error("L out of range for stack adjustment: 0x%08x", l); + } + o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2 } - } virtual int jumpOffset() { @@ -594,6 +612,7 @@ class compiler { } return 0; } + private: static FILE* disasmOut; @@ -635,6 +654,22 @@ class compiler { return BRANCH_REL_ADDRESS_MASK & (value >> 2); } + typedef int (*int2FnPtr)(int a, int b); + void callRuntime(int2FnPtr fn) { + o4(0xE59F2000); // ldr r2, .L1 + o4(0xEA000000); // b .L99 + o4((int) fn); //.L1: .word fn + o4(0xE12FFF32); //.L99: blx r2 + } + + static int runtime_DIV(int a, int b) { + return b / a; + } + + static int runtime_MOD(int a, int b) { + return b % a; + } + void error(const char* fmt,...) { va_list ap; va_start(ap, fmt); @@ -644,6 +679,10 @@ class compiler { } }; +#endif // PROVIDE_X86_CODEGEN + +#ifdef PROVIDE_X86_CODEGEN + class X86CodeGenerator : public CodeGenerator { public: X86CodeGenerator() {} @@ -723,29 +762,28 @@ class compiler { gmov(6, ea); /* mov %eax, EA */ } - virtual void loadEAX(int ea) { + virtual void loadEAX(int ea, bool isIncDec, int op) { gmov(8, ea); /* mov EA, %eax */ - } - - virtual void postIncrementOrDecrement(int n, int op) { - /* Implement post-increment or post decrement. - */ - gmov(0, n); /* 83 ADD */ - o(decodeOp(op)); + if (isIncDec) { + /* Implement post-increment or post decrement. + */ + gmov(0, ea); /* 83 ADD */ + o(decodeOp(op)); + } } virtual int beginFunctionCallArguments() { return oad(0xec81, 0); /* sub $xxx, %esp */ } - virtual void endFunctionCallArguments(int a, int l) { - * (int*) a = l; - } - virtual void storeEAToArg(int l) { oad(0x248489, l); /* movl %eax, xxx(%esp) */ } + virtual void endFunctionCallArguments(int a, int l) { + * (int*) a = l; + } + virtual int callForward(int symbol) { return psym(0xe8, symbol); /* call xxx */ } @@ -758,7 +796,10 @@ class compiler { oad(0x2494ff, l); /* call *xxx(%esp) */ } - virtual void adjustStackAfterCall(int l) { + virtual void adjustStackAfterCall(int l, bool isIndirect) { + if (isIndirect) { + l += 4; + } oad(0xc481, l); /* add $xxx, %esp */ } @@ -770,7 +811,45 @@ class compiler { return 1; } + /* output a symbol and patch all calls to it */ + virtual void gsym(int t) { + int n; + int pc = getPC(); + while (t) { + n = *(int *) t; /* next value */ + *(int *) t = pc - t - 4; + t = n; + } + } + private: + + /** Output 1 to 4 bytes. + * + */ + void o(int n) { + /* cannot use unsigned, so we must do a hack */ + while (n && n != -1) { + ob(n & 0xff); + n = n >> 8; + } + } + + /* psym is used to put an instruction with a data field which is a + reference to a symbol. It is in fact the same as oad ! */ + int psym(int n, int t) { + return oad(n, t); + } + + /* instruction + address */ + int oad(int n, int t) { + o(n); + int result = getPC(); + o4(t); + return result; + } + + static const int operatorHelper[]; int decodeOp(int op) { @@ -787,6 +866,8 @@ class compiler { } }; +#endif // PROVIDE_X86_CODEGEN + /* vars: value of variables loc : local variable index glo : global variable index @@ -796,7 +877,7 @@ class compiler { dstk: define stack dptr, dch: macro state */ - int tok, tokc, tokl, ch, vars, rsym, loc, glo, sym_stk, dstk, + intptr_t tok, tokc, tokl, ch, vars, rsym, loc, glo, sym_stk, dstk, dptr, dch, last_id; void* pSymbolBase; void* pGlobalBase; @@ -932,7 +1013,7 @@ class compiler { } else { *(char *) dstk = TAG_TOK; /* no need to mark end of string (we suppose data is initialized to zero by calloc) */ - tok = (int) (strstr((char*) sym_stk, (char*) (last_id - 1)) + tok = (intptr_t) (strstr((char*) sym_stk, (char*) (last_id - 1)) - sym_stk); *(char *) dstk = 0; /* mark real end of ident for dlsym() */ tok = tok * 8 + TOK_IDENT; @@ -1034,7 +1115,7 @@ class compiler { exit(1); } - void skip(int c) { + void skip(intptr_t c) { if (tok != c) { error("'%c' expected", c); } @@ -1042,8 +1123,8 @@ class compiler { } /* l is one if '=' parsing wanted (quick hack) */ - void unary(int l) { - int n, t, a, c; + void unary(intptr_t l) { + intptr_t n, t, a, c; t = 0; n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */ @@ -1108,7 +1189,7 @@ class compiler { n = *(int *) t; /* forward reference: try dlsym */ if (!n) { - n = (int) dlsym(RTLD_DEFAULT, (char*) last_id); + n = (intptr_t) dlsym(RTLD_DEFAULT, (char*) last_id); } if ((tok == '=') & l) { /* assignment */ @@ -1117,9 +1198,8 @@ class compiler { pGen->storeEAX(n); } else if (tok != '(') { /* variable */ - pGen->loadEAX(n); + pGen->loadEAX(n, tokl == 11, tokc); if (tokl == 11) { - pGen->postIncrementOrDecrement(n, tokc); next(); } } @@ -1150,17 +1230,16 @@ class compiler { *(int *) t = pGen->callForward(*(int *) t); } else if (n == 1) { pGen->callIndirect(l); - l = l + 4; } else { - pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset()); /* call xxx */ + pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset()); } - if (l) - pGen->adjustStackAfterCall(l); + if (l | (n == 1)) + pGen->adjustStackAfterCall(l, n == 1); } } - void sum(int l) { - int t, n, a; + void sum(intptr_t l) { + intptr_t t, n, a; t = 0; if (l-- == 1) unary(1); @@ -1207,8 +1286,8 @@ class compiler { return pGen->gtst(0, 0); } - void block(int l) { - int a, n, t; + void block(intptr_t l) { + intptr_t a, n, t; if (tok == TOK_IF) { next(); @@ -1250,7 +1329,7 @@ class compiler { } } skip(')'); - block((int) &a); + block((intptr_t) &a); pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */ pGen->gsym(a); } else if (tok == '{') { @@ -1276,8 +1355,8 @@ class compiler { } /* 'l' is true if local declarations */ - void decl(int l) { - int a; + void decl(bool l) { + intptr_t a; while ((tok == TOK_INT) | ((tok != -1) & (!l))) { if (tok == TOK_INT) { @@ -1368,17 +1447,30 @@ class compiler { pGen = 0; if (architecture != NULL) { - if (strcmp(architecture, "arm") == 0) { +#ifdef PROVIDE_ARM_CODEGEN + if (! pGen && strcmp(architecture, "arm") == 0) { pGen = new ARMCodeGenerator(); - } else if (strcmp(architecture, "x86") == 0) { + } +#endif +#ifdef PROVIDE_X86_CODEGEN + if (! pGen && strcmp(architecture, "x86") == 0) { pGen = new X86CodeGenerator(); - } else { - fprintf(stderr, "Unknown architecture %s", architecture); + } +#endif + if (!pGen ) { + fprintf(stderr, "Unknown architecture %s\n", architecture); } } if (pGen == NULL) { +#if defined(DEFAULT_ARM_CODEGEN) pGen = new ARMCodeGenerator(); +#elif defined(DEFAULT_X86_CODEGEN) + pGen = new X86CodeGenerator(); +#endif + } + if (pGen == NULL) { + fprintf(stderr, "No code generator defined."); } } @@ -1390,11 +1482,11 @@ public: const char* architecture; }; - compiler() { + Compiler() { clear(); } - ~compiler() { + ~Compiler() { cleanup(); } @@ -1403,16 +1495,19 @@ public: clear(); codeBuf.init(ALLOC_SIZE); setArchitecture(args.architecture); + if (!pGen) { + return -1; + } pGen->init(&codeBuf); file = in; - sym_stk = (int) calloc(1, ALLOC_SIZE); - dstk = (int) strcpy((char*) sym_stk, + sym_stk = (intptr_t) calloc(1, ALLOC_SIZE); + dstk = (intptr_t) strcpy((char*) sym_stk, " int if else while break return for define main ") + TOK_STR_SIZE; pGlobalBase = calloc(1, ALLOC_SIZE); - glo = (int) pGlobalBase; + glo = (intptr_t) pGlobalBase; pVarsBase = calloc(1, ALLOC_SIZE); - vars = (int) pVarsBase; + vars = (intptr_t) pVarsBase; inp(); next(); decl(0); @@ -1441,10 +1536,10 @@ public: }; -const char* compiler::operatorChars = +const char* Compiler::operatorChars = "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@"; -const char compiler::operatorLevel[] = +const char Compiler::operatorLevel[] = {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, /* ==, != */ 9, 10, /* &&, || */ @@ -1452,9 +1547,12 @@ const char compiler::operatorLevel[] = 2, 2 /* ~ ! */ }; -FILE* compiler::ARMCodeGenerator::disasmOut; +#ifdef PROVIDE_ARM_CODEGEN +FILE* Compiler::ARMCodeGenerator::disasmOut; +#endif -const int compiler::X86CodeGenerator::operatorHelper[] = { +#ifdef PROVIDE_X86_CODEGEN +const int Compiler::X86CodeGenerator::operatorHelper[] = { 0x1, // ++ 0xff, // -- 0xc1af0f, // * @@ -1478,11 +1576,12 @@ const int compiler::X86CodeGenerator::operatorHelper[] = { 0xd0f7, // ~ 0x4 // ! }; +#endif } // namespace acc // This is a separate function so it can easily be set by breakpoint in gdb. -int run(acc::compiler& c, int argc, char** argv) { +int run(acc::Compiler& c, int argc, char** argv) { return c.run(argc, argv); } @@ -1491,7 +1590,7 @@ int main(int argc, char** argv) { bool doDisassemble = false; const char* inFile = NULL; const char* outFile = NULL; - const char* architecture = "arm"; + const char* architecture = NULL; int i; for (i = 1; i < argc; i++) { char* arg = argv[i]; @@ -1536,9 +1635,11 @@ int main(int argc, char** argv) { return 1; } } - acc::compiler compiler; - acc::compiler::args args; - args.architecture = architecture; + acc::Compiler compiler; + acc::Compiler::args args; + if (architecture != NULL) { + args.architecture = architecture; + } int compileResult = compiler.compile(in, args); if (in != stdin) { fclose(in); diff --git a/libacc/test b/libacc/test index 0b767da..28b7655 100755 --- a/libacc/test +++ b/libacc/test @@ -1,3 +1,13 @@ #!/bin/sh +rm -f tests/acc g++ acc.cpp disassem.cpp -g -ldl -o tests/acc && tests/acc tests/otcc.c -a x86 -d tests/otcc.out && diff tests/otcc.out tests/otcc.out-orig -tests/acc -S tests/returnval.c +if [ -x "tests/acc" ]; then + tests/acc -S tests/returnval.c + + if [ "$(uname)" = "Linux" ]; then + if [ "$(uname -m)" = "i686" ]; then + echo "Linux i686. Testing otcc.c" + tests/acc tests/otcc.c tests/otcc.c tests/returnval.c + fi + fi +fi diff --git a/libacc/testarm b/libacc/testarm new file mode 100755 index 0000000..d1a442e --- /dev/null +++ b/libacc/testarm @@ -0,0 +1,4 @@ +#!/bin/sh +adb remount +adb push tests/returnval.c /system/bin/returnval.c +mm -j8 && adb sync && adb shell /system/bin/acc -S /system/bin/returnval.c diff --git a/libcutils/Android.mk b/libcutils/Android.mk index 3bc48fb..aaee8bf 100644 --- a/libcutils/Android.mk +++ b/libcutils/Android.mk @@ -17,6 +17,7 @@ LOCAL_PATH := $(my-dir) include $(CLEAR_VARS) commonSources := \ + abort_socket.c \ array.c \ hashmap.c \ atomic.c \ @@ -62,7 +63,6 @@ else commonSources += \ mspace.c \ selector.c \ - fdevent.c \ tztime.c \ adb_networking.c \ zygote.c diff --git a/libcutils/abort_socket.c b/libcutils/abort_socket.c new file mode 100644 index 0000000..d732142 --- /dev/null +++ b/libcutils/abort_socket.c @@ -0,0 +1,293 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <sys/poll.h> + +#include "cutils/abort_socket.h" + +struct asocket *asocket_init(int fd) { + int abort_fd[2]; + int flags; + struct asocket *s; + + /* set primary socket to non-blocking */ + flags = fcntl(fd, F_GETFL); + if (flags == -1) + return NULL; + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) + return NULL; + + /* create pipe with non-blocking write, so that asocket_close() cannot + block */ + if (pipe(abort_fd)) + return NULL; + flags = fcntl(abort_fd[1], F_GETFL); + if (flags == -1) + return NULL; + if (fcntl(abort_fd[1], F_SETFL, flags | O_NONBLOCK)) + return NULL; + + s = malloc(sizeof(struct asocket)); + if (!s) + return NULL; + + s->fd = fd; + s->abort_fd[0] = abort_fd[0]; + s->abort_fd[1] = abort_fd[1]; + + return s; +} + +int asocket_connect(struct asocket *s, const struct sockaddr *addr, + socklen_t addrlen, int timeout) { + + int ret; + + do { + ret = connect(s->fd, addr, addrlen); + } while (ret && errno == EINTR); + + if (ret && errno == EINPROGRESS) { + /* ready to poll() */ + socklen_t retlen; + struct pollfd pfd[2]; + + pfd[0].fd = s->fd; + pfd[0].events = POLLOUT; + pfd[0].revents = 0; + pfd[1].fd = s->abort_fd[0]; + pfd[1].events = POLLIN; + pfd[1].revents = 0; + + do { + ret = poll(pfd, 2, timeout); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) + return -1; + else if (ret == 0) { + /* timeout */ + errno = ETIMEDOUT; + return -1; + } + + if (pfd[1].revents) { + /* abort due to asocket_abort() */ + errno = ECANCELED; + return -1; + } + + if (pfd[0].revents) { + if (pfd[0].revents & POLLOUT) { + /* connect call complete, read return code */ + retlen = sizeof(ret); + if (getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &ret, &retlen)) + return -1; + /* got connect() return code */ + if (ret) { + errno = ret; + } + } else { + /* some error event on this fd */ + errno = ECONNABORTED; + return -1; + } + } + } + + return ret; +} + +int asocket_accept(struct asocket *s, struct sockaddr *addr, + socklen_t *addrlen, int timeout) { + + int ret; + struct pollfd pfd[2]; + + pfd[0].fd = s->fd; + pfd[0].events = POLLIN; + pfd[0].revents = 0; + pfd[1].fd = s->abort_fd[0]; + pfd[1].events = POLLIN; + pfd[1].revents = 0; + + do { + ret = poll(pfd, 2, timeout); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) + return -1; + else if (ret == 0) { + /* timeout */ + errno = ETIMEDOUT; + return -1; + } + + if (pfd[1].revents) { + /* abort due to asocket_abort() */ + errno = ECANCELED; + return -1; + } + + if (pfd[0].revents) { + if (pfd[0].revents & POLLIN) { + /* ready to accept() without blocking */ + do { + ret = accept(s->fd, addr, addrlen); + } while (ret < 0 && errno == EINTR); + } else { + /* some error event on this fd */ + errno = ECONNABORTED; + return -1; + } + } + + return ret; +} + +int asocket_read(struct asocket *s, void *buf, size_t count, int timeout) { + int ret; + struct pollfd pfd[2]; + + pfd[0].fd = s->fd; + pfd[0].events = POLLIN; + pfd[0].revents = 0; + pfd[1].fd = s->abort_fd[0]; + pfd[1].events = POLLIN; + pfd[1].revents = 0; + + do { + ret = poll(pfd, 2, timeout); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) + return -1; + else if (ret == 0) { + /* timeout */ + errno = ETIMEDOUT; + return -1; + } + + if (pfd[1].revents) { + /* abort due to asocket_abort() */ + errno = ECANCELED; + return -1; + } + + if (pfd[0].revents) { + if (pfd[0].revents & POLLIN) { + /* ready to read() without blocking */ + do { + ret = read(s->fd, buf, count); + } while (ret < 0 && errno == EINTR); + } else { + /* some error event on this fd */ + errno = ECONNABORTED; + return -1; + } + } + + return ret; +} + +int asocket_write(struct asocket *s, const void *buf, size_t count, + int timeout) { + int ret; + struct pollfd pfd[2]; + + pfd[0].fd = s->fd; + pfd[0].events = POLLOUT; + pfd[0].revents = 0; + pfd[1].fd = s->abort_fd[0]; + pfd[1].events = POLLIN; + pfd[1].revents = 0; + + do { + ret = poll(pfd, 2, timeout); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) + return -1; + else if (ret == 0) { + /* timeout */ + errno = ETIMEDOUT; + return -1; + } + + if (pfd[1].revents) { + /* abort due to asocket_abort() */ + errno = ECANCELED; + return -1; + } + + if (pfd[0].revents) { + if (pfd[0].revents & POLLIN) { + /* ready to write() without blocking */ + do { + ret = write(s->fd, buf, count); + } while (ret < 0 && errno == EINTR); + } else { + /* some error event on this fd */ + errno = ECONNABORTED; + return -1; + } + } + + return ret; +} + +void asocket_abort(struct asocket *s) { + int ret; + char buf = 0; + + /* Prevent further use of fd, without yet releasing the fd */ + shutdown(s->fd, SHUT_RDWR); + + /* wake up calls blocked at poll() */ + do { + ret = write(s->abort_fd[1], &buf, 1); + } while (ret < 0 && errno == EINTR); +} + +void asocket_destroy(struct asocket *s) { + struct asocket s_copy = *s; + + /* Clients should *not* be using these fd's after calling + asocket_destroy(), but in case they do, set to -1 so they cannot use a + stale fd */ + s->fd = -1; + s->abort_fd[0] = -1; + s->abort_fd[1] = -1; + + /* Call asocket_abort() in case there are still threads blocked on this + socket. Clients should not rely on this behavior - it is racy because we + are about to close() these sockets - clients should instead make sure + all threads are done with the socket before calling asocket_destory(). + */ + asocket_abort(&s_copy); + + /* enough safety checks, close and release memory */ + close(s_copy.abort_fd[1]); + close(s_copy.abort_fd[0]); + close(s_copy.fd); + + free(s); +} diff --git a/libcutils/native_handle.c b/libcutils/native_handle.c index 842e1ed..4089968 100644 --- a/libcutils/native_handle.c +++ b/libcutils/native_handle.c @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "Gralloc" +#define LOG_TAG "NativeHandle" #include <stdint.h> #include <errno.h> @@ -25,30 +25,30 @@ #include <cutils/log.h> #include <cutils/native_handle.h> -native_handle* native_handle_create(int numFds, int numInts) +native_handle_t* native_handle_create(int numFds, int numInts) { - native_handle* h = malloc( - sizeof(native_handle) + sizeof(int)*(numFds+numInts)); - - h->version = sizeof(native_handle); + native_handle_t* h = malloc( + sizeof(native_handle_t) + sizeof(int)*(numFds+numInts)); + + h->version = sizeof(native_handle_t); h->numFds = numFds; h->numInts = numInts; return h; } -int native_handle_delete(native_handle* h) +int native_handle_delete(native_handle_t* h) { if (h) { - if (h->version != sizeof(native_handle)) + if (h->version != sizeof(native_handle_t)) return -EINVAL; free(h); } return 0; } -int native_handle_close(const native_handle* h) +int native_handle_close(const native_handle_t* h) { - if (h->version != sizeof(native_handle)) + if (h->version != sizeof(native_handle_t)) return -EINVAL; const int numFds = h->numFds; diff --git a/libcutils/tzstrftime.c b/libcutils/tzstrftime.c index 29c5015..e37d79a 100644 --- a/libcutils/tzstrftime.c +++ b/libcutils/tzstrftime.c @@ -172,10 +172,17 @@ label: pt, ptlim, modifier); continue; case 'B': - pt = _add((t->tm_mon < 0 || - t->tm_mon >= MONSPERYEAR) ? - "?" : Locale->month[t->tm_mon], - pt, ptlim, modifier); + if (modifier == '-') { + pt = _add((t->tm_mon < 0 || + t->tm_mon >= MONSPERYEAR) ? + "?" : Locale->standalone_month[t->tm_mon], + pt, ptlim, modifier); + } else { + pt = _add((t->tm_mon < 0 || + t->tm_mon >= MONSPERYEAR) ? + "?" : Locale->month[t->tm_mon], + pt, ptlim, modifier); + } continue; case 'b': case 'h': diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk index 2f3e106..dd2b32d 100644 --- a/libsysutils/Android.mk +++ b/libsysutils/Android.mk @@ -16,6 +16,7 @@ LOCAL_SRC_FILES:= \ src/NetlinkEvent.cpp \ src/FrameworkCommand.cpp \ src/SocketClient.cpp \ + src/ServiceManager.cpp \ LOCAL_MODULE:= libsysutils diff --git a/libsysutils/src/FrameworkClient.cpp b/libsysutils/src/FrameworkClient.cpp index 237bb60..1686996 100644 --- a/libsysutils/src/FrameworkClient.cpp +++ b/libsysutils/src/FrameworkClient.cpp @@ -13,8 +13,7 @@ FrameworkClient::FrameworkClient(int socket) { pthread_mutex_init(&mWriteMutex, NULL); } -int FrameworkClient::sendMsg(char *msg) { - LOGD("FrameworkClient::sendMsg(%s)", msg); +int FrameworkClient::sendMsg(const char *msg) { if (mSocket < 0) { errno = EHOSTUNREACH; return -1; @@ -28,7 +27,7 @@ int FrameworkClient::sendMsg(char *msg) { return 0; } -int FrameworkClient::sendMsg(char *msg, char *data) { +int FrameworkClient::sendMsg(const char *msg, const char *data) { char *buffer = (char *) alloca(strlen(msg) + strlen(data) + 1); if (!buffer) { errno = -ENOMEM; diff --git a/libsysutils/src/ServiceManager.cpp b/libsysutils/src/ServiceManager.cpp new file mode 100644 index 0000000..700ac91 --- /dev/null +++ b/libsysutils/src/ServiceManager.cpp @@ -0,0 +1,73 @@ +#include <errno.h> + +#include <sysutils/ServiceManager.h> + +#define LOG_TAG "Service" +#include <cutils/log.h> +#include <cutils/properties.h> + +ServiceManager::ServiceManager() { +} + +int ServiceManager::start(const char *name) { + if (isRunning(name)) { + LOGW("Service '%s' is already running", name); + return 0; + } + + LOGD("Starting service '%s'", name); + property_set("ctl.start", name); + + int count = 200; + while(count--) { + sched_yield(); + if (isRunning(name)) + break; + } + if (!count) { + LOGW("Timed out waiting for service '%s' to start", name); + errno = ETIMEDOUT; + return -1; + } + LOGD("Sucessfully started '%s'", name); + return 0; +} + +int ServiceManager::stop(const char *name) { + if (!isRunning(name)) { + LOGW("Service '%s' is already stopped", name); + return 0; + } + + LOGD("Stopping service '%s'", name); + property_set("ctl.stop", name); + + int count = 200; + while(count--) { + sched_yield(); + if (!isRunning(name)) + break; + } + + if (!count) { + LOGW("Timed out waiting for service '%s' to stop", name); + errno = ETIMEDOUT; + return -1; + } + LOGD("Sucessfully stopped '%s'", name); + return 0; +} + +bool ServiceManager::isRunning(const char *name) { + char propVal[PROPERTY_VALUE_MAX]; + char propName[255]; + + snprintf(propName, sizeof(propVal), "init.svc.%s", name); + + + if (property_get(propName, propVal, NULL)) { + if (!strcmp(propVal, "running")) + return true; + } + return false; +} diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp index ab020ca..b229627 100644 --- a/libsysutils/src/SocketClient.cpp +++ b/libsysutils/src/SocketClient.cpp @@ -14,7 +14,7 @@ SocketClient::SocketClient(int socket) { pthread_mutex_init(&mWriteMutex, NULL); } -int SocketClient::sendMsg(int code, char *msg, bool addErrno) { +int SocketClient::sendMsg(int code, const char *msg, bool addErrno) { char *buf; if (addErrno) { @@ -27,23 +27,24 @@ int SocketClient::sendMsg(int code, char *msg, bool addErrno) { return sendMsg(buf); } -int SocketClient::sendMsg(char *msg) { +int SocketClient::sendMsg(const char *msg) { if (mSocket < 0) { errno = EHOSTUNREACH; return -1; } - char *bp; - + char *tmp; + const char *bp = msg; + if (msg[strlen(msg)] != '\n') { - bp = (char *) alloca(strlen(msg) + 1); - strcpy(bp, msg); - strcat(bp, "\n"); - } else - bp = msg; + tmp = (char *) alloca(strlen(msg) + 1); + strcpy(tmp, msg); + strcat(tmp, "\n"); + bp = tmp; + } int rc = 0; - char *p = bp; + const char *p = bp; int brtw = strlen(bp); pthread_mutex_lock(&mWriteMutex); diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp index acc4a67..cb7dd80 100644 --- a/libsysutils/src/SocketListener.cpp +++ b/libsysutils/src/SocketListener.cpp @@ -173,7 +173,7 @@ void SocketListener::runListener() { } } -void SocketListener::sendBroadcast(int code, char *msg, bool addErrno) { +void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) { pthread_mutex_lock(&mClientsLock); SocketClientCollection::iterator i; @@ -185,7 +185,7 @@ void SocketListener::sendBroadcast(int code, char *msg, bool addErrno) { pthread_mutex_unlock(&mClientsLock); } -void SocketListener::sendBroadcast(char *msg) { +void SocketListener::sendBroadcast(const char *msg) { pthread_mutex_lock(&mClientsLock); SocketClientCollection::iterator i; diff --git a/logcat/event-log-tags b/logcat/event-log-tags index 28cad0a..f9355ec 100644 --- a/logcat/event-log-tags +++ b/logcat/event-log-tags @@ -323,6 +323,12 @@ # PDP drop caused by network 50109 pdp_network_drop (cid|1|5), (network_type|1|5) +# CDMA data network setup failure +50110 cdma_data_setup_failed (cause|1|5), (cid|1|5), (network_type|1|5) + +# CDMA data network drop +50111 cdma_data_drop (cid|1|5), (network_type|1|5) + # Do not change these names without updating tag in: #//device/dalvik/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.c 51000 socket_stats (send|1|2),(recv|1|2),(ip|1|5),(port|1|5),(close|1|5) diff --git a/nexus/CommandListener.cpp b/nexus/CommandListener.cpp index d9ee971..fdf3fed 100644 --- a/nexus/CommandListener.cpp +++ b/nexus/CommandListener.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ #include <stdlib.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> #include <errno.h> #define LOG_TAG "CommandListener" @@ -25,6 +28,7 @@ #include "Controller.h" #include "NetworkManager.h" #include "WifiController.h" +#include "VpnController.h" #include "ErrorCode.h" CommandListener::CommandListener() : @@ -40,6 +44,8 @@ CommandListener::CommandListener() : registerCmd(new WifiGetVarCmd()); registerCmd(new VpnEnableCmd()); + registerCmd(new VpnSetVarCmd()); + registerCmd(new VpnGetVarCmd()); registerCmd(new VpnDisableCmd()); } @@ -261,6 +267,79 @@ int CommandListener::VpnEnableCmd::runCommand(SocketClient *cli, char *data) { return 0; } +CommandListener::VpnSetVarCmd::VpnSetVarCmd() : + NexusCommand("vpn_setvar") { +} + +int CommandListener::VpnSetVarCmd::runCommand(SocketClient *cli, char *data) { + VpnController *vc = (VpnController *) NetworkManager::Instance()->findController("VPN"); + + char *bword; + char *last; + char varname[32]; + char val[250]; + + if (!(bword = strtok_r(data, ":", &last))) + goto out_inval; + + strncpy(varname, bword, sizeof(varname)); + + if (!(bword = strtok_r(NULL, ":", &last))) + goto out_inval; + + strncpy(val, bword, sizeof(val)); + + if (!strcasecmp(varname, "vpn_gateway")) { + if (vc->setVpnGateway(val)) + goto out_inval; + } else { + cli->sendMsg(ErrorCode::CommandParameterError, "Variable not found.", true); + return 0; + } + + cli->sendMsg(ErrorCode::CommandOkay, "Variable written.", false); + return 0; + +out_inval: + errno = EINVAL; + cli->sendMsg(ErrorCode::CommandParameterError, "Failed to set variable.", true); + return 0; +} + +CommandListener::VpnGetVarCmd::VpnGetVarCmd() : + NexusCommand("vpn_getvar") { +} + +int CommandListener::VpnGetVarCmd::runCommand(SocketClient *cli, char *data) { + VpnController *vc = (VpnController *) NetworkManager::Instance()->findController("VPN"); + + char *bword; + char *last; + char varname[32]; + + if (!(bword = strtok_r(data, ":", &last))) + goto out_inval; + + strncpy(varname, bword, sizeof(varname)); + + if (!strcasecmp(varname, "vpn_gateway")) { + char buffer[255]; + + sprintf(buffer, "%s:%s", varname, inet_ntoa(vc->getVpnGateway())); + cli->sendMsg(ErrorCode::VariableRead, buffer, false); + } else { + cli->sendMsg(ErrorCode::CommandParameterError, "Variable not found.", true); + return 0; + } + + cli->sendMsg(ErrorCode::CommandOkay, "Variable read.", false); + return 0; +out_inval: + errno = EINVAL; + cli->sendMsg(ErrorCode::CommandParameterError, "Failed to get variable.", true); + return 0; +} + CommandListener::VpnDisableCmd::VpnDisableCmd() : NexusCommand("vpn_disable") { } diff --git a/nexus/CommandListener.h b/nexus/CommandListener.h index 7bc89e3..a44aa29 100644 --- a/nexus/CommandListener.h +++ b/nexus/CommandListener.h @@ -95,6 +95,20 @@ private: int runCommand(SocketClient *c, char *data); }; + class VpnSetVarCmd : public NexusCommand { + public: + VpnSetVarCmd(); + virtual ~VpnSetVarCmd() {} + int runCommand(SocketClient *c, char *data); + }; + + class VpnGetVarCmd : public NexusCommand { + public: + VpnGetVarCmd(); + virtual ~VpnGetVarCmd() {} + int runCommand(SocketClient *c, char *data); + }; + class VpnDisableCmd : public NexusCommand { public: VpnDisableCmd(); diff --git a/nexus/ErrorCode.h b/nexus/ErrorCode.h index 8ca6cae..57c99c2 100644 --- a/nexus/ErrorCode.h +++ b/nexus/ErrorCode.h @@ -26,6 +26,9 @@ public: static const int WifiScanResult = 125; static const int WifiNetworkList = 126; + static const int VariableRead = 127; + static const int VariableWrite = 128; + // 200 series - Requested action has been successfully completed static const int CommandOkay = 200; diff --git a/nexus/OpenVpnController.cpp b/nexus/OpenVpnController.cpp index eff653a..411a0c7 100644 --- a/nexus/OpenVpnController.cpp +++ b/nexus/OpenVpnController.cpp @@ -14,17 +14,28 @@ * limitations under the License. */ #include <errno.h> +#include <netinet/in.h> +#include <arpa/inet.h> #define LOG_TAG "OpenVpnController" #include <cutils/log.h> #include <cutils/properties.h> +#include <sysutils/ServiceManager.h> + #include "OpenVpnController.h" #define DAEMON_PROP_NAME "vpn.openvpn.status" +#define DAEMON_CONFIG_FILE "/data/misc/openvpn/openvpn.conf" + OpenVpnController::OpenVpnController() : VpnController() { + mServiceManager = new ServiceManager(); +} + +OpenVpnController::~OpenVpnController() { + delete mServiceManager; } int OpenVpnController::start() { @@ -36,69 +47,24 @@ int OpenVpnController::stop() { } int OpenVpnController::enable() { - - // Validate configuration file - - // Validate key file - - if (startServiceDaemon()) + char svc[PROPERTY_VALUE_MAX]; + char tmp[64]; + + if (!getProperty("vpn.gateway", tmp, sizeof(tmp))) { + LOGE("Error reading property 'vpn.gateway' (%s)", strerror(errno)); return -1; - - errno = -ENOSYS; - return -1; -} - -int OpenVpnController::startServiceDaemon() { - char status[PROPERTY_VALUE_MAX]; - int count = 100; - - property_set("ctl.start", "openvpn"); - sched_yield(); - - while (count-- > 0) { - if (property_get(DAEMON_PROP_NAME, status, NULL)) { - if (strcmp(status, "ok") == 0) - return 0; - else if (strcmp(DAEMON_PROP_NAME, "failed") == 0) - return -1; - } - usleep(200000); } - property_set(DAEMON_PROP_NAME, "timeout"); - return -1; -} - -int OpenVpnController::stopServiceDaemon() { - char status[PROPERTY_VALUE_MAX] = {'\0'}; - int count = 50; - - if (property_get(DAEMON_PROP_NAME, status, NULL) && - !strcmp(status, "stopped")) { - LOGD("Service already stopped"); - return 0; - } - - property_set("ctl.stop", "openvpn"); - sched_yield(); + snprintf(svc, sizeof(svc), "openvpn:--remote %s 1194", tmp); - while (count-- > 0) { - if (property_get(DAEMON_PROP_NAME, status, NULL)) { - if (!strcmp(status, "stopped")) - break; - } - usleep(100000); - } - - if (!count) { - LOGD("Timed out waiting for openvpn to stop"); - errno = ETIMEDOUT; + if (mServiceManager->start(svc)) return -1; - } return 0; } int OpenVpnController::disable() { - errno = -ENOSYS; - return -1; + + if (mServiceManager->stop("openvpn")) + return -1; + return 0; } diff --git a/nexus/OpenVpnController.h b/nexus/OpenVpnController.h index 1ecc3fb..b321029 100644 --- a/nexus/OpenVpnController.h +++ b/nexus/OpenVpnController.h @@ -19,22 +19,20 @@ #include "VpnController.h" +class ServiceManager; + class OpenVpnController : public VpnController { +private: + ServiceManager *mServiceManager; public: OpenVpnController(); - virtual ~OpenVpnController() {} + virtual ~OpenVpnController(); int start(); int stop(); int enable(); int disable(); - -protected: - -private: - int startServiceDaemon(); - int stopServiceDaemon(); }; #endif diff --git a/nexus/Supplicant.cpp b/nexus/Supplicant.cpp index 22964bb..6737d91 100644 --- a/nexus/Supplicant.cpp +++ b/nexus/Supplicant.cpp @@ -25,12 +25,7 @@ #include "private/android_filesystem_config.h" -#undef HAVE_LIBC_SYSTEM_PROPERTIES - -#ifdef HAVE_LIBC_SYSTEM_PROPERTIES -#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ -#include <sys/_system_properties.h> -#endif +#include <sysutils/ServiceManager.h> #include "Supplicant.h" #include "SupplicantListener.h" @@ -44,12 +39,10 @@ #define IFACE_DIR "/data/system/wpa_supplicant" #define DRIVER_PROP_NAME "wlan.driver.status" -#define SUPPLICANT_NAME "wpa_supplicant" -#define SUPP_PROP_NAME "init.svc.wpa_supplicant" +#define SUPPLICANT_SERVICE_NAME "wpa_supplicant" #define SUPP_CONFIG_TEMPLATE "/system/etc/wifi/wpa_supplicant.conf" #define SUPP_CONFIG_FILE "/data/misc/wifi/wpa_supplicant.conf" - Supplicant::Supplicant() { mCtrl = NULL; mMonitor = NULL; @@ -57,62 +50,25 @@ Supplicant::Supplicant() { mState = SupplicantState::UNKNOWN; - mLatestScanResults = new ScanResultCollection(); + mServiceManager = new ServiceManager(); + mLatestScanResults = new ScanResultCollection(); pthread_mutex_init(&mLatestScanResultsLock, NULL); } +Supplicant::~Supplicant() { + delete mServiceManager; +} + int Supplicant::start() { if (setupConfig()) { LOGW("Unable to setup supplicant.conf"); } - - char status[PROPERTY_VALUE_MAX] = {'\0'}; - int count = 200; -#ifdef HAVE_LIBC_SYSTEM_PROPERTIES - const prop_info *pi; - unsigned int serial = 0; -#endif - - if (property_get(SUPP_PROP_NAME, status, NULL) && - !strcmp(status, "running")) { - } else { -#ifdef HAVE_LIBC_SYSTEM_PROPERTIES - pi = __system_property_find(SUPP_PROP_NAME); - if (pi != NULL) - serial = pi->serial; -#endif - - LOGD("Starting Supplicant"); - property_set("ctl.start", SUPPLICANT_NAME); - sched_yield(); - while (count--) { -#ifdef HAVE_LIBC_SYSTEM_PROPERTIES - if (!pi) - pi = __system_property_find(SUPP_PROP_NAME); - if (pi) { - __system_property_read(pi, NULL, status); - if (strcmp(status, "running") == 0) - break; - else if (pi->serial != serial && - strcmp(status, "stopped") == 0) { - errno = EIO; - return -1; - } - } -#else - if (property_get(SUPP_PROP_NAME, status, NULL)) { - if (!strcmp(status, "running")) - break; - } -#endif - usleep(100000); - } - if (!count) { - errno = ETIMEDOUT; - return -1; - } + + if (mServiceManager->start(SUPPLICANT_SERVICE_NAME)) { + LOGE("Error starting supplicant (%s)", strerror(errno)); + return -1; } wpa_ctrl_cleanup(); @@ -125,30 +81,13 @@ int Supplicant::start() { int Supplicant::stop() { - char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; - int count = 50; - if (mListener->stopListener()) { LOGW("Unable to stop supplicant listener (%s)", strerror(errno)); return -1; } - if (property_get(SUPP_PROP_NAME, supp_status, NULL) - && strcmp(supp_status, "stopped") == 0) { - LOGD("Supplicant already stopped"); - return 0; - } - - LOGD("Stopping Supplicant"); - property_set("ctl.stop", SUPPLICANT_NAME); - sched_yield(); - - while (count-- > 0) { - if (property_get(SUPP_PROP_NAME, supp_status, NULL)) { - if (strcmp(supp_status, "stopped") == 0) - break; - } - usleep(100000); + if (mServiceManager->stop(SUPPLICANT_SERVICE_NAME)) { + LOGW("Error stopping supplicant (%s)", strerror(errno)); } if (mCtrl) { @@ -160,35 +99,15 @@ int Supplicant::stop() { mMonitor = NULL; } - if (!count) { - LOGD("Timed out waiting for supplicant to stop"); - errno = ETIMEDOUT; - return -1; - } - - LOGD("Supplicant shutdown"); - return 0; } bool Supplicant::isStarted() { - char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; - - property_get(SUPP_PROP_NAME, supp_status, NULL); - - if (!strcmp(supp_status, "running")) - return true; - - return false; + return mServiceManager->isRunning(SUPPLICANT_SERVICE_NAME); } int Supplicant::connectToSupplicant() { - char ifname[256]; - char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; - - LOGD("connectToSupplicant()"); - if (!property_get(SUPP_PROP_NAME, supp_status, NULL) - || strcmp(supp_status, "running") != 0) { + if (!isStarted()) { LOGE("Supplicant not running, cannot connect"); return -1; } @@ -229,7 +148,7 @@ int Supplicant::sendCommand(const char *cmd, char *reply, size_t *reply_len) return -1; } - LOGD("sendCommand(): -> '%s'", cmd); +// LOGD("sendCommand(): -> '%s'", cmd); int rc; if ((rc = wpa_ctrl_request(mCtrl, cmd, strlen(cmd), reply, reply_len, NULL)) == -2) { @@ -245,7 +164,7 @@ int Supplicant::sendCommand(const char *cmd, char *reply, size_t *reply_len) !strncmp(cmd, "SCAN_RESULTS", 12)) reply[*reply_len] = '\0'; - LOGD("sendCommand(): <- '%s'", reply); +// LOGD("sendCommand(): <- '%s'", reply); return 0; } diff --git a/nexus/Supplicant.h b/nexus/Supplicant.h index 4a7ec3a..2ea0892 100644 --- a/nexus/Supplicant.h +++ b/nexus/Supplicant.h @@ -19,6 +19,7 @@ struct wpa_ctrl; class SupplicantListener; class SupplicantEvent; +class ServiceManager; #include <pthread.h> @@ -31,13 +32,14 @@ private: struct wpa_ctrl *mMonitor; SupplicantListener *mListener; int mState; + ServiceManager *mServiceManager; ScanResultCollection *mLatestScanResults; pthread_mutex_t mLatestScanResultsLock; public: Supplicant(); - virtual ~Supplicant() {} + virtual ~Supplicant(); int start(); int stop(); @@ -50,7 +52,6 @@ public: int removeNetwork(int networkId); WifiNetworkCollection *createNetworkList(); - int getState() { return mState; } diff --git a/nexus/VpnController.cpp b/nexus/VpnController.cpp index 17bfe41..cd24c19 100644 --- a/nexus/VpnController.cpp +++ b/nexus/VpnController.cpp @@ -13,7 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +#include <string.h> #include <errno.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + #include "VpnController.h" VpnController::VpnController() : @@ -21,21 +27,34 @@ VpnController::VpnController() : } int VpnController::start() { - errno = -ENOSYS; + errno = ENOSYS; return -1; } int VpnController::stop() { - errno = -ENOSYS; + errno = ENOSYS; return -1; } int VpnController::enable() { - errno = -ENOSYS; + errno = ENOSYS; return -1; } int VpnController::disable() { - errno = -ENOSYS; + errno = ENOSYS; return -1; } + +int VpnController::setVpnGateway(const char *vpnGw) { + if (!inet_aton(vpnGw, &mVpnGateway)) { + errno = EINVAL; + return -1; + } + return 0; +} + +int VpnController::setVpnGateway(struct in_addr *vpnGw) { + memcpy(&mVpnGateway, vpnGw, sizeof(struct in_addr)); + return 0; +} diff --git a/nexus/VpnController.h b/nexus/VpnController.h index 049fe6e..4088e6a 100644 --- a/nexus/VpnController.h +++ b/nexus/VpnController.h @@ -16,9 +16,15 @@ #ifndef _VPN_CONTROLLER_H #define _VPN_CONTROLLER_H +#include <netinet/in.h> + #include "Controller.h" class VpnController : public Controller { + /* + * Gateway of the VPN server to connect to + */ + struct in_addr mVpnGateway; public: VpnController(); @@ -30,6 +36,10 @@ public: virtual int enable(); virtual int disable(); + struct in_addr &getVpnGateway() { return mVpnGateway; } + int setVpnGateway(const char *vpnGw); + int setVpnGateway(struct in_addr *vpnGw); + protected: }; diff --git a/rootdir/init.rc b/rootdir/init.rc index c20eeaa..9853cc6 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -246,6 +246,12 @@ service bootsound /system/bin/playmp3 group audio oneshot +service bootanim /system/bin/bootanimation + user graphics + group graphics + disabled + oneshot + service dbus /system/bin/dbus-daemon --system --nofork socket dbus stream 660 bluetooth bluetooth user bluetooth diff --git a/vold/volmgr_vfat.c b/vold/volmgr_vfat.c index 344a166..4013df8 100644 --- a/vold/volmgr_vfat.c +++ b/vold/volmgr_vfat.c @@ -39,6 +39,7 @@ int vfat_identify(blkdev_t *dev) int vfat_check(blkdev_t *dev) { int rc; + boolean rw = true; #if VFAT_DEBUG LOG_VOL("vfat_check(%d:%d):", dev->major, dev->minor); @@ -50,47 +51,51 @@ int vfat_check(blkdev_t *dev) return 0; } -#ifdef VERIFY_PASS - char *args[7]; - args[0] = FSCK_MSDOS_PATH; - args[1] = "-v"; - args[2] = "-V"; - args[3] = "-w"; - args[4] = "-p"; - args[5] = blkdev_get_devpath(dev); - args[6] = NULL; - rc = logwrap(6, args); - free(args[5]); -#else - char *args[6]; - args[0] = FSCK_MSDOS_PATH; - args[1] = "-v"; - args[2] = "-w"; - args[3] = "-p"; - args[4] = blkdev_get_devpath(dev); - args[5] = NULL; - rc = logwrap(5, args); - free(args[4]); -#endif + do { + + char *args[6]; + args[0] = FSCK_MSDOS_PATH; + args[1] = "-v"; + + if (rw) { + args[2] = "-w"; + args[3] = "-p"; + args[4] = blkdev_get_devpath(dev); + args[5] = NULL; + rc = logwrap(5, args); + free(args[4]); + } else { + args[2] = "-n"; + args[3] = blkdev_get_devpath(dev); + args[4] = NULL; + rc = logwrap(4, args); + free(args[3]); + } + + if (rc == 0) { + LOG_VOL("Filesystem check completed OK"); + return 0; + } else if (rc == 1) { + LOG_VOL("Filesystem check failed (general failure)"); + return -EINVAL; + } else if (rc == 2) { + LOG_VOL("Filesystem check failed (invalid usage)"); + return -EIO; + } else if (rc == 4) { + LOG_VOL("Filesystem check completed (errors fixed)"); + } else if (rc == 6) { + LOG_VOL("Filesystem read-only - retrying check RO"); + rw = false; + continue; + } else if (rc == 8) { + LOG_VOL("Filesystem check failed (not a FAT filesystem)"); + return -ENODATA; + } else { + LOG_VOL("Filesystem check failed (unknown exit code %d)", rc); + return -EIO; + } + } while (0); - if (rc == 0) { - LOG_VOL("Filesystem check completed OK"); - return 0; - } else if (rc == 1) { - LOG_VOL("Filesystem check failed (general failure)"); - return -EINVAL; - } else if (rc == 2) { - LOG_VOL("Filesystem check failed (invalid usage)"); - return -EIO; - } else if (rc == 4) { - LOG_VOL("Filesystem check completed (errors fixed)"); - } else if (rc == 8) { - LOG_VOL("Filesystem check failed (not a FAT filesystem)"); - return -ENODATA; - } else { - LOG_VOL("Filesystem check failed (unknown exit code %d)", rc); - return -EIO; - } return 0; } @@ -105,7 +110,7 @@ int vfat_mount(blkdev_t *dev, volume_t *vol, boolean safe_mode) LOG_VOL("vfat_mount(%d:%d, %s, %d):", dev->major, dev->minor, vol->mount_point, safe_mode); #endif - flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC; + flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC | MS_SYNCHRONOUS; if (vol->state == volstate_mounted) { LOG_VOL("Remounting %d:%d on %s, safe mode %d", dev->major, @@ -113,15 +118,22 @@ int vfat_mount(blkdev_t *dev, volume_t *vol, boolean safe_mode) flags |= MS_REMOUNT; } + /* + * The mount masks restrict access so that: + * 1. The 'system' user cannot access the SD card at all - + * (protects system_server from grabbing file references) + * 2. Group users can RWX + * 3. Others can only RX + */ rc = mount(devpath, vol->mount_point, "vfat", flags, - "utf8,uid=1000,gid=1000,fmask=711,dmask=700,shortname=mixed"); + "utf8,uid=1000,gid=1015,fmask=702,dmask=702,shortname=mixed"); if (rc && errno == EROFS) { LOGE("vfat_mount(%d:%d, %s): Read only filesystem - retrying mount RO", dev->major, dev->minor, vol->mount_point); flags |= MS_RDONLY; rc = mount(devpath, vol->mount_point, "vfat", flags, - "utf8,uid=1000,gid=1000,fmask=711,dmask=700,shortname=mixed"); + "utf8,uid=1000,gid=1015,fmask=702,dmask=702,shortname=mixed"); } #if VFAT_DEBUG |