Merge korg/donut into korg/master
diff --git a/Android.mk b/Android.mk
index 8b79ceb..fa2f6f8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -21,6 +21,7 @@
include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
adb \
libcutils \
+ libsysutils \
liblog \
libnetutils \
libpixelflinger \
diff --git a/adb/Android.mk b/adb/Android.mk
index 2296610..9725478 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -7,7 +7,6 @@
# adb host tool
# =========================================================
-ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean (also unused with the sim)
include $(CLEAR_VARS)
# Default to a virtual (sockets) usb interface
@@ -54,10 +53,13 @@
$(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
@@ -77,7 +79,6 @@
$(LOCAL_INSTALLED_MODULE): $(HOST_OUT_EXECUTABLES)/AdbWinApi.dll
endif
-endif
# adbd device daemon
# =========================================================
@@ -100,6 +101,7 @@
LOCAL_SRC_FILES := \
adb.c \
+ fdevent.c \
transport.c \
transport_local.c \
transport_usb.c \
diff --git a/adb/adb.c b/adb/adb.c
index 12a36f5..956df54 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -23,12 +23,15 @@
#include <errno.h>
#include <string.h>
#include <time.h>
+#include <sys/time.h>
#include "sysdeps.h"
#include "adb.h"
#if !ADB_HOST
#include <private/android_filesystem_config.h>
+#else
+#include "usb_vendors.h"
#endif
@@ -655,10 +658,25 @@
void start_device_log(void)
{
int fd;
- char path[100];
+ char path[PATH_MAX];
+ struct tm now;
+ time_t t;
+ char value[PROPERTY_VALUE_MAX];
- snprintf(path, sizeof path, "/data/adb_%ld.txt", (long)time(NULL));
- fd = unix_open(path, O_WRONLY | O_CREAT | O_APPEND, 0640);
+ // read the trace mask from persistent property persist.adb.trace_mask
+ // give up if the property is not set or cannot be parsed
+ property_get("persist.adb.trace_mask", value, "");
+ if (sscanf(value, "%x", &adb_trace_mask) != 1)
+ return;
+
+ adb_mkdir("/data/adb", 0775);
+ tzset();
+ time(&t);
+ localtime_r(&t, &now);
+ strftime(path, sizeof(path),
+ "/data/adb/adb-%Y-%m-%d-%H-%M-%S.txt",
+ &now);
+ fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
if (fd < 0)
return;
@@ -669,11 +687,6 @@
fd = unix_open("/dev/null", O_RDONLY);
dup2(fd, 0);
-
- // log everything
- adb_trace_mask = ~0;
- // except TRACE_RWX is a bit too verbose
- adb_trace_mask &= ~TRACE_RWX;
}
#endif
@@ -818,19 +831,6 @@
#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 +846,7 @@
#if ADB_HOST
HOST = 1;
+ usb_vendors_init();
usb_init();
local_init();
@@ -885,9 +886,10 @@
** AID_INET to diagnose network issues (netcfg, ping)
** AID_GRAPHICS to access the frame buffer
** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
+ ** AID_SDCARD_RW to allow writing to the SD card
*/
gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
- AID_NET_BT, AID_NET_BT_ADMIN };
+ AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_RW };
setgroups(sizeof(groups)/sizeof(groups[0]), groups);
/* then switch user and group to "shell" */
@@ -1088,9 +1090,8 @@
adb_device_banner = "recovery";
recovery_mode = 1;
}
-#if ADB_DEVICE_LOG
+
start_device_log();
-#endif
return adb_main(0);
#endif
}
diff --git a/adb/adb.h b/adb/adb.h
index a17c8dd..b9ed556 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -345,11 +345,6 @@
#endif
-/* set this to log to /data/adb/adb_<time>.txt on the device.
- * has no effect if the /data/adb/ directory does not exist.
- */
-#define ADB_DEVICE_LOG 0
-
#if !TRACE_PACKETS
#define print_packet(tag,p) do {} while (0)
#endif
@@ -357,18 +352,10 @@
#define ADB_PORT 5037
#define ADB_LOCAL_TRANSPORT_PORT 5555
-// Google's USB Vendor ID
-#define VENDOR_ID_GOOGLE 0x18d1
-// HTC's USB Vendor ID
-#define VENDOR_ID_HTC 0x0bb4
+#define ADB_CLASS 0xff
+#define ADB_SUBCLASS 0x42
+#define ADB_PROTOCOL 0x1
-// products for VENDOR_ID_GOOGLE
-#define PRODUCT_ID_SOONER 0xd00d // Sooner bootloader
-#define PRODUCT_ID_SOONER_COMP 0xdeed // Sooner composite device
-
-// products for VENDOR_ID_HTC
-#define PRODUCT_ID_DREAM 0x0c01 // Dream bootloader
-#define PRODUCT_ID_DREAM_COMP 0x0c02 // Dream composite device
void local_init();
int local_connect(int port);
@@ -382,7 +369,9 @@
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/adb/adb_client.c b/adb/adb_client.c
index 5868744..243f0fa 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -213,7 +213,7 @@
fprintf(stdout,"* daemon started successfully *\n");
}
/* give the server some time to start properly and detect devices */
- adb_sleep_ms(2000);
+ adb_sleep_ms(3000);
// fall through to _adb_connect
} else {
// if server was running, check its version to make sure it is not out of date
diff --git a/libcutils/fdevent.c b/adb/fdevent.c
similarity index 98%
rename from libcutils/fdevent.c
rename to 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 @@
{
/* 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 @@
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_disconnect(fdevent *fde)
{
struct epoll_event ev;
-
+
memset(&ev, 0, sizeof(ev));
ev.events = 0;
ev.data.ptr = fde;
@@ -133,9 +133,9 @@
{
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_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 @@
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 @@
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 @@
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 @@
{
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_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_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
similarity index 89%
rename from include/cutils/fdevent.h
rename to 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 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_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 @@
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_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 @@
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 @@
--- 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 @@
reversed.
-
+
--- CONNECT(version, maxdata, "system-identity-string") ----------------
The CONNECT message establishes the presence of a remote system.
@@ -114,7 +114,7 @@
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 @@
#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 @@
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 @@
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 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_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 @@
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 @@
#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 @@
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 adb_open_mode( const char* pathname, int options, int mode )
{
- return open( pathname, options, mode );
+ return open( pathname, options, mode );
}
@@ -368,11 +368,11 @@
{
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__ 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 @@
{
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 @@
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 @@
{
FH fh = _fh_from_int(fd);
int on;
-
+
if ( !fh || fh->clazz != &_fh_socket_class )
return;
@@ -1746,7 +1746,7 @@
/** 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..3737c5c 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,21 @@
#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;
- }
+ unsigned i;
+ for (i = 0; i < vendorIdCount; i++) {
+ if (vid == vendorIds[i]) {
+ if (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS &&
+ usb_protocol == ADB_PROTOCOL) {
+ return 1;
+ }
- /* 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 49e1eef..4892c38 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -28,24 +28,12 @@
#define TRACE_TAG TRACE_USB
#include "adb.h"
+#include "usb_vendors.h"
#define DBG D
-typedef struct {
- int vid;
- int pid;
-} VendorProduct;
-
-#define kSupportedDeviceCount 4
-VendorProduct kSupportedDevices[kSupportedDeviceCount] = {
- { VENDOR_ID_GOOGLE, PRODUCT_ID_SOONER },
- { VENDOR_ID_GOOGLE, PRODUCT_ID_SOONER_COMP },
- { VENDOR_ID_HTC, PRODUCT_ID_DREAM },
- { VENDOR_ID_HTC, PRODUCT_ID_DREAM_COMP },
-};
-
static IONotificationPortRef notificationPort = 0;
-static io_iterator_t notificationIterators[kSupportedDeviceCount];
+static io_iterator_t* notificationIterators;
struct usb_handle
{
@@ -61,17 +49,20 @@
static pthread_cond_t start_cond;
-static void AndroidDeviceAdded(void *refCon, io_iterator_t iterator);
-static void AndroidDeviceNotify(void *refCon, io_iterator_t iterator, natural_t messageType, void *messageArgument);
-static usb_handle* FindDeviceInterface(IOUSBDeviceInterface **dev, UInt16 vendor, UInt16 product);
+static void AndroidInterfaceAdded(void *refCon, io_iterator_t iterator);
+static void AndroidInterfaceNotify(void *refCon, io_iterator_t iterator,
+ natural_t messageType,
+ void *messageArgument);
+static usb_handle* CheckInterface(IOUSBInterfaceInterface **iface,
+ UInt16 vendor, UInt16 product);
static int
InitUSB()
{
CFMutableDictionaryRef matchingDict;
CFRunLoopSourceRef runLoopSource;
- SInt32 vendor, product;
- int i;
+ SInt32 vendor, if_subclass, if_protocol;
+ unsigned i;
//* To set up asynchronous notifications, create a notification port and
//* add its run loop event source to the program's run loop
@@ -81,51 +72,57 @@
memset(notificationIterators, 0, sizeof(notificationIterators));
- //* loop through all supported vendor/product pairs
- for (i = 0; i < kSupportedDeviceCount; i++) {
- //* Create our matching dictionary to find the Android device
- //* IOServiceAddMatchingNotification consumes the reference, so we do not need to release this
- matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
+ //* loop through all supported vendors
+ 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
+ //* not need to release this
+ matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
if (!matchingDict) {
DBG("ERR: Couldn't create USB matching dictionary.\n");
return -1;
}
- //* Set up two matching dictionaries, one for each product ID we support.
- //* This will cause the kernel to notify us only if the vendor and product IDs match.
- vendor = kSupportedDevices[i].vid;
- product = kSupportedDevices[i].pid;
- CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor));
- CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product));
-
- //* Now set up two notifications: one to be called when a raw device
- //* is first matched by the I/O Kit and another to be called when the
- //* device is terminated.
- //* we need to do this with each matching dictionary.
+ //* Match based on vendor id, interface subclass and protocol
+ vendor = vendorIds[i];
+ if_subclass = ADB_SUBCLASS;
+ if_protocol = ADB_PROTOCOL;
+ CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID),
+ CFNumberCreate(kCFAllocatorDefault,
+ kCFNumberSInt32Type, &vendor));
+ CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass),
+ CFNumberCreate(kCFAllocatorDefault,
+ kCFNumberSInt32Type, &if_subclass));
+ CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol),
+ CFNumberCreate(kCFAllocatorDefault,
+ kCFNumberSInt32Type, &if_protocol));
IOServiceAddMatchingNotification(
notificationPort,
kIOFirstMatchNotification,
matchingDict,
- AndroidDeviceAdded,
+ AndroidInterfaceAdded,
NULL,
¬ificationIterators[i]);
- //* Iterate over set of matching devices to access already-present devices
- //* and to arm the notification
- AndroidDeviceAdded(NULL, notificationIterators[i]);
+ //* Iterate over set of matching interfaces to access already-present
+ //* devices and to arm the notification
+ AndroidInterfaceAdded(NULL, notificationIterators[i]);
}
return 0;
}
static void
-AndroidDeviceAdded(void *refCon, io_iterator_t iterator)
+AndroidInterfaceAdded(void *refCon, io_iterator_t iterator)
{
kern_return_t kr;
io_service_t usbDevice;
+ io_service_t usbInterface;
IOCFPlugInInterface **plugInInterface = NULL;
- IOUSBDeviceInterface182 **dev = NULL;
+ IOUSBInterfaceInterface220 **iface = NULL;
+ IOUSBDeviceInterface197 **dev = NULL;
HRESULT result;
SInt32 score;
UInt16 vendor;
@@ -133,28 +130,66 @@
UInt8 serialIndex;
char serial[256];
- while ((usbDevice = IOIteratorNext(iterator))) {
- //* Create an intermediate plugin
+ while ((usbInterface = IOIteratorNext(iterator))) {
+ //* Create an intermediate interface plugin
+ kr = IOCreatePlugInInterfaceForService(usbInterface,
+ kIOUSBInterfaceUserClientTypeID,
+ kIOCFPlugInInterfaceID,
+ &plugInInterface, &score);
+ IOObjectRelease(usbInterface);
+ if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
+ DBG("ERR: Unable to create an interface plug-in (%08x)\n", kr);
+ continue;
+ }
+
+ //* This gets us the interface object
+ result = (*plugInInterface)->QueryInterface(plugInInterface,
+ CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)
+ &iface);
+ //* We only needed the plugin to get the interface, so discard it
+ (*plugInInterface)->Release(plugInInterface);
+ if (result || !iface) {
+ DBG("ERR: Couldn't query the interface (%08x)\n", (int) result);
+ continue;
+ }
+
+ //* this gets us an ioservice, with which we will find the actual
+ //* device; after getting a plugin, and querying the interface, of
+ //* course.
+ //* Gotta love OS X
+ kr = (*iface)->GetDevice(iface, &usbDevice);
+ if (kIOReturnSuccess != kr || !usbDevice) {
+ DBG("ERR: Couldn't grab device from interface (%08x)\n", kr);
+ continue;
+ }
+
+ plugInInterface = NULL;
+ score = 0;
+ //* create an intermediate device plugin
kr = IOCreatePlugInInterfaceForService(usbDevice,
kIOUSBDeviceUserClientTypeID,
kIOCFPlugInInterfaceID,
&plugInInterface, &score);
-
+ //* only needed this to find the plugin
+ (void)IOObjectRelease(usbDevice);
if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
- DBG("ERR: Unable to create a plug-in (%08x)\n", kr);
- goto continue1;
+ DBG("ERR: Unable to create a device plug-in (%08x)\n", kr);
+ continue;
}
- //* Now create the device interface
result = (*plugInInterface)->QueryInterface(plugInInterface,
CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev);
-
+ //* only needed this to query the plugin
+ (*plugInInterface)->Release(plugInInterface);
if (result || !dev) {
- DBG("ERR: Couldn't create a device interface (%08x)\n", (int) result);
- goto continue2;
+ DBG("ERR: Couldn't create a device interface (%08x)\n",
+ (int) result);
+ continue;
}
- //* Check the device to see if it's ours
+ //* Now after all that, we actually have a ref to the device and
+ //* the interface that matched our criteria
+
kr = (*dev)->GetDeviceVendor(dev, &vendor);
kr = (*dev)->GetDeviceProduct(dev, &product);
kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
@@ -163,7 +198,8 @@
IOUSBDevRequest req;
UInt16 buffer[256];
- req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+ req.bmRequestType =
+ USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
req.bRequest = kUSBRqGetDescriptor;
req.wValue = (kUSBStringDesc << 8) | serialIndex;
req.wIndex = 0;
@@ -174,219 +210,149 @@
if (kr == kIOReturnSuccess && req.wLenDone > 0) {
int i, count;
- // skip first word, and copy the rest to the serial string, changing shorts to bytes.
+ // skip first word, and copy the rest to the serial string,
+ // changing shorts to bytes.
count = (req.wLenDone - 1) / 2;
for (i = 0; i < count; i++)
serial[i] = buffer[i + 1];
serial[i] = 0;
}
}
+ (*dev)->Release(dev);
- usb_handle* handle = NULL;
+ DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product,
+ serial);
- //* Open the device
- kr = (*dev)->USBDeviceOpen(dev);
-
- if (kr != kIOReturnSuccess) {
- DBG("ERR: Could not open device: %08x\n", kr);
- goto continue3;
- } else {
- //* Find an interface for the device
- handle = FindDeviceInterface((IOUSBDeviceInterface**)dev, vendor, product);
- }
-
+ usb_handle* handle = CheckInterface((IOUSBInterfaceInterface**)iface,
+ vendor, product);
if (handle == NULL) {
DBG("ERR: Could not find device interface: %08x\n", kr);
- (*dev)->USBDeviceClose(dev);
- goto continue3;
+ (*iface)->Release(iface);
+ continue;
}
DBG("AndroidDeviceAdded calling register_usb_transport\n");
register_usb_transport(handle, (serial[0] ? serial : NULL));
- // Register for an interest notification of this device being removed. Pass the reference to our
- // private data as the refCon for the notification.
+ // Register for an interest notification of this device being removed.
+ // Pass the reference to our private data as the refCon for the
+ // notification.
kr = IOServiceAddInterestNotification(notificationPort,
- usbDevice,
+ usbInterface,
kIOGeneralInterest,
- AndroidDeviceNotify,
+ AndroidInterfaceNotify,
handle,
&handle->usbNotification);
+
if (kIOReturnSuccess != kr) {
DBG("ERR: Unable to create interest notification (%08x)\n", kr);
}
-
-continue3:
- (void)(*dev)->Release(dev);
-continue2:
- IODestroyPlugInInterface(plugInInterface);
-continue1:
- IOObjectRelease(usbDevice);
}
}
static void
-AndroidDeviceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument)
+AndroidInterfaceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument)
{
usb_handle *handle = (usb_handle *)refCon;
if (messageType == kIOMessageServiceIsTerminated) {
- DBG("AndroidDeviceNotify\n");
+ if (!handle) {
+ DBG("ERR: NULL handle\n");
+ return;
+ }
+ DBG("AndroidInterfaceNotify\n");
IOObjectRelease(handle->usbNotification);
usb_kick(handle);
}
}
+//* TODO: simplify this further since we only register to get ADB interface
+//* subclass+protocol events
static usb_handle*
-FindDeviceInterface(IOUSBDeviceInterface **dev, UInt16 vendor, UInt16 product)
+CheckInterface(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 product)
{
usb_handle* handle = NULL;
IOReturn kr;
- IOUSBFindInterfaceRequest request;
- io_iterator_t iterator;
- io_service_t usbInterface;
- IOCFPlugInInterface **plugInInterface;
- IOUSBInterfaceInterface **interface = NULL;
- HRESULT result;
- SInt32 score;
UInt8 interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
- UInt8 endpoint, configuration;
+ UInt8 endpoint;
- //* Placing the constant KIOUSBFindInterfaceDontCare into the following
- //* fields of the IOUSBFindInterfaceRequest structure will allow us to
- //* find all of the interfaces
- request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
- request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
- request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
- request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
- //* SetConfiguration will kill an existing UMS connection, so let's not do this if not necessary.
- configuration = 0;
- (*dev)->GetConfiguration(dev, &configuration);
- if (configuration != 1)
- (*dev)->SetConfiguration(dev, 1);
-
- //* Get an iterator for the interfaces on the device
- kr = (*dev)->CreateInterfaceIterator(dev, &request, &iterator);
-
+ //* Now open the interface. This will cause the pipes associated with
+ //* the endpoints in the interface descriptor to be instantiated
+ kr = (*interface)->USBInterfaceOpen(interface);
if (kr != kIOReturnSuccess) {
- DBG("ERR: Couldn't create a device interface iterator: (%08x)\n", kr);
+ DBG("ERR: Could not open interface: (%08x)\n", kr);
return NULL;
}
- while ((usbInterface = IOIteratorNext(iterator))) {
- //* Create an intermediate plugin
- kr = IOCreatePlugInInterfaceForService(
- usbInterface,
- kIOUSBInterfaceUserClientTypeID,
- kIOCFPlugInInterfaceID,
- &plugInInterface,
- &score);
-
- //* No longer need the usbInterface object now that we have the plugin
- (void) IOObjectRelease(usbInterface);
-
- if ((kr != kIOReturnSuccess) || (!plugInInterface)) {
- DBG("ERR: Unable to create plugin (%08x)\n", kr);
- break;
- }
-
- //* Now create the interface interface for the interface
- result = (*plugInInterface)->QueryInterface(
- plugInInterface,
- CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
- (LPVOID) &interface);
-
- //* No longer need the intermediate plugin
- (*plugInInterface)->Release(plugInInterface);
-
- if (result || !interface) {
- DBG("ERR: Couldn't create interface interface: (%08x)\n",
- (unsigned int) result);
- break;
- }
-
- //* Now open the interface. This will cause the pipes associated with
- //* the endpoints in the interface descriptor to be instantiated
- kr = (*interface)->USBInterfaceOpen(interface);
-
- if (kr != kIOReturnSuccess)
- {
- DBG("ERR: Could not open interface: (%08x)\n", kr);
- (void) (*interface)->Release(interface);
- //* continue so we can try the next interface
- continue;
- }
-
- //* Get the number of endpoints associated with this interface
- kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
-
- if (kr != kIOReturnSuccess) {
- DBG("ERR: Unable to get number of endpoints: (%08x)\n", kr);
- goto next_interface;
- }
-
- //* Get interface class, subclass and protocol
- if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess ||
- (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess ||
- (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess)
- {
- DBG("ERR: Unable to get interface class, subclass and protocol\n");
- goto next_interface;
- }
-
- //* check to make sure interface class, subclass and protocol match ADB
- //* avoid opening mass storage endpoints
- if (is_adb_interface(vendor, product, interfaceClass, interfaceSubClass, interfaceProtocol)) {
- handle = calloc(1, sizeof(usb_handle));
-
- //* Iterate over the endpoints for this interface and find the first
- //* bulk in/out pipes available. These will be our read/write pipes.
- for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) {
- UInt8 transferType;
- UInt16 maxPacketSize;
- UInt8 interval;
- UInt8 number;
- UInt8 direction;
-
- kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
- &number, &transferType, &maxPacketSize, &interval);
-
- if (kIOReturnSuccess == kr) {
- if (kUSBBulk != transferType)
- continue;
-
- if (kUSBIn == direction)
- handle->bulkIn = endpoint;
-
- if (kUSBOut == direction)
- handle->bulkOut = endpoint;
-
- if (interfaceProtocol == 0x01) {
- handle->zero_mask = maxPacketSize - 1;
- }
-
- } else {
- DBG("ERR: FindDeviceInterface - could not get pipe properties\n");
- }
- }
-
- handle->interface = interface;
- break;
- }
-
-next_interface:
- (*interface)->USBInterfaceClose(interface);
- (*interface)->Release(interface);
+ //* Get the number of endpoints associated with this interface
+ kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
+ if (kr != kIOReturnSuccess) {
+ DBG("ERR: Unable to get number of endpoints: (%08x)\n", kr);
+ goto err_get_num_ep;
}
+ //* Get interface class, subclass and protocol
+ if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess ||
+ (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess ||
+ (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) {
+ DBG("ERR: Unable to get interface class, subclass and protocol\n");
+ goto err_get_interface_class;
+ }
+
+ //* check to make sure interface class, subclass and protocol match ADB
+ //* avoid opening mass storage endpoints
+ if (!is_adb_interface(vendor, product, interfaceClass,
+ interfaceSubClass, interfaceProtocol))
+ goto err_bad_adb_interface;
+
+ handle = calloc(1, sizeof(usb_handle));
+
+ //* Iterate over the endpoints for this interface and find the first
+ //* bulk in/out pipes available. These will be our read/write pipes.
+ for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) {
+ UInt8 transferType;
+ UInt16 maxPacketSize;
+ UInt8 interval;
+ UInt8 number;
+ UInt8 direction;
+
+ kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
+ &number, &transferType, &maxPacketSize, &interval);
+
+ if (kIOReturnSuccess == kr) {
+ if (kUSBBulk != transferType)
+ continue;
+
+ if (kUSBIn == direction)
+ handle->bulkIn = endpoint;
+
+ if (kUSBOut == direction)
+ handle->bulkOut = endpoint;
+
+ handle->zero_mask = maxPacketSize - 1;
+ } else {
+ DBG("ERR: FindDeviceInterface - could not get pipe properties\n");
+ goto err_get_pipe_props;
+ }
+ }
+
+ handle->interface = interface;
return handle;
+
+err_get_pipe_props:
+ free(handle);
+err_bad_adb_interface:
+err_get_interface_class:
+err_get_num_ep:
+ (*interface)->USBInterfaceClose(interface);
+ return NULL;
}
void* RunLoopThread(void* unused)
{
- int i;
+ unsigned i;
InitUSB();
@@ -400,7 +366,7 @@
CFRunLoopRun();
currentRunLoop = 0;
- for (i = 0; i < kSupportedDeviceCount; i++) {
+ for (i = 0; i < vendorIdCount; i++) {
IOObjectRelease(notificationIterators[i]);
}
IONotificationPortDestroy(notificationPort);
@@ -417,6 +383,9 @@
{
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);
@@ -441,6 +410,11 @@
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)
@@ -527,6 +501,9 @@
void usb_kick(usb_handle *handle)
{
/* release the interface */
+ if (!handle)
+ return;
+
if (handle->interface)
{
(*handle->interface)->USBInterfaceClose(handle->interface);
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
new file mode 100644
index 0000000..9a15146
--- /dev/null
+++ b/adb/usb_vendors.c
@@ -0,0 +1,134 @@
+/*
+ * 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 <stdio.h>
+
+#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
+# include "windows.h"
+# include "shlobj.h"
+#else
+# include <unistd.h>
+# include <sys/stat.h>
+#endif
+
+#include "sysdeps.h"
+#include "adb.h"
+
+#define ANDROID_PATH ".android"
+#define ANDROID_ADB_INI "adb_usb.ini"
+
+#define TRACE_TAG TRACE_USB
+
+// Google's USB Vendor ID
+#define VENDOR_ID_GOOGLE 0x18d1
+// HTC's USB Vendor ID
+#define VENDOR_ID_HTC 0x0bb4
+
+/** built-in vendor list */
+int builtInVendorIds[] = {
+ VENDOR_ID_GOOGLE,
+ VENDOR_ID_HTC,
+};
+
+#define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
+
+/* max number of supported vendor ids (built-in + 3rd party). increase as needed */
+#define VENDOR_COUNT_MAX 128
+
+int vendorIds[VENDOR_COUNT_MAX];
+unsigned vendorIdCount = 0;
+
+int get_adb_usb_ini(char* buff, size_t len);
+
+void usb_vendors_init(void)
+{
+ if (VENDOR_COUNT_MAX < BUILT_IN_VENDOR_COUNT) {
+ fprintf(stderr, "VENDOR_COUNT_MAX not big enough for built-in vendor list.\n");
+ exit(2);
+ }
+
+ /* add the built-in vendors at the beginning of the array */
+ memcpy(vendorIds, builtInVendorIds, sizeof(builtInVendorIds));
+
+ /* default array size is the number of built-in vendors */
+ vendorIdCount = BUILT_IN_VENDOR_COUNT;
+
+ if (VENDOR_COUNT_MAX == BUILT_IN_VENDOR_COUNT)
+ return;
+
+ char temp[PATH_MAX];
+ if (get_adb_usb_ini(temp, sizeof(temp)) == 0) {
+ FILE * f = fopen(temp, "rt");
+
+ if (f != NULL) {
+ /* The vendor id file is pretty basic. 1 vendor id per line.
+ Lines starting with # are comments */
+ while (fgets(temp, sizeof(temp), f) != NULL) {
+ if (temp[0] == '#')
+ continue;
+
+ long value = strtol(temp, NULL, 0);
+ if (errno == EINVAL || errno == ERANGE || value > INT_MAX || value < 0) {
+ fprintf(stderr, "Invalid content in %s. Quitting.\n", ANDROID_ADB_INI);
+ exit(2);
+ }
+
+ vendorIds[vendorIdCount++] = (int)value;
+
+ /* make sure we don't go beyond the array */
+ if (vendorIdCount == VENDOR_COUNT_MAX) {
+ break;
+ }
+ }
+ }
+ }
+}
+
+/* Utils methods */
+
+/* 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) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/* fills buff with the path to the adb vendor id file. returns 0 if success */
+int get_adb_usb_ini(char* buff, size_t len)
+{
+#ifdef _WIN32
+ const char* home = getenv("ANDROID_SDK_HOME");
+ if (home != NULL) {
+ return build_path(buff, len, "%s\\%s\\%s", home);
+ } else {
+ char path[MAX_PATH];
+ SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, path);
+ return build_path(buff, len, "%s\\%s\\%s", path);
+ }
+#else
+ const char* home = getenv("HOME");
+ if (home == NULL)
+ home = "/tmp";
+
+ return build_path(buff, len, "%s/%s/%s", home);
+#endif
+}
diff --git a/adb/usb_vendors.h b/adb/usb_vendors.h
new file mode 100644
index 0000000..43790b9
--- /dev/null
+++ b/adb/usb_vendors.h
@@ -0,0 +1,25 @@
+/*
+ * 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);
+
+#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 @@
}
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/fastboot/bootimg.c b/fastboot/bootimg.c
index 1d77b3c..e5aea4e 100644
--- a/fastboot/bootimg.c
+++ b/fastboot/bootimg.c
@@ -40,7 +40,7 @@
boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size,
void *ramdisk, unsigned ramdisk_size,
void *second, unsigned second_size,
- unsigned page_size,
+ unsigned page_size, unsigned base,
unsigned *bootimg_size)
{
unsigned kernel_actual;
@@ -65,15 +65,14 @@
memcpy(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
- hdr->kernel_size = kernel_size;
- hdr->kernel_addr = 0x10008000;
+ hdr->kernel_size = kernel_size;
hdr->ramdisk_size = ramdisk_size;
- hdr->ramdisk_addr = 0x11000000;
- hdr->second_size = second_size;
- hdr->second_addr = 0x10F00000;
-
- hdr->tags_addr = 0x10000100;
- hdr->page_size = page_size;
+ hdr->second_size = second_size;
+ hdr->kernel_addr = base + 0x00008000;
+ hdr->ramdisk_addr = base + 0x01000000;
+ hdr->second_addr = base + 0x00F00000;
+ hdr->tags_addr = base + 0x00000100;
+ hdr->page_size = page_size;
memcpy(hdr->magic + page_size,
kernel, kernel_size);
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 498b4a6..850e10b 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -42,6 +42,14 @@
#include "fastboot.h"
+void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
+
+boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size,
+ void *ramdisk, unsigned ramdisk_size,
+ void *second, unsigned second_size,
+ unsigned page_size, unsigned base,
+ unsigned *bootimg_size);
+
static usb_handle *usb = 0;
static const char *serial = 0;
static const char *product = 0;
@@ -49,6 +57,8 @@
static int wipe_data = 0;
static unsigned short vendor_id = 0;
+static unsigned base_addr = 0x10000000;
+
void die(const char *fmt, ...)
{
va_list ap;
@@ -212,6 +222,7 @@
" -p <product> specify product name\n"
" -c <cmdline> override kernel commandline\n"
" -i <vendor id> specify a custom USB vendor id\n"
+ " -b <base_addr> specify a custom kernel base address\n"
);
exit(1);
}
@@ -257,7 +268,7 @@
}
fprintf(stderr,"creating boot image...\n");
- bdata = mkbootimg(kdata, ksize, rdata, rsize, 0, 0, 2048, &bsize);
+ bdata = mkbootimg(kdata, ksize, rdata, rsize, 0, 0, 2048, base_addr, &bsize);
if(bdata == 0) {
fprintf(stderr,"failed to create boot.img\n");
return 0;
@@ -545,6 +556,10 @@
if(!strcmp(*argv, "-w")) {
wants_wipe = 1;
skip(1);
+ } else if(!strcmp(*argv, "-b")) {
+ require(2);
+ base_addr = strtoul(argv[1], 0, 16);
+ skip(2);
} else if(!strcmp(*argv, "-s")) {
require(2);
serial = argv[1];
diff --git a/include/android/log.h b/include/android/log.h
new file mode 100644
index 0000000..0ea4c29
--- /dev/null
+++ b/include/android/log.h
@@ -0,0 +1,128 @@
+/*
+ * 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 _ANDROID_LOG_H
+#define _ANDROID_LOG_H
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ * This file is part of Android's set of stable system headers
+ * exposed by the Android NDK (Native Development Kit) since
+ * platform release 1.5
+ *
+ * Third-party source AND binary code relies on the definitions
+ * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+/*
+ * Support routines to send messages to the Android in-kernel log buffer,
+ * which can later be accessed through the 'logcat' utility.
+ *
+ * Each log message must have
+ * - a priority
+ * - a log tag
+ * - some text
+ *
+ * The tag normally corresponds to the component that emits the log message,
+ * and should be reasonably small.
+ *
+ * Log message text may be truncated to less than an implementation-specific
+ * limit (e.g. 1023 characters max).
+ *
+ * Note that a newline character ("\n") will be appended automatically to your
+ * log message, if not already there. It is not possible to send several messages
+ * and have them appear on a single line in logcat.
+ *
+ * PLEASE USE LOGS WITH MODERATION:
+ *
+ * - Sending log messages eats CPU and slow down your application and the
+ * system.
+ *
+ * - The circular log buffer is pretty small (<64KB), sending many messages
+ * might push off other important log messages from the rest of the system.
+ *
+ * - In release builds, only send log messages to account for exceptional
+ * conditions.
+ *
+ * NOTE: These functions MUST be implemented by /system/lib/liblog.so
+ */
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Android log priority values, in ascending priority order.
+ */
+typedef enum android_LogPriority {
+ ANDROID_LOG_UNKNOWN = 0,
+ ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
+ ANDROID_LOG_VERBOSE,
+ ANDROID_LOG_DEBUG,
+ ANDROID_LOG_INFO,
+ ANDROID_LOG_WARN,
+ ANDROID_LOG_ERROR,
+ ANDROID_LOG_FATAL,
+ ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
+} android_LogPriority;
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_write(int prio, const char *tag, const char *text);
+
+/*
+ * Send a formatted string to the log, used like printf(fmt,...)
+ */
+int __android_log_print(int prio, const char *tag, const char *fmt, ...)
+#if defined(__GNUC__)
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+ ;
+
+/*
+ * A variant of __android_log_print() that takes a va_list to list
+ * additional parameters.
+ */
+int __android_log_vprint(int prio, const char *tag,
+ const char *fmt, va_list ap);
+
+/*
+ * Log an assertion failure and SIGTRAP the process to have a chance
+ * to inspect it, if a debugger is attached. This uses the FATAL priority.
+ */
+void __android_log_assert(const char *cond, const char *tag,
+ const char *fmt, ...)
+#if defined(__GNUC__)
+ __attribute__ ((noreturn))
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+ ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ANDROID_LOG_H */
diff --git a/include/cutils/ashmem.h b/include/cutils/ashmem.h
index fd71352..0683bf2 100644
--- a/include/cutils/ashmem.h
+++ b/include/cutils/ashmem.h
@@ -18,6 +18,7 @@
int ashmem_set_prot_region(int fd, int prot);
int ashmem_pin_region(int fd, size_t offset, size_t len);
int ashmem_unpin_region(int fd, size_t offset, size_t len);
+int ashmem_get_size_region(int fd);
#ifdef __cplusplus
}
diff --git a/include/cutils/logd.h b/include/cutils/logd.h
index a1cb012..8737639 100644
--- a/include/cutils/logd.h
+++ b/include/cutils/logd.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 The Android Open Source Project
+ * 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.
@@ -17,6 +17,12 @@
#ifndef _ANDROID_CUTILS_LOGD_H
#define _ANDROID_CUTILS_LOGD_H
+/* the stable/frozen log-related definitions have been
+ * moved to this header, which is exposed by the NDK
+ */
+#include <android/log.h>
+
+/* the rest is only used internally by the system */
#include <time.h>
#include <stdio.h>
#include <unistd.h>
@@ -32,45 +38,10 @@
extern "C" {
#endif
-/*
- * Priority values, in ascending priority order.
- */
-typedef enum android_LogPriority {
- ANDROID_LOG_UNKNOWN = 0,
- ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
- ANDROID_LOG_VERBOSE,
- ANDROID_LOG_DEBUG,
- ANDROID_LOG_INFO,
- ANDROID_LOG_WARN,
- ANDROID_LOG_ERROR,
- ANDROID_LOG_FATAL,
- ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
-} android_LogPriority;
-
-int __android_log_write(int prio, const char *tag, const char *text);
-
-int __android_log_vprint(int prio, const char *tag,
- const char *fmt, va_list ap);
-
int __android_log_bwrite(int32_t tag, const void *payload, size_t len);
int __android_log_btwrite(int32_t tag, char type, const void *payload,
size_t len);
-int __android_log_print(int prio, const char *tag, const char *fmt, ...)
-#if defined(__GNUC__)
- __attribute__ ((format(printf, 3, 4)))
-#endif
- ;
-
-
-void __android_log_assert(const char *cond, const char *tag,
- const char *fmt, ...)
-#if defined(__GNUC__)
- __attribute__ ((noreturn))
- __attribute__ ((format(printf, 3, 4)))
-#endif
- ;
-
#ifdef __cplusplus
}
#endif
diff --git a/include/cutils/native_handle.h b/include/cutils/native_handle.h
index 2b64893..89d6b65 100644
--- a/include/cutils/native_handle.h
+++ b/include/cutils/native_handle.h
@@ -17,12 +17,57 @@
#ifndef NATIVE_HANDLE_H_
#define NATIVE_HANDLE_H_
+#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_t
+ *
+ * return 0 on success, or a negative error code on failure
+ *
+ */
+int native_handle_close(const native_handle_t* h);
+
+
+/*
+ * native_handle_create
+ *
+ * creates a native_handle_t and initializes it. must be destroyed with
+ * native_handle_delete().
+ *
+ */
+native_handle_t* native_handle_create(int numFds, int numInts);
+
+/*
+ * native_handle_delete
+ *
+ * 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_t* h);
+
+
+#ifdef __cplusplus
+}
+#endif
#endif /* NATIVE_HANDLE_H_ */
diff --git a/include/cutils/tztime.h b/include/cutils/tztime.h
index 9b3ece8..69dbc88 100644
--- a/include/cutils/tztime.h
+++ b/include/cutils/tztime.h
@@ -27,6 +27,7 @@
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 c855187..6ba574b 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -48,6 +48,9 @@
#define AID_INSTALL 1012 /* group for installing packages */
#define AID_MEDIA 1013 /* mediaserver process */
#define AID_DHCP 1014 /* dhcp client */
+#define AID_SDCARD_RW 1015 /* external storage write access */
+#define AID_VPN 1016 /* vpn system */
+#define AID_KEYSTORE 1017 /* keystore subsystem */
#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
@@ -59,6 +62,7 @@
#define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm or l2cap sockets */
#define AID_INET 3003 /* can create AF_INET and AF_INET6 sockets */
#define AID_NET_RAW 3004 /* can create raw INET sockets */
+#define AID_NET_ADMIN 3005 /* can configure interfaces and routing tables. */
#define AID_MISC 9998 /* access to misc storage */
#define AID_NOBODY 9999
@@ -93,8 +97,12 @@
{ "diag", AID_DIAG, },
{ "net_bt_admin", AID_NET_BT_ADMIN, },
{ "net_bt", AID_NET_BT, },
- { "inet", AID_INET, },
+ { "sdcard_rw", AID_SDCARD_RW, },
+ { "vpn", AID_VPN, },
+ { "keystore", AID_KEYSTORE, },
+ { "inet", AID_INET, },
{ "net_raw", AID_NET_RAW, },
+ { "net_admin", AID_NET_ADMIN, },
{ "misc", AID_MISC, },
{ "nobody", AID_NOBODY, },
};
@@ -129,7 +137,7 @@
{ 00750, AID_ROOT, AID_SHELL, "sbin" },
{ 00755, AID_ROOT, AID_SHELL, "system/bin" },
{ 00755, AID_ROOT, AID_SHELL, "system/xbin" },
- { 00777, AID_ROOT, AID_ROOT, "system/etc/ppp" }, /* REMOVE */
+ { 00755, AID_ROOT, AID_ROOT, "system/etc/ppp" },
{ 00777, AID_ROOT, AID_ROOT, "sdcard" },
{ 00755, AID_ROOT, AID_ROOT, 0 },
};
@@ -141,20 +149,18 @@
** and will allow partial matches.
*/
static struct fs_path_config android_files[] = {
- { 00555, AID_ROOT, AID_ROOT, "system/etc/ppp/ip-up" },
- { 00555, AID_ROOT, AID_ROOT, "system/etc/ppp/ip-down" },
{ 00440, AID_ROOT, AID_SHELL, "system/etc/init.goldfish.rc" },
{ 00550, AID_ROOT, AID_SHELL, "system/etc/init.goldfish.sh" },
{ 00440, AID_ROOT, AID_SHELL, "system/etc/init.trout.rc" },
{ 00550, AID_ROOT, AID_SHELL, "system/etc/init.ril" },
{ 00550, AID_ROOT, AID_SHELL, "system/etc/init.testmenu" },
- { 00550, AID_ROOT, AID_SHELL, "system/etc/init.gprs-pppd" },
{ 00550, AID_DHCP, AID_SHELL, "system/etc/dhcpcd/dhcpcd-run-hooks" },
{ 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/dbus.conf" },
{ 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/hcid.conf" },
{ 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/input.conf" },
{ 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/audio.conf" },
- { 00440, AID_RADIO, AID_AUDIO, "/system/etc/AudioPara4.csv" },
+ { 00440, AID_RADIO, AID_AUDIO, "system/etc/AudioPara4.csv" },
+ { 00555, AID_ROOT, AID_ROOT, "system/etc/ppp/*" },
{ 00644, AID_SYSTEM, AID_SYSTEM, "data/app/*" },
{ 00644, AID_SYSTEM, AID_SYSTEM, "data/app-private/*" },
{ 00644, AID_APP, AID_APP, "data/data/*" },
@@ -168,6 +174,7 @@
{ 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
new file mode 100644
index 0000000..0ef0753
--- /dev/null
+++ b/include/sysutils/FrameworkClient.h
@@ -0,0 +1,21 @@
+#ifndef _FRAMEWORK_CLIENT_H
+#define _FRAMEWORK_CLIENT_H
+
+#include "../../../frameworks/base/include/utils/List.h"
+
+#include <pthread.h>
+
+class FrameworkClient {
+ int mSocket;
+ pthread_mutex_t mWriteMutex;
+
+public:
+ FrameworkClient(int sock);
+ virtual ~FrameworkClient() {}
+
+ int sendMsg(const char *msg);
+ int sendMsg(const char *msg, const char *data);
+};
+
+typedef android::List<FrameworkClient *> FrameworkClientCollection;
+#endif
diff --git a/include/sysutils/FrameworkCommand.h b/include/sysutils/FrameworkCommand.h
new file mode 100644
index 0000000..6c1fca6
--- /dev/null
+++ b/include/sysutils/FrameworkCommand.h
@@ -0,0 +1,38 @@
+/*
+ * 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 __FRAMEWORK_CMD_HANDLER_H
+#define __FRAMEWORK_CMD_HANDLER_H
+
+#include "../../../frameworks/base/include/utils/List.h"
+
+class SocketClient;
+
+class FrameworkCommand {
+private:
+ const char *mCommand;
+
+public:
+
+ FrameworkCommand(const char *cmd);
+ virtual ~FrameworkCommand() { }
+
+ virtual int runCommand(SocketClient *c, int argc, char **argv) = 0;
+
+ const char *getCommand() { return mCommand; }
+};
+
+typedef android::List<FrameworkCommand *> FrameworkCommandCollection;
+#endif
diff --git a/include/sysutils/FrameworkListener.h b/include/sysutils/FrameworkListener.h
new file mode 100644
index 0000000..4e3d396
--- /dev/null
+++ b/include/sysutils/FrameworkListener.h
@@ -0,0 +1,41 @@
+/*
+ * 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 _FRAMEWORKSOCKETLISTENER_H
+#define _FRAMEWORKSOCKETLISTENER_H
+
+#include "SocketListener.h"
+#include "FrameworkCommand.h"
+
+class SocketClient;
+
+class FrameworkListener : public SocketListener {
+public:
+ static const int CMD_ARGS_MAX = 8;
+private:
+ FrameworkCommandCollection *mCommands;
+
+public:
+ FrameworkListener(const char *socketName);
+ virtual ~FrameworkListener() {}
+
+protected:
+ void registerCmd(FrameworkCommand *cmd);
+ virtual bool onDataAvailable(SocketClient *c);
+
+private:
+ void dispatchCommand(SocketClient *c, char *data);
+};
+#endif
diff --git a/include/sysutils/NetlinkEvent.h b/include/sysutils/NetlinkEvent.h
new file mode 100644
index 0000000..95e83a3
--- /dev/null
+++ b/include/sysutils/NetlinkEvent.h
@@ -0,0 +1,44 @@
+/*
+ * 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 _NETLINKEVENT_H
+#define _NETLINKEVENT_H
+
+#define NL_PARAMS_MAX 32
+
+class NetlinkEvent {
+ int mSeq;
+ char *mPath;
+ int mAction;
+ char *mSubsystem;
+ char *mParams[NL_PARAMS_MAX];
+
+public:
+ const static int NlActionUnknown;
+ const static int NlActionAdd;
+ const static int NlActionRemove;
+ const static int NlActionChange;
+
+ NetlinkEvent();
+ virtual ~NetlinkEvent();
+
+ bool decode(char *buffer, int size);
+ const char *findParam(const char *paramName);
+
+ const char *getSubsystem() { return mSubsystem; }
+ int getAction() { return mAction; }
+};
+
+#endif
diff --git a/include/sysutils/NetlinkListener.h b/include/sysutils/NetlinkListener.h
new file mode 100644
index 0000000..6dcc005
--- /dev/null
+++ b/include/sysutils/NetlinkListener.h
@@ -0,0 +1,32 @@
+/*
+ * 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 _NETLINKLISTENER_H
+#define _NETLINKLISTENER_H
+
+#include "SocketListener.h"
+
+class NetlinkEvent;
+
+class NetlinkListener : public SocketListener {
+ char mBuffer[64 * 1024];
+
+public:
+ NetlinkListener(int socket);
+ virtual ~NetlinkListener() {}
+protected:
+ virtual bool onDataAvailable(SocketClient *cli);
+};
+#endif
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
new file mode 100644
index 0000000..469dd9d
--- /dev/null
+++ b/include/sysutils/SocketClient.h
@@ -0,0 +1,23 @@
+#ifndef _SOCKET_CLIENT_H
+#define _SOCKET_CLIENT_H
+
+#include "../../../frameworks/base/include/utils/List.h"
+
+#include <pthread.h>
+
+class SocketClient {
+ int mSocket;
+ pthread_mutex_t mWriteMutex;
+
+public:
+ SocketClient(int sock);
+ virtual ~SocketClient() {}
+
+ int getSocket() { return mSocket; }
+
+ int sendMsg(int code, const char *msg, bool addErrno);
+ int sendMsg(const char *msg);
+};
+
+typedef android::List<SocketClient *> SocketClientCollection;
+#endif
diff --git a/include/sysutils/SocketListener.h b/include/sysutils/SocketListener.h
new file mode 100644
index 0000000..68dcb8f
--- /dev/null
+++ b/include/sysutils/SocketListener.h
@@ -0,0 +1,50 @@
+/*
+ * 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 _SOCKETLISTENER_H
+#define _SOCKETLISTENER_H
+
+#include <pthread.h>
+
+#include <sysutils/SocketClient.h>
+
+class SocketListener {
+ int mSock;
+ const char *mSocketName;
+ SocketClientCollection *mClients;
+ pthread_mutex_t mClientsLock;
+ bool mListen;
+ int mCtrlPipe[2];
+ pthread_t mThread;
+
+public:
+ SocketListener(const char *socketNames, bool listen);
+ SocketListener(int socketFd, bool listen);
+
+ virtual ~SocketListener() {}
+ int startListener();
+ int stopListener();
+
+ void sendBroadcast(int code, const char *msg, bool addErrno);
+ void sendBroadcast(const char *msg);
+
+protected:
+ virtual bool onDataAvailable(SocketClient *c) = 0;
+
+private:
+ static void *threadStart(void *obj);
+ void runListener();
+};
+#endif
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 @@
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 @@
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 @@
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 e0b1f1f..60f9b9c 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -115,6 +115,7 @@
{ "/dev/oncrpc/", 0660, AID_ROOT, AID_SYSTEM, 1 },
{ "/dev/adsp/", 0660, AID_SYSTEM, AID_AUDIO, 1 },
{ "/dev/mt9t013", 0660, AID_SYSTEM, AID_SYSTEM, 0 },
+ { "/dev/msm_camera/", 0660, AID_SYSTEM, AID_SYSTEM, 1 },
{ "/dev/akm8976_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 },
{ "/dev/akm8976_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 },
{ "/dev/akm8976_pffd", 0640, AID_COMPASS, AID_SYSTEM, 0 },
@@ -126,10 +127,13 @@
{ "/dev/msm_audpre", 0660, AID_SYSTEM, AID_AUDIO, 0 },
{ "/dev/htc-acoustic", 0660, AID_SYSTEM, AID_AUDIO, 0 },
{ "/dev/smd0", 0640, AID_RADIO, AID_RADIO, 0 },
+ { "/dev/qemu_trace", 0666, AID_SYSTEM, AID_SYSTEM, 0 },
{ "/dev/qmi", 0640, AID_RADIO, AID_RADIO, 0 },
{ "/dev/qmi0", 0640, AID_RADIO, AID_RADIO, 0 },
{ "/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 },
{ "/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 },
+ { "/dev/ppp", 0660, AID_RADIO, AID_VPN, 0 },
+ { "/dev/tun", 0640, AID_VPN, AID_VPN, 0 },
{ NULL, 0, 0, 0, 0 },
};
@@ -380,7 +384,10 @@
} else if (!strncmp(uevent->subsystem, "adsp", 4)) {
base = "/dev/adsp/";
mkdir(base, 0755);
- } else if(!strncmp(uevent->subsystem, "input", 5)) {
+ } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) {
+ base = "/dev/msm_camera/";
+ mkdir(base, 0755);
+ } else if(!strncmp(uevent->subsystem, "input", 5)) {
base = "/dev/input/";
mkdir(base, 0755);
} else if(!strncmp(uevent->subsystem, "mtd", 3)) {
diff --git a/init/init.c b/init/init.c
index 1630155..dfc858a 100644
--- a/init/init.c
+++ b/init/init.c
@@ -156,7 +156,7 @@
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 @@
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 @@
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';
+ if (execve(svc->args[0], (char**) arg_ptrs, (char**) ENV) < 0)
+ ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
}
_exit(127);
}
@@ -381,7 +407,7 @@
if (next_start_time <= gettime()) {
svc->flags &= (~SVC_RESTARTING);
- service_start(svc);
+ service_start(svc, NULL);
return;
}
@@ -407,13 +433,28 @@
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)
@@ -423,7 +464,7 @@
if (svc) {
service_stop(svc);
} else {
- ERROR("no such service '%s'\n");
+ ERROR("no such service '%s'\n", name);
}
}
@@ -739,7 +780,7 @@
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 b686869..f306b7b 100644
--- a/init/init.h
+++ b/init/init.h
@@ -29,7 +29,8 @@
void log_init(void);
void log_set_level(int level);
void log_close(void);
-void log_write(int level, const char *fmt, ...);
+void log_write(int level, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
#define ERROR(x...) log_write(3, "<3>init: " x)
#define NOTICE(x...) log_write(5, "<5>init: " x)
@@ -115,6 +116,8 @@
#define NR_SVC_SUPP_GIDS 6 /* six supplementary groups */
+#define SVC_MAXARGS 64
+
struct service {
/* list of all services */
struct listnode slist;
@@ -136,15 +139,17 @@
struct socketinfo *sockets;
struct svcenvinfo *envvars;
- int nargs;
- char *args[1];
struct action onrestart; /* Actions to execute on restart. */
/* keycodes for triggering this service via /dev/keychord */
int *keycodes;
int nkeycodes;
int keychord_id;
-};
+
+ int nargs;
+ /* "MUST BE AT THE END OF THE STRUCT" */
+ char *args[1];
+}; /* ^-------'args' MUST be at the end of this struct! */
int parse_config_file(const char *fn);
@@ -157,7 +162,7 @@
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 6a22d24..33c1a68 100644
--- a/init/parser.c
+++ b/init/parser.c
@@ -60,8 +60,6 @@
#endif
}
-#define MAXARGS 64
-
#define T_EOF 0
#define T_TEXT 1
#define T_NEWLINE 2
@@ -357,7 +355,7 @@
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 @@
}
break;
case T_TEXT:
- if (nargs < MAXARGS) {
+ if (nargs < SVC_MAXARGS) {
args[nargs++] = state.text;
}
break;
@@ -536,7 +534,7 @@
const char* name = act->name + strlen("property:");
const char* equals = strchr(name, '=');
if (equals) {
- char* prop_name[PROP_NAME_MAX + 1];
+ char prop_name[PROP_NAME_MAX + 1];
const char* value;
int length = equals - name;
if (length > PROP_NAME_MAX) {
@@ -546,7 +544,7 @@
prop_name[length] = 0;
/* does the property exist, and match the trigger value? */
- value = property_get((const char *)&prop_name[0]);
+ value = property_get(prop_name);
if (value && !strcmp(equals + 1, value)) {
action_add_queue_tail(act);
}
diff --git a/init/property_service.c b/init/property_service.c
index 0bc6239..23a8821 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -67,6 +67,8 @@
{ "wlan.", AID_SYSTEM },
{ "dhcp.", AID_SYSTEM },
{ "dhcp.", AID_DHCP },
+ { "vpn.", AID_SYSTEM },
+ { "vpn.", AID_VPN },
{ "debug.", AID_SHELL },
{ "log.", AID_SHELL },
{ "service.adb.root", AID_SHELL },
@@ -296,7 +298,7 @@
__futex_wake(&pa->serial, INT32_MAX);
}
/* If name starts with "net." treat as a DNS property. */
- if (strncmp("net.", name, sizeof("net.") - 1) == 0) {
+ if (strncmp("net.", name, strlen("net.")) == 0) {
if (strcmp("net.change", name) == 0) {
return 0;
}
@@ -307,7 +309,7 @@
*/
property_set("net.change", name);
} else if (persistent_properties_loaded &&
- strncmp("persist.", name, sizeof("persist.") - 1) == 0) {
+ strncmp("persist.", name, strlen("persist.")) == 0) {
/*
* Don't write properties to disk until after we have read all default properties
* to prevent them from being overwritten by default values.
@@ -446,8 +448,7 @@
if (dir) {
while ((entry = readdir(dir)) != NULL) {
- if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..") ||
- strncmp("persist.", entry->d_name, sizeof("persist.") - 1))
+ if (strncmp("persist.", entry->d_name, strlen("persist.")))
continue;
#if HAVE_DIRENT_D_TYPE
if (entry->d_type != DT_REG)
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 46b8d0c..98e59ee 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -21,6 +21,7 @@
array.c \
hashmap.c \
atomic.c \
+ native_handle.c \
buffer.c \
socket_inaddr_any_server.c \
socket_local_client.c \
@@ -59,7 +60,6 @@
commonSources += \
mspace.c \
selector.c \
- fdevent.c \
tztime.c \
tzstrftime.c \
adb_networking.c \
diff --git a/libcutils/ashmem-dev.c b/libcutils/ashmem-dev.c
index 5e158af..8b71f87 100644
--- a/libcutils/ashmem-dev.c
+++ b/libcutils/ashmem-dev.c
@@ -83,3 +83,8 @@
struct ashmem_pin pin = { offset, len };
return ioctl(fd, ASHMEM_UNPIN, &pin);
}
+
+int ashmem_get_size_region(int fd)
+{
+ return ioctl(fd, ASHMEM_GET_SIZE, NULL);
+}
diff --git a/libcutils/ashmem-host.c b/libcutils/ashmem-host.c
index dbb52bc..f03e130 100644
--- a/libcutils/ashmem-host.c
+++ b/libcutils/ashmem-host.c
@@ -92,3 +92,23 @@
{
return ASHMEM_IS_UNPINNED;
}
+
+int ashmem_get_size_region(int fd)
+{
+ struct stat buf;
+ int result;
+
+ result = fstat(fd, &buf);
+ if (result == -1) {
+ return -1;
+ }
+
+ // Check if this is an "ashmem" region.
+ // TODO: This is very hacky, and can easily break. We need some reliable indicator.
+ if (!(buf.st_nlink == 0 && S_ISREG(buf.st_mode))) {
+ errno = ENOTTY;
+ return -1;
+ }
+
+ return (int)buf.st_size; // TODO: care about overflow (> 2GB file)?
+}
diff --git a/libcutils/native_handle.c b/libcutils/native_handle.c
new file mode 100644
index 0000000..4089968
--- /dev/null
+++ b/libcutils/native_handle.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "NativeHandle"
+
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <cutils/log.h>
+#include <cutils/native_handle.h>
+
+native_handle_t* native_handle_create(int numFds, int numInts)
+{
+ 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_t* h)
+{
+ if (h) {
+ if (h->version != sizeof(native_handle_t))
+ return -EINVAL;
+ free(h);
+ }
+ return 0;
+}
+
+int native_handle_close(const native_handle_t* h)
+{
+ if (h->version != sizeof(native_handle_t))
+ return -EINVAL;
+
+ const int numFds = h->numFds;
+ int i;
+ for (i=0 ; i<numFds ; i++) {
+ close(h->data[i]);
+ }
+ return 0;
+}
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 @@
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/liblog/logd_write.c b/liblog/logd_write.c
index 80867d1..96da38b 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -143,12 +143,16 @@
/* XXX: This needs to go! */
if (!strcmp(tag, "HTC_RIL") ||
!strcmp(tag, "RILJ") ||
+ !strcmp(tag, "RILB") ||
!strcmp(tag, "RILC") ||
!strcmp(tag, "RILD") ||
!strcmp(tag, "RIL") ||
!strcmp(tag, "AT") ||
!strcmp(tag, "GSM") ||
- !strcmp(tag, "STK"))
+ !strcmp(tag, "STK") ||
+ !strcmp(tag, "CDMA") ||
+ !strcmp(tag, "PHONE") ||
+ !strcmp(tag, "SMS"))
log_id = LOG_ID_RADIO;
vec[0].iov_base = (unsigned char *) &prio;
diff --git a/libpixelflinger/codeflinger/ARMAssembler.h b/libpixelflinger/codeflinger/ARMAssembler.h
index 8837e07..ef3b66a 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.h
+++ b/libpixelflinger/codeflinger/ARMAssembler.h
@@ -21,8 +21,9 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Vector.h>
-#include <utils/KeyedVector.h>
+#include "tinyutils/Vector.h"
+#include "tinyutils/KeyedVector.h"
+#include "tinyutils/smartpointer.h"
#include "tinyutils/smartpointer.h"
#include "codeflinger/ARMAssemblerInterface.h"
diff --git a/libpixelflinger/codeflinger/CodeCache.h b/libpixelflinger/codeflinger/CodeCache.h
index 370ce17..8ff1366 100644
--- a/libpixelflinger/codeflinger/CodeCache.h
+++ b/libpixelflinger/codeflinger/CodeCache.h
@@ -23,8 +23,7 @@
#include <pthread.h>
#include <sys/types.h>
-#include <utils/KeyedVector.h>
-
+#include "tinyutils/KeyedVector.h"
#include "tinyutils/smartpointer.h"
namespace android {
diff --git a/libpixelflinger/tinyutils/Errors.h b/libpixelflinger/tinyutils/Errors.h
new file mode 100644
index 0000000..b9fd5f4
--- /dev/null
+++ b/libpixelflinger/tinyutils/Errors.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_ERRORS_H
+#define ANDROID_ERRORS_H
+
+#include <sys/types.h>
+#include <errno.h>
+
+namespace android {
+
+// use this type to return error codes
+typedef int32_t status_t;
+
+/*
+ * Error codes.
+ * All error codes are negative values.
+ */
+
+enum {
+ OK = 0, // Everything's swell.
+ NO_ERROR = 0, // No errors.
+
+ UNKNOWN_ERROR = 0x80000000,
+
+ NO_MEMORY = -ENOMEM,
+ INVALID_OPERATION = -ENOSYS,
+ BAD_VALUE = -EINVAL,
+ BAD_TYPE = 0x80000001,
+ NAME_NOT_FOUND = -ENOENT,
+ PERMISSION_DENIED = -EPERM,
+ NO_INIT = -ENODEV,
+ ALREADY_EXISTS = -EEXIST,
+ DEAD_OBJECT = -EPIPE,
+ FAILED_TRANSACTION = 0x80000002,
+ JPARKS_BROKE_IT = -EPIPE,
+ BAD_INDEX = -EOVERFLOW,
+ NOT_ENOUGH_DATA = -ENODATA,
+ WOULD_BLOCK = -EWOULDBLOCK,
+ TIMED_OUT = -ETIME,
+ UNKNOWN_TRANSACTION = -EBADMSG,
+};
+
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_ERRORS_H
diff --git a/libpixelflinger/tinyutils/SortedVector.h b/libpixelflinger/tinyutils/SortedVector.h
new file mode 100644
index 0000000..7a6b443
--- /dev/null
+++ b/libpixelflinger/tinyutils/SortedVector.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2005 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_SORTED_VECTOR_H
+#define ANDROID_SORTED_VECTOR_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "tinyutils/Vector.h"
+#include "tinyutils/VectorImpl.h"
+#include "tinyutils/TypeHelpers.h"
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+template <class TYPE>
+class SortedVector : private SortedVectorImpl
+{
+public:
+ typedef TYPE value_type;
+
+ /*!
+ * Constructors and destructors
+ */
+
+ SortedVector();
+ SortedVector(const SortedVector<TYPE>& rhs);
+ virtual ~SortedVector();
+
+ /*! copy operator */
+ const SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs) const;
+ SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs);
+
+ /*
+ * empty the vector
+ */
+
+ inline void clear() { VectorImpl::clear(); }
+
+ /*!
+ * vector stats
+ */
+
+ //! returns number of items in the vector
+ inline size_t size() const { return VectorImpl::size(); }
+ //! returns wether or not the vector is empty
+ inline bool isEmpty() const { return VectorImpl::isEmpty(); }
+ //! returns how many items can be stored without reallocating the backing store
+ inline size_t capacity() const { return VectorImpl::capacity(); }
+ //! setst the capacity. capacity can never be reduced less than size()
+ inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); }
+
+ /*!
+ * C-style array access
+ */
+
+ //! read-only C-style access
+ inline const TYPE* array() const;
+
+ //! read-write C-style access. BE VERY CAREFUL when modifying the array
+ //! you ust keep it sorted! You usually don't use this function.
+ TYPE* editArray();
+
+ //! finds the index of an item
+ ssize_t indexOf(const TYPE& item) const;
+
+ //! finds where this item should be inserted
+ size_t orderOf(const TYPE& item) const;
+
+
+ /*!
+ * accessors
+ */
+
+ //! read-only access to an item at a given index
+ inline const TYPE& operator [] (size_t index) const;
+ //! alternate name for operator []
+ inline const TYPE& itemAt(size_t index) const;
+ //! stack-usage of the vector. returns the top of the stack (last element)
+ const TYPE& top() const;
+ //! same as operator [], but allows to access the vector backward (from the end) with a negative index
+ const TYPE& mirrorItemAt(ssize_t index) const;
+
+ /*!
+ * modifing the array
+ */
+
+ //! add an item in the right place (and replace the one that is there)
+ ssize_t add(const TYPE& item);
+
+ //! editItemAt() MUST NOT change the order of this item
+ TYPE& editItemAt(size_t index) {
+ return *( static_cast<TYPE *>(VectorImpl::editItemLocation(index)) );
+ }
+
+ //! merges a vector into this one
+ ssize_t merge(const Vector<TYPE>& vector);
+ ssize_t merge(const SortedVector<TYPE>& vector);
+
+ //! removes an item
+ ssize_t remove(const TYPE&);
+
+ //! remove several items
+ inline ssize_t removeItemsAt(size_t index, size_t count = 1);
+ //! remove one item
+ inline ssize_t removeAt(size_t index) { return removeItemsAt(index); }
+
+protected:
+ virtual void do_construct(void* storage, size_t num) const;
+ virtual void do_destroy(void* storage, size_t num) const;
+ virtual void do_copy(void* dest, const void* from, size_t num) const;
+ virtual void do_splat(void* dest, const void* item, size_t num) const;
+ virtual void do_move_forward(void* dest, const void* from, size_t num) const;
+ virtual void do_move_backward(void* dest, const void* from, size_t num) const;
+ virtual int do_compare(const void* lhs, const void* rhs) const;
+};
+
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts from here...
+// ---------------------------------------------------------------------------
+
+template<class TYPE> inline
+SortedVector<TYPE>::SortedVector()
+ : SortedVectorImpl(sizeof(TYPE),
+ ((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
+ |(traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
+ |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0)
+ |(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
+ )
+{
+}
+
+template<class TYPE> inline
+SortedVector<TYPE>::SortedVector(const SortedVector<TYPE>& rhs)
+ : SortedVectorImpl(rhs) {
+}
+
+template<class TYPE> inline
+SortedVector<TYPE>::~SortedVector() {
+ finish_vector();
+}
+
+template<class TYPE> inline
+SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) {
+ SortedVectorImpl::operator = (rhs);
+ return *this;
+}
+
+template<class TYPE> inline
+const SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const {
+ SortedVectorImpl::operator = (rhs);
+ return *this;
+}
+
+template<class TYPE> inline
+const TYPE* SortedVector<TYPE>::array() const {
+ return static_cast<const TYPE *>(arrayImpl());
+}
+
+template<class TYPE> inline
+TYPE* SortedVector<TYPE>::editArray() {
+ return static_cast<TYPE *>(editArrayImpl());
+}
+
+
+template<class TYPE> inline
+const TYPE& SortedVector<TYPE>::operator[](size_t index) const {
+ assert( index<size() );
+ return *(array() + index);
+}
+
+template<class TYPE> inline
+const TYPE& SortedVector<TYPE>::itemAt(size_t index) const {
+ return operator[](index);
+}
+
+template<class TYPE> inline
+const TYPE& SortedVector<TYPE>::mirrorItemAt(ssize_t index) const {
+ assert( (index>0 ? index : -index)<size() );
+ return *(array() + ((index<0) ? (size()-index) : index));
+}
+
+template<class TYPE> inline
+const TYPE& SortedVector<TYPE>::top() const {
+ return *(array() + size() - 1);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::add(const TYPE& item) {
+ return SortedVectorImpl::add(&item);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::indexOf(const TYPE& item) const {
+ return SortedVectorImpl::indexOf(&item);
+}
+
+template<class TYPE> inline
+size_t SortedVector<TYPE>::orderOf(const TYPE& item) const {
+ return SortedVectorImpl::orderOf(&item);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::merge(const Vector<TYPE>& vector) {
+ return SortedVectorImpl::merge(reinterpret_cast<const VectorImpl&>(vector));
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::merge(const SortedVector<TYPE>& vector) {
+ return SortedVectorImpl::merge(reinterpret_cast<const SortedVectorImpl&>(vector));
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::remove(const TYPE& item) {
+ return SortedVectorImpl::remove(&item);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::removeItemsAt(size_t index, size_t count) {
+ return VectorImpl::removeItemsAt(index, count);
+}
+
+// ---------------------------------------------------------------------------
+
+template<class TYPE>
+void SortedVector<TYPE>::do_construct(void* storage, size_t num) const {
+ construct_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_destroy(void* storage, size_t num) const {
+ destroy_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_copy(void* dest, const void* from, size_t num) const {
+ copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_splat(void* dest, const void* item, size_t num) const {
+ splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const {
+ move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const {
+ move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+int SortedVector<TYPE>::do_compare(const void* lhs, const void* rhs) const {
+ return compare_type( *reinterpret_cast<const TYPE*>(lhs), *reinterpret_cast<const TYPE*>(rhs) );
+}
+
+}; // namespace android
+
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_SORTED_VECTOR_H
diff --git a/libpixelflinger/tinyutils/Vector.h b/libpixelflinger/tinyutils/Vector.h
index 182bc7b..14cf99a 100644
--- a/libpixelflinger/tinyutils/Vector.h
+++ b/libpixelflinger/tinyutils/Vector.h
@@ -15,6 +15,7 @@
#include <cutils/log.h>
+#include "tinyutils/Errors.h"
#include "tinyutils/VectorImpl.h"
#include "tinyutils/TypeHelpers.h"
@@ -302,16 +303,6 @@
return VectorImpl::removeItemsAt(index, count);
}
-template<class TYPE> inline
-status_t Vector<TYPE>::sort(Vector<TYPE>::compar_t cmp) {
- return VectorImpl::sort((VectorImpl::compar_t)cmp);
-}
-
-template<class TYPE> inline
-status_t Vector<TYPE>::sort(Vector<TYPE>::compar_r_t cmp, void* state) {
- return VectorImpl::sort((VectorImpl::compar_r_t)cmp, state);
-}
-
// ---------------------------------------------------------------------------
template<class TYPE>
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
new file mode 100644
index 0000000..dd2b32d
--- /dev/null
+++ b/libsysutils/Android.mk
@@ -0,0 +1,35 @@
+BUILD_LIBSYSUTILS := false
+ifneq ($(TARGET_SIMULATOR),true)
+ BUILD_LIBSYSUTILS := true
+endif
+
+ifeq ($(BUILD_LIBSYSUTILS),true)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ src/SocketListener.cpp \
+ src/FrameworkListener.cpp \
+ src/NetlinkListener.cpp \
+ src/NetlinkEvent.cpp \
+ src/FrameworkCommand.cpp \
+ src/SocketClient.cpp \
+ src/ServiceManager.cpp \
+
+LOCAL_MODULE:= libsysutils
+
+LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
+
+LOCAL_CFLAGS :=
+
+LOCAL_SHARED_LIBRARIES := libcutils
+
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -lpthread
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/libsysutils/src/FrameworkClient.cpp b/libsysutils/src/FrameworkClient.cpp
new file mode 100644
index 0000000..1686996
--- /dev/null
+++ b/libsysutils/src/FrameworkClient.cpp
@@ -0,0 +1,40 @@
+#include <alloca.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#define LOG_TAG "FrameworkClient"
+#include <cutils/log.h>
+
+#include <sysutils/FrameworkClient.h>
+
+FrameworkClient::FrameworkClient(int socket) {
+ mSocket = socket;
+ pthread_mutex_init(&mWriteMutex, NULL);
+}
+
+int FrameworkClient::sendMsg(const char *msg) {
+ if (mSocket < 0) {
+ errno = EHOSTUNREACH;
+ return -1;
+ }
+
+ pthread_mutex_lock(&mWriteMutex);
+ if (write(mSocket, msg, strlen(msg) +1) < 0) {
+ LOGW("Unable to send msg '%s' (%s)", msg, strerror(errno));
+ }
+ pthread_mutex_unlock(&mWriteMutex);
+ return 0;
+}
+
+int FrameworkClient::sendMsg(const char *msg, const char *data) {
+ char *buffer = (char *) alloca(strlen(msg) + strlen(data) + 1);
+ if (!buffer) {
+ errno = -ENOMEM;
+ return -1;
+ }
+ strcpy(buffer, msg);
+ strcat(buffer, data);
+ return sendMsg(buffer);
+}
+
diff --git a/libsysutils/src/FrameworkCommand.cpp b/libsysutils/src/FrameworkCommand.cpp
new file mode 100644
index 0000000..c52eac7
--- /dev/null
+++ b/libsysutils/src/FrameworkCommand.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+#include <errno.h>
+
+#define LOG_TAG "FrameworkCommand"
+
+#include <cutils/log.h>
+
+#include <sysutils/FrameworkCommand.h>
+
+FrameworkCommand::FrameworkCommand(const char *cmd) {
+ mCommand = cmd;
+}
+
+int FrameworkCommand::runCommand(SocketClient *c, int argc, char **argv) {
+ LOGW("Command %s has no run handler!", getCommand());
+ errno = ENOSYS;
+ return -1;
+}
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
new file mode 100644
index 0000000..e9ca897
--- /dev/null
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+#include <errno.h>
+#include <string.h>
+
+#define LOG_TAG "FrameworkListener"
+
+#include <cutils/log.h>
+
+#include <sysutils/FrameworkListener.h>
+#include <sysutils/FrameworkCommand.h>
+#include <sysutils/SocketClient.h>
+
+FrameworkListener::FrameworkListener(const char *socketName) :
+ SocketListener(socketName, true) {
+ mCommands = new FrameworkCommandCollection();
+}
+
+bool FrameworkListener::onDataAvailable(SocketClient *c) {
+ char buffer[255];
+ int len;
+
+ if ((len = read(c->getSocket(), buffer, sizeof(buffer) -1)) < 0) {
+ LOGE("read() failed (%s)", strerror(errno));
+ return errno;
+ } else if (!len)
+ return false;
+
+ int offset = 0;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (buffer[i] == '\0') {
+ dispatchCommand(c, buffer + offset);
+ offset = i + 1;
+ }
+ }
+ return true;
+}
+
+void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
+ mCommands->push_back(cmd);
+}
+
+void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
+ int argc;
+ char *argv[FrameworkListener::CMD_ARGS_MAX];
+
+ if (!index(data, '"')) {
+ char *next = data;
+ char *field;
+ int i;
+
+ for (i = 0; (i < FrameworkListener::CMD_ARGS_MAX) &&
+ (argv[i] = strsep(&next, " ")); i++);
+ argc = i+1;
+ } else {
+ LOGD("blehhh not supported");
+ return;
+ }
+
+ FrameworkCommandCollection::iterator i;
+
+ for (i = mCommands->begin(); i != mCommands->end(); ++i) {
+ FrameworkCommand *c = *i;
+
+ if (!strcmp(argv[0], c->getCommand())) {
+ if (c->runCommand(cli, argc, argv)) {
+ LOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
+ }
+ return;
+ }
+ }
+
+ cli->sendMsg(500, "Command not recognized", false);
+ return;
+}
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
new file mode 100644
index 0000000..5573c3f
--- /dev/null
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_TAG "NetlinkEvent"
+#include <cutils/log.h>
+
+#include <sysutils/NetlinkEvent.h>
+
+const int NetlinkEvent::NlActionUnknown = 0;
+const int NetlinkEvent::NlActionAdd = 1;
+const int NetlinkEvent::NlActionRemove = 2;
+const int NetlinkEvent::NlActionChange = 3;
+
+NetlinkEvent::NetlinkEvent() {
+ mAction = NlActionUnknown;
+}
+
+NetlinkEvent::~NetlinkEvent() {
+ int i;
+ if (mPath)
+ free(mPath);
+ if (mSubsystem)
+ free(mSubsystem);
+ for (i = 0; i < NL_PARAMS_MAX; i++) {
+ if (!mParams[i])
+ break;
+ free(mParams[i]);
+ }
+}
+
+bool NetlinkEvent::decode(char *buffer, int size) {
+ char *s = buffer;
+ char *end;
+ int param_idx = 0;
+ int i;
+ int first = 1;
+
+ end = s + size;
+ while (s < end) {
+ if (first) {
+ char *p;
+ for (p = s; *p != '@'; p++);
+ p++;
+ mPath = strdup(p);
+ first = 0;
+ } else {
+ if (!strncmp(s, "ACTION=", strlen("ACTION="))) {
+ char *a = s + strlen("ACTION=");
+ if (!strcmp(a, "add"))
+ mAction = NlActionAdd;
+ else if (!strcmp(a, "remove"))
+ mAction = NlActionRemove;
+ else if (!strcmp(a, "change"))
+ mAction = NlActionChange;
+ } else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM=")))
+ mSeq = atoi(s + strlen("SEQNUM="));
+ else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM=")))
+ mSubsystem = strdup(s + strlen("SUBSYSTEM="));
+ else
+ mParams[param_idx++] = strdup(s);
+ }
+ s+= strlen(s) + 1;
+ }
+ return true;
+}
+
+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];
+ }
+
+ LOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName);
+ return NULL;
+}
diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp
new file mode 100644
index 0000000..3ec9d9d
--- /dev/null
+++ b/libsysutils/src/NetlinkListener.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <string.h>
+
+#define LOG_TAG "NetlinkListener"
+#include <cutils/log.h>
+
+#include <sysutils/NetlinkListener.h>
+#include <sysutils/NetlinkEvent.h>
+
+NetlinkListener::NetlinkListener(int socket) :
+ SocketListener(socket, false) {
+}
+
+bool NetlinkListener::onDataAvailable(SocketClient *cli)
+{
+ int socket = cli->getSocket();
+ LOGD("NetlinkListener::onDataAvailable()");
+
+ int count;
+
+ if ((count = recv(socket, mBuffer, sizeof(mBuffer), 0)) < 0) {
+ LOGE("recv failed (%s)", strerror(errno));
+ return false;
+ }
+
+ NetlinkEvent *evt = new NetlinkEvent();
+ if (!evt->decode(mBuffer, count)) {
+ LOGE("Error decoding NetlinkEvent");
+ goto out;
+ }
+
+ LOGD("Ignoring '%s' netlink event", evt->getSubsystem());
+
+out:
+ delete evt;
+ return true;
+}
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
new file mode 100644
index 0000000..857ed4d
--- /dev/null
+++ b/libsysutils/src/SocketClient.cpp
@@ -0,0 +1,58 @@
+#include <alloca.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <string.h>
+
+#define LOG_TAG "SocketClient"
+#include <cutils/log.h>
+
+#include <sysutils/SocketClient.h>
+
+SocketClient::SocketClient(int socket) {
+ mSocket = socket;
+ pthread_mutex_init(&mWriteMutex, NULL);
+}
+
+int SocketClient::sendMsg(int code, const char *msg, bool addErrno) {
+ char *buf;
+
+ if (addErrno) {
+ buf = (char *) alloca(strlen(msg) + strlen(strerror(errno)) + 8);
+ sprintf(buf, "%.3d %s (%s)", code, msg, strerror(errno));
+ } else {
+ buf = (char *) alloca(strlen(msg) + strlen("XXX "));
+ sprintf(buf, "%.3d %s", code, msg);
+ }
+ return sendMsg(buf);
+}
+
+int SocketClient::sendMsg(const char *msg) {
+ if (mSocket < 0) {
+ errno = EHOSTUNREACH;
+ return -1;
+ }
+
+ // Send the message including null character
+ int rc = 0;
+ const char *p = msg;
+ int brtw = strlen(msg) + 1;
+
+ pthread_mutex_lock(&mWriteMutex);
+ while(brtw) {
+ if ((rc = write(mSocket,p, brtw)) < 0) {
+ LOGW("Unable to send msg '%s' (%s)", msg, strerror(errno));
+ pthread_mutex_unlock(&mWriteMutex);
+ return -1;
+ } else if (!rc) {
+ LOGW("0 length write :(");
+ errno = EIO;
+ pthread_mutex_unlock(&mWriteMutex);
+ return -1;
+ }
+ p += rc;
+ brtw -= rc;
+ }
+ pthread_mutex_unlock(&mWriteMutex);
+ return 0;
+}
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
new file mode 100644
index 0000000..1a937c2
--- /dev/null
+++ b/libsysutils/src/SocketListener.cpp
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#define LOG_TAG "SocketListener"
+#include <cutils/log.h>
+#include <cutils/sockets.h>
+
+#include <sysutils/SocketListener.h>
+#include <sysutils/SocketClient.h>
+
+SocketListener::SocketListener(const char *socketName, bool listen) {
+ mListen = listen;
+ mSocketName = socketName;
+ mSock = -1;
+ pthread_mutex_init(&mClientsLock, NULL);
+ mClients = new SocketClientCollection();
+}
+
+SocketListener::SocketListener(int socketFd, bool listen) {
+ mListen = listen;
+ mSocketName = NULL;
+ mSock = socketFd;
+ pthread_mutex_init(&mClientsLock, NULL);
+ mClients = new SocketClientCollection();
+}
+
+int SocketListener::startListener() {
+
+ if (!mSocketName && mSock == -1) {
+ errno = EINVAL;
+ return -1;
+ } else if (mSocketName) {
+ if ((mSock = android_get_control_socket(mSocketName)) < 0) {
+ LOGE("Obtaining file descriptor socket '%s' failed: %s",
+ mSocketName, strerror(errno));
+ return -1;
+ }
+ }
+
+ if (mListen && listen(mSock, 4) < 0) {
+ LOGE("Unable to listen on socket (%s)", strerror(errno));
+ return -1;
+ } else if (!mListen)
+ mClients->push_back(new SocketClient(mSock));
+
+ if (pipe(mCtrlPipe))
+ return -1;
+
+ if (pthread_create(&mThread, NULL, SocketListener::threadStart, this))
+ return -1;
+
+ return 0;
+}
+
+int SocketListener::stopListener() {
+ char c = 0;
+
+ if (write(mCtrlPipe[1], &c, 1) != 1) {
+ LOGE("Error writing to control pipe (%s)", strerror(errno));
+ return -1;
+ }
+
+ void *ret;
+ if (pthread_join(mThread, &ret)) {
+ LOGE("Error joining to listener thread (%s)", strerror(errno));
+ return -1;
+ }
+ close(mCtrlPipe[0]);
+ close(mCtrlPipe[1]);
+ return 0;
+}
+
+void *SocketListener::threadStart(void *obj) {
+ SocketListener *me = reinterpret_cast<SocketListener *>(obj);
+
+ me->runListener();
+ pthread_exit(NULL);
+ return NULL;
+}
+
+void SocketListener::runListener() {
+
+ while(1) {
+ SocketClientCollection::iterator it;
+ fd_set read_fds;
+ int rc = 0;
+ int max = 0;
+
+ FD_ZERO(&read_fds);
+
+ if (mListen) {
+ max = mSock;
+ FD_SET(mSock, &read_fds);
+ }
+
+ FD_SET(mCtrlPipe[0], &read_fds);
+ if (mCtrlPipe[0] > max)
+ max = mCtrlPipe[0];
+
+ 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();
+ }
+ pthread_mutex_unlock(&mClientsLock);
+
+ if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
+ LOGE("select failed (%s)", strerror(errno));
+ sleep(1);
+ continue;
+ } else if (!rc)
+ continue;
+
+ if (FD_ISSET(mCtrlPipe[0], &read_fds))
+ break;
+ if (mListen && FD_ISSET(mSock, &read_fds)) {
+ struct sockaddr addr;
+ socklen_t alen = sizeof(addr);
+ int c;
+
+ if ((c = accept(mSock, &addr, &alen)) < 0) {
+ LOGE("accept failed (%s)", strerror(errno));
+ sleep(1);
+ continue;
+ }
+ pthread_mutex_lock(&mClientsLock);
+ mClients->push_back(new SocketClient(c));
+ 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);
+ }
+ FD_CLR(fd, &read_fds);
+ continue;
+ }
+ }
+ pthread_mutex_unlock(&mClientsLock);
+ } while (0);
+ }
+}
+
+void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
+ pthread_mutex_lock(&mClientsLock);
+ SocketClientCollection::iterator i;
+
+ for (i = mClients->begin(); i != mClients->end(); ++i) {
+ if ((*i)->sendMsg(code, msg, addErrno)) {
+ LOGW("Error sending broadcast (%s)", strerror(errno));
+ }
+ }
+ pthread_mutex_unlock(&mClientsLock);
+}
+
+void SocketListener::sendBroadcast(const char *msg) {
+ pthread_mutex_lock(&mClientsLock);
+ SocketClientCollection::iterator i;
+
+ for (i = mClients->begin(); i != mClients->end(); ++i) {
+ if ((*i)->sendMsg(msg)) {
+ LOGW("Error sending broadcast (%s)", strerror(errno));
+ }
+ }
+ pthread_mutex_unlock(&mClientsLock);
+}
diff --git a/logcat/event-log-tags b/logcat/event-log-tags
index 28cad0a..6df3792 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)
@@ -344,3 +350,6 @@
# browser stats for diary study
70101 browser_zoom_level_change (start level|1|5),(end level|1|5),(time|2|3)
70102 browser_double_tap_duration (duration|1|3),(time|2|3)
+
+# NOTE - the range 1000000-2000000 is reserved for partners and others who
+# want to define their own log tags without conflicting with the core platform.
diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c
index d803cf6..3642647 100644
--- a/mkbootimg/mkbootimg.c
+++ b/mkbootimg/mkbootimg.c
@@ -63,6 +63,7 @@
" [ --second <2ndbootloader-filename> ]\n"
" [ --cmdline <kernel-commandline> ]\n"
" [ --board <boardname> ]\n"
+ " [ --base <address> ]\n"
" -o|--output <filename>\n"
);
return 1;
@@ -104,7 +105,6 @@
char *bootimg = 0;
char *board = "";
unsigned pagesize = 2048;
- unsigned saddr = 0;
int fd;
SHA_CTX ctx;
uint8_t* sha;
@@ -114,6 +114,14 @@
memset(&hdr, 0, sizeof(hdr));
+ /* default load addresses */
+ hdr.kernel_addr = 0x10008000;
+ hdr.ramdisk_addr = 0x11000000;
+ hdr.second_addr = 0x10F00000;
+ hdr.tags_addr = 0x10000100;
+
+ hdr.page_size = pagesize;
+
while(argc > 0){
char *arg = argv[0];
char *val = argv[1];
@@ -132,8 +140,12 @@
second_fn = val;
} else if(!strcmp(arg, "--cmdline")) {
cmdline = val;
- } else if(!strcmp(arg, "--saddr")) {
- saddr = strtoul(val, 0, 16);
+ } else if(!strcmp(arg, "--base")) {
+ unsigned base = strtoul(val, 0, 16);
+ hdr.kernel_addr = base + 0x00008000;
+ hdr.ramdisk_addr = base + 0x01000000;
+ hdr.second_addr = base + 0x00F00000;
+ hdr.tags_addr = base + 0x00000100;
} else if(!strcmp(arg, "--board")) {
board = val;
} else {
@@ -163,16 +175,6 @@
strcpy(hdr.name, board);
- hdr.kernel_addr = 0x10008000;
- hdr.ramdisk_addr = 0x11000000;
- if(saddr) {
- hdr.second_addr = 0x00300000;
- } else {
- hdr.second_addr = 0x10F00000;
- }
- hdr.tags_addr = 0x10000100;
- hdr.page_size = pagesize;
-
memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
if(strlen(cmdline) > (BOOT_ARGS_SIZE - 1)) {
diff --git a/mountd/ASEC.c b/mountd/ASEC.c
deleted file mode 100644
index a6aab9c..0000000
--- a/mountd/ASEC.c
+++ /dev/null
@@ -1,774 +0,0 @@
-/*
- * 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.
- */
-
-/*
-** Android Secure External Cache
-*/
-
-#include "mountd.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <pwd.h>
-#include <stdlib.h>
-#include <poll.h>
-#include <errno.h>
-
-#include <sys/ioctl.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-
-#include <linux/dm-ioctl.h>
-#include <linux/loop.h>
-
-#include <cutils/properties.h>
-#include <cutils/misc.h>
-
-#include "ASEC.h"
-
-//#define MODULE_FAILURE_IS_FATAL
-
-extern int init_module(void *, unsigned long, const char *);
-extern int delete_module(const char *, unsigned int);
-
-struct asec_context
-{
- char *name; // Device mapper volume name
- char *srcPath; // Path to the source (original) mount
- char *backingFile; // Name of the image file
- unsigned int sectors; // Number of sectors
- char *dstPath; // Destination mount point
- char *crypt; // Crypt options
-
- boolean needs_format;
- boolean started;
- int cacheFd;
- int lo_num;
- int dm_num;
- unsigned char key[16];
-};
-
-static const char *MODULES[] = { "dm_mod", "crypto", "crypto_algapi", "crypto_blkcipher",
- "cryptomgr", "dm_crypt", "jbd",
- "twofish_common", "twofish", "cbc",
- "mbcache", "ext3",
- NULL };
-static const char KEY_PATH[] = "/data/system/asec.key";
-static const char MODULE_PATH[] = "/system/lib/modules";
-static const char MKE2FS_PATH[] = "/system/bin/mke2fs";
-static const char E2FSCK_PATH[] = "/system/bin/e2fsck";
-
-boolean AsecIsStarted(void *Handle)
-{
- struct asec_context *ctx = (struct asec_context *) Handle;
-
- return ctx->started;
-}
-
-const char *AsecMountPoint(void *Handle)
-{
- struct asec_context *ctx = (struct asec_context *) Handle;
-
- return ctx->dstPath;
-}
-
-static boolean AsecIsEnabled()
-{
- char value[PROPERTY_VALUE_MAX];
- int enabled;
-
- property_get(ASEC_ENABLED, value, "0");
-
- if (atoi(value) == 1)
- return true;
- return false;
-}
-
-void *AsecInit(const char *Name, const char *SrcPath, const char *BackingFile,
- const char *Size, const char *DstPath, const char *Crypt)
-{
- struct asec_context *ctx;
-
- if (!AsecIsEnabled())
- return NULL;
-
- LOG_ASEC("AsecInit(%s, %s, %s, %s, %s, %s):\n",
- Name, SrcPath, BackingFile, Size, DstPath, Crypt);
-
- if (!Name || !SrcPath || !BackingFile || !Size || !DstPath || !Crypt) {
- LOG_ERROR("AsecInit(): Invalid arguments\n");
- return NULL;
- }
-
- if (!(ctx = malloc(sizeof(struct asec_context)))) {
- LOG_ERROR("AsecInit(): Out of memory\n");
- return NULL;
- }
-
- memset(ctx, 0, sizeof(struct asec_context));
- ctx->name = strdup(Name);
- ctx->srcPath = strdup(SrcPath);
- ctx->backingFile = strdup(BackingFile);
- ctx->sectors = atoi(Size);
- ctx->dstPath = strdup(DstPath);
- ctx->crypt = strdup(Crypt);
- return ctx;
-}
-
-void AsecDeinit(void *Handle)
-{
- struct asec_context *ctx = (struct asec_context *) Handle;
-
- free(ctx->name);
- free(ctx->srcPath);
- free(ctx->backingFile);
- free(ctx->dstPath);
- free(ctx->crypt);
-
- free(ctx);
-}
-
-static int AsecLoadModules()
-{
- int i;
-
- for (i = 0; MODULES[i] != NULL; i++) {
- const char *moduleName = MODULES[i];
- char moduleFile[255];
- int rc = 0;
- void *module;
- unsigned int size;
-
- sprintf(moduleFile, "%s/%s.ko", MODULE_PATH, moduleName);
- module = load_file(moduleFile, &size);
- if (!module) {
- LOG_ERROR("Failed to load module %s (%d)\n", moduleFile, errno);
- return -1;
- }
-
- rc = init_module(module, size, "");
- free(module);
- if (rc && errno != EEXIST) {
- LOG_ERROR("Failed to init module %s (%d)\n", moduleFile, errno);
- return -errno;
- }
- }
- return 0;
-}
-
-static int AsecUnloadModules()
-{
- int i, j, rc;
-
- for (i = 0; MODULES[i] != NULL; i++);
-
- for (j = (i - 1); j >= 0; j--) {
- const char *moduleName = MODULES[j];
- int maxretry = 10;
- while(maxretry-- > 0) {
- rc = delete_module(moduleName, O_NONBLOCK | O_EXCL);
- if (rc < 0 && errno == EAGAIN)
- usleep(500000);
- else
- break;
- }
- if (rc != 0) {
- LOG_ERROR("Failed to unload module %s\n", moduleName);
- return -errno;
- }
- }
- return 0;
-}
-
-static int AsecGenerateKey(struct asec_context *ctx)
-{
- LOG_ASEC("AsecGenerateKey():\n");
-
- memset((void *) ctx->key, 0x69, sizeof(ctx->key));
- return 0;
-}
-
-static int AsecLoadGenerateKey(struct asec_context *ctx)
-{
- int fd;
- int rc = 0;
-
- if ((fd = open(KEY_PATH, O_RDWR | O_CREAT, 0600)) < 0) {
- LOG_ERROR("Error opening / creating keyfile (%d)\n", errno);
- return -errno;
- }
-
- if (read(fd, ctx->key, sizeof(ctx->key)) != sizeof(ctx->key)) {
- LOG_ASEC("Generating key\n");
- if ((rc = AsecGenerateKey(ctx)) < 0) {
- LOG_ERROR("Error generating key (%d)\n", rc);
- goto out;
- }
- if (write(fd, ctx->key, sizeof(ctx->key)) != sizeof(ctx->key)) {
- LOG_ERROR("Error writing keyfile (%d)\n", errno);
- rc = -1;
- goto out;
- }
- }
-
- out:
- close (fd);
- return rc;
-}
-
-static int AsecFormatFilesystem(struct asec_context *ctx)
-{
- char cmdline[255];
- int rc;
-
- sprintf(cmdline,
- "%s -b 4096 -m 1 -j -L \"%s\" /dev/block/dm-%d",
- MKE2FS_PATH, ctx->name, ctx->dm_num);
-
- LOG_ASEC("Formatting filesystem (%s)\n", cmdline);
- // XXX: PROTECT FROM VIKING KILLER
- if ((rc = system(cmdline)) < 0) {
- LOG_ERROR("Error executing format command (%d)\n", errno);
- return -errno;
- }
-
- rc = WEXITSTATUS(rc);
-
- if (!rc) {
- LOG_ASEC("Format completed\n");
- } else {
- LOG_ASEC("Format failed (%d)\n", rc);
- }
-
- return rc;
-}
-
-static int AsecCheckFilesystem(struct asec_context *ctx)
-{
- char cmdline[255];
- int rc;
-
- sprintf(cmdline, "%s -p /dev/block/dm-%d", E2FSCK_PATH, ctx->dm_num);
-
- LOG_ASEC("Checking filesystem (%s)\n", cmdline);
- // XXX: PROTECT FROM VIKING KILLER
- if ((rc = system(cmdline)) < 0) {
- LOG_ERROR("Error executing check command (%d)\n", errno);
- return -errno;
- }
-
- rc = WEXITSTATUS(rc);
-
- if (rc == 0) {
- LOG_ASEC("ASEC volume '%s' had no errors\n", ctx->name);
- } else if (rc == 1) {
- LOG_ASEC("ASEC volume '%s' had corrected errors\n", ctx->name);
- rc = 0;
- } else if (rc == 2) {
- LOG_ERROR("ASEC volume '%s' had corrected errors (system should be rebooted)\n", ctx->name);
- } else if (rc == 4) {
- LOG_ERROR("ASEC volume '%s' had uncorrectable errors\n", ctx->name);
- } else if (rc == 8) {
- LOG_ERROR("Operational error while checking volume '%s'\n", ctx->name);
- } else {
- LOG_ERROR("Unknown e2fsck exit code (%d)\n", rc);
- }
- return rc;
-}
-
-static int AsecOpenCreateCache(struct asec_context *ctx)
-{
- char filepath[255];
-
- sprintf(filepath, "%s/%s", ctx->srcPath, ctx->backingFile);
-
- if ((ctx->cacheFd = open(filepath, O_RDWR)) < 0) {
- if (errno == ENOENT) {
- int rc = 0;
-
- LOG_ASEC("Creating cache file (%u sectors)\n", ctx->sectors);
- if ((ctx->cacheFd = creat(filepath, 0600)) < 0) {
- LOG_ERROR("Error creating cache (%d)\n", errno);
- return -errno;
- }
- if (ftruncate(ctx->cacheFd, ctx->sectors * 512) < 0) {
- LOG_ERROR("Error truncating cache (%d)\n", errno);
- close(ctx->cacheFd);
- unlink(filepath);
- return -errno;
- }
- LOG_ASEC("Cache created (%u sectors) \n", ctx->sectors);
- close(ctx->cacheFd); // creat() is WRONLY
-
- if ((ctx->cacheFd = open(filepath, O_RDWR)) < 0) {
- LOG_ERROR("Error opening cache file (%d)\n", errno);
- close(ctx->cacheFd);
- unlink(filepath);
- return -errno;
- }
-
- ctx->needs_format = 1;
- } else
- return -errno;
- } else {
- struct stat stat_buf;
-
- if (fstat(ctx->cacheFd, &stat_buf) < 0) {
- LOG_ERROR("Failed to fstat cache (%d)\n", errno);
- close(ctx->cacheFd);
- return -errno;
- }
- if (stat_buf.st_size != ctx->sectors * 512) {
- LOG_ERROR("Cache size %lld != configured size %u\n",
- stat_buf.st_size, ctx->sectors * 512);
- }
-
- // XXX: Verify volume label matches ctx->name
- }
-
- return 0;
-}
-
-static void AsecCloseCache(struct asec_context *ctx)
-{
- close(ctx->cacheFd);
-}
-
-static void *_align(void *ptr, unsigned int a)
-{
- register unsigned long agn = --a;
-
- return (void *) (((unsigned long) ptr + agn) & ~agn);
-}
-
-static struct dm_ioctl *_dm_ioctl_setup(struct asec_context *ctx, int flags)
-{
- void *buffer;
- void *p;
- const size_t min_size = 16 * 1024;
- size_t len = sizeof(struct dm_ioctl);
- struct dm_ioctl *io;
- struct dm_target_spec *tgt;
- int i;
- char params[1024];
- char key[80];
-
- key[0] = '\0';
-
- for (i = 0; i < (int) sizeof(ctx->key); i++) {
- char tmp[8];
-
- sprintf(tmp, "%02x", ctx->key[i]);
- strcat(key, tmp);
- }
-
- // XXX: Handle ctx->crypt
- sprintf(params, "twofish %s 0 /dev/block/loop%d 0", key, ctx->lo_num);
-
- if (len < min_size)
- len = min_size;
-
- if (!(buffer = malloc(len))) {
- LOG_ERROR("Unable to allocate memory\n");
- return NULL;
- }
-
- memset(buffer, 0, len);
- io = buffer;
- tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
-
- io->version[0] = 4;
- io->version[1] = 0;
- io->version[2] = 0;
-
- io->data_size = len;
- io->data_start = sizeof(struct dm_ioctl);
-
- io->flags = flags;
- io->dev = 0;
-
- io->target_count = 1;
- io->event_nr = 1;
- strncpy(io->name, ctx->name, sizeof(io->name));
-
- tgt->status = 0;
- tgt->sector_start = 0;
- tgt->length = ctx->sectors;
- strncpy(tgt->target_type, "crypt", sizeof(tgt->target_type));
-
- p = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
- strcpy((char *) p, params);
- p+= strlen(params) + 1;
-
- p = _align(p, 8);
- tgt->next = p - buffer;
-
- return io;
-}
-
-static int FindNextAvailableDm()
-{
- int i;
-
- for (i = 0; i < 8; i++) {
- char path[255];
- sprintf(path, "/dev/block/dm-%d", i);
- if ((access(path, F_OK) < 0) && (errno == ENOENT))
- return i;
- }
-
- LOG_ERROR("Out of device mapper numbers\n");
- return -1;
-}
-
-static int AsecCreateDeviceMapping(struct asec_context *ctx)
-{
- struct dm_ioctl *io;
- int dmFd;
- int rc = 0;
-
- ctx->dm_num = FindNextAvailableDm();
-
- if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) {
- LOG_ERROR("Error opening device mapper (%d)\n", errno);
- return -errno;
- }
-
- if (!(io = _dm_ioctl_setup(ctx, 0))) {
- LOG_ERROR("Unable to setup ioctl (out of memory)\n");
- close(dmFd);
- return -ENOMEM;
- }
-
- if ((rc = ioctl(dmFd, DM_DEV_CREATE, io)) < 0) {
- LOG_ERROR("device-mapper create ioctl failed (%d)\n", errno);
- rc = -errno;
- goto out_free;
- }
-
- free(io);
-
- if (!(io = _dm_ioctl_setup(ctx, DM_STATUS_TABLE_FLAG))) {
- LOG_ERROR("Unable to setup ioctl (out of memory)\n");
- rc = -ENOMEM;
- goto out_nofree;
- }
-
- if ((rc = ioctl(dmFd, DM_TABLE_LOAD, io)) < 0) {
- LOG_ERROR("device-mapper load ioctl failed (%d)\n", errno);
- rc = -errno;
- goto out_free;
- }
-
- free(io);
-
- if (!(io = _dm_ioctl_setup(ctx, 0))) {
- LOG_ERROR("Unable to setup ioctl (out of memory)\n");
- rc = -ENOMEM;
- goto out_nofree;
- }
-
- if ((rc = ioctl(dmFd, DM_DEV_SUSPEND, io)) < 0) {
- LOG_ERROR("device-mapper resume ioctl failed (%d)\n", errno);
- rc = -errno;
- goto out_free;
- }
-
-out_free:
- free (io);
-out_nofree:
- close (dmFd);
- return rc;
-}
-
-static int AsecDestroyDeviceMapping(struct asec_context *ctx)
-{
- struct dm_ioctl *io;
- int dmFd;
- int rc = 0;
-
- if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) {
- LOG_ERROR("Error opening device mapper (%d)\n", errno);
- return -errno;
- }
-
- if (!(io = _dm_ioctl_setup(ctx, DM_PERSISTENT_DEV_FLAG))) {
- LOG_ERROR("Unable to setup ioctl (out of memory)\n");
- rc = -ENOMEM;
- goto out_nofree;
- }
-
- if ((rc = ioctl(dmFd, DM_DEV_REMOVE, io)) < 0) {
- LOG_ERROR("device-mapper remove ioctl failed (%d)\n", errno);
- rc = -errno;
- goto out_free;
- }
-
-out_free:
- free (io);
-out_nofree:
- close (dmFd);
- return rc;
-}
-
-static int AsecMountCache(struct asec_context *ctx)
-{
- int flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_NOATIME | MS_NODIRATIME;
- char devname[255];
-
- if (access(ctx->dstPath, R_OK)) {
- LOG_ERROR("Destination mount point '%s' unavailable (%d)\n", ctx->dstPath, errno);
- return -errno;
- }
-
- sprintf(devname, "/dev/block/dm-%d", ctx->dm_num);
-
- if (mount(devname, ctx->dstPath, "ext3", flags, NULL)) {
- LOG_ERROR("ASEC mount failed (%d)\n", errno);
- return -errno;
- }
-
- return 0;
-}
-
-static int AsecUnmountCache(struct asec_context *ctx)
-{
- if (umount(ctx->dstPath)) {
- if (errno == EBUSY) {
- LOG_ASEC("ASEC volume '%s' still busy\n", ctx->name);
- } else {
- LOG_ERROR("ASEC umount failed (%d)\n", errno);
- }
- return -errno;
- }
- LOG_ASEC("ASEC volume '%s' unmounted\n", ctx->name);
- return 0;
-}
-
-static int FindNextAvailableLoop()
-{
- int i;
-
- for (i = 0; i < MAX_LOOP; i++) {
- struct loop_info info;
- char devname[255];
- int fd;
-
- sprintf(devname, "/dev/block/loop%d", i);
-
- if ((fd = open(devname, O_RDONLY)) < 0) {
- LOG_ERROR("Unable to open %s (%d)\n", devname, errno);
- return -errno;
- }
-
- if (ioctl(fd, LOOP_GET_STATUS, &info) < 0) {
- close(fd);
-
- if (errno == ENXIO)
- return i;
-
- LOG_ERROR("Unable to get loop status for %s (%d)\n", devname, errno);
- return -errno;
- }
- close(fd);
- }
- return -ENXIO;
-}
-
-static int AsecCreateLoop(struct asec_context *ctx)
-{
- char devname[255];
- int device_fd;
- int rc = 0;
-
- ctx->lo_num = FindNextAvailableLoop();
- if (ctx->lo_num < 0) {
- LOG_ERROR("No loop devices available\n");
- return -ENXIO;
- }
-
- sprintf(devname, "/dev/block/loop%d", ctx->lo_num);
- device_fd = open(devname, O_RDWR);
- if (device_fd < 0) {
- LOG_ERROR("failed to open loop device (%d)\n", errno);
- return -errno;
- }
-
- if (ioctl(device_fd, LOOP_SET_FD, ctx->cacheFd) < 0) {
- LOG_ERROR("loop_set_fd ioctl failed (%d)\n", errno);
- rc = -errno;
- }
- close(device_fd);
- return rc;
-}
-
-static int AsecDestroyLoop(struct asec_context *ctx)
-{
- char devname[255];
- int device_fd;
- int rc = 0;
-
- sprintf(devname, "/dev/block/loop%d", ctx->lo_num);
- device_fd = open(devname, O_RDONLY);
- if (device_fd < 0) {
- LOG_ERROR("Failed to open loop (%d)\n", errno);
- return -errno;
- }
-
- if (ioctl(device_fd, LOOP_CLR_FD, 0) < 0) {
- LOG_ERROR("Failed to destroy loop (%d)\n", errno);
- rc = -errno;
- }
-
- close(device_fd);
- return rc;
-}
-
-int AsecStart(void *Handle)
-{
- struct asec_context *ctx = (struct asec_context *) Handle;
- char value[PROPERTY_VALUE_MAX];
- int rc = 0;
-
- if (!ctx)
- return -EINVAL;
-
- if (ctx->started)
- return -EBUSY;
-
- LOG_ASEC("AsecStart(%s):\n", ctx->name);
-
- NotifyAsecState(ASEC_BUSY, ctx->dstPath);
-
- if ((rc = AsecLoadModules()) < 0) {
- LOG_ERROR("AsecStart: Failed to load kernel modules\n");
-#ifdef MODULE_FAILURE_IS_FATAL
- NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
- return rc;
-#endif
- }
-
- if ((rc = AsecLoadGenerateKey(ctx))) {
- LOG_ERROR("AsecStart: Failed to load / generate key\n");
- NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
- return rc;
- }
-
- if ((rc = AsecOpenCreateCache(ctx)) < 0) {
- LOG_ERROR("AsecStart: Failed to open / create cache\n");
- NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
- return rc;
- }
-
- if ((rc = AsecCreateLoop(ctx)) < 0) {
- LOG_ERROR("AsecStart: Failed to create loop\n");
- NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
- goto fail_closecache;
- }
-
- if ((rc = AsecCreateDeviceMapping(ctx)) < 0) {
- LOG_ERROR("AsecStart: Failed to create devmapping (%d)\n", rc);
- NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
- goto fail_destroyloop;
- }
-
- if (ctx->needs_format) {
- if ((rc = AsecFormatFilesystem(ctx))) {
- LOG_ERROR("AsecStart: Failed to format cache (%d)\n", rc);
- NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
- goto fail_destroydm;
- }
- ctx->needs_format = 0;
- } else {
- if ((rc = AsecCheckFilesystem(ctx))) {
- LOG_ERROR("AsecStart: Failed to check filesystem (%d)\n", rc);
- NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
- goto fail_destroydm;
- }
- }
-
- if ((rc = AsecMountCache(ctx)) < 0) {
- LOG_ERROR("AsecStart: Failed to mount cache (%d)\n", rc);
- NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
- goto fail_destroydm;
- }
-
- NotifyAsecState(ASEC_AVAILABLE, ctx->dstPath);
- ctx->started = true;
-
- return rc;
-
- fail_destroydm:
- AsecDestroyDeviceMapping(ctx);
- fail_destroyloop:
- AsecDestroyLoop(ctx);
- fail_closecache:
- AsecCloseCache(ctx);
- return rc;
-}
-
-int AsecStop(void *Handle)
-{
- struct asec_context *ctx = (struct asec_context *) Handle;
- int rc = 0;
-
- if (!ctx->started)
- return -EINVAL;
-
- LOG_ASEC("AsecStop(%s):\n", ctx->name);
-
- NotifyAsecState(ASEC_BUSY, ctx->dstPath);
-
- if ((rc = AsecUnmountCache(ctx)) < 0) {
- LOG_ERROR("AsecStop: Failed to unmount cache (%d)\n", rc);
- NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
- return rc;
- }
-
- if ((rc = AsecDestroyDeviceMapping(ctx)) < 0) {
- LOG_ERROR("AsecStop: Failed to destroy devmapping (%d)\n", rc);
- NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
- return rc;
- }
-
- if ((rc = AsecDestroyLoop(ctx)) < 0) {
- LOG_ERROR("AsecStop: Failed to destroy loop device (%d)\n", rc);
- NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
- return rc;
- }
-
- AsecCloseCache(ctx);
-
- if ((rc = AsecUnloadModules()) < 0) {
- if (rc == -EAGAIN) {
- LOG_ASEC("AsecStop: Kernel modules still in use\n");
- } else {
- LOG_ERROR("AsecStop: Failed to unload kernel modules (%d)\n", rc);
-#ifdef MODULE_FAILURE_IS_FATAL
- NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
- return rc;
-#endif
- }
- }
-
- ctx->started = false;
- NotifyAsecState(ASEC_DISABLED, ctx->dstPath);
- return rc;
-}
diff --git a/mountd/ASEC.h b/mountd/ASEC.h
deleted file mode 100644
index c87b288..0000000
--- a/mountd/ASEC.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef _ASEC_H
-#define _ASEC_H
-
-#define ASEC_STORES_MAX 4
-#define MAX_LOOP 8
-
-typedef enum AsecState {
- // Feature disabled
- ASEC_DISABLED,
-
- // Feature enabled and operational
- ASEC_AVAILABLE,
-
- // Busy
- ASEC_BUSY,
-
- // Internal Error
- ASEC_FAILED_INTERR,
-
- // No media available
- ASEC_FAILED_NOMEDIA,
-
- // Media is corrupt
- ASEC_FAILED_BADMEDIA,
-
- // Key mismatch
- ASEC_FAILED_BADKEY,
-} AsecState;
-
-/*
- * ASEC commands
- */
-#define ASEC_CMD_SEND_STATUS "asec_send_status"
-#define ASEC_CMD_ENABLE "asec_enable"
-#define ASEC_CMD_DISABLE "asec_disable"
-
-/*
- * ASEC events
- */
-
-// These events correspond to the states in the AsecState enum.
-// A path to the ASEC mount point follows the colon
-#define ASEC_EVENT_DISABLED "asec_disabled:"
-#define ASEC_EVENT_AVAILABLE "asec_available:"
-#define ASEC_EVENT_BUSY "asec_busy:"
-#define ASEC_EVENT_FAILED_INTERR "asec_failed_interror:"
-#define ASEC_EVENT_FAILED_NOMEDIA "asec_failed_nomedia"
-#define ASEC_EVENT_FAILED_BADMEDIA "asec_failed_badmedia:"
-#define ASEC_EVENT_FAILED_BADKEY "asec_failed_badkey:"
-
-/*
- * System Properties
- */
-
-#define ASEC_ENABLED "asec.enabled"
-
-#define ASEC_STATUS "ro.asec.status"
-#define ASEC_STATUS_DISABLED "disabled"
-#define ASEC_STATUS_AVAILABLE "available"
-#define ASEC_STATUS_BUSY "busy"
-#define ASEC_STATUS_FAILED_INTERR "internal_error"
-#define ASEC_STATUS_FAILED_NOMEDIA "no_media"
-#define ASEC_STATUS_FAILED_BADMEDIA "bad_media"
-#define ASEC_STATUS_FAILED_BADKEY "bad_key"
-
-#endif
diff --git a/mountd/Android.mk b/mountd/Android.mk
deleted file mode 100644
index 16532fa..0000000
--- a/mountd/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- AutoMount.c \
- ProcessKiller.c \
- Server.c \
- mountd.c \
- ASEC.c \
- logwrapper.c
-
-LOCAL_MODULE:= mountd
-
-LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
-
-LOCAL_CFLAGS := -DCREATE_MOUNT_POINTS=0
-
-LOCAL_SHARED_LIBRARIES := libcutils
-
-# disabled - we are using vold now instead
-# include $(BUILD_EXECUTABLE)
diff --git a/mountd/AutoMount.c b/mountd/AutoMount.c
deleted file mode 100644
index 12ad572..0000000
--- a/mountd/AutoMount.c
+++ /dev/null
@@ -1,1062 +0,0 @@
-/*
- * 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.
- */
-
-/*
-** mountd automount support
-*/
-
-#include "mountd.h"
-
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <pwd.h>
-#include <stdlib.h>
-#include <poll.h>
-
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <linux/loop.h>
-#include <sys/inotify.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <linux/netlink.h>
-
-#define DEVPATH "/dev/block/"
-#define DEVPATHLENGTH 11 // strlen(DEVPATH)
-
-// FIXME - only one loop mount is supported at a time
-#define LOOP_DEVICE "/dev/block/loop0"
-
-// timeout value for poll() when retries are pending
-#define POLL_TIMEOUT 1000
-
-#define MAX_MOUNT_RETRIES 3
-#define MAX_UNMOUNT_RETRIES 5
-
-typedef enum {
- // device is unmounted
- kUnmounted,
-
- // attempting to mount device
- kMounting,
-
- // device is unmounted
- kMounted,
-
- // attempting to unmount device
- // so the media can be removed
- kUnmountingForEject,
-
- // attempting to mount device
- // so it can be shared via USB mass storage
- kUnmountingForUms,
-} MountState;
-
-typedef struct MountPoint {
- // block device to mount
- const char* device;
-
- // mount point for device
- const char* mountPoint;
-
- // path to the UMS driver file for specifying the block device path
- const char* driverStorePath;
-
- // true if device can be shared via
- // USB mass storage
- boolean enableUms;
-
- // Array of ASEC handles
- void *asecHandles[ASEC_STORES_MAX];
-
- // true if the device is being shared via USB mass storage
- boolean umsActive;
-
- // current state of the mount point
- MountState state;
-
- // number of mount or unmount retries so far,
- // when attempting to mount or unmount the device
- int retryCount;
-
- // next in sMountPointList linked list
- struct MountPoint* next;
-} MountPoint;
-
-// list of our mount points (does not change after initialization)
-static MountPoint* sMountPointList = NULL;
-boolean gMassStorageEnabled = false;
-boolean gMassStorageConnected = false;
-
-static pthread_t sAutoMountThread = 0;
-static pid_t gExcludedPids[2] = {-1, -1};
-
-static const char FSCK_MSDOS_PATH[] = "/system/bin/dosfsck";
-
-// number of mount points that have timeouts pending
-static int sRetriesPending = 0;
-
-// for synchronization between sAutoMountThread and the server thread
-static pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
-
-// requests the USB mass_storage driver to begin or end sharing a block device
-// via USB mass storage.
-static void SetBackingStore(MountPoint* mp, boolean enable)
-{
- int fd;
-
- if (!mp->driverStorePath) {
- LOG_ERROR("no driver_store_path specified in config file for %s", mp->device);
- return;
- }
-
- LOG_MOUNT("SetBackingStore enable: %s\n", (enable ? "true" : "false"));
- fd = open(mp->driverStorePath, O_WRONLY);
- if (fd < 0)
- {
- LOG_ERROR("could not open driver_store_path %s\n", mp->driverStorePath);
- }
- else
- {
- if (enable)
- {
- write(fd, mp->device, strlen(mp->device));
- mp->umsActive = true;
- }
- else
- {
- char ch = 0;
- write(fd, &ch, 1);
- mp->umsActive = false;
- }
- close(fd);
- }
-}
-
-static boolean ReadMassStorageState()
-{
- FILE* file = fopen("/sys/class/switch/usb_mass_storage/state", "r");
- if (file)
- {
- char buffer[20];
- fgets(buffer, sizeof(buffer), file);
- fclose(file);
- return (strncmp(buffer, "online", strlen("online")) == 0);
- }
- else
- {
- LOG_ERROR("could not read initial mass storage state\n");
- return false;
- }
-}
-
-static boolean IsLoopMounted(const char* path)
-{
- FILE* f;
- int count;
- char device[256];
- char mount_path[256];
- char rest[256];
- int result = 0;
- int path_length = strlen(path);
-
- f = fopen("/proc/mounts", "r");
- if (!f) {
- LOG_ERROR("could not open /proc/mounts\n");
- return -1;
- }
-
- do {
- count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest);
- if (count == 3) {
- if (strcmp(LOOP_DEVICE, device) == 0 && strcmp(path, mount_path) == 0)
- {
- result = 1;
- break;
- }
- }
- } while (count == 3);
-
- fclose(f);
- LOG_MOUNT("IsLoopMounted: %s returning %d\n", path, result);
- return result;
-}
-
-static int CheckFilesystem(const char *device)
-{
- char cmdline[255];
- int rc;
-
- // XXX: SAN: Check for FAT signature
-
- int result = access(FSCK_MSDOS_PATH, X_OK);
- if (result != 0) {
- LOG_MOUNT("CheckFilesystem(%s): %s not found (skipping checks)\n", FSCK_MSDOS_PATH, device);
- return 0;
- }
-
- char *args[7];
- args[0] = FSCK_MSDOS_PATH;
- args[1] = "-v";
- args[2] = "-V";
- args[3] = "-w";
- args[4] = "-p";
- args[5] = device;
- args[6] = NULL;
-
- LOG_MOUNT("Checking filesystem on %s\n", device);
- rc = logwrap(6, args);
-
- // XXX: We need to be able to distinguish between a FS with an error
- // and a block device which does not have a FAT fs at all on it
- if (rc == 0) {
- LOG_MOUNT("Filesystem check completed OK\n");
- return 0;
- } else if (rc == 1) {
- LOG_MOUNT("Filesystem check failed (general failure)\n");
- return -EINVAL;
- } else if (rc == 2) {
- LOG_MOUNT("Filesystem check failed (invalid usage)\n");
- return -EIO;
- } else {
- LOG_MOUNT("Filesystem check failed (unknown exit code %d)\n", rc);
- return -EIO;
- }
-}
-
-static int DoMountDevice(const char* device, const char* mountPoint)
-{
- LOG_MOUNT("Attempting mount of %s on %s\n", device, mountPoint);
-
-#if CREATE_MOUNT_POINTS
- // make sure mount point exists
- mkdir(mountPoint, 0000);
-#endif
-
- int flags = 0;
-
- if (device && strncmp(device, "/dev/", 5))
- {
- // mount with the loop driver if device does not start with "/dev/"
- int file_fd, device_fd;
-
- // FIXME - only one loop mount supported at a time
- file_fd = open(device, O_RDWR);
- if (file_fd < -1) {
- LOG_ERROR("open backing file %s failed\n", device);
- return 1;
- }
- device_fd = open(LOOP_DEVICE, O_RDWR);
- if (device_fd < -1) {
- LOG_ERROR("open %s failed", LOOP_DEVICE);
- close(file_fd);
- return 1;
- }
- if (ioctl(device_fd, LOOP_SET_FD, file_fd) < 0)
- {
- LOG_ERROR("ioctl LOOP_SET_FD failed\n");
- close(file_fd);
- close(device_fd);
- return 1;
- }
-
- close(file_fd);
- close(device_fd);
- device = "/dev/block/loop0";
- }
-
- int result = access(device, R_OK);
- if (result) {
- LOG_ERROR("Unable to access '%s' (%d)\n", device, errno);
- return -errno;
- }
-
-#if 0
- if ((result = CheckFilesystem(device))) {
- LOG_ERROR("Not mounting filesystem due to check failure (%d)\n", result);
- // XXX: Notify framework - need a new SDCARD state for the following:
- // - SD cards which are not present
- // - SD cards with no partition table
- // - SD cards with no filesystem
- // - SD cards with bad filesystem
- return result;
- }
-#endif
-
- // Extra safety measures:
- flags |= MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
- // Also, set fmask = 711 so that files cannot be marked executable,
- // and cannot by opened by uid 1000 (system). Similar, dmask = 700
- // so that directories cannot be accessed by uid 1000.
- result = mount(device, mountPoint, "vfat", flags,
- "utf8,uid=1000,gid=1000,fmask=711,dmask=700");
- if (result && errno == EROFS) {
- LOG_ERROR("mount failed EROFS, try again read-only\n");
- flags |= MS_RDONLY;
- result = mount(device, mountPoint, "vfat", flags,
- "utf8,uid=1000,gid=1000,fmask=711,dmask=700");
- }
-
- if (result == 0) {
- LOG_MOUNT("Partition %s mounted on %s\n", device, mountPoint);
- NotifyMediaState(mountPoint, MEDIA_MOUNTED, (flags & MS_RDONLY) != 0);
-
- MountPoint* mp = sMountPointList;
- while (mp) {
- if (!strcmp(mountPoint, mp->mountPoint)) {
- int i;
-
- for (i = 0; i < ASEC_STORES_MAX; i++) {
- if (mp->asecHandles[i] != NULL) {
- int a_result;
- if ((a_result = AsecStart(mp->asecHandles[i])) < 0) {
- LOG_ERROR("ASEC start failure (%d)\n", a_result);
- }
- }
- }
- break;
- }
- mp = mp -> next;
- }
- } else if (errno == EBUSY) {
- LOG_MOUNT("Mount failed (already mounted)\n");
- result = 0;
- } else {
-#if CREATE_MOUNT_POINTS
- rmdir(mountPoint);
-#endif
- LOG_MOUNT("Unable to mount %s on %s\n", device, mountPoint);
- }
-
- return result;
-}
-
-static int DoUnmountDevice(MountPoint *mp)
-{
- boolean loop = IsLoopMounted(mp->mountPoint);
- int i;
-
- for (i = 0; i < ASEC_STORES_MAX; i++) {
- if (mp->asecHandles[i] && AsecIsStarted(mp->asecHandles[i]))
- AsecStop(mp->asecHandles[i]);
- }
-
- int result = umount(mp->mountPoint);
- LOG_MOUNT("umount returned %d errno: %d\n", result, errno);
-
- if (result == 0)
- {
-#if CREATE_MOUNT_POINTS
- rmdir(mountPoint);
-#endif
- NotifyMediaState(mp->mountPoint, MEDIA_UNMOUNTED, false);
- }
-
- if (loop)
- {
- // free the loop device
- int loop_fd = open(LOOP_DEVICE, O_RDONLY);
- if (loop_fd < -1) {
- LOG_ERROR("open loop device failed\n");
- }
- if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
- LOG_ERROR("ioctl LOOP_CLR_FD failed\n");
- }
-
- close(loop_fd);
- }
-
- // ignore EINVAL and ENOENT, since it usually means the device is already unmounted
- if (result && (errno == EINVAL || errno == ENOENT))
- result = 0;
-
- return result;
-}
-
-static int MountPartition(const char* device, const char* mountPoint)
-{
- char buf[100];
- int i;
-
- // attempt to mount subpartitions of the device
- for (i = 1; i < 10; i++)
- {
- int rc;
- snprintf(buf, sizeof(buf), "%sp%d", device, i);
- rc = DoMountDevice(buf, mountPoint);
- LOG_MOUNT("DoMountDevice(%s, %s) = %d\n", buf, mountPoint, rc);
- if (rc == 0)
- return 0;
- }
-
- return -1;
-}
-
-/*****************************************************
- *
- * AUTO-MOUNTER STATE ENGINE IMPLEMENTATION
- *
- *****************************************************/
-
-static void SetState(MountPoint* mp, MountState state)
-{
- mp->state = state;
-}
-
-// Enter a state that requires retries and timeouts.
-static void SetRetries(MountPoint* mp, MountState state)
-{
- SetState(mp, state);
- mp->retryCount = 0;
-
- sRetriesPending++;
- // wake up the automounter thread if we are being called
- // from somewhere else with no retries pending
- if (sRetriesPending == 1 && sAutoMountThread != 0 &&
- pthread_self() != sAutoMountThread)
- pthread_kill(sAutoMountThread, SIGUSR1);
-}
-
-// Exit a state that requires retries and timeouts.
-static void ClearRetries(MountPoint* mp, MountState state)
-{
- SetState(mp, state);
- sRetriesPending--;
-}
-
-// attempt to mount the specified mount point.
-// set up retry/timeout if it does not succeed at first.
-static void RequestMount(MountPoint* mp)
-{
- LOG_MOUNT("RequestMount %s\n", mp->mountPoint);
-
- if (mp->state != kMounted && mp->state != kMounting &&
- access(mp->device, R_OK) == 0) {
- // try raw device first
- if (DoMountDevice(mp->device, mp->mountPoint) == 0 ||
- MountPartition(mp->device, mp->mountPoint) == 0)
- {
- SetState(mp, kMounted);
- }
- else
- {
- SetState(mp, kMounting);
- mp->retryCount = 0;
- SetRetries(mp, kMounting);
- }
- }
-}
-
-// Force the kernel to drop all caches.
-static void DropSystemCaches(void)
-{
- int fd;
-
- LOG_MOUNT("Dropping system caches\n");
- fd = open("/proc/sys/vm/drop_caches", O_WRONLY);
-
- if (fd > 0) {
- char ch = 3;
- int rc;
-
- rc = write(fd, &ch, 1);
- if (rc <= 0)
- LOG_MOUNT("Error dropping caches (%d)\n", rc);
- close(fd);
- }
-}
-
-// attempt to unmount the specified mount point.
-// set up retry/timeout if it does not succeed at first.
-static void RequestUnmount(MountPoint* mp, MountState retryState)
-{
- int result;
-
- LOG_MOUNT("RequestUnmount %s retryState: %d\n", mp->mountPoint, retryState);
-
- if (mp->state == kMounted)
- {
- SendUnmountRequest(mp->mountPoint);
-
- // do this in case the user pulls the SD card before we can successfully unmount
- sync();
- DropSystemCaches();
-
- if (DoUnmountDevice(mp) == 0)
- {
- SetState(mp, kUnmounted);
- if (retryState == kUnmountingForUms)
- {
- SetBackingStore(mp, true);
- NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
- }
- }
- else
- {
- LOG_MOUNT("unmount failed, set retry\n");
- SetRetries(mp, retryState);
- }
- }
- else if (mp->state == kMounting)
- {
- SetState(mp, kUnmounted);
- }
-}
-
-// returns true if the mount point should be shared via USB mass storage
-static boolean MassStorageEnabledForMountPoint(const MountPoint* mp)
-{
- return (gMassStorageEnabled && gMassStorageConnected && mp->enableUms);
-}
-
-// handles changes in gMassStorageEnabled and gMassStorageConnected
-static void MassStorageStateChanged()
-{
- MountPoint* mp = sMountPointList;
-
- boolean enable = (gMassStorageEnabled && gMassStorageConnected);
- LOG_MOUNT("MassStorageStateChanged enable: %s\n", (enable ? "true" : "false"));
-
- while (mp)
- {
- if (mp->enableUms)
- {
- if (enable)
- {
- if (mp->state == kMounting)
- SetState(mp, kUnmounted);
- if (mp->state == kUnmounted)
- {
- SetBackingStore(mp, true);
- NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
- }
- else
- {
- LOG_MOUNT("MassStorageStateChanged requesting unmount\n");
- // need to successfully unmount first
- RequestUnmount(mp, kUnmountingForUms);
- }
- } else if (mp->umsActive) {
- SetBackingStore(mp, false);
- if (mp->state == kUnmountingForUms)
- {
- ClearRetries(mp, kMounted);
- NotifyMediaState(mp->mountPoint, MEDIA_MOUNTED, false);
- }
- else if (mp->state == kUnmounted)
- {
- NotifyMediaState(mp->mountPoint, MEDIA_UNMOUNTED, false);
- RequestMount(mp);
- }
- }
- }
-
- mp = mp->next;
- }
-}
-
-// called when USB mass storage connected state changes
-static void HandleMassStorageOnline(boolean connected)
-{
- if (connected != gMassStorageConnected)
- {
- gMassStorageConnected = connected;
- SendMassStorageConnected(connected);
-
- // we automatically reset to mass storage off after USB is connected
- if (!connected)
- gMassStorageEnabled = false;
-
- MassStorageStateChanged();
- }
-}
-
-// called when a new block device has been created
-static void HandleMediaInserted(const char* device)
-{
- MountPoint* mp = sMountPointList;
-
- LOG_MOUNT("HandleMediaInserted(%s):\n", device);
-
- while (mp)
- {
- // see if the device matches mount point's block device
- if (mp->state == kUnmounted &&
- strncmp(device, mp->device + DEVPATHLENGTH, strlen(mp->device) - DEVPATHLENGTH) == 0)
- {
- if (MassStorageEnabledForMountPoint(mp))
- {
- SetBackingStore(mp, true);
- NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
- }
- else
- RequestMount(mp);
- }
- mp = mp->next;
- }
-}
-
-// called when a new block device has been deleted
-static void HandleMediaRemoved(const char* device)
-{
- MountPoint* mp = sMountPointList;
- while (mp)
- {
- if (strncmp(device, mp->device + DEVPATHLENGTH, strlen(mp->device) - DEVPATHLENGTH) == 0)
- {
- if (mp->enableUms)
- SetBackingStore(mp, false);
-
- if (mp->state == kMounted)
- {
- RequestUnmount(mp, kUnmountingForEject);
- NotifyMediaState(mp->mountPoint, MEDIA_BAD_REMOVAL, false);
- }
-
- NotifyMediaState(mp->mountPoint, MEDIA_REMOVED, false);
- break;
- }
- mp = mp->next;
- }
-}
-
-// Handle retrying to mount or unmount devices,
-// and handle timeout condition if we have tried too many times
-static void HandleRetries()
-{
- MountPoint* mp = sMountPointList;
-
- while (mp)
- {
- if (mp->state == kMounting)
- {
- if (MountPartition(mp->device, mp->mountPoint) == 0)
- {
- // mount succeeded - clear the retry for this mount point
- ClearRetries(mp, kMounted);
- }
- else
- {
- mp->retryCount++;
- if (mp->retryCount == MAX_MOUNT_RETRIES)
- {
- // we failed to mount the device too many times
- ClearRetries(mp, kUnmounted);
- // notify that we failed to mount
- NotifyMediaState(mp->mountPoint, MEDIA_UNMOUNTABLE, false);
- }
- }
- }
- else if (mp->state == kUnmountingForEject || mp->state == kUnmountingForUms)
- {
- if (DoUnmountDevice(mp) == 0)
- {
- // unmounting succeeded
- // start mass storage, if state is kUnmountingForUms
- if (mp->state == kUnmountingForUms)
- {
- SetBackingStore(mp, true);
- NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
- }
- // clear the retry for this mount point
- ClearRetries(mp, kUnmounted);
- }
- else
- {
- mp->retryCount++;
- if (mp->retryCount >= MAX_UNMOUNT_RETRIES)
- {
- // kill any processes that are preventing the device from unmounting
- // send SIGKILL instead of SIGTERM if the first attempt did not succeed
- boolean sigkill = (mp->retryCount > MAX_UNMOUNT_RETRIES);
-
- int i;
-
- for (i = 0; i < ASEC_STORES_MAX; i++) {
- if (mp->asecHandles[i] && AsecIsStarted(mp->asecHandles[i])) {
- LOG_MOUNT("Killing processes for ASEC path '%s'\n",
- AsecMountPoint(mp->asecHandles[i]));
- KillProcessesWithOpenFiles(AsecMountPoint(mp->asecHandles[i]),
- sigkill,
- gExcludedPids, sizeof(gExcludedPids) / sizeof(pid_t));
-
- // Now that we've killed the processes, try to stop the volume again
- AsecStop(mp->asecHandles[i]);
- }
- }
-
- // unmounting the device is failing, so start killing processes
- KillProcessesWithOpenFiles(mp->mountPoint, sigkill, gExcludedPids,
- sizeof(gExcludedPids) / sizeof(pid_t));
-
- }
- }
- }
-
- mp = mp->next;
- }
-}
-
-/*****************************************************
- *
- * AUTO-MOUNTER THREAD
- *
- *****************************************************/
-
-static void sigusr1_handler(int signo)
-{
- // don't need to do anything here
-}
-
-// create a socket for listening to inotify events
-int CreateINotifySocket()
-{
- // initialize inotify
- int fd = inotify_init();
-
- if (fd < 0) {
- LOG_ERROR("inotify_init failed, %s\n", strerror(errno));
- return -1;
- }
-
- fcntl(fd, F_SETFL, O_NONBLOCK | fcntl(fd, F_GETFL));
-
- return fd;
-}
-
-
-// create a socket for listening to uevents
-int CreateUEventSocket()
-{
- struct sockaddr_nl addr;
- int sz = 64*1024;
- int fd;
-
- memset(&addr, 0, sizeof(addr));
- addr.nl_family = AF_NETLINK;
- addr.nl_pid = getpid();
- addr.nl_groups = 0xffffffff;
-
- fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
- if(fd < 0)
- {
- LOG_ERROR("could not create NETLINK_KOBJECT_UEVENT socket\n");
- return -1;
- }
-
- setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
-
- if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- LOG_ERROR("could not bind NETLINK_KOBJECT_UEVENT socket\n");
- close(fd);
- return -1;
- }
-
- return fd;
-}
-
-/*
- * Automounter main event thread.
- * This thread listens for block devices being created and deleted via inotify,
- * and listens for changes in the USB mass storage connected/disconnected via uevents from the
- * power supply driver.
- * This thread also handles retries and timeouts for requests to mount or unmount a device.
- */
-static void* AutoMountThread(void* arg)
-{
- int inotify_fd;
- int uevent_fd;
- int id;
- struct sigaction actions;
-
- gExcludedPids[1] = getpid();
-
- memset(&actions, 0, sizeof(actions));
- sigemptyset(&actions.sa_mask);
- actions.sa_flags = 0;
- actions.sa_handler = sigusr1_handler;
- sigaction(SIGUSR1, &actions, NULL);
-
- // initialize inotify
- inotify_fd = CreateINotifySocket();
- // watch for files created and deleted in "/dev"
- inotify_add_watch(inotify_fd, DEVPATH, IN_CREATE|IN_DELETE);
-
- // initialize uevent watcher
- uevent_fd = CreateUEventSocket();
- if (uevent_fd < 0)
- {
- LOG_ERROR("CreateUEventSocket failed, %s\n", strerror(errno));
- return NULL;
- }
-
- while (1)
- {
- struct pollfd fds[2];
- int timeout, result;
-
-#define INOTIFY_IDX 0
-#define UEVENT_IDX 1
-
- fds[INOTIFY_IDX].fd = inotify_fd;
- fds[INOTIFY_IDX].events = POLLIN;
- fds[INOTIFY_IDX].revents = 0;
- fds[UEVENT_IDX].fd = uevent_fd;
- fds[UEVENT_IDX].events = POLLIN;
- fds[UEVENT_IDX].revents = 0;
-
- // wait for an event or a timeout to occur.
- // poll() can also return in response to a SIGUSR1 signal
- timeout = (sRetriesPending ? POLL_TIMEOUT : -1);
- result = poll(fds, 2, timeout);
-
- // lock the mutex while we are handling events
- pthread_mutex_lock(&sMutex);
-
- // handle inotify notifications for block device creation and deletion
- if (fds[INOTIFY_IDX].revents == POLLIN)
- {
- struct inotify_event event;
- char buffer[512];
- int length = read(inotify_fd, buffer, sizeof(buffer));
- int offset = 0;
-
- while (length >= (int)sizeof(struct inotify_event))
- {
- struct inotify_event* event = (struct inotify_event *)&buffer[offset];
-
- if (event->mask == IN_CREATE)
- {
- LOG_MOUNT("/dev/block/%s created\n", event->name);
- HandleMediaInserted(event->name);
- }
- else if (event->mask == IN_DELETE)
- {
- LOG_MOUNT("/dev/block/%s deleted\n", event->name);
- HandleMediaRemoved(event->name);
- }
-
- int size = sizeof(struct inotify_event) + event->len;
- length -= size;
- offset += size;
- }
- }
-
- // handle uevent notifications for USB state changes
- if (fds[UEVENT_IDX].revents == POLLIN)
- {
- char buffer[64*1024];
- int count;
-
- count = recv(uevent_fd, buffer, sizeof(buffer), 0);
- if (count > 0) {
- char* s = buffer;
- char* end = s + count;
- char* type = NULL;
- char* online = NULL;
- char* switchName = NULL;
- char* switchState = NULL;
-
- while (s < end) {
- if (!strncmp("POWER_SUPPLY_TYPE=", s, strlen("POWER_SUPPLY_TYPE=")))
- type = s + strlen("POWER_SUPPLY_TYPE=");
- else if (!strncmp("POWER_SUPPLY_ONLINE=", s, strlen("POWER_SUPPLY_ONLINE=")))
- online = s + strlen("POWER_SUPPLY_ONLINE=");
- else if (!strncmp("SWITCH_NAME=", s, strlen("SWITCH_NAME=")))
- switchName = s + strlen("SWITCH_NAME=");
- else if (!strncmp("SWITCH_STATE=", s, strlen("SWITCH_STATE=")))
- switchState = s + strlen("SWITCH_STATE=");
- s += (strlen(s) + 1);
- }
-
- // we use the usb_mass_storage switch state to tell us when USB is online
- if (switchName && switchState &&
- !strcmp(switchName, "usb_mass_storage") && !strcmp(switchState, "online"))
- {
- LOG_MOUNT("USB online\n");
- HandleMassStorageOnline(true);
- }
-
- // and we use the power supply state to tell us when USB is offline
- // we can't rely on the switch for offline detection because we get false positives
- // when USB is reenumerated by the host.
- if (type && online && !strcmp(type, "USB") && !strcmp(online, "0"))
- {
- LOG_MOUNT("USB offline\n");
- HandleMassStorageOnline(false);
- }
- }
- }
-
- // handle retries
- if (sRetriesPending)
- HandleRetries();
-
- // done handling events, so unlock the mutex
- pthread_mutex_unlock(&sMutex);
- }
-
- inotify_rm_watch(inotify_fd, id);
- close(inotify_fd);
- close(uevent_fd);
-
- return NULL;
-}
-
-/*****************************************************
- *
- * THESE FUNCTIONS ARE CALLED FROM THE SERVER THREAD
- *
- *****************************************************/
-
-// Called to enable or disable USB mass storage support
-void EnableMassStorage(boolean enable)
-{
- pthread_mutex_lock(&sMutex);
-
- LOG_MOUNT("EnableMassStorage %s\n", (enable ? "true" : "false"));
- gMassStorageEnabled = enable;
- MassStorageStateChanged();
- pthread_mutex_unlock(&sMutex);
- }
-
-// Called to request that the specified mount point be mounted
-void MountMedia(const char* mountPoint)
-{
- MountPoint* mp = sMountPointList;
-
- LOG_MOUNT("MountMedia(%s)\n", mountPoint);
-
- pthread_mutex_lock(&sMutex);
- while (mp)
- {
- if (strcmp(mp->mountPoint, mountPoint) == 0)
- {
- if (mp->state == kUnmountingForEject)
- {
- // handle the case where we try to remount before we actually unmounted
- ClearRetries(mp, kMounted);
- }
-
- // don't attempt to mount if mass storage is active
- if (!MassStorageEnabledForMountPoint(mp))
- RequestMount(mp);
- }
-
- mp = mp->next;
- }
- pthread_mutex_unlock(&sMutex);
- }
-
-// Called to request that the specified mount point be unmounted
-void UnmountMedia(const char* mountPoint)
-{
- MountPoint* mp = sMountPointList;
-
- pthread_mutex_lock(&sMutex);
- while (mp)
- {
- if (strcmp(mp->mountPoint, mountPoint) == 0)
- RequestUnmount(mp, kUnmountingForEject);
-
- mp = mp->next;
- }
- pthread_mutex_unlock(&sMutex);
-}
-
-boolean IsMassStorageEnabled()
-{
- return gMassStorageEnabled;
-}
-
-boolean IsMassStorageConnected()
-{
- return gMassStorageConnected;
-}
-
-/***********************************************
- *
- * THESE FUNCTIONS ARE CALLED ONLY AT STARTUP
- *
- ***********************************************/
-
-void *AddMountPoint(const char* device, const char* mountPoint, const char * driverStorePath, boolean enableUms)
-{
- MountPoint* newMountPoint;
-
- LOG_MOUNT("AddMountPoint device: %s, mountPoint: %s driverStorePath: %s\n", device, mountPoint, driverStorePath);
- // add a new MountPoint to the head of our linked list
- newMountPoint = (MountPoint *)malloc(sizeof(MountPoint));
- newMountPoint->device = device;
- newMountPoint->mountPoint = mountPoint;
- newMountPoint->driverStorePath = driverStorePath;
- newMountPoint->enableUms = enableUms;
- newMountPoint->umsActive = false;
- newMountPoint->state = kUnmounted;
- newMountPoint->retryCount = 0;
-
- // add to linked list
- newMountPoint->next = sMountPointList;
- sMountPointList = newMountPoint;
- return newMountPoint;
-}
-
-int AddAsecToMountPoint(void *Mp, const char *name, const char *backing_file, const char *size,
- const char *mount_point, const char *crypt)
-{
- MountPoint *mp = (MountPoint *) Mp;
- int i;
-
- for (i = 0; i < ASEC_STORES_MAX; i++) {
- if (!mp->asecHandles[i])
- break;
- }
-
- if (i == ASEC_STORES_MAX) {
- LOG_ERROR("Maximum # of ASEC stores exceeded\n");
- return -EINVAL;
- }
-
- if (!(mp->asecHandles[i] = AsecInit(name, mp->mountPoint, backing_file, size, mount_point, crypt)))
- return -1;
-
- return 0;
-}
-static void MountDevices()
-{
- MountPoint* mp = sMountPointList;
- while (mp)
- {
- RequestMount(mp);
- mp = mp->next;
- }
-}
-
-void StartAutoMounter()
-{
- gExcludedPids[0] = getpid();
-
- gMassStorageConnected = ReadMassStorageState();
- LOG_MOUNT(gMassStorageConnected ? "USB online\n" : "USB offline\n");
-
- MountDevices();
- pthread_create(&sAutoMountThread, NULL, AutoMountThread, NULL);
-}
diff --git a/mountd/MODULE_LICENSE_APACHE2 b/mountd/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/mountd/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/mountd/NOTICE b/mountd/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/mountd/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/mountd/ProcessKiller.c b/mountd/ProcessKiller.c
deleted file mode 100644
index e377774..0000000
--- a/mountd/ProcessKiller.c
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * 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.
- */
-
-/*
-** mountd process killer
-*/
-
-#include "mountd.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <pwd.h>
-#include <stdlib.h>
-#include <poll.h>
-#include <sys/stat.h>
-
-
-static boolean ReadSymLink(const char* path, char* link)
-{
- struct stat s;
- int length;
-
- if (lstat(path, &s) < 0)
- return false;
- if ((s.st_mode & S_IFMT) != S_IFLNK)
- return false;
-
- // we have a symlink
- length = readlink(path, link, PATH_MAX - 1);
- if (length <= 0)
- return false;
- link[length] = 0;
- return true;
-}
-
-static boolean PathMatchesMountPoint(const char* path, const char* mountPoint)
-{
- int length = strlen(mountPoint);
- if (length > 1 && strncmp(path, mountPoint, length) == 0)
- {
- // we need to do extra checking if mountPoint does not end in a '/'
- if (mountPoint[length - 1] == '/')
- return true;
- // if mountPoint does not have a trailing slash, we need to make sure
- // there is one in the path to avoid partial matches.
- return (path[length] == 0 || path[length] == '/');
- }
-
- return false;
-}
-
-static void GetProcessName(int pid, char buffer[PATH_MAX])
-{
- int fd;
- sprintf(buffer, "/proc/%d/cmdline", pid);
- fd = open(buffer, O_RDONLY);
- if (fd < 0) {
- strcpy(buffer, "???");
- } else {
- int length = read(fd, buffer, PATH_MAX - 1);
- buffer[length] = 0;
- close(fd);
- }
-}
-
-static boolean CheckFileDescriptorSymLinks(int pid, const char* mountPoint)
-{
- DIR* dir;
- struct dirent* de;
- boolean fileOpen = false;
- char path[PATH_MAX];
- char link[PATH_MAX];
- int parent_length;
-
- // compute path to process's directory of open files
- sprintf(path, "/proc/%d/fd", pid);
- dir = opendir(path);
- if (!dir)
- return false;
-
- // remember length of the path
- parent_length = strlen(path);
- // append a trailing '/'
- path[parent_length++] = '/';
-
- while ((de = readdir(dir)) != 0 && !fileOpen) {
- if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
- continue;
-
- // append the file name, after truncating to parent directory
- path[parent_length] = 0;
- strcat(path, de->d_name);
-
- if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint))
- {
- char name[PATH_MAX];
- GetProcessName(pid, name);
- LOG_ERROR("process %s (%d) has open file %s\n", name, pid, link);
- fileOpen = true;
- }
- }
-
- closedir(dir);
- return fileOpen;
-}
-
-static boolean CheckFileMaps(int pid, const char* mountPoint)
-{
- FILE* file;
- char buffer[PATH_MAX + 100];
- boolean mapOpen = false;
-
- sprintf(buffer, "/proc/%d/maps", pid);
- file = fopen(buffer, "r");
- if (!file)
- return false;
-
- while (!mapOpen && fgets(buffer, sizeof(buffer), file))
- {
- // skip to the path
- const char* path = strchr(buffer, '/');
- if (path && PathMatchesMountPoint(path, mountPoint))
- {
- char name[PATH_MAX];
- GetProcessName(pid, name);
- LOG_ERROR("process %s (%d) has open file map for %s\n", name, pid, path);
- mapOpen = true;
- }
- }
-
- fclose(file);
- return mapOpen;
-}
-
-static boolean CheckSymLink(int pid, const char* mountPoint, const char* name, const char* message)
-{
- char path[PATH_MAX];
- char link[PATH_MAX];
-
- sprintf(path, "/proc/%d/%s", pid, name);
- if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint))
- {
- char name[PATH_MAX];
- GetProcessName(pid, name);
- LOG_ERROR("process %s (%d) has %s in %s\n", name, pid, message, mountPoint);
- return true;
- }
- else
- return false;
-}
-
-static int get_pid(const char* s)
-{
- int result = 0;
- while (*s) {
- if (!isdigit(*s)) return -1;
- result = 10 * result + (*s++ - '0');
- }
- return result;
-}
-
-// hunt down and kill processes that have files open on the given mount point
-void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *excluded, int num_excluded)
-{
- DIR* dir;
- struct dirent* de;
-
- LOG_ERROR("KillProcessesWithOpenFiles %s\n", mountPoint);
- dir = opendir("/proc");
- if (!dir) return;
-
- while ((de = readdir(dir)) != 0)
- {
- boolean killed = false;
- // does the name look like a process ID?
- int pid = get_pid(de->d_name);
- if (pid == -1) continue;
-
- if (CheckFileDescriptorSymLinks(pid, mountPoint) // check for open files
- || CheckFileMaps(pid, mountPoint) // check for mmap()
- || CheckSymLink(pid, mountPoint, "cwd", "working directory") // check working directory
- || CheckSymLink(pid, mountPoint, "root", "chroot") // check for chroot()
- || CheckSymLink(pid, mountPoint, "exe", "executable path") // check executable path
- )
- {
- int i;
- boolean hit = false;
-
- for (i = 0; i < num_excluded; i++) {
- if (pid == excluded[i]) {
- LOG_ERROR("I just need a little more TIME captain!\n");
- hit = true;
- break;
- }
- }
-
- if (!hit) {
- LOG_ERROR("Killing process %d\n", pid);
- kill(pid, (sigkill ? SIGKILL : SIGTERM));
- }
- }
- }
-
- closedir(dir);
-}
diff --git a/mountd/Server.c b/mountd/Server.c
deleted file mode 100644
index 64459bd..0000000
--- a/mountd/Server.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * 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.
- */
-
-/*
-** mountd server support
-*/
-
-#include "mountd.h"
-#include "ASEC.h"
-
-#include <cutils/properties.h>
-#include <cutils/sockets.h>
-
-#include <pthread.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/socket.h>
-
-#include <private/android_filesystem_config.h>
-
-
-// current client file descriptor
-static int sFD = -1;
-
-// to synchronize writing to client
-static pthread_mutex_t sWriteMutex = PTHREAD_MUTEX_INITIALIZER;
-
-// path for media that failed to mount before the runtime is connected
-static char* sDeferredUnmountableMediaPath = NULL;
-
-// last asec msg before the runtime was connected
-static char* sAsecDeferredMessage = NULL;
-static char* sAsecDeferredArgument = NULL;
-
-static int Write(const char* message)
-{
- int result = -1;
-
- pthread_mutex_lock(&sWriteMutex);
-
- LOG_SERVER("Write: %s\n", message);
- if (sFD >= 0)
- result = write(sFD, message, strlen(message) + 1);
-
- pthread_mutex_unlock(&sWriteMutex);
-
- return result;
-}
-
-static int Write2(const char* message, const char* data)
-{
- int result = -1;
-
- char* buffer = (char *)alloca(strlen(message) + strlen(data) + 1);
- if (!buffer)
- {
- LOG_ERROR("alloca failed in Write2\n");
- return -1;
- }
-
- strcpy(buffer, message);
- strcat(buffer, data);
- return Write(buffer);
-}
-
-static void SendStatus()
-{
- Write(IsMassStorageConnected() ? MOUNTD_UMS_CONNECTED : MOUNTD_UMS_DISCONNECTED);
- Write(IsMassStorageEnabled() ? MOUNTD_UMS_ENABLED : MOUNTD_UMS_DISABLED);
-}
-
-static void DoCommand(const char* command)
-{
- LOG_SERVER("DoCommand %s\n", command);
-
- if (strcmp(command, MOUNTD_ENABLE_UMS) == 0)
- {
- EnableMassStorage(true);
- Write(MOUNTD_UMS_ENABLED);
- }
- else if (strcmp(command, MOUNTD_DISABLE_UMS) == 0)
- {
- EnableMassStorage(false);
- Write(MOUNTD_UMS_DISABLED);
- }
- else if (strcmp(command, MOUNTD_SEND_STATUS) == 0)
- {
- SendStatus();
- }
- else if (strncmp(command, MOUNTD_MOUNT_MEDIA, strlen(MOUNTD_MOUNT_MEDIA)) == 0)
- {
- const char* path = command + strlen(MOUNTD_MOUNT_MEDIA);
- MountMedia(path);
- }
- else if (strncmp(command, MOUNTD_EJECT_MEDIA, strlen(MOUNTD_EJECT_MEDIA)) == 0)
- {
- const char* path = command + strlen(MOUNTD_EJECT_MEDIA);
- UnmountMedia(path);
- }
- else if (strncmp(command, ASEC_CMD_ENABLE, strlen(ASEC_CMD_ENABLE)) == 0) {
- LOG_ASEC("Got ASEC_CMD_ENABLE\n");
- // XXX: SAN: Impliment
- }
- else if (strncmp(command, ASEC_CMD_DISABLE, strlen(ASEC_CMD_DISABLE)) == 0) {
- LOG_ASEC("Got ASEC_CMD_DISABLE\n");
- // XXX: SAN: Impliment
- }
- else if (strncmp(command, ASEC_CMD_SEND_STATUS, strlen(ASEC_CMD_SEND_STATUS)) == 0) {
- LOG_ASEC("Got ASEC_CMD_SEND_STATUS\n");
- // XXX: SAN: Impliment
- }
- else
- LOGE("unknown command %s\n", command);
-}
-
-int RunServer()
-{
- int socket = android_get_control_socket(MOUNTD_SOCKET);
- if (socket < 0) {
- LOGE("Obtaining file descriptor for socket '%s' failed: %s",
- MOUNTD_SOCKET, strerror(errno));
- return -1;
- }
-
- if (listen(socket, 4) < 0) {
- LOGE("Unable to listen on file descriptor '%d' for socket '%s': %s",
- socket, MOUNTD_SOCKET, strerror(errno));
- return -1;
- }
-
- while (1)
- {
- struct sockaddr addr;
- socklen_t alen;
- struct ucred cred;
- socklen_t size;
-
- alen = sizeof(addr);
- sFD = accept(socket, &addr, &alen);
- if (sFD < 0)
- continue;
-
- if (sDeferredUnmountableMediaPath) {
- NotifyMediaState(sDeferredUnmountableMediaPath, MEDIA_UNMOUNTABLE, false);
- free(sDeferredUnmountableMediaPath);
- sDeferredUnmountableMediaPath = NULL;
- }
-
- if (sAsecDeferredMessage) {
-
- if (Write2(sAsecDeferredMessage, sAsecDeferredArgument) < 0)
- LOG_ERROR("Failed to deliver deferred ASEC msg to framework\n");
- free(sAsecDeferredMessage);
- free(sAsecDeferredArgument);
- sAsecDeferredMessage = sAsecDeferredArgument = NULL;
- }
-
- while (1)
- {
- char buffer[101];
- int result = read(sFD, buffer, sizeof(buffer) - 1);
- if (result > 0)
- {
- int start = 0;
- int i;
- // command should be zero terminated, but just in case
- buffer[result] = 0;
- for (i = 0; i < result; i++)
- {
- if (buffer[i] == 0)
- {
- DoCommand(buffer + start);
- start = i + 1;
- }
- }
- }
- else
- {
- close(sFD);
- sFD = -1;
- break;
- }
- }
- }
-
- // should never get here
- return 0;
-}
-
-void SendMassStorageConnected(boolean connected)
-{
- Write(connected ? MOUNTD_UMS_CONNECTED : MOUNTD_UMS_DISCONNECTED);
-}
-
-void SendUnmountRequest(const char* path)
-{
- Write2(MOUNTD_REQUEST_EJECT, path);
-}
-
-void NotifyAsecState(AsecState state, const char *argument)
-{
- const char *event = NULL;
- const char *status = NULL;
- boolean deferr = true;;
-
- switch (state) {
- case ASEC_DISABLED:
- event = ASEC_EVENT_DISABLED;
- status = ASEC_STATUS_DISABLED;
- break;
- case ASEC_AVAILABLE:
- event = ASEC_EVENT_AVAILABLE;
- status = ASEC_STATUS_AVAILABLE;
- break;
- case ASEC_BUSY:
- event = ASEC_EVENT_BUSY;
- status = ASEC_STATUS_BUSY;
- deferr = false;
- break;
- case ASEC_FAILED_INTERR:
- event = ASEC_EVENT_FAILED_INTERR;
- status = ASEC_STATUS_FAILED_INTERR;
- break;
- case ASEC_FAILED_NOMEDIA:
- event = ASEC_EVENT_FAILED_NOMEDIA;
- status = ASEC_STATUS_FAILED_NOMEDIA;
- break;
- case ASEC_FAILED_BADMEDIA:
- event = ASEC_EVENT_FAILED_BADMEDIA;
- status = ASEC_STATUS_FAILED_BADMEDIA;
- break;
- case ASEC_FAILED_BADKEY:
- event = ASEC_EVENT_FAILED_BADKEY;
- status = ASEC_STATUS_FAILED_BADKEY;
- break;
- default:
- LOG_ERROR("unknown AsecState %d in NotifyAsecState\n", state);
- return;
- }
-
- property_set(ASEC_STATUS, status);
-
- int result = Write2(event, argument);
- if ((result < 0) && deferr) {
- if (sAsecDeferredMessage)
- free(sAsecDeferredMessage);
- sAsecDeferredMessage = strdup(event);
- if (sAsecDeferredArgument)
- free(sAsecDeferredArgument);
- sAsecDeferredArgument = strdup(argument);
- LOG_ASEC("Deferring event '%s' arg '%s' until framework connects\n", event, argument);
- }
-}
-
-void NotifyMediaState(const char* path, MediaState state, boolean readOnly)
-{
- const char* event = NULL;
- const char* propertyValue = NULL;
-
- switch (state) {
- case MEDIA_REMOVED:
- event = MOUNTD_MEDIA_REMOVED;
- propertyValue = EXTERNAL_STORAGE_REMOVED;
- break;
- case MEDIA_UNMOUNTED:
- event = MOUNTD_MEDIA_UNMOUNTED;
- propertyValue = EXTERNAL_STORAGE_UNMOUNTED;
- break;
- case MEDIA_MOUNTED:
- event = (readOnly ? MOUNTD_MEDIA_MOUNTED_READ_ONLY : MOUNTD_MEDIA_MOUNTED);
- propertyValue = (readOnly ? EXTERNAL_STORAGE_MOUNTED_READ_ONLY : EXTERNAL_STORAGE_MOUNTED);
- break;
- case MEDIA_SHARED:
- event = MOUNTD_MEDIA_SHARED;
- propertyValue = EXTERNAL_STORAGE_SHARED;
- break;
- case MEDIA_BAD_REMOVAL:
- event = MOUNTD_MEDIA_BAD_REMOVAL;
- propertyValue = EXTERNAL_STORAGE_BAD_REMOVAL;
- break;
- case MEDIA_UNMOUNTABLE:
- event = MOUNTD_MEDIA_UNMOUNTABLE;
- propertyValue = EXTERNAL_STORAGE_UNMOUNTABLE;
- break;
- default:
- LOG_ERROR("unknown MediaState %d in NotifyMediaState\n", state);
- return;
- }
-
- property_set(EXTERNAL_STORAGE_STATE, propertyValue);
- int result = Write2(event, path);
- if (result < 0 && state == MEDIA_UNMOUNTABLE) {
-
- // if we cannot communicate with the runtime, defer this message until the runtime is available
- sDeferredUnmountableMediaPath = strdup(path);
- }
-}
diff --git a/mountd/logwrapper.c b/mountd/logwrapper.c
deleted file mode 100644
index 69606ab..0000000
--- a/mountd/logwrapper.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * 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.
- */
-
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include "private/android_filesystem_config.h"
-#include "cutils/log.h"
-
-int parent(const char *tag, int parent_read) {
- int status;
- char buffer[4096];
-
- int a = 0; // start index of unprocessed data
- int b = 0; // end index of unprocessed data
- int sz;
- while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
-
- sz += b;
- // Log one line at a time
- for (b = 0; b < sz; b++) {
- if (buffer[b] == '\r') {
- buffer[b] = '\0';
- } else if (buffer[b] == '\n') {
- buffer[b] = '\0';
- LOG(LOG_INFO, tag, &buffer[a]);
- a = b + 1;
- }
- }
-
- if (a == 0 && b == sizeof(buffer) - 1) {
- // buffer is full, flush
- buffer[b] = '\0';
- LOG(LOG_INFO, tag, &buffer[a]);
- b = 0;
- } else if (a != b) {
- // Keep left-overs
- b -= a;
- memmove(buffer, &buffer[a], b);
- a = 0;
- } else {
- a = 0;
- b = 0;
- }
-
- }
- // Flush remaining data
- if (a != b) {
- buffer[b] = '\0';
- LOG(LOG_INFO, tag, &buffer[a]);
- }
- status = 0xAAAA;
- if (wait(&status) != -1) { // Wait for child
- if (WIFEXITED(status)) {
- LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
- WEXITSTATUS(status));
- return WEXITSTATUS(status);
- } else if (WIFSIGNALED(status))
- LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
- WTERMSIG(status));
- else if (WIFSTOPPED(status))
- LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
- WSTOPSIG(status));
- } else
- LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
- strerror(errno), errno);
- return -EAGAIN;
-}
-
-void child(int argc, char* argv[]) {
- // create null terminated argv_child array
- char* argv_child[argc + 1];
- memcpy(argv_child, argv, argc * sizeof(char *));
- argv_child[argc] = NULL;
-
- // XXX: PROTECT FROM VIKING KILLER
- if (execvp(argv_child[0], argv_child)) {
- LOG(LOG_ERROR, "logwrapper",
- "executing %s failed: %s\n", argv_child[0], strerror(errno));
- exit(-1);
- }
-}
-
-int logwrap(int argc, char* argv[])
-{
- pid_t pid;
-
- int parent_ptty;
- int child_ptty;
- char *child_devname = NULL;
-
- /* Use ptty instead of socketpair so that STDOUT is not buffered */
- parent_ptty = open("/dev/ptmx", O_RDWR);
- if (parent_ptty < 0) {
- LOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty\n");
- return -errno;
- }
-
- if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
- ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
- LOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx\n");
- return -1;
- }
-
- pid = fork();
- if (pid < 0) {
- LOG(LOG_ERROR, "logwrapper", "Failed to fork\n");
- return -errno;
- } else if (pid == 0) {
- child_ptty = open(child_devname, O_RDWR);
- if (child_ptty < 0) {
- LOG(LOG_ERROR, "logwrapper", "Problem with child ptty\n");
- return -errno;
- }
-
- // redirect stdout and stderr
- close(parent_ptty);
- dup2(child_ptty, 1);
- dup2(child_ptty, 2);
- close(child_ptty);
-
- child(argc, argv);
- } else {
- // switch user and group to "log"
- // this may fail if we are not root,
- // but in that case switching user/group is unnecessary
-
- // setgid(AID_LOG);
- // setuid(AID_LOG);
-
- return parent(argv[0], parent_ptty);
- }
-
- return 0;
-}
diff --git a/mountd/mountd.c b/mountd/mountd.c
deleted file mode 100644
index 27ec8de..0000000
--- a/mountd/mountd.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * 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.
- */
-
-/*
-** mountd main program
-*/
-
-#include "mountd.h"
-
-#include <cutils/config_utils.h>
-#include <cutils/cpu_info.h>
-#include <cutils/properties.h>
-
-#include <sys/mount.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <linux/capability.h>
-#include <linux/prctl.h>
-
-#include <private/android_filesystem_config.h>
-
-#ifdef MOUNTD_LOG
-FILE* logFile;
-#endif
-
-struct asec_cfg {
- const char *name;
- const char *backing_file;
- const char *size;
- const char *mount_point;
- const char *crypt;
-};
-
-static int ProcessAsecData(cnode *node, struct asec_cfg *stores, int idx)
-{
- cnode *child = node->first_child;
- const char *name = NULL;
- const char *file = NULL;
- const char *size = NULL;
- const char *mp = NULL;
- const char *crypt = NULL;
-
- LOG_ASEC("ProcessAsecData(%s, %p, %d)\n", node->name, stores, idx);
-
- while (child) {
- if (!strcmp(child->name, "name"))
- name = child->value;
- else if (!strcmp(child->name, "backing_file"))
- file = child->value;
- else if (!strcmp(child->name, "size"))
- size = child->value;
- else if (!strcmp(child->name, "mount_point"))
- mp = child->value;
- else if (!strcmp(child->name, "crypt"))
- crypt = child->value;
- child = child->next;
- }
-
- if (!name || !file || !size || !mp || !crypt) {
- LOG_ERROR("Missing required token from config. Skipping ASEC volume\n");
- return -1;
- } else if (idx == ASEC_STORES_MAX) {
- LOG_ERROR("Maximum # of ASEC stores already defined\n");
- return -1;
- }
-
- stores[idx].name = name;
- stores[idx].backing_file = file;
- stores[idx].size = size;
- stores[idx].mount_point = mp;
- stores[idx].crypt = crypt;
- return ++idx;
-}
-
-static void ReadConfigFile(const char* path)
-{
- cnode* root = config_node("", "");
- cnode* node;
-
- config_load_file(root, path);
- node = root->first_child;
-
- while (node)
- {
- if (strcmp(node->name, "mount") == 0)
- {
- const char* block_device = NULL;
- const char* mount_point = NULL;
- const char* driver_store_path = NULL;
- boolean enable_ums = false;
- cnode* child = node->first_child;
- struct asec_cfg asec_stores[ASEC_STORES_MAX];
- int asec_idx = 0;
-
- memset(asec_stores, 0, sizeof(asec_stores));
-
- while (child)
- {
- const char* name = child->name;
- const char* value = child->value;
-
- if (!strncmp(name, "asec_", 5)) {
- int rc = ProcessAsecData(child, asec_stores, asec_idx);
- if (rc < 0) {
- LOG_ERROR("Error processing ASEC cfg data\n");
- } else
- asec_idx = rc;
- } else if (strcmp(name, "block_device") == 0)
- block_device = value;
- else if (strcmp(name, "mount_point") == 0)
- mount_point = value;
- else if (strcmp(name, "driver_store_path") == 0)
- driver_store_path = value;
- else if (strcmp(name, "enable_ums") == 0 &&
- strcmp(value, "true") == 0)
- enable_ums = true;
-
- child = child->next;
- }
-
- // mount point and removable fields are optional
- if (block_device && mount_point)
- {
- void *mp = AddMountPoint(block_device, mount_point, driver_store_path, enable_ums);
- int i;
-
- for (i = 0; i < asec_idx; i++) {
- AddAsecToMountPoint(mp, asec_stores[i].name, asec_stores[i].backing_file,
- asec_stores[i].size, asec_stores[i].mount_point,
- asec_stores[i].crypt);
- }
- }
- }
-
- node = node->next;
- }
-}
-
-int main(int argc, char* argv[])
-{
- const char* configPath = "/system/etc/mountd.conf";
- int i;
-
- for (i = 1; i < argc; i++)
- {
- const char* arg = argv[i];
-
- if (strcmp(arg, "-f") == 0)
- {
- if (i < argc - 1)
- configPath = argv[++i];
- }
- }
-
- ReadConfigFile(configPath);
- StartAutoMounter();
- return RunServer();
-}
diff --git a/mountd/mountd.h b/mountd/mountd.h
deleted file mode 100644
index c4bc91d..0000000
--- a/mountd/mountd.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * 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 MOUNTD_H__
-#define MOUNTD_H__
-
-#define LOG_TAG "mountd"
-#include "cutils/log.h"
-
-#include "ASEC.h"
-
-typedef int boolean;
-enum {
- false = 0,
- true = 1
-};
-
-#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
-
-// Set this for logging error messages
-#define ENABLE_LOG_ERROR
-
-// set this to log automounter events
-#define ENABLE_LOG_MOUNT
-
-// set this to log server events
-//#define ENABLE_LOG_SERVER
-
-// set this to log ASEC events
-#define ENABLE_LOG_ASEC
-
-#ifdef ENABLE_LOG_ERROR
-#define LOG_ERROR(fmt, args...) \
- { LOGE(fmt , ## args); }
-#else
-#define LOG_ERROR(fmt, args...) \
- do { } while (0)
-#endif /* ENABLE_LOG_ERROR */
-
-#ifdef ENABLE_LOG_MOUNT
-#define LOG_MOUNT(fmt, args...) \
- { LOGD(fmt , ## args); }
-#else
-#define LOG_MOUNT(fmt, args...) \
- do { } while (0)
-#endif /* ENABLE_LOG_MOUNT */
-
-#ifdef ENABLE_LOG_SERVER
-#define LOG_SERVER(fmt, args...) \
- { LOGD(fmt , ## args); }
-#else
-#define LOG_SERVER(fmt, args...) \
- do { } while (0)
-#endif /* ENABLE_LOG_SERVER */
-
-#ifdef ENABLE_LOG_ASEC
-#define LOG_ASEC(fmt, args...) \
- { LOGD(fmt , ## args); }
-#else
-#define LOG_ASEC(fmt, args...) \
- do { } while (0)
-#endif /* ENABLE_LOG_ASEC */
-
-
-typedef enum MediaState {
- // no media in SD card slot
- MEDIA_REMOVED,
-
- // media in SD card slot, but not mounted
- MEDIA_UNMOUNTED,
-
- // media in SD card slot and mounted at its mount point
- MEDIA_MOUNTED,
-
- // media in SD card slot, unmounted, and shared as a mass storage device
- MEDIA_SHARED,
-
- // media was removed from SD card slot, but mount point was not unmounted
- // this state is cleared after the mount point is unmounted
- MEDIA_BAD_REMOVAL,
-
- // media in SD card slot could not be mounted (corrupt file system?)
- MEDIA_UNMOUNTABLE,
-} MediaState;
-
-// socket name for connecting to mountd
-#define MOUNTD_SOCKET "mountd"
-
-// mountd commands
-// these must match the corresponding strings in //device/java/android/android/os/UsbListener.java
-#define MOUNTD_ENABLE_UMS "enable_ums"
-#define MOUNTD_DISABLE_UMS "disable_ums"
-#define MOUNTD_SEND_STATUS "send_status"
-
-// these commands should contain a mount point following the colon
-#define MOUNTD_MOUNT_MEDIA "mount_media:"
-#define MOUNTD_EJECT_MEDIA "eject_media:"
-
-// mountd events
-// these must match the corresponding strings in //device/java/android/android/os/UsbListener.java
-#define MOUNTD_UMS_ENABLED "ums_enabled"
-#define MOUNTD_UMS_DISABLED "ums_disabled"
-#define MOUNTD_UMS_CONNECTED "ums_connected"
-#define MOUNTD_UMS_DISCONNECTED "ums_disconnected"
-
-// these events correspond to the states in the MediaState enum.
-// a path to the mount point follows the colon.
-#define MOUNTD_MEDIA_REMOVED "media_removed:"
-#define MOUNTD_MEDIA_UNMOUNTED "media_unmounted:"
-#define MOUNTD_MEDIA_MOUNTED "media_mounted:"
-#define MOUNTD_MEDIA_MOUNTED_READ_ONLY "media_mounted_ro:"
-#define MOUNTD_MEDIA_SHARED "media_shared:"
-#define MOUNTD_MEDIA_BAD_REMOVAL "media_bad_removal:"
-#define MOUNTD_MEDIA_UNMOUNTABLE "media_unmountable:"
-
-// this event sent to request unmount for media mount point
-#define MOUNTD_REQUEST_EJECT "request_eject:"
-
-// system properties
-// these must match the corresponding strings in //device/java/android/android/os/Environment.java
-#define EXTERNAL_STORAGE_STATE "EXTERNAL_STORAGE_STATE"
-#define EXTERNAL_STORAGE_REMOVED "removed"
-#define EXTERNAL_STORAGE_UNMOUNTED "unmounted"
-#define EXTERNAL_STORAGE_MOUNTED "mounted"
-#define EXTERNAL_STORAGE_MOUNTED_READ_ONLY "mounted_ro"
-#define EXTERNAL_STORAGE_SHARED "shared"
-#define EXTERNAL_STORAGE_BAD_REMOVAL "bad_removal"
-#define EXTERNAL_STORAGE_UNMOUNTABLE "unmountable"
-
-// AutoMount.c
-
-boolean IsMassStorageEnabled();
-boolean IsMassStorageConnected();
-
-void MountMedia(const char* mountPoint);
-void UnmountMedia(const char* mountPoint);
-void EnableMassStorage(boolean enable);
-
-// call this before StartAutoMounter() to add a mount point to monitor
-void *AddMountPoint(const char* device, const char* mountPoint, const char* driverStorePath,
- boolean enableUms);
-
-int AddAsecToMountPoint(void *Mp, const char *name, const char *backing_file,
- const char *size, const char *mount_point, const char *crypt);
-
-// start automounter thread
-void StartAutoMounter();
-
-// check /proc/mounts for mounted file systems, and notify mount or unmount for any that are in our automount list
-void NotifyExistingMounts();
-
-
-// ASEC.c
-
-void *AsecInit(const char *Name, const char *SrcPath, const char *BackingFile,
- const char *Size, const char *DstPath, const char *Crypt);
-int AsecStart(void *Handle);
-int AsecStop(void *Handle);
-void AsecDeinit(void *Handle);
-boolean AsecIsStarted(void *Handle);
-const char *AsecMountPoint(void *Handle);
-
-// ProcessKiller.c
-
-void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, pid_t *excluded, int num_excluded);
-
-// logwrapper.c
-int logwrap(int argc, char* argv[]);
-
-// Server.c
-
-int RunServer();
-void SendMassStorageConnected(boolean connected);
-void SendUnmountRequest(const char* path);
-void NotifyMediaState(const char* path, MediaState state, boolean readOnly);
-void NotifyAsecState(AsecState state, const char *argument);
-#endif // MOUNTD_H__
diff --git a/nexus/Android.mk b/nexus/Android.mk
new file mode 100644
index 0000000..cd477ef
--- /dev/null
+++ b/nexus/Android.mk
@@ -0,0 +1,64 @@
+BUILD_NEXUS := false
+ifeq ($(BUILD_NEXUS),true)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ main.cpp \
+ NetworkManager.cpp \
+ CommandListener.cpp \
+ Controller.cpp \
+ WifiController.cpp \
+ LoopController.cpp \
+ NexusCommand.cpp \
+ TiwlanWifiController.cpp \
+ Supplicant.cpp \
+ SupplicantEvent.cpp \
+ SupplicantListener.cpp \
+ VpnController.cpp \
+ ScanResult.cpp \
+ WifiScanner.cpp \
+ WifiNetwork.cpp \
+ OpenVpnController.cpp \
+ InterfaceConfig.cpp \
+ PropertyManager.cpp \
+ SupplicantState.cpp \
+ SupplicantEventFactory.cpp \
+ SupplicantConnectedEvent.cpp \
+ SupplicantAssociatingEvent.cpp \
+ SupplicantAssociatedEvent.cpp \
+ SupplicantStateChangeEvent.cpp \
+ SupplicantScanResultsEvent.cpp \
+ SupplicantConnectionTimeoutEvent.cpp \
+ SupplicantDisconnectedEvent.cpp \
+ SupplicantStatus.cpp \
+ TiwlanEventListener.cpp \
+ DhcpClient.cpp DhcpListener.cpp \
+
+LOCAL_MODULE:= nexus
+
+LOCAL_C_INCLUDES := $(KERNEL_HEADERS) -I../../../frameworks/base/include/
+
+LOCAL_CFLAGS :=
+
+LOCAL_SHARED_LIBRARIES := libsysutils libwpa_client
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= \
+ nexctl.c \
+
+LOCAL_MODULE:= nexctl
+
+LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
+
+LOCAL_CFLAGS :=
+
+LOCAL_SHARED_LIBRARIES := libcutils
+
+include $(BUILD_EXECUTABLE)
+
+endif # ifeq ($(BUILD_NEXUS),true)
diff --git a/nexus/CommandListener.cpp b/nexus/CommandListener.cpp
new file mode 100644
index 0000000..8eb378b
--- /dev/null
+++ b/nexus/CommandListener.cpp
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#define LOG_TAG "CommandListener"
+#include <cutils/log.h>
+
+#include <sysutils/SocketClient.h>
+
+#include "CommandListener.h"
+#include "Controller.h"
+#include "Property.h"
+#include "NetworkManager.h"
+#include "WifiController.h"
+#include "VpnController.h"
+#include "ErrorCode.h"
+
+CommandListener::CommandListener() :
+ FrameworkListener("nexus") {
+ registerCmd(new WifiScanResultsCmd());
+ registerCmd(new WifiListNetworksCmd());
+ registerCmd(new WifiCreateNetworkCmd());
+ registerCmd(new WifiRemoveNetworkCmd());
+
+ registerCmd(new GetCmd());
+ registerCmd(new SetCmd());
+ registerCmd(new ListCmd());
+}
+
+/* -------------
+ * Wifi Commands
+ * ------------ */
+
+CommandListener::WifiCreateNetworkCmd::WifiCreateNetworkCmd() :
+ NexusCommand("wifi_create_network") {
+}
+
+int CommandListener::WifiCreateNetworkCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ NetworkManager *nm = NetworkManager::Instance();
+ WifiController *wc = (WifiController *) nm->findController("WIFI");
+ WifiNetwork *wn;
+
+ if (!(wn = wc->createNetwork()))
+ cli->sendMsg(ErrorCode::OperationFailed, "Failed to create network", true);
+ else {
+ char tmp[128];
+ sprintf(tmp, "Created network id %d.", wn->getNetworkId());
+ cli->sendMsg(ErrorCode::CommandOkay, tmp, false);
+ }
+ return 0;
+}
+
+CommandListener::WifiRemoveNetworkCmd::WifiRemoveNetworkCmd() :
+ NexusCommand("wifi_remove_network") {
+}
+
+int CommandListener::WifiRemoveNetworkCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ NetworkManager *nm = NetworkManager::Instance();
+ WifiController *wc = (WifiController *) nm->findController("WIFI");
+
+ if (wc->removeNetwork(atoi(argv[1])))
+ cli->sendMsg(ErrorCode::OperationFailed, "Failed to remove network", true);
+ else {
+ cli->sendMsg(ErrorCode::CommandOkay, "Network removed.", false);
+ }
+ return 0;
+}
+
+CommandListener::WifiScanResultsCmd::WifiScanResultsCmd() :
+ NexusCommand("wifi_scan_results") {
+}
+
+int CommandListener::WifiScanResultsCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ NetworkManager *nm = NetworkManager::Instance();
+ WifiController *wc = (WifiController *) nm->findController("WIFI");
+
+ ScanResultCollection *src = wc->createScanResults();
+ ScanResultCollection::iterator it;
+ char buffer[256];
+
+ for(it = src->begin(); it != src->end(); ++it) {
+ sprintf(buffer, "%s:%u:%d:%s:%s",
+ (*it)->getBssid(), (*it)->getFreq(), (*it)->getLevel(),
+ (*it)->getFlags(), (*it)->getSsid());
+ cli->sendMsg(ErrorCode::WifiScanResult, buffer, false);
+ delete (*it);
+ it = src->erase(it);
+ }
+
+ delete src;
+ cli->sendMsg(ErrorCode::CommandOkay, "Scan results complete.", false);
+ return 0;
+}
+
+CommandListener::WifiListNetworksCmd::WifiListNetworksCmd() :
+ NexusCommand("wifi_list_networks") {
+}
+
+int CommandListener::WifiListNetworksCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ NetworkManager *nm = NetworkManager::Instance();
+ WifiController *wc = (WifiController *) nm->findController("WIFI");
+
+ WifiNetworkCollection *src = wc->createNetworkList();
+ WifiNetworkCollection::iterator it;
+ char buffer[256];
+
+ for(it = src->begin(); it != src->end(); ++it) {
+ sprintf(buffer, "%d:%s", (*it)->getNetworkId(), (*it)->getSsid());
+ cli->sendMsg(ErrorCode::WifiNetworkList, buffer, false);
+ delete (*it);
+ }
+
+ delete src;
+ cli->sendMsg(ErrorCode::CommandOkay, "Network listing complete.", false);
+ return 0;
+}
+
+/* ------------
+ * Vpn Commands
+ * ------------ */
+
+/* ----------------
+ * Generic Commands
+ * ---------------- */
+CommandListener::GetCmd::GetCmd() :
+ NexusCommand("get") {
+}
+
+int CommandListener::GetCmd::runCommand(SocketClient *cli, int argc, char **argv) {
+ char val[Property::ValueMaxSize];
+
+ if (!NetworkManager::Instance()->getPropMngr()->get(argv[1],
+ val,
+ sizeof(val))) {
+ goto out_inval;
+ }
+
+ char *tmp;
+ asprintf(&tmp, "%s %s", argv[1], val);
+ cli->sendMsg(ErrorCode::PropertyRead, tmp, false);
+ free(tmp);
+
+ cli->sendMsg(ErrorCode::CommandOkay, "Property read.", false);
+ return 0;
+out_inval:
+ errno = EINVAL;
+ cli->sendMsg(ErrorCode::CommandParameterError, "Failed to read property.", true);
+ return 0;
+}
+
+CommandListener::SetCmd::SetCmd() :
+ NexusCommand("set") {
+}
+
+int CommandListener::SetCmd::runCommand(SocketClient *cli, int argc,
+ char **argv) {
+ if (NetworkManager::Instance()->getPropMngr()->set(argv[1], argv[2]))
+ goto out_inval;
+
+ cli->sendMsg(ErrorCode::CommandOkay, "Property set.", false);
+ return 0;
+
+out_inval:
+ errno = EINVAL;
+ cli->sendMsg(ErrorCode::CommandParameterError, "Failed to set property.", true);
+ return 0;
+}
+
+CommandListener::ListCmd::ListCmd() :
+ NexusCommand("list") {
+}
+
+int CommandListener::ListCmd::runCommand(SocketClient *cli, int argc, char **argv) {
+ android::List<char *> *pc;
+
+ if (!(pc = NetworkManager::Instance()->getPropMngr()->createPropertyList())) {
+ errno = ENODATA;
+ cli->sendMsg(ErrorCode::CommandParameterError, "Failed to list properties.", true);
+ return 0;
+ }
+
+ android::List<char *>::iterator it;
+
+ for (it = pc->begin(); it != pc->end(); ++it) {
+ char p_v[Property::ValueMaxSize];
+
+ if (!NetworkManager::Instance()->getPropMngr()->get((*it),
+ p_v,
+ sizeof(p_v))) {
+ LOGW("Failed to get %s (%s)", (*it), strerror(errno));
+ }
+
+ char *buf;
+ if (asprintf(&buf, "%s %s", (*it), p_v) < 0) {
+ LOGE("Failed to allocate memory");
+ free((*it));
+ continue;
+ }
+ cli->sendMsg(ErrorCode::PropertyList, buf, false);
+ free(buf);
+
+ free((*it));
+ }
+
+ delete pc;
+
+ cli->sendMsg(ErrorCode::CommandOkay, "Properties list complete.", false);
+ return 0;
+}
diff --git a/nexus/CommandListener.h b/nexus/CommandListener.h
new file mode 100644
index 0000000..30c6dc0
--- /dev/null
+++ b/nexus/CommandListener.h
@@ -0,0 +1,87 @@
+/*
+ * 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 _COMMANDLISTENER_H__
+#define _COMMANDLISTENER_H__
+
+#include <sysutils/FrameworkListener.h>
+#include "NexusCommand.h"
+
+class CommandListener : public FrameworkListener {
+public:
+ CommandListener();
+ virtual ~CommandListener() {}
+
+private:
+
+ class WifiScanCmd : public NexusCommand {
+ public:
+ WifiScanCmd();
+ virtual ~WifiScanCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+ class WifiScanResultsCmd : public NexusCommand {
+ public:
+ WifiScanResultsCmd();
+ virtual ~WifiScanResultsCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+ class WifiCreateNetworkCmd : public NexusCommand {
+ public:
+ WifiCreateNetworkCmd();
+ virtual ~WifiCreateNetworkCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+ class WifiRemoveNetworkCmd : public NexusCommand {
+ public:
+ WifiRemoveNetworkCmd();
+ virtual ~WifiRemoveNetworkCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+ class WifiListNetworksCmd : public NexusCommand {
+ public:
+ WifiListNetworksCmd();
+ virtual ~WifiListNetworksCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+ class SetCmd : public NexusCommand {
+ public:
+ SetCmd();
+ virtual ~SetCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+ class GetCmd : public NexusCommand {
+ public:
+ GetCmd();
+ virtual ~GetCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+ class ListCmd : public NexusCommand {
+ public:
+ ListCmd();
+ virtual ~ListCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+};
+
+#endif
diff --git a/nexus/Controller.cpp b/nexus/Controller.cpp
new file mode 100644
index 0000000..17fb519
--- /dev/null
+++ b/nexus/Controller.cpp
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define LOG_TAG "Controller"
+
+#include <cutils/log.h>
+
+#include "Controller.h"
+
+extern "C" int init_module(void *, unsigned int, const char *);
+extern "C" int delete_module(const char *, unsigned int);
+
+Controller::Controller(const char *name, PropertyManager *propMngr,
+ IControllerHandler *handlers) {
+ mPropMngr = propMngr;
+ mName = strdup(name);
+ mHandlers = handlers;
+ mBoundInterface = NULL;
+}
+
+Controller::~Controller() {
+ if (mBoundInterface)
+ free(mBoundInterface);
+ if (mName)
+ free(mName);
+}
+
+int Controller::start() {
+ return 0;
+}
+
+int Controller::stop() {
+ return 0;
+}
+
+int Controller::set(const char *name, const char *value) {
+ errno = ENOENT;
+ return -1;
+}
+
+const char *Controller::get(const char *name, char *buffer, size_t maxsize) {
+ errno = ENOENT;
+ return NULL;
+}
+
+int Controller::loadKernelModule(char *modpath, const char *args) {
+ void *module;
+ unsigned int size;
+
+ module = loadFile(modpath, &size);
+ if (!module) {
+ errno = -EIO;
+ return -1;
+ }
+
+ int rc = init_module(module, size, args);
+ free (module);
+ return rc;
+}
+
+int Controller::unloadKernelModule(const char *modtag) {
+ int rc = -1;
+ int retries = 10;
+
+ while (retries--) {
+ rc = delete_module(modtag, O_NONBLOCK | O_EXCL);
+ if (rc < 0 && errno == EAGAIN)
+ usleep(1000*500);
+ else
+ break;
+ }
+
+ if (rc != 0) {
+ LOGW("Unable to unload kernel driver '%s' (%s)", modtag,
+ strerror(errno));
+ }
+ return rc;
+}
+
+bool Controller::isKernelModuleLoaded(const char *modtag) {
+ FILE *fp = fopen("/proc/modules", "r");
+
+ if (!fp) {
+ LOGE("Unable to open /proc/modules (%s)", strerror(errno));
+ return false;
+ }
+
+ char line[255];
+ while(fgets(line, sizeof(line), fp)) {
+ char *endTag = strchr(line, ' ');
+
+ if (!endTag) {
+ LOGW("Unable to find tag for line '%s'", line);
+ continue;
+ }
+ if (!strncmp(line, modtag, (endTag - line))) {
+ fclose(fp);
+ return true;
+ }
+ }
+
+ fclose(fp);
+ return false;
+}
+
+void *Controller::loadFile(char *filename, unsigned int *_size)
+{
+ int ret, fd;
+ struct stat sb;
+ ssize_t size;
+ void *buffer = NULL;
+
+ /* open the file */
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ /* find out how big it is */
+ if (fstat(fd, &sb) < 0)
+ goto bail;
+ size = sb.st_size;
+
+ /* allocate memory for it to be read into */
+ buffer = malloc(size);
+ if (!buffer)
+ goto bail;
+
+ /* slurp it into our buffer */
+ ret = read(fd, buffer, size);
+ if (ret != size)
+ goto bail;
+
+ /* let the caller know how big it is */
+ *_size = size;
+
+bail:
+ close(fd);
+ return buffer;
+}
+
+int Controller::bindInterface(const char *ifname) {
+ mBoundInterface = strdup(ifname);
+ LOGD("Controller %s bound to %s", mName, ifname);
+ return 0;
+}
+
+int Controller::unbindInterface(const char *ifname) {
+ free(mBoundInterface);
+ mBoundInterface = NULL;
+ LOGD("Controller %s unbound from %s", mName, ifname);
+ return 0;
+}
diff --git a/nexus/Controller.h b/nexus/Controller.h
new file mode 100644
index 0000000..af03d2e
--- /dev/null
+++ b/nexus/Controller.h
@@ -0,0 +1,74 @@
+/*
+ * 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 _CONTROLLER_H
+#define _CONTROLLER_H
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <utils/List.h>
+
+class PropertyManager;
+class IControllerHandler;
+
+#include "PropertyManager.h"
+#include "IPropertyProvider.h"
+
+class Controller : public IPropertyProvider {
+ /*
+ * Name of this controller - WIFI/VPN/USBNET/BTNET/BTDUN/LOOP/etc
+ */
+ char *mName;
+
+ /*
+ * Name of the system ethernet interface which this controller is
+ * bound to.
+ */
+ char *mBoundInterface;
+
+protected:
+ PropertyManager *mPropMngr;
+ IControllerHandler *mHandlers;
+
+public:
+ Controller(const char *name, PropertyManager *propMngr,
+ IControllerHandler *handlers);
+ virtual ~Controller();
+
+ virtual int start();
+ virtual int stop();
+
+ const char *getName() { return mName; }
+ const char *getBoundInterface() { return mBoundInterface; }
+
+ /* IPropertyProvider methods */
+ virtual int set(const char *name, const char *value);
+ virtual const char *get(const char *name, char *buffer, size_t maxsize);
+
+protected:
+ int loadKernelModule(char *modpath, const char *args);
+ bool isKernelModuleLoaded(const char *modtag);
+ int unloadKernelModule(const char *modtag);
+ int bindInterface(const char *ifname);
+ int unbindInterface(const char *ifname);
+
+private:
+ void *loadFile(char *filename, unsigned int *_size);
+};
+
+typedef android::List<Controller *> ControllerCollection;
+#endif
diff --git a/nexus/DhcpClient.cpp b/nexus/DhcpClient.cpp
new file mode 100644
index 0000000..2bd9c68
--- /dev/null
+++ b/nexus/DhcpClient.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+
+#define LOG_TAG "DhcpClient"
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <sysutils/ServiceManager.h>
+
+#include "DhcpClient.h"
+#include "DhcpState.h"
+#include "DhcpListener.h"
+#include "IDhcpEventHandlers.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::STOPPED), mHandlers(handlers) {
+ mServiceManager = new ServiceManager();
+ mListener = NULL;
+}
+
+DhcpClient::~DhcpClient() {
+ delete mServiceManager;
+ if (mListener)
+ delete mListener;
+}
+
+int DhcpClient::start(const char *interface) {
+
+ char svc[PROPERTY_VALUE_MAX];
+ snprintf(svc, sizeof(svc), "dhcpcd_ng:%s", interface);
+
+ if (mServiceManager->start(svc)) {
+ LOGE("Failed to start dhcp service");
+ return -1;
+ }
+
+ mListener = new DhcpListener(mHandlers);
+ if (mListener->startListener()) {
+ LOGE("Failed to start listener");
+#if 0
+ mServiceManager->stop("dhcpcd_ng");
+ return -1;
+#endif
+ delete mListener;
+ mListener = NULL;
+ }
+
+ mState = DhcpState::STARTED;
+
+ return 0;
+}
+
+int DhcpClient::stop() {
+ if (mListener) {
+ mListener->stopListener();
+ delete mListener;
+ mListener = NULL;
+ }
+
+ if (mServiceManager->stop("dhcpcd_ng"))
+ LOGW("Failed to stop DHCP service (%s)", strerror(errno));
+ mState = DhcpState::STOPPED;
+ return 0;
+}
diff --git a/nexus/DhcpClient.h b/nexus/DhcpClient.h
new file mode 100644
index 0000000..e0a2784
--- /dev/null
+++ b/nexus/DhcpClient.h
@@ -0,0 +1,41 @@
+
+/*
+ * 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 _DhcpClient_H
+#define _DhcpClient_H
+
+class IDhcpEventHandlers;
+class ServiceManager;
+class DhcpListener;
+
+class DhcpClient {
+ int mState;
+ IDhcpEventHandlers *mHandlers;
+ ServiceManager *mServiceManager;
+ DhcpListener *mListener;
+
+public:
+ DhcpClient(IDhcpEventHandlers *handlers);
+ virtual ~DhcpClient();
+
+ int getState() { return mState; }
+
+ int start(const char *interface);
+ int stop();
+};
+
+#endif
diff --git a/nexus/DhcpListener.cpp b/nexus/DhcpListener.cpp
new file mode 100644
index 0000000..2d07ee8
--- /dev/null
+++ b/nexus/DhcpListener.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "DhcpListener"
+#include <cutils/log.h>
+
+#include <DhcpListener.h>
+#include "IDhcpEventHandlers.h"
+
+DhcpListener::DhcpListener(IDhcpEventHandlers *handlers) :
+ SocketListener("dhcp_ng", false) {
+ mHandlers = handlers;
+}
+
+DhcpListener::~DhcpListener() {
+}
+
+bool DhcpListener::onDataAvailable(SocketClient *cli) {
+ LOGD("onDataAvailable()");
+ return true;
+}
diff --git a/nexus/DhcpListener.h b/nexus/DhcpListener.h
new file mode 100644
index 0000000..bfc5a37
--- /dev/null
+++ b/nexus/DhcpListener.h
@@ -0,0 +1,36 @@
+/*
+ * 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 _DhcpListener_H
+#define _DhcpListener_H
+
+#include <sysutils/SocketListener.h>
+
+class IDhcpEventHandlers;
+
+class DhcpListener : public SocketListener {
+ IDhcpEventHandlers *mHandlers;
+
+public:
+
+ DhcpListener(IDhcpEventHandlers *handlers);
+ virtual ~DhcpListener();
+
+private:
+ bool onDataAvailable(SocketClient *cli);
+};
+
+#endif
diff --git a/nexus/DhcpState.h b/nexus/DhcpState.h
new file mode 100644
index 0000000..27d7c7e
--- /dev/null
+++ b/nexus/DhcpState.h
@@ -0,0 +1,27 @@
+/*
+ * 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 _DhcpState_H
+#define _DhcpState_H
+
+class DhcpState {
+public:
+ static const int UNKNOWN = 0;
+ static const int STOPPED = 1;
+ static const int STARTED = 2;
+};
+
+#endif
diff --git a/nexus/ErrorCode.h b/nexus/ErrorCode.h
new file mode 100644
index 0000000..414dd2c
--- /dev/null
+++ b/nexus/ErrorCode.h
@@ -0,0 +1,48 @@
+/*
+ * 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 _ERRORCODE_H
+#define _ERRORCODE_H
+
+class ErrorCode {
+public:
+ // 100 series - Requestion action was initiated; expect another reply
+ // before proceeding with a new command.
+ static const int ActionInitiated = 100;
+
+ static const int WifiScanResult = 125;
+ static const int WifiNetworkList = 126;
+
+ static const int PropertyRead = 127;
+ static const int PropertySet = 128;
+ static const int PropertyList = 129;
+
+ // 200 series - Requested action has been successfully completed
+ static const int CommandOkay = 200;
+
+ // 400 series - The command was accepted but the requested action
+ // did not take place.
+ static const int OperationFailed = 400;
+
+ // 500 series - The command was not accepted and the requested
+ // action did not take place.
+ static const int CommandSyntaxError = 500;
+ static const int CommandParameterError = 501;
+
+ // 600 series - Unsolicited broadcasts
+ static const int UnsolicitedInformational = 600;
+};
+#endif
diff --git a/nexus/IControllerHandler.h b/nexus/IControllerHandler.h
new file mode 100644
index 0000000..f7be39c
--- /dev/null
+++ b/nexus/IControllerHandler.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 _ICONTROLLER_HANDLER_H
+#define _ICONTROLLER_HANDLER_H
+
+class Controller;
+class InterfaceConfig;
+
+class IControllerHandler {
+public:
+ virtual void onInterfaceConnected(Controller *c, const InterfaceConfig *cfg) = 0;
+ virtual void onInterfaceDisconnected(Controller *c, const char *name) = 0;
+};
+
+#endif
+
diff --git a/nexus/IDhcpEventHandlers.h b/nexus/IDhcpEventHandlers.h
new file mode 100644
index 0000000..3f51f64
--- /dev/null
+++ b/nexus/IDhcpEventHandlers.h
@@ -0,0 +1,25 @@
+
+/*
+ * 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 _IDhcpEventHandlers_H
+#define _IDhcpEventHandlers_H
+
+class IDhcpEventHandlers {
+public:
+};
+
+#endif
diff --git a/nexus/IPropertyProvider.h b/nexus/IPropertyProvider.h
new file mode 100644
index 0000000..17ad5f8
--- /dev/null
+++ b/nexus/IPropertyProvider.h
@@ -0,0 +1,33 @@
+/*
+ * 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 _IPROPERTY_PROVIDER_H
+#define _IPROPERTY_PROVIDER_H
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <utils/List.h>
+
+class IPropertyProvider {
+public:
+ virtual int set(const char *name, const char *value) = 0;
+ virtual const char *get(const char *name, char *buffer, size_t max) = 0;
+};
+
+typedef android::List<IPropertyProvider *> IPropertyProviderCollection;
+
+#endif
diff --git a/nexus/ISupplicantEventHandler.h b/nexus/ISupplicantEventHandler.h
new file mode 100644
index 0000000..b7fd17b
--- /dev/null
+++ b/nexus/ISupplicantEventHandler.h
@@ -0,0 +1,51 @@
+/*
+ * 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 _ISUPPLICANT_EVENT_HANDLER_H
+#define _ISUPPLICANT_EVENT_HANDLER_H
+
+class SupplicantAssociatingEvent;
+class SupplicantAssociatedEvent;
+class SupplicantConnectedEvent;
+class SupplicantScanResultsEvent;
+class SupplicantStateChangeEvent;
+class SupplicantConnectionTimeoutEvent;
+class SupplicantDisconnectedEvent;
+
+class ISupplicantEventHandler {
+public:
+ virtual void onAssociatingEvent(SupplicantAssociatingEvent *evt) = 0;
+ virtual void onAssociatedEvent(SupplicantAssociatedEvent *evt) = 0;
+ virtual void onConnectedEvent(SupplicantConnectedEvent *evt) = 0;
+ virtual void onScanResultsEvent(SupplicantScanResultsEvent *evt) = 0;
+ virtual void onStateChangeEvent(SupplicantStateChangeEvent *evt) = 0;
+ virtual void onConnectionTimeoutEvent(SupplicantConnectionTimeoutEvent *evt) = 0;
+ virtual void onDisconnectedEvent(SupplicantDisconnectedEvent *evt) = 0;
+#if 0
+ virtual void onTerminatingEvent(SupplicantEvent *evt) = 0;
+ virtual void onPasswordChangedEvent(SupplicantEvent *evt) = 0;
+ virtual void onEapNotificationEvent(SupplicantEvent *evt) = 0;
+ virtual void onEapStartedEvent(SupplicantEvent *evt) = 0;
+ virtual void onEapMethodEvent(SupplicantEvent *evt) = 0;
+ virtual void onEapSuccessEvent(SupplicantEvent *evt) = 0;
+ virtual void onEapFailureEvent(SupplicantEvent *evt) = 0;
+ virtual void onLinkSpeedEvent(SupplicantEvent *evt) = 0;
+ virtual void onDriverStateEvent(SupplicantEvent *evt) = 0;
+#endif
+};
+
+#endif
+
diff --git a/nexus/InterfaceConfig.cpp b/nexus/InterfaceConfig.cpp
new file mode 100644
index 0000000..66861d0
--- /dev/null
+++ b/nexus/InterfaceConfig.cpp
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_TAG "InterfaceConfig"
+#include <cutils/log.h>
+
+#include "InterfaceConfig.h"
+#include "NetworkManager.h"
+
+const char *InterfaceConfig::PropertyNames[] = { "dhcp", "ip",
+ "netmask",
+ "gateway", "dns1", "dns2",
+ "dns3", '\0' };
+
+InterfaceConfig::InterfaceConfig(const char *prop_prefix) {
+ mPropPrefix = strdup(prop_prefix);
+ mUseDhcp = true;
+ registerProperties();
+}
+
+InterfaceConfig::~InterfaceConfig() {
+ unregisterProperties();
+ free(mPropPrefix);
+}
+
+InterfaceConfig::InterfaceConfig(const char *prop_prefix,
+ const char *ip, const char *nm,
+ const char *gw, const char *dns1, const char *dns2,
+ const char *dns3) {
+ mPropPrefix = strdup(prop_prefix);
+ mUseDhcp = false;
+
+ if (!inet_aton(ip, &mIp))
+ LOGW("Unable to parse ip (%s)", ip);
+ if (!inet_aton(nm, &mNetmask))
+ LOGW("Unable to parse netmask (%s)", nm);
+ if (!inet_aton(gw, &mGateway))
+ LOGW("Unable to parse gateway (%s)", gw);
+ if (!inet_aton(dns1, &mDns1))
+ LOGW("Unable to parse dns1 (%s)", dns1);
+ if (!inet_aton(dns2, &mDns2))
+ LOGW("Unable to parse dns2 (%s)", dns2);
+ if (!inet_aton(dns3, &mDns3))
+ LOGW("Unable to parse dns3 (%s)", dns3);
+ registerProperties();
+}
+
+InterfaceConfig::InterfaceConfig(const char *prop_prefix,
+ const struct in_addr *ip,
+ const struct in_addr *nm, const struct in_addr *gw,
+ const struct in_addr *dns1, const struct in_addr *dns2,
+ const struct in_addr *dns3) {
+ mPropPrefix = strdup(prop_prefix);
+ mUseDhcp = false;
+
+ memcpy(&mIp, ip, sizeof(struct in_addr));
+ memcpy(&mNetmask, nm, sizeof(struct in_addr));
+ memcpy(&mGateway, gw, sizeof(struct in_addr));
+ memcpy(&mDns1, dns1, sizeof(struct in_addr));
+ memcpy(&mDns2, dns2, sizeof(struct in_addr));
+ memcpy(&mDns3, dns3, sizeof(struct in_addr));
+ registerProperties();
+}
+
+int InterfaceConfig::registerProperties() {
+ for (const char **p = InterfaceConfig::PropertyNames; *p != '\0'; p++) {
+ char *tmp;
+ asprintf(&tmp, "%s.if.%s", mPropPrefix, *p);
+
+ if (NetworkManager::Instance()->getPropMngr()->registerProperty(tmp,
+ this)) {
+ free(tmp);
+ return -1;
+ }
+ free(tmp);
+ }
+ return 0;
+}
+
+int InterfaceConfig::unregisterProperties() {
+ for (const char **p = InterfaceConfig::PropertyNames; *p != '\0'; p++) {
+ char *tmp;
+ asprintf(&tmp, "%s.if.%s", mPropPrefix, *p);
+
+ if (NetworkManager::Instance()->getPropMngr()->unregisterProperty(tmp))
+ LOGW("Unable to remove property '%s' (%s)", tmp, strerror(errno));
+ free(tmp);
+ }
+ return 0;
+}
+
+int InterfaceConfig::set(const char *name, const char *value) {
+ const char *n;
+
+ for (n = &name[strlen(name)]; *n != '.'; n--);
+ n++;
+
+ if (!strcasecmp(n, "name")) {
+ errno = EROFS;
+ return -1;
+ } else if (!strcasecmp(n, "ip") && !inet_aton(value, &mIp))
+ goto out_inval;
+ else if (!strcasecmp(n, "dhcp"))
+ mUseDhcp = (atoi(value) == 0 ? false : true);
+ else if (!strcasecmp(n, "netmask") && !inet_aton(value, &mNetmask))
+ goto out_inval;
+ else if (!strcasecmp(n, "gateway") && !inet_aton(value, &mGateway))
+ goto out_inval;
+ else if (!strcasecmp(n, "dns1") && !inet_aton(value, &mDns1))
+ goto out_inval;
+ else if (!strcasecmp(n, "dns2") && !inet_aton(value, &mDns2))
+ goto out_inval;
+ else if (!strcasecmp(n, "dns3") && !inet_aton(value, &mDns3))
+ goto out_inval;
+ else {
+ errno = ENOENT;
+ return -1;
+ }
+
+ return 0;
+
+out_inval:
+ errno = EINVAL;
+ return -1;
+}
+
+const char *InterfaceConfig::get(const char *name, char *buffer, size_t max) {
+ const char *n;
+
+ for (n = &name[strlen(name)]; *n != '.'; n--);
+ n++;
+
+ if (!strcasecmp(n, "ip"))
+ strncpy(buffer, inet_ntoa(mIp), max);
+ else if (!strcasecmp(n, "dhcp"))
+ snprintf(buffer, max, "%d", mUseDhcp);
+ else if (!strcasecmp(n, "netmask"))
+ strncpy(buffer, inet_ntoa(mNetmask), max);
+ else if (!strcasecmp(n, "gateway"))
+ strncpy(buffer, inet_ntoa(mGateway), max);
+ else if (!strcasecmp(n, "dns1"))
+ strncpy(buffer, inet_ntoa(mDns1), max);
+ else if (!strcasecmp(n, "dns2"))
+ strncpy(buffer, inet_ntoa(mDns2), max);
+ else if (!strcasecmp(n, "dns3"))
+ strncpy(buffer, inet_ntoa(mDns3), max);
+ else {
+ strncpy(buffer, "(internal error)", max);
+ errno = ENOENT;
+ return NULL;
+ }
+ return buffer;
+}
diff --git a/nexus/InterfaceConfig.h b/nexus/InterfaceConfig.h
new file mode 100644
index 0000000..d97f20b
--- /dev/null
+++ b/nexus/InterfaceConfig.h
@@ -0,0 +1,75 @@
+/*
+ * 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 _INTERFACE_CONFIG_H
+#define _INTERFACE_CONFIG_H
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "IPropertyProvider.h"
+
+class PropertyManager;
+
+class InterfaceConfig : public IPropertyProvider {
+public:
+ static const char *PropertyNames[];
+
+private:
+ char *mPropPrefix;
+ bool mUseDhcp;
+ struct in_addr mIp;
+ struct in_addr mNetmask;
+ struct in_addr mGateway;
+ struct in_addr mDns1;
+ struct in_addr mDns2;
+ struct in_addr mDns3;
+
+public:
+ InterfaceConfig(const char *prop_prefix);
+ InterfaceConfig(const char *prop_prefix,
+ const char *ip, const char *nm,
+ const char *gw, const char *dns1, const char *dns2,
+ const char *dns3);
+
+ InterfaceConfig(const char *prop_prefix,
+ const struct in_addr *ip,
+ const struct in_addr *nm, const struct in_addr *gw,
+ const struct in_addr *dns1, const struct in_addr *dns2,
+ const struct in_addr *dns3);
+
+ virtual ~InterfaceConfig();
+
+ int set(const char *name, const char *value);
+ const char *get(const char *name, char *buffer, size_t maxsize);
+
+ bool getUseDhcp() const { return mUseDhcp; }
+ const struct in_addr &getIp() const { return mIp; }
+ const struct in_addr &getNetmask() const { return mNetmask; }
+ const struct in_addr &getGateway() const { return mGateway; }
+ const struct in_addr &getDns1() const { return mDns1; }
+ const struct in_addr &getDns2() const { return mDns2; }
+ const struct in_addr &getDns3() const { return mDns3; }
+
+private:
+ int registerProperties();
+ int unregisterProperties();
+};
+
+
+#endif
diff --git a/nexus/LoopController.cpp b/nexus/LoopController.cpp
new file mode 100644
index 0000000..5cfb1fe
--- /dev/null
+++ b/nexus/LoopController.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+
+#include "LoopController.h"
+#include "PropertyManager.h"
+
+LoopController::LoopController(PropertyManager *propmngr,
+ IControllerHandler *handlers) :
+ Controller("LOOP", propmngr, handlers) {
+}
+
+int LoopController::set(const char *name, const char *value) {
+ return Controller::set(name, value);
+}
+
+const char *LoopController::get(const char *name, char *buffer, size_t maxsize) {
+ return Controller::get(name, buffer, maxsize);
+}
+
diff --git a/nexus/LoopController.h b/nexus/LoopController.h
new file mode 100644
index 0000000..53d16f1
--- /dev/null
+++ b/nexus/LoopController.h
@@ -0,0 +1,33 @@
+/*
+ * 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 _LOOP_CONTROLLER_H
+#define _LOOP_CONTROLLER_H
+
+#include "Controller.h"
+
+class ControllerHandler;
+
+class LoopController : public Controller {
+public:
+ LoopController(PropertyManager *propmngr, IControllerHandler *h);
+ virtual ~LoopController() {}
+
+ int set(const char *name, const char *value);
+ const char *get(const char *name, char *buffer, size_t maxsize);
+};
+
+#endif
diff --git a/nexus/NetworkManager.cpp b/nexus/NetworkManager.cpp
new file mode 100644
index 0000000..7450b95
--- /dev/null
+++ b/nexus/NetworkManager.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+
+#define LOG_TAG "Nexus"
+
+#include <cutils/log.h>
+
+#include "NetworkManager.h"
+#include "InterfaceConfig.h"
+#include "DhcpClient.h"
+
+NetworkManager *NetworkManager::sInstance = NULL;
+
+NetworkManager *NetworkManager::Instance() {
+ if (!sInstance)
+ sInstance = new NetworkManager(new PropertyManager());
+ return sInstance;
+}
+
+NetworkManager::NetworkManager(PropertyManager *propMngr) {
+ mBroadcaster = NULL;
+ mControllers = new ControllerCollection();
+ mPropMngr = propMngr;
+ mDhcp = new DhcpClient(this);
+}
+
+NetworkManager::~NetworkManager() {
+}
+
+int NetworkManager::run() {
+ if (startControllers()) {
+ LOGW("Unable to start all controllers (%s)", strerror(errno));
+ }
+ return 0;
+}
+
+int NetworkManager::attachController(Controller *c) {
+ mControllers->push_back(c);
+ return 0;
+}
+
+int NetworkManager::startControllers() {
+ int rc = 0;
+ ControllerCollection::iterator i;
+
+ for (i = mControllers->begin(); i != mControllers->end(); ++i) {
+ int irc = (*i)->start();
+ LOGD("Controller '%s' start rc = %d", (*i)->getName(), irc);
+ if (irc && !rc)
+ rc = irc;
+ }
+ return rc;
+}
+
+int NetworkManager::stopControllers() {
+ int rc = 0;
+ ControllerCollection::iterator i;
+
+ for (i = mControllers->begin(); i != mControllers->end(); ++i) {
+ int irc = (*i)->stop();
+ LOGD("Controller '%s' stop rc = %d", (*i)->getName(), irc);
+ if (irc && !rc)
+ rc = irc;
+ }
+ return rc;
+}
+
+Controller *NetworkManager::findController(const char *name) {
+ ControllerCollection::iterator i;
+ for (i = mControllers->begin(); i != mControllers->end(); ++i) {
+ if (!strcmp((*i)->getName(), name))
+ return *i;
+ }
+ LOGW("Controller '%s' not found", name);
+ return NULL;
+}
+
+void NetworkManager::onInterfaceConnected(Controller *c, const InterfaceConfig *cfg) {
+ LOGD("Controller %s interface %s connected", c->getName(), c->getBoundInterface());
+
+ // Look up the interface
+
+ if (0) { // already started?
+ }
+
+ if (cfg) {
+ if (cfg->getUseDhcp() && mDhcp->start(c->getBoundInterface())) {
+ LOGE("DHCP start failed");
+ } else if (!cfg->getUseDhcp()) {
+ // Static configuration
+ }
+ } else {
+ LOGD("No InterfaceConfig for %s:%s - assuming self-managed",
+ c->getName(), c->getBoundInterface());
+ }
+}
+
+void NetworkManager::onInterfaceDisconnected(Controller *c, const char *name) {
+ LOGD("Controller %s interface %s disconnected", c->getName(), name);
+
+ // If we have a DHCP request out on this interface then stop it
+ if (1) {
+ mDhcp->stop();
+ }
+}
diff --git a/nexus/NetworkManager.h b/nexus/NetworkManager.h
new file mode 100644
index 0000000..44f3417
--- /dev/null
+++ b/nexus/NetworkManager.h
@@ -0,0 +1,64 @@
+/*
+ * 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 _NETWORKMANAGER_H
+#define _NETWORKMANAGER_H
+
+#include <sysutils/SocketListener.h>
+
+#include "Controller.h"
+#include "PropertyManager.h"
+#include "IControllerHandler.h"
+#include "IDhcpEventHandlers.h"
+
+class InterfaceConfig;
+class DhcpClient;
+
+class NetworkManager : public IControllerHandler, public IDhcpEventHandlers {
+private:
+ static NetworkManager *sInstance;
+
+private:
+ ControllerCollection *mControllers;
+ SocketListener *mBroadcaster;
+ PropertyManager *mPropMngr;
+ DhcpClient *mDhcp;
+
+public:
+ virtual ~NetworkManager();
+
+ int run();
+
+ int attachController(Controller *controller);
+
+ Controller *findController(const char *name);
+
+ void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
+ SocketListener *getBroadcaster() { return mBroadcaster; }
+ PropertyManager *getPropMngr() { return mPropMngr; }
+
+ static NetworkManager *Instance();
+
+private:
+ int startControllers();
+ int stopControllers();
+
+ NetworkManager(PropertyManager *propMngr);
+
+ void onInterfaceConnected(Controller *c, const InterfaceConfig *cfg);
+ void onInterfaceDisconnected(Controller *c, const char *name);
+};
+#endif
diff --git a/nexus/NexusCommand.cpp b/nexus/NexusCommand.cpp
new file mode 100644
index 0000000..541eeeb
--- /dev/null
+++ b/nexus/NexusCommand.cpp
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+#include "NexusCommand.h"
+
+NexusCommand::NexusCommand(const char *cmd) :
+ FrameworkCommand(cmd) {
+}
diff --git a/nexus/NexusCommand.h b/nexus/NexusCommand.h
new file mode 100644
index 0000000..a7f944a
--- /dev/null
+++ b/nexus/NexusCommand.h
@@ -0,0 +1,28 @@
+/*
+ * 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 _NEXUS_COMMAND_H
+#define _NEXUS_COMMAND_H
+
+#include <sysutils/FrameworkCommand.h>
+
+class NexusCommand : public FrameworkCommand {
+public:
+ NexusCommand(const char *cmd);
+ virtual ~NexusCommand() {}
+};
+
+#endif
diff --git a/nexus/OpenVpnController.cpp b/nexus/OpenVpnController.cpp
new file mode 100644
index 0000000..f1ea510
--- /dev/null
+++ b/nexus/OpenVpnController.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#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"
+#include "PropertyManager.h"
+
+#define DAEMON_PROP_NAME "vpn.openvpn.status"
+#define DAEMON_CONFIG_FILE "/data/misc/openvpn/openvpn.conf"
+
+OpenVpnController::OpenVpnController(PropertyManager *propmngr,
+ IControllerHandler *handlers) :
+ VpnController(propmngr, handlers) {
+ mServiceManager = new ServiceManager();
+}
+
+OpenVpnController::~OpenVpnController() {
+ delete mServiceManager;
+}
+
+int OpenVpnController::start() {
+ return VpnController::start();
+}
+
+int OpenVpnController::stop() {
+ return VpnController::stop();
+}
+
+int OpenVpnController::enable() {
+ char svc[PROPERTY_VALUE_MAX];
+ char tmp[64];
+
+ if (!mPropMngr->get("vpn.gateway", tmp, sizeof(tmp))) {
+ LOGE("Error reading property 'vpn.gateway' (%s)", strerror(errno));
+ return -1;
+ }
+ snprintf(svc, sizeof(svc), "openvpn:--remote %s 1194", tmp);
+
+ if (mServiceManager->start(svc))
+ return -1;
+
+ return 0;
+}
+
+int OpenVpnController::disable() {
+ if (mServiceManager->stop("openvpn"))
+ return -1;
+ return 0;
+}
diff --git a/nexus/OpenVpnController.h b/nexus/OpenVpnController.h
new file mode 100644
index 0000000..529aab5
--- /dev/null
+++ b/nexus/OpenVpnController.h
@@ -0,0 +1,42 @@
+/*
+ * 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 _OPEN_VPN_CONTROLLER_H
+#define _OPEN_VPN_CONTROLLER_H
+
+#include "PropertyManager.h"
+#include "VpnController.h"
+
+class ServiceManager;
+class IControllerHandler;
+
+class OpenVpnController : public VpnController {
+private:
+ ServiceManager *mServiceManager;
+
+public:
+ OpenVpnController(PropertyManager *propmngr, IControllerHandler *handlers);
+ virtual ~OpenVpnController();
+
+ int start();
+ int stop();
+
+private:
+ int enable();
+ int disable();
+};
+
+#endif
diff --git a/nexus/Property.h b/nexus/Property.h
new file mode 100644
index 0000000..198f722
--- /dev/null
+++ b/nexus/Property.h
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+class Property {
+public:
+ static const int NameMaxSize = 128;
+ static const int ValueMaxSize = 255;
+};
diff --git a/nexus/PropertyManager.cpp b/nexus/PropertyManager.cpp
new file mode 100644
index 0000000..6faf9b8
--- /dev/null
+++ b/nexus/PropertyManager.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "PropertyManager"
+
+#include <cutils/log.h>
+
+#include "PropertyManager.h"
+
+PropertyManager::PropertyManager() {
+ mPropertyPairs = new PropertyPairCollection();
+ pthread_mutex_init(&mLock, NULL);
+}
+
+PropertyManager::~PropertyManager() {
+ delete mPropertyPairs;
+}
+
+int PropertyManager::registerProperty(const char *name, IPropertyProvider *pp) {
+ PropertyPairCollection::iterator it;
+
+// LOGD("registerProperty(%s)", name);
+ pthread_mutex_lock(&mLock);
+ for (it = mPropertyPairs->begin(); it != mPropertyPairs->end(); ++it) {
+ if (!strcmp(name, (*it)->getName())) {
+ errno = EADDRINUSE;
+ LOGE("Failed to register property %s (%s)",
+ name, strerror(errno));
+ pthread_mutex_unlock(&mLock);
+ return -1;
+ }
+ }
+ mPropertyPairs->push_back(new PropertyPair(name, pp));
+ pthread_mutex_unlock(&mLock);
+ return 0;
+}
+
+int PropertyManager::unregisterProperty(const char *name) {
+ PropertyPairCollection::iterator it;
+
+// LOGD("unregisterProperty(%s)", name);
+ pthread_mutex_lock(&mLock);
+ for (it = mPropertyPairs->begin(); it != mPropertyPairs->end(); ++it) {
+ if (!strcmp(name, (*it)->getName())) {
+ delete ((*it));
+ mPropertyPairs->erase(it);
+ pthread_mutex_unlock(&mLock);
+ return 0;
+ }
+ }
+ pthread_mutex_unlock(&mLock);
+ errno = ENOENT;
+ return -1;
+}
+
+/*
+ * IPropertyManager methods
+ */
+
+int PropertyManager::set(const char *name, const char *value) {
+ PropertyPairCollection::iterator it;
+
+ pthread_mutex_lock(&mLock);
+ for (it = mPropertyPairs->begin(); it != mPropertyPairs->end(); ++it) {
+ if (!strcmp(name, (*it)->getName())) {
+ pthread_mutex_unlock(&mLock);
+ return (*it)->getProvider()->set(name, value);
+ }
+ }
+ pthread_mutex_unlock(&mLock);
+ errno = ENOENT;
+ return -1;
+}
+
+const char *PropertyManager::get(const char *name, char *buffer, size_t max) {
+ PropertyPairCollection::iterator it;
+
+ memset(buffer, 0, max);
+ pthread_mutex_lock(&mLock);
+ for (it = mPropertyPairs->begin(); it != mPropertyPairs->end(); ++it) {
+ if (!strcmp(name, (*it)->getName())) {
+ pthread_mutex_unlock(&mLock);
+ return (*it)->getProvider()->get(name, buffer, max);
+ }
+ }
+ pthread_mutex_unlock(&mLock);
+ errno = ENOENT;
+ return NULL;
+}
+
+android::List<char *> *PropertyManager::createPropertyList() {
+ android::List<char *> *c = new android::List<char *>();
+
+ PropertyPairCollection::iterator it;
+
+ pthread_mutex_lock(&mLock);
+ for (it = mPropertyPairs->begin(); it != mPropertyPairs->end(); ++it)
+ c->push_back(strdup((*it)->getName()));
+ pthread_mutex_unlock(&mLock);
+ return c;
+}
+
+PropertyPair::PropertyPair(const char *name, IPropertyProvider *pp) {
+ mName = strdup(name);
+ mPp = pp;
+}
+
+PropertyPair::~PropertyPair() {
+ free(mName);
+}
diff --git a/nexus/PropertyManager.h b/nexus/PropertyManager.h
new file mode 100644
index 0000000..10d0b2a
--- /dev/null
+++ b/nexus/PropertyManager.h
@@ -0,0 +1,57 @@
+/*
+ * 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 _PROPERTY_MANAGER_H
+#define _PROPERTY_MANAGER_H
+
+#include <errno.h>
+#include <pthread.h>
+
+#include <utils/List.h>
+
+#include "IPropertyProvider.h"
+
+class PropertyPair {
+private:
+ char *mName;
+ IPropertyProvider *mPp;
+
+public:
+ PropertyPair(const char *name, IPropertyProvider *pp);
+ virtual ~PropertyPair();
+
+ const char *getName() { return mName; }
+ IPropertyProvider *getProvider() { return mPp; }
+};
+
+typedef android::List<PropertyPair *> PropertyPairCollection;
+
+class PropertyManager {
+ PropertyPairCollection *mPropertyPairs;
+ pthread_mutex_t mLock;
+
+public:
+ PropertyManager();
+ virtual ~PropertyManager();
+ int registerProperty(const char *name, IPropertyProvider *pp);
+ int unregisterProperty(const char *name);
+ android::List<char *> *createPropertyList();
+
+ int set(const char *name, const char *value);
+ const char *get(const char *name, char *buffer, size_t max);
+};
+
+#endif
diff --git a/nexus/ScanResult.cpp b/nexus/ScanResult.cpp
new file mode 100644
index 0000000..e9a286c
--- /dev/null
+++ b/nexus/ScanResult.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+
+#define LOG_TAG "ScanResult"
+#include <cutils/log.h>
+
+#include "ScanResult.h"
+
+ScanResult::ScanResult() {
+}
+
+ScanResult::ScanResult(char *rawResult) {
+ char *p = rawResult, *q = rawResult;
+ char tmp[255];
+
+ // BSSID
+ for (q = p; *q != '\t'; ++q);
+ strncpy(tmp, p, (q - p));
+ tmp[q-p] = '\0';
+ mBssid = strdup(tmp);
+ ++q;
+
+ // FREQ
+ for (p = q; *q != '\t'; ++q);
+ strncpy(tmp, p, (q - p));
+ tmp[q-p] = '\0';
+ mFreq = atoi(tmp);
+ ++q;
+
+ // LEVEL
+ for (p = q; *q != '\t'; ++q);
+ strncpy(tmp, p, (q - p));
+ tmp[q-p] = '\0';
+ mLevel = atoi(tmp);
+ ++q;
+
+ // FLAGS
+ for (p = q; *q != '\t'; ++q);
+ strncpy(tmp, p, (q - p));
+ tmp[q-p] = '\0';
+ mFlags = strdup(tmp);
+ ++q;
+
+ // XXX: For some reason Supplicant sometimes sends a double-tab here.
+ // haven't had time to dig into it ...
+ if (*q == '\t')
+ q++;
+
+ for (p = q; *q != '\t'; ++q) {
+ if (*q == '\0')
+ break;
+ }
+
+ strncpy(tmp, p, (q - p));
+ tmp[q-p] = '\0';
+ mSsid = strdup(tmp);
+ ++q;
+
+ return;
+ out_bad:
+ LOGW("Malformatted scan result (%s)", rawResult);
+}
+
+ScanResult::~ScanResult() {
+ if (mBssid)
+ free(mBssid);
+ if (mFlags)
+ free(mFlags);
+ if (mSsid)
+ free(mSsid);
+}
+
+ScanResult *ScanResult::clone() {
+ ScanResult *r = new ScanResult();
+
+ r->mBssid = strdup(mBssid);
+ r->mFreq = mFreq;
+ r->mLevel = mLevel;
+ r->mFlags = strdup(mFlags);
+ r->mSsid = strdup(mSsid);
+
+ return r;
+}
diff --git a/nexus/ScanResult.h b/nexus/ScanResult.h
new file mode 100644
index 0000000..68ad0f0
--- /dev/null
+++ b/nexus/ScanResult.h
@@ -0,0 +1,49 @@
+/*
+ * 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 _SCAN_RESULT_H
+#define _SCAN_RESULT_H
+
+#include <sys/types.h>
+
+#include <utils/List.h>
+
+class ScanResult {
+ char *mBssid;
+ uint32_t mFreq;
+ int mLevel;
+ char *mFlags;
+ char *mSsid;
+
+private:
+ ScanResult();
+
+public:
+ ScanResult(char *rawResult);
+ virtual ~ScanResult();
+
+ ScanResult *clone();
+
+ const char *getBssid() { return mBssid; }
+ uint32_t getFreq() { return mFreq; }
+ int getLevel() { return mLevel; }
+ const char *getFlags() { return mFlags; }
+ const char *getSsid() { return mSsid; }
+};
+
+typedef android::List<ScanResult *> ScanResultCollection;
+
+#endif
diff --git a/nexus/Supplicant.cpp b/nexus/Supplicant.cpp
new file mode 100644
index 0000000..9bb6bf2
--- /dev/null
+++ b/nexus/Supplicant.cpp
@@ -0,0 +1,471 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define LOG_TAG "Supplicant"
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "private/android_filesystem_config.h"
+
+#include <sysutils/ServiceManager.h>
+
+#include "Supplicant.h"
+#include "SupplicantListener.h"
+#include "NetworkManager.h"
+#include "ErrorCode.h"
+#include "WifiController.h"
+#include "SupplicantStatus.h"
+
+#include "libwpa_client/wpa_ctrl.h"
+
+#define IFACE_DIR "/data/system/wpa_supplicant"
+#define DRIVER_PROP_NAME "wlan.driver.status"
+#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(WifiController *wc, ISupplicantEventHandler *handlers) {
+ mHandlers = handlers;
+ mController = wc;
+ mInterfaceName = NULL;
+ mCtrl = NULL;
+ mMonitor = NULL;
+ mListener = NULL;
+
+ mServiceManager = new ServiceManager();
+
+ mNetworks = new WifiNetworkCollection();
+ pthread_mutex_init(&mNetworksLock, NULL);
+}
+
+Supplicant::~Supplicant() {
+ delete mServiceManager;
+ if (mInterfaceName)
+ free(mInterfaceName);
+}
+
+int Supplicant::start() {
+
+ if (setupConfig()) {
+ LOGW("Unable to setup supplicant.conf");
+ }
+
+ if (mServiceManager->start(SUPPLICANT_SERVICE_NAME)) {
+ LOGE("Error starting supplicant (%s)", strerror(errno));
+ return -1;
+ }
+
+ wpa_ctrl_cleanup();
+ if (connectToSupplicant()) {
+ LOGE("Error connecting to supplicant (%s)\n", strerror(errno));
+ return -1;
+ }
+
+ if (retrieveInterfaceName()) {
+ LOGE("Error retrieving interface name (%s)\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int Supplicant::stop() {
+
+ if (mListener->stopListener()) {
+ LOGW("Unable to stop supplicant listener (%s)", strerror(errno));
+ return -1;
+ }
+
+ if (mServiceManager->stop(SUPPLICANT_SERVICE_NAME)) {
+ LOGW("Error stopping supplicant (%s)", strerror(errno));
+ }
+
+ if (mCtrl) {
+ wpa_ctrl_close(mCtrl);
+ mCtrl = NULL;
+ }
+ if (mMonitor) {
+ wpa_ctrl_close(mMonitor);
+ mMonitor = NULL;
+ }
+
+ return 0;
+}
+
+bool Supplicant::isStarted() {
+ return mServiceManager->isRunning(SUPPLICANT_SERVICE_NAME);
+}
+
+SupplicantStatus *Supplicant::getStatus() {
+ char *reply;
+ size_t len = 4096;
+
+ if (!(reply = (char *) malloc(len))) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ if (sendCommand("STATUS", reply, &len)) {
+ free(reply);
+ return NULL;
+ }
+
+ SupplicantStatus *ss = SupplicantStatus::createStatus(reply, len);
+
+ free (reply);
+ return ss;
+}
+
+/*
+ * Retrieves the list of networks from Supplicant
+ * and merge them into our current list
+ */
+int Supplicant::refreshNetworkList() {
+ char *reply;
+ size_t len = 4096;
+
+ if (!(reply = (char *) malloc(len))) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (sendCommand("LIST_NETWORKS", reply, &len)) {
+ free(reply);
+ return -1;
+ }
+
+ char *linep;
+ char *linep_next = NULL;
+
+ if (!strtok_r(reply, "\n", &linep_next)) {
+ LOGW("Malformatted network list\n");
+ free(reply);
+ errno = EIO;
+ return -1;
+ }
+
+ pthread_mutex_lock(&mNetworksLock);
+
+ int num_added = 0;
+ int num_refreshed = 0;
+ int num_removed = 0;
+ while((linep = strtok_r(NULL, "\n", &linep_next))) {
+ // TODO: Move the decode into a static method so we
+ // don't create new_wn when we don't have to.
+ WifiNetwork *new_wn = new WifiNetwork(mController, this, linep);
+ WifiNetwork *merge_wn;
+
+ if ((merge_wn = this->lookupNetwork_UNLOCKED(new_wn->getNetworkId()))) {
+ num_refreshed++;
+ if (merge_wn->refresh()) {
+ LOGW("Error refreshing network %d (%s)",
+ merge_wn->getNetworkId(), strerror(errno));
+ }
+ delete new_wn;
+ } else {
+ num_added++;
+ new_wn->registerProperties();
+ mNetworks->push_back(new_wn);
+ if (new_wn->refresh()) {
+ LOGW("Unable to refresh network id %d (%s)",
+ new_wn->getNetworkId(), strerror(errno));
+ }
+ }
+ }
+
+ if (!mNetworks->empty()) {
+ // TODO: Add support for detecting removed networks
+ WifiNetworkCollection::iterator i;
+
+ for (i = mNetworks->begin(); i != mNetworks->end(); ++i) {
+ if (0) {
+ num_removed++;
+ (*i)->unregisterProperties();
+ delete (*i);
+ i = mNetworks->erase(i);
+ }
+ }
+ }
+
+
+ LOGD("Networks added %d, refreshed %d, removed %d\n",
+ num_added, num_refreshed, num_removed);
+ pthread_mutex_unlock(&mNetworksLock);
+
+ free(reply);
+ return 0;
+}
+
+int Supplicant::connectToSupplicant() {
+ if (!isStarted())
+ LOGW("Supplicant service not running");
+
+ mCtrl = wpa_ctrl_open("tiwlan0"); // XXX:
+ if (mCtrl == NULL) {
+ LOGE("Unable to open connection to supplicant on \"%s\": %s",
+ "tiwlan0", strerror(errno));
+ return -1;
+ }
+ mMonitor = wpa_ctrl_open("tiwlan0");
+ if (mMonitor == NULL) {
+ wpa_ctrl_close(mCtrl);
+ mCtrl = NULL;
+ return -1;
+ }
+ if (wpa_ctrl_attach(mMonitor) != 0) {
+ wpa_ctrl_close(mMonitor);
+ wpa_ctrl_close(mCtrl);
+ mCtrl = mMonitor = NULL;
+ return -1;
+ }
+
+ mListener = new SupplicantListener(mHandlers, mMonitor);
+
+ if (mListener->startListener()) {
+ LOGE("Error - unable to start supplicant listener");
+ stop();
+ return -1;
+ }
+ return 0;
+}
+
+int Supplicant::sendCommand(const char *cmd, char *reply, size_t *reply_len)
+{
+ if (!mCtrl) {
+ errno = ENOTCONN;
+ return -1;
+ }
+
+// LOGD("sendCommand(): -> '%s'", cmd);
+
+ int rc;
+ memset(reply, 0, *reply_len);
+ if ((rc = wpa_ctrl_request(mCtrl, cmd, strlen(cmd), reply, reply_len, NULL)) == -2) {
+ errno = ETIMEDOUT;
+ return -1;
+ } else if (rc < 0 || !strncmp(reply, "FAIL", 4)) {
+ strcpy(reply, "FAIL");
+ errno = EIO;
+ return -1;
+ }
+
+// LOGD("sendCommand(): <- '%s'", reply);
+ return 0;
+}
+
+int Supplicant::triggerScan(bool active) {
+ char reply[255];
+ size_t len = sizeof(reply);
+
+ if (sendCommand((active ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"),
+ reply, &len)) {
+ LOGW("triggerScan(%d): Error setting scan mode (%s)", active,
+ strerror(errno));
+ return -1;
+ }
+ len = sizeof(reply);
+
+ if (sendCommand("SCAN", reply, &len)) {
+ LOGW("triggerScan(%d): Error initiating scan", active);
+ return -1;
+ }
+ return 0;
+}
+
+WifiNetwork *Supplicant::createNetwork() {
+ char reply[255];
+ size_t len = sizeof(reply) -1;
+
+ if (sendCommand("ADD_NETWORK", reply, &len))
+ return NULL;
+
+ if (reply[strlen(reply) -1] == '\n')
+ reply[strlen(reply) -1] = '\0';
+
+ WifiNetwork *wn = new WifiNetwork(mController, this, atoi(reply));
+ pthread_mutex_lock(&mNetworksLock);
+ mNetworks->push_back(wn);
+ pthread_mutex_unlock(&mNetworksLock);
+ return wn;
+}
+
+int Supplicant::removeNetwork(WifiNetwork *wn) {
+ char req[64];
+
+ sprintf(req, "REMOVE_NETWORK %d", wn->getNetworkId());
+ char reply[32];
+ size_t len = sizeof(reply) -1;
+
+ if (sendCommand(req, reply, &len))
+ return -1;
+
+ pthread_mutex_lock(&mNetworksLock);
+ WifiNetworkCollection::iterator it;
+ for (it = mNetworks->begin(); it != mNetworks->end(); ++it) {
+ if ((*it) == wn) {
+ mNetworks->erase(it);
+ break;
+ }
+ }
+ pthread_mutex_unlock(&mNetworksLock);
+ return 0;
+}
+
+WifiNetwork *Supplicant::lookupNetwork(int networkId) {
+ pthread_mutex_lock(&mNetworksLock);
+ WifiNetwork *wn = lookupNetwork_UNLOCKED(networkId);
+ pthread_mutex_unlock(&mNetworksLock);
+ return wn;
+}
+
+WifiNetwork *Supplicant::lookupNetwork_UNLOCKED(int networkId) {
+ WifiNetworkCollection::iterator it;
+ for (it = mNetworks->begin(); it != mNetworks->end(); ++it) {
+ if ((*it)->getNetworkId() == networkId) {
+ return *it;
+ }
+ }
+ errno = ENOENT;
+ return NULL;
+}
+
+WifiNetworkCollection *Supplicant::createNetworkList() {
+ WifiNetworkCollection *d = new WifiNetworkCollection();
+ WifiNetworkCollection::iterator i;
+
+ pthread_mutex_lock(&mNetworksLock);
+ for (i = mNetworks->begin(); i != mNetworks->end(); ++i)
+ d->push_back((*i)->clone());
+
+ pthread_mutex_unlock(&mNetworksLock);
+ return d;
+}
+
+int Supplicant::setupConfig() {
+ char buf[2048];
+ int srcfd, destfd;
+ int nread;
+
+ if (access(SUPP_CONFIG_FILE, R_OK|W_OK) == 0) {
+ return 0;
+ } else if (errno != ENOENT) {
+ LOGE("Cannot access \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno));
+ return -1;
+ }
+
+ srcfd = open(SUPP_CONFIG_TEMPLATE, O_RDONLY);
+ if (srcfd < 0) {
+ LOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
+ return -1;
+ }
+
+ destfd = open(SUPP_CONFIG_FILE, O_CREAT|O_WRONLY, 0660);
+ if (destfd < 0) {
+ close(srcfd);
+ LOGE("Cannot create \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno));
+ return -1;
+ }
+
+ while ((nread = read(srcfd, buf, sizeof(buf))) != 0) {
+ if (nread < 0) {
+ LOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
+ close(srcfd);
+ close(destfd);
+ unlink(SUPP_CONFIG_FILE);
+ return -1;
+ }
+ write(destfd, buf, nread);
+ }
+
+ close(destfd);
+ close(srcfd);
+
+ if (chown(SUPP_CONFIG_FILE, AID_SYSTEM, AID_WIFI) < 0) {
+ LOGE("Error changing group ownership of %s to %d: %s",
+ SUPP_CONFIG_FILE, AID_WIFI, strerror(errno));
+ unlink(SUPP_CONFIG_FILE);
+ return -1;
+ }
+ return 0;
+}
+
+int Supplicant::setNetworkVar(int networkId, const char *var, const char *val) {
+ char reply[255];
+ size_t len = sizeof(reply) -1;
+
+ char *tmp;
+ asprintf(&tmp, "SET_NETWORK %d %s \"%s\"", networkId, var, val);
+ if (sendCommand(tmp, reply, &len)) {
+ free(tmp);
+ return -1;
+ }
+ free(tmp);
+
+ len = sizeof(reply) -1;
+ if (sendCommand("SAVE_CONFIG", reply, &len)) {
+ LOGE("Error saving config after %s = %s", var, val);
+ return -1;
+ }
+ return 0;
+}
+
+const char *Supplicant::getNetworkVar(int networkId, const char *var,
+ char *buffer, size_t max) {
+ size_t len = max - 1;
+ char *tmp;
+
+ asprintf(&tmp, "GET_NETWORK %d %s", networkId, var);
+ if (sendCommand(tmp, buffer, &len)) {
+ free(tmp);
+ return NULL;
+ }
+ free(tmp);
+ return buffer;
+}
+
+int Supplicant::enableNetwork(int networkId, bool enabled) {
+ char req[64];
+
+ if (enabled)
+ sprintf(req, "ENABLE_NETWORK %d", networkId);
+ else
+ sprintf(req, "DISABLE_NETWORK %d", networkId);
+
+ char reply[16];
+ size_t len = sizeof(reply) -1;
+
+ if (sendCommand(req, reply, &len))
+ return -1;
+ return 0;
+}
+
+
+int Supplicant::retrieveInterfaceName() {
+ char reply[255];
+ size_t len = sizeof(reply) -1;
+
+ if (sendCommand("INTERFACES", reply, &len))
+ return -1;
+
+ reply[strlen(reply)-1] = '\0';
+ mInterfaceName = strdup(reply);
+ return 0;
+}
diff --git a/nexus/Supplicant.h b/nexus/Supplicant.h
new file mode 100644
index 0000000..3efbe4c
--- /dev/null
+++ b/nexus/Supplicant.h
@@ -0,0 +1,80 @@
+/*
+ * 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 _SUPPLICANT_H
+#define _SUPPLICANT_H
+
+struct wpa_ctrl;
+class SupplicantListener;
+class ServiceManager;
+class Controller;
+class WifiController;
+class SupplicantStatus;
+
+#include <pthread.h>
+
+#include "WifiNetwork.h"
+#include "ISupplicantEventHandler.h"
+
+class Supplicant {
+private:
+ struct wpa_ctrl *mCtrl;
+ struct wpa_ctrl *mMonitor;
+ SupplicantListener *mListener;
+ ServiceManager *mServiceManager;
+ WifiController *mController;
+ char *mInterfaceName;
+
+ WifiNetworkCollection *mNetworks;
+ pthread_mutex_t mNetworksLock;
+ ISupplicantEventHandler *mHandlers;
+
+public:
+ Supplicant(WifiController *wc, ISupplicantEventHandler *handlers);
+ virtual ~Supplicant();
+
+ int start();
+ int stop();
+ bool isStarted();
+
+ int triggerScan(bool active);
+
+ WifiNetwork *createNetwork();
+ WifiNetwork *lookupNetwork(int networkId);
+ int removeNetwork(WifiNetwork *net);
+ WifiNetworkCollection *createNetworkList();
+ int refreshNetworkList();
+
+ int setNetworkVar(int networkId, const char *var, const char *value);
+ const char *getNetworkVar(int networkid, const char *var, char *buffer,
+ size_t max);
+ int enableNetwork(int networkId, bool enabled);
+
+ SupplicantStatus *getStatus();
+
+ Controller *getController() { return (Controller *) mController; }
+ const char *getInterfaceName() { return mInterfaceName; }
+
+ int sendCommand(const char *cmd, char *reply, size_t *reply_len);
+
+private:
+ int connectToSupplicant();
+ int setupConfig();
+ int retrieveInterfaceName();
+ WifiNetwork *lookupNetwork_UNLOCKED(int networkId);
+};
+
+#endif
diff --git a/nexus/SupplicantAssociatedEvent.cpp b/nexus/SupplicantAssociatedEvent.cpp
new file mode 100644
index 0000000..e40411e
--- /dev/null
+++ b/nexus/SupplicantAssociatedEvent.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+
+#define LOG_TAG "SupplicantAssociatedEvent"
+#include <cutils/log.h>
+
+#include "SupplicantAssociatedEvent.h"
+
+SupplicantAssociatedEvent::SupplicantAssociatedEvent(int level, char *event,
+ size_t len) :
+ SupplicantEvent(SupplicantEvent::EVENT_ASSOCIATED,
+ level) {
+ char *p = event;
+
+ // "00:13:46:40:40:aa"
+ mBssid = (char *) malloc(18);
+ strncpy(mBssid, p, 17);
+ mBssid[17] = '\0';
+}
+
+SupplicantAssociatedEvent::~SupplicantAssociatedEvent() {
+ if (mBssid)
+ free(mBssid);
+}
+
diff --git a/nexus/SupplicantAssociatedEvent.h b/nexus/SupplicantAssociatedEvent.h
new file mode 100644
index 0000000..aa33c59
--- /dev/null
+++ b/nexus/SupplicantAssociatedEvent.h
@@ -0,0 +1,34 @@
+/*
+ * 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 _SupplicantAssociatedEvent_H
+#define _SupplicantAssociatedEvent_H
+
+#include "SupplicantEvent.h"
+
+class SupplicantAssociatedEvent : public SupplicantEvent {
+ char *mBssid;
+ char *mSsid;
+ int mFreq;
+
+public:
+ SupplicantAssociatedEvent(int level, char *event, size_t len);
+ virtual ~SupplicantAssociatedEvent();
+
+ const char *getBssid() { return mBssid; }
+};
+
+#endif
diff --git a/nexus/SupplicantAssociatingEvent.cpp b/nexus/SupplicantAssociatingEvent.cpp
new file mode 100644
index 0000000..c6e9fe3
--- /dev/null
+++ b/nexus/SupplicantAssociatingEvent.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+
+#define LOG_TAG "SupplicantAssociatingEvent"
+#include <cutils/log.h>
+
+#include "SupplicantAssociatingEvent.h"
+
+SupplicantAssociatingEvent::SupplicantAssociatingEvent(int level, char *event,
+ size_t len) :
+ SupplicantEvent(SupplicantEvent::EVENT_ASSOCIATING,
+ level) {
+ char *p = event;
+
+ mBssid = NULL;
+ mSsid = NULL;
+ mFreq = -1;
+
+ // SSID 'default'
+ // OR
+ // "00:13:46:40:40:aa (SSID='default' freq=2437 MHz)"
+
+ if (strncmp(event, "SSID", 4)) {
+ mBssid = (char *) malloc(18);
+ strncpy(mBssid, p, 17);
+ mBssid[17] = '\0';
+ p += 25;
+
+ // "00:13:46:40:40:aa (SSID='default' freq=2437 MHz)"
+ // ^
+ // p
+ char *q = index(p, '\'');
+ if (!q) {
+ LOGE("Unable to decode SSID (p = {%s})\n", p);
+ return;
+ }
+ mSsid = (char *) malloc((q - p) +1);
+ strncpy(mSsid, p, q-p);
+ mSsid[q-p] = '\0';
+
+ p = q + 7;
+
+ // "00:13:46:40:40:aa (SSID='default' freq=2437 MHz)"
+ // ^
+ // p
+ if (!(q = index(p, ' '))) {
+ LOGE("Unable to decode frequency\n");
+ return;
+ }
+ *q = '\0';
+ mFreq = atoi(p);
+ } else {
+ p+= 6;
+
+ // SSID 'default'
+ // ^
+ // p
+
+ char *q = index(p, '\'');
+ if (!q) {
+ LOGE("Unable to decode SSID (p = {%s})\n", p);
+ return;
+ }
+ mSsid = (char *) malloc((q - p) +1);
+ strncpy(mSsid, p, q-p);
+ mSsid[q-p] = '\0';
+ }
+}
+
+SupplicantAssociatingEvent::SupplicantAssociatingEvent(const char *bssid,
+ const char *ssid,
+ int freq) :
+ SupplicantEvent(SupplicantEvent::EVENT_ASSOCIATING, -1) {
+ mBssid = strdup(bssid);
+ mSsid= strdup(ssid);
+ mFreq = freq;
+}
+
+SupplicantAssociatingEvent::~SupplicantAssociatingEvent() {
+ if (mBssid)
+ free(mBssid);
+ if (mSsid)
+ free(mSsid);
+}
+
diff --git a/nexus/SupplicantAssociatingEvent.h b/nexus/SupplicantAssociatingEvent.h
new file mode 100644
index 0000000..d3a4d5c
--- /dev/null
+++ b/nexus/SupplicantAssociatingEvent.h
@@ -0,0 +1,37 @@
+/*
+ * 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 _SupplicantAssociatingEvent_H
+#define _SupplicantAssociatingEvent_H
+
+#include "SupplicantEvent.h"
+
+class SupplicantAssociatingEvent : public SupplicantEvent {
+ char *mBssid;
+ char *mSsid;
+ int mFreq;
+
+public:
+ SupplicantAssociatingEvent(int level, char *event, size_t len);
+ SupplicantAssociatingEvent(const char *bssid, const char *ssid, int freq);
+ virtual ~SupplicantAssociatingEvent();
+
+ const char *getBssid() { return mBssid; }
+ const char *getSsid() { return mSsid; }
+ int getFreq() { return mFreq;}
+};
+
+#endif
diff --git a/nexus/SupplicantConnectedEvent.cpp b/nexus/SupplicantConnectedEvent.cpp
new file mode 100644
index 0000000..e58bab2
--- /dev/null
+++ b/nexus/SupplicantConnectedEvent.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SupplicantConnectedEvent"
+#include <cutils/log.h>
+
+#include "SupplicantConnectedEvent.h"
+
+SupplicantConnectedEvent::SupplicantConnectedEvent(int level, char *event,
+ size_t len) :
+ SupplicantEvent(SupplicantEvent::EVENT_CONNECTED,
+ level) {
+ char *p;
+
+ // "- Connection to 00:13:46:40:40:aa completed (auth) [id=1 id_str=], 89"
+
+ if ((p = index(event + 2, ' ')) && (++p = index(p, ' '))) {
+ mBssid = (char *) malloc(18);
+ strncpy(mBssid, ++p, 17);
+ mBssid[17] = '\0';
+
+ // "- Connection to 00:13:46:40:40:aa completed (auth) [id=1 id_str=], 89"
+ // ^
+ // p
+
+ if ((p = index(p, ' ')) && ((++p = index(p, ' ')))) {
+ if (!strncmp(++p, "(auth)", 6))
+ mReassociated = false;
+ else
+ mReassociated = true;
+ } else
+ LOGE("Unable to decode re-assocation");
+ } else
+ LOGE("Unable to decode event");
+}
+
+SupplicantConnectedEvent::SupplicantConnectedEvent(const char *bssid,
+ bool reassocated) :
+ SupplicantEvent(SupplicantEvent::EVENT_CONNECTED, -1) {
+ mBssid = strdup(bssid);
+ mReassociated = reassocated;
+}
+
+SupplicantConnectedEvent::~SupplicantConnectedEvent() {
+ if (mBssid)
+ free(mBssid);
+}
+
diff --git a/nexus/SupplicantConnectedEvent.h b/nexus/SupplicantConnectedEvent.h
new file mode 100644
index 0000000..03e9842
--- /dev/null
+++ b/nexus/SupplicantConnectedEvent.h
@@ -0,0 +1,36 @@
+/*
+ * 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 _SupplicantConnectedEvent_H
+#define _SupplicantConnectedEvent_H
+
+#include "SupplicantEvent.h"
+
+class SupplicantConnectedEvent : public SupplicantEvent {
+private:
+ char *mBssid;
+ bool mReassociated;
+
+public:
+ SupplicantConnectedEvent(int level, char *event, size_t len);
+ SupplicantConnectedEvent(const char *bssid, bool reassicated);
+ virtual ~SupplicantConnectedEvent();
+
+ const char *getBssid() { return mBssid; }
+ bool getReassociated() { return mReassociated; }
+};
+
+#endif
diff --git a/nexus/SupplicantConnectionTimeoutEvent.cpp b/nexus/SupplicantConnectionTimeoutEvent.cpp
new file mode 100644
index 0000000..8b8a7d7
--- /dev/null
+++ b/nexus/SupplicantConnectionTimeoutEvent.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SupplicantConnectionTimeoutEvent"
+#include <cutils/log.h>
+
+#include "SupplicantConnectionTimeoutEvent.h"
+
+SupplicantConnectionTimeoutEvent::SupplicantConnectionTimeoutEvent(int level, char *event,
+ size_t len) :
+ SupplicantEvent(SupplicantEvent::EVENT_CONNECTIONTIMEOUT,
+ level) {
+ // 00:13:46:40:40:aa timed out.'
+ mBssid = (char *) malloc(18);
+ strncpy(mBssid, event, 17);
+ mBssid[17] = '\0';
+}
+
+SupplicantConnectionTimeoutEvent::~SupplicantConnectionTimeoutEvent() {
+ if (mBssid)
+ free(mBssid);
+}
+
diff --git a/nexus/SupplicantConnectionTimeoutEvent.h b/nexus/SupplicantConnectionTimeoutEvent.h
new file mode 100644
index 0000000..0d2606d
--- /dev/null
+++ b/nexus/SupplicantConnectionTimeoutEvent.h
@@ -0,0 +1,34 @@
+/*
+ * 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 _SupplicantConnectionTimeoutEvent_H
+#define _SupplicantConnectionTimeoutEvent_H
+
+#include "SupplicantEvent.h"
+
+class SupplicantConnectionTimeoutEvent : public SupplicantEvent {
+private:
+ char *mBssid;
+ bool mReassociated;
+
+public:
+ SupplicantConnectionTimeoutEvent(int level, char *event, size_t len);
+ virtual ~SupplicantConnectionTimeoutEvent();
+
+ const char *getBssid() { return mBssid; }
+};
+
+#endif
diff --git a/nexus/SupplicantDisconnectedEvent.cpp b/nexus/SupplicantDisconnectedEvent.cpp
new file mode 100644
index 0000000..11e499d
--- /dev/null
+++ b/nexus/SupplicantDisconnectedEvent.cpp
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SupplicantDisconnectedEvent"
+#include <cutils/log.h>
+
+#include "SupplicantDisconnectedEvent.h"
+
+SupplicantDisconnectedEvent::SupplicantDisconnectedEvent(int level, char *event,
+ size_t len) :
+ SupplicantEvent(SupplicantEvent::EVENT_DISCONNECTED,
+ level) {
+}
+
+SupplicantDisconnectedEvent::SupplicantDisconnectedEvent() :
+ SupplicantEvent(SupplicantEvent::EVENT_DISCONNECTED, -1) {
+}
+
+SupplicantDisconnectedEvent::~SupplicantDisconnectedEvent() {
+}
diff --git a/nexus/SupplicantDisconnectedEvent.h b/nexus/SupplicantDisconnectedEvent.h
new file mode 100644
index 0000000..c09ec62
--- /dev/null
+++ b/nexus/SupplicantDisconnectedEvent.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 _SupplicantDisconnectedEvent_H
+#define _SupplicantDisconnectedEvent_H
+
+#include "SupplicantEvent.h"
+
+class SupplicantDisconnectedEvent : public SupplicantEvent {
+
+public:
+ SupplicantDisconnectedEvent(int level, char *event, size_t len);
+ SupplicantDisconnectedEvent();
+ virtual ~SupplicantDisconnectedEvent();
+};
+
+#endif
diff --git a/nexus/SupplicantEvent.cpp b/nexus/SupplicantEvent.cpp
new file mode 100644
index 0000000..faf7b45
--- /dev/null
+++ b/nexus/SupplicantEvent.cpp
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+
+#define LOG_TAG "SupplicantEvent"
+#include <cutils/log.h>
+
+#include "SupplicantEvent.h"
+
+#include "libwpa_client/wpa_ctrl.h"
+
+SupplicantEvent::SupplicantEvent(int type, int level) {
+ mType = type;
+ mLevel = level;
+}
diff --git a/nexus/SupplicantEvent.h b/nexus/SupplicantEvent.h
new file mode 100644
index 0000000..9d7cbd9
--- /dev/null
+++ b/nexus/SupplicantEvent.h
@@ -0,0 +1,54 @@
+/*
+ * 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 _SUPPLICANT_EVENT_H
+#define _SUPPLICANT_EVENT_H
+
+#include <sys/types.h>
+
+class SupplicantEvent {
+private:
+ int mType;
+ int mLevel;
+
+public:
+ static const int EVENT_UNKNOWN = 0;
+ static const int EVENT_CONNECTED = 1;
+ static const int EVENT_DISCONNECTED = 2;
+ static const int EVENT_TERMINATING = 3;
+ static const int EVENT_PASSWORD_CHANGED = 4;
+ static const int EVENT_EAP_NOTIFICATION = 5;
+ static const int EVENT_EAP_STARTED = 6;
+ static const int EVENT_EAP_METHOD = 7;
+ static const int EVENT_EAP_SUCCESS = 8;
+ static const int EVENT_EAP_FAILURE = 9;
+ static const int EVENT_SCAN_RESULTS = 10;
+ static const int EVENT_STATE_CHANGE = 11;
+ static const int EVENT_LINK_SPEED = 12;
+ static const int EVENT_DRIVER_STATE = 13;
+ static const int EVENT_ASSOCIATING = 14;
+ static const int EVENT_ASSOCIATED = 15;
+ static const int EVENT_CONNECTIONTIMEOUT = 16;
+
+public:
+ SupplicantEvent(int type, int level);
+ virtual ~SupplicantEvent() {}
+
+ int getType() { return mType; }
+ int getLevel() { return mLevel; }
+};
+
+#endif
diff --git a/nexus/SupplicantEventFactory.cpp b/nexus/SupplicantEventFactory.cpp
new file mode 100644
index 0000000..8695aca
--- /dev/null
+++ b/nexus/SupplicantEventFactory.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+
+#define LOG_TAG "SupplicantEventFactory"
+#include <cutils/log.h>
+
+#include "SupplicantEvent.h"
+#include "SupplicantEventFactory.h"
+#include "SupplicantAssociatingEvent.h"
+#include "SupplicantAssociatedEvent.h"
+#include "SupplicantConnectedEvent.h"
+#include "SupplicantStateChangeEvent.h"
+#include "SupplicantScanResultsEvent.h"
+#include "SupplicantConnectionTimeoutEvent.h"
+#include "SupplicantDisconnectedEvent.h"
+#if 0
+#include "SupplicantTerminatingEvent.h"
+#include "SupplicantPasswordChangedEvent.h"
+#include "SupplicantEapNotificationEvent.h"
+#include "SupplicantEapStartedEvent.h"
+#include "SupplicantEapMethodEvent.h"
+#include "SupplicantEapSuccessEvent.h"
+#include "SupplicantEapFailureEvent.h"
+#include "SupplicantLinkSpeedEvent.h"
+#include "SupplicantDriverStateEvent.h"
+#endif
+
+#include "libwpa_client/wpa_ctrl.h"
+
+SupplicantEventFactory::SupplicantEventFactory() {
+}
+
+SupplicantEvent *SupplicantEventFactory::createEvent(char *event, size_t len) {
+ int level = 0;
+
+ if (event[0] == '<') {
+ char *match = strchr(event, '>');
+ if (match) {
+ char tmp[16];
+
+ strncpy(tmp, &event[1], (match - event));
+ level = atoi(tmp);
+ event += (match - event) + 1;
+ } else
+ LOGW("Unclosed level brace in event");
+ } else
+ LOGW("No level specified in event");
+
+ /*
+ * <N>CTRL-EVENT-XXX
+ * ^
+ * +---- event
+ */
+
+ if (!strncmp(event, "Authentication with ", 20)) {
+ if (!strcmp(event + strlen(event) - strlen(" timed out."),
+ " timed out.")) {
+ return new SupplicantConnectionTimeoutEvent(level,
+ event + 20,
+ len);
+ } else
+ return NULL;
+
+ } else if (!strncmp(event, "Associated with ", 16))
+ return new SupplicantAssociatedEvent(level, event + 16, len);
+ else if (!strncmp(event, "Trying to associate with ", 25))
+ return new SupplicantAssociatingEvent(level, event + 25, len);
+ else if (!strncmp(event, WPA_EVENT_CONNECTED, strlen(WPA_EVENT_CONNECTED))) {
+ return new SupplicantConnectedEvent(level,
+ event + strlen(WPA_EVENT_CONNECTED),
+ len);
+ } else if (!strncmp(event, WPA_EVENT_SCAN_RESULTS, strlen(WPA_EVENT_SCAN_RESULTS))) {
+ return new SupplicantScanResultsEvent(level,
+ event + strlen(WPA_EVENT_SCAN_RESULTS),
+ len);
+ } else if (!strncmp(event, WPA_EVENT_STATE_CHANGE, strlen(WPA_EVENT_STATE_CHANGE))) {
+ return new SupplicantStateChangeEvent(level,
+ event + strlen(WPA_EVENT_STATE_CHANGE),
+ len);
+ }
+ else if (!strncmp(event, WPA_EVENT_DISCONNECTED, strlen(WPA_EVENT_DISCONNECTED)))
+ return new SupplicantDisconnectedEvent(level, event, len);
+#if 0
+ else if (!strncmp(event, WPA_EVENT_TERMINATING, strlen(WPA_EVENT_TERMINATING)))
+ return new SupplicantTerminatingEvent(event, len);
+ else if (!strncmp(event, WPA_EVENT_PASSWORD_CHANGED, strlen(WPA_EVENT_PASSWORD_CHANGED)))
+ return new SupplicantPasswordChangedEvent(event, len);
+ else if (!strncmp(event, WPA_EVENT_EAP_NOTIFICATION, strlen(WPA_EVENT_EAP_NOTIFICATION)))
+ return new SupplicantEapNotificationEvent(event, len);
+ else if (!strncmp(event, WPA_EVENT_EAP_STARTED, strlen(WPA_EVENT_EAP_STARTED)))
+ return new SupplicantEapStartedEvent(event, len);
+ else if (!strncmp(event, WPA_EVENT_EAP_METHOD, strlen(WPA_EVENT_EAP_METHOD)))
+ return new SupplicantEapMethodEvent(event, len);
+ else if (!strncmp(event, WPA_EVENT_EAP_SUCCESS, strlen(WPA_EVENT_EAP_SUCCESS)))
+ return new SupplicantEapSuccessEvent(event, len);
+ else if (!strncmp(event, WPA_EVENT_EAP_FAILURE, strlen(WPA_EVENT_EAP_FAILURE)))
+ return new SupplicantEapFailureEvent(event, len);
+ else if (!strncmp(event, WPA_EVENT_LINK_SPEED, strlen(WPA_EVENT_LINK_SPEED)))
+ return new SupplicantLinkSpeedEvent(event, len);
+ else if (!strncmp(event, WPA_EVENT_DRIVER_STATE, strlen(WPA_EVENT_DRIVER_STATE)))
+ return new SupplicantDriverStateEvent(event, len);
+#endif
+ return NULL;
+}
diff --git a/nexus/SupplicantEventFactory.h b/nexus/SupplicantEventFactory.h
new file mode 100644
index 0000000..22e5707
--- /dev/null
+++ b/nexus/SupplicantEventFactory.h
@@ -0,0 +1,31 @@
+
+/*
+ * 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 _SupplicantEventFactory_H
+#define _SupplicantEventFactory_H
+
+class SupplicantEvent;
+
+class SupplicantEventFactory {
+public:
+ SupplicantEventFactory();
+ virtual ~SupplicantEventFactory() {}
+
+ SupplicantEvent *createEvent(char *event, size_t len);
+};
+
+#endif
diff --git a/nexus/SupplicantListener.cpp b/nexus/SupplicantListener.cpp
new file mode 100644
index 0000000..b91fc02
--- /dev/null
+++ b/nexus/SupplicantListener.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#define LOG_TAG "SupplicantListener"
+#include <cutils/log.h>
+
+#include "libwpa_client/wpa_ctrl.h"
+
+#include "SupplicantListener.h"
+#include "ISupplicantEventHandler.h"
+#include "SupplicantEventFactory.h"
+#include "SupplicantEvent.h"
+#include "SupplicantAssociatingEvent.h"
+#include "SupplicantAssociatedEvent.h"
+#include "SupplicantConnectedEvent.h"
+#include "SupplicantScanResultsEvent.h"
+#include "SupplicantStateChangeEvent.h"
+
+SupplicantListener::SupplicantListener(ISupplicantEventHandler *handlers,
+ struct wpa_ctrl *monitor) :
+ SocketListener(wpa_ctrl_get_fd(monitor), false) {
+ mHandlers = handlers;
+ mMonitor = monitor;
+ mFactory = new SupplicantEventFactory();
+}
+
+bool SupplicantListener::onDataAvailable(SocketClient *cli) {
+ char buf[255];
+ size_t buflen = sizeof(buf);
+ int rc;
+ size_t nread = buflen - 1;
+
+ if ((rc = wpa_ctrl_recv(mMonitor, buf, &nread))) {
+ LOGE("wpa_ctrl_recv failed (%s)", strerror(errno));
+ return false;
+ }
+
+ buf[nread] = '\0';
+ if (!rc && !nread) {
+ LOGD("Received EOF on supplicant socket\n");
+ strncpy(buf, WPA_EVENT_TERMINATING " - signal 0 received", buflen-1);
+ buf[buflen-1] = '\0';
+ return false;
+ }
+
+ SupplicantEvent *evt = mFactory->createEvent(buf, nread);
+
+ if (!evt) {
+ LOGW("Dropping unknown supplicant event '%s'", buf);
+ return true;
+ }
+
+ // Call the appropriate handler
+ if (evt->getType() == SupplicantEvent::EVENT_ASSOCIATING)
+ mHandlers->onAssociatingEvent((SupplicantAssociatingEvent *) evt);
+ else if (evt->getType() == SupplicantEvent::EVENT_ASSOCIATED)
+ mHandlers->onAssociatedEvent((SupplicantAssociatedEvent *) evt);
+ else if (evt->getType() == SupplicantEvent::EVENT_CONNECTED)
+ mHandlers->onConnectedEvent((SupplicantConnectedEvent *) evt);
+ else if (evt->getType() == SupplicantEvent::EVENT_SCAN_RESULTS)
+ mHandlers->onScanResultsEvent((SupplicantScanResultsEvent *) evt);
+ else if (evt->getType() == SupplicantEvent::EVENT_STATE_CHANGE)
+ mHandlers->onStateChangeEvent((SupplicantStateChangeEvent *) evt);
+ else if (evt->getType() == SupplicantEvent::EVENT_CONNECTIONTIMEOUT)
+ mHandlers->onConnectionTimeoutEvent((SupplicantConnectionTimeoutEvent *) evt);
+ else if (evt->getType() == SupplicantEvent::EVENT_DISCONNECTED)
+ mHandlers->onDisconnectedEvent((SupplicantDisconnectedEvent *) evt);
+ else
+ LOGW("Whoops - no handler available for event '%s'\n", buf);
+#if 0
+ else if (evt->getType() == SupplicantEvent::EVENT_TERMINATING)
+ mHandlers->onTerminatingEvent(evt);
+ else if (evt->getType() == SupplicantEvent::EVENT_PASSWORD_CHANGED)
+ mHandlers->onPasswordChangedEvent(evt);
+ else if (evt->getType() == SupplicantEvent::EVENT_EAP_NOTIFICATION)
+ mHandlers->onEapNotificationEvent(evt);
+ else if (evt->getType() == SupplicantEvent::EVENT_EAP_STARTED)
+ mHandlers->onEapStartedEvent(evt);
+ else if (evt->getType() == SupplicantEvent::EVENT_EAP_SUCCESS)
+ mHandlers->onEapSuccessEvent(evt);
+ else if (evt->getType() == SupplicantEvent::EVENT_EAP_FAILURE)
+ mHandlers->onEapFailureEvent(evt);
+ else if (evt->getType() == SupplicantEvent::EVENT_LINK_SPEED)
+ mHandlers->onLinkSpeedEvent(evt);
+ else if (evt->getType() == SupplicantEvent::EVENT_DRIVER_STATE)
+ mHandlers->onDriverStateEvent(evt);
+#endif
+
+ delete evt;
+
+ return true;
+}
diff --git a/nexus/SupplicantListener.h b/nexus/SupplicantListener.h
new file mode 100644
index 0000000..a1da773
--- /dev/null
+++ b/nexus/SupplicantListener.h
@@ -0,0 +1,44 @@
+/*
+ * 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 _SUPPLICANTLISTENER_H__
+#define _SUPPLICANTLISTENER_H__
+
+#include <sysutils/SocketListener.h>
+
+struct wpa_ctrl;
+class Supplicant;
+class SocketClient;
+class ISupplicantEventHandler;
+class SupplicantEventFactory;
+
+class SupplicantListener: public SocketListener {
+ struct wpa_ctrl *mMonitor;
+ ISupplicantEventHandler *mHandlers;
+ SupplicantEventFactory *mFactory;
+
+public:
+ SupplicantListener(ISupplicantEventHandler *handlers,
+ struct wpa_ctrl *monitor);
+ virtual ~SupplicantListener() {}
+
+ struct wpa_ctrl *getMonitor() { return mMonitor; }
+
+protected:
+ virtual bool onDataAvailable(SocketClient *c);
+};
+
+#endif
diff --git a/nexus/SupplicantScanResultsEvent.cpp b/nexus/SupplicantScanResultsEvent.cpp
new file mode 100644
index 0000000..c53adad
--- /dev/null
+++ b/nexus/SupplicantScanResultsEvent.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SupplicantScanResultsEvent"
+#include <cutils/log.h>
+
+#include "SupplicantScanResultsEvent.h"
+
+SupplicantScanResultsEvent::SupplicantScanResultsEvent(int level, char *event,
+ size_t len) :
+ SupplicantEvent(SupplicantEvent::EVENT_SCAN_RESULTS,
+ level) {
+}
+
+SupplicantScanResultsEvent::SupplicantScanResultsEvent() :
+ SupplicantEvent(SupplicantEvent::EVENT_SCAN_RESULTS, -1) {
+}
+
+SupplicantScanResultsEvent::~SupplicantScanResultsEvent() {
+}
+
diff --git a/nexus/SupplicantScanResultsEvent.h b/nexus/SupplicantScanResultsEvent.h
new file mode 100644
index 0000000..5f82041
--- /dev/null
+++ b/nexus/SupplicantScanResultsEvent.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 _SupplicantScanResultsEvent_H
+#define _SupplicantScanResultsEvent_H
+
+#include "SupplicantEvent.h"
+
+class SupplicantScanResultsEvent : public SupplicantEvent {
+
+public:
+ SupplicantScanResultsEvent(int level, char *event, size_t len);
+ SupplicantScanResultsEvent();
+ virtual ~SupplicantScanResultsEvent();
+};
+
+#endif
diff --git a/nexus/SupplicantState.cpp b/nexus/SupplicantState.cpp
new file mode 100644
index 0000000..a16d370
--- /dev/null
+++ b/nexus/SupplicantState.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+
+#define LOG_TAG "SupplicantState"
+#include <cutils/log.h>
+
+#include "SupplicantState.h"
+
+char *SupplicantState::toString(int val, char *buffer, int max) {
+ if (val == SupplicantState::UNKNOWN)
+ strncpy(buffer, "Unknown", max);
+ else if (val == SupplicantState::DISCONNECTED)
+ strncpy(buffer, "Disconnected", max);
+ else if (val == SupplicantState::INACTIVE)
+ strncpy(buffer, "Inactive", max);
+ else if (val == SupplicantState::SCANNING)
+ strncpy(buffer, "Scanning", max);
+ else if (val == SupplicantState::ASSOCIATING)
+ strncpy(buffer, "Associating", max);
+ else if (val == SupplicantState::ASSOCIATED)
+ strncpy(buffer, "Associated", max);
+ else if (val == SupplicantState::FOURWAY_HANDSHAKE)
+ strncpy(buffer, "Fourway Handshake", max);
+ else if (val == SupplicantState::GROUP_HANDSHAKE)
+ strncpy(buffer, "Group Handshake", max);
+ else if (val == SupplicantState::COMPLETED)
+ strncpy(buffer, "Completed", max);
+ else if (val == SupplicantState::IDLE)
+ strncpy(buffer, "Idle", max);
+ else
+ strncpy(buffer, "(internal error)", max);
+
+ return buffer;
+}
diff --git a/nexus/SupplicantState.h b/nexus/SupplicantState.h
new file mode 100644
index 0000000..6882f0c
--- /dev/null
+++ b/nexus/SupplicantState.h
@@ -0,0 +1,36 @@
+/*
+ * 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 _SUPPLICANT_STATE_H
+#define _SUPPLICANT_STATE_H
+
+class SupplicantState {
+public:
+ static const int UNKNOWN = -1;
+ static const int DISCONNECTED = 0;
+ static const int INACTIVE = 1;
+ static const int SCANNING = 2;
+ static const int ASSOCIATING = 3;
+ static const int ASSOCIATED = 4;
+ static const int FOURWAY_HANDSHAKE = 5;
+ static const int GROUP_HANDSHAKE = 6;
+ static const int COMPLETED = 7;
+ static const int IDLE = 8;
+
+ static char *toString(int val, char *buffer, int max);
+};
+
+#endif
diff --git a/nexus/SupplicantStateChangeEvent.cpp b/nexus/SupplicantStateChangeEvent.cpp
new file mode 100644
index 0000000..cf0b9da
--- /dev/null
+++ b/nexus/SupplicantStateChangeEvent.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+
+#define LOG_TAG "SupplicantStateChangeEvent"
+#include <cutils/log.h>
+
+#include "SupplicantStateChangeEvent.h"
+
+SupplicantStateChangeEvent::SupplicantStateChangeEvent(int level, char *event,
+ size_t len) :
+ SupplicantEvent(SupplicantEvent::EVENT_STATE_CHANGE,
+ level) {
+ // XXX: move this stuff into a static creation method
+ char *p = index(event, ' ');
+ if (!p) {
+ LOGW("Bad event '%s'\n", event);
+ return;
+ }
+
+ mState = atoi(p + strlen("state=") + 1);
+}
+
+SupplicantStateChangeEvent::SupplicantStateChangeEvent(int state) :
+ SupplicantEvent(SupplicantEvent::EVENT_STATE_CHANGE, -1) {
+ mState = state;
+}
+
+SupplicantStateChangeEvent::~SupplicantStateChangeEvent() {
+}
+
diff --git a/nexus/SupplicantStateChangeEvent.h b/nexus/SupplicantStateChangeEvent.h
new file mode 100644
index 0000000..77bff65
--- /dev/null
+++ b/nexus/SupplicantStateChangeEvent.h
@@ -0,0 +1,34 @@
+/*
+ * 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 _SupplicantStateChangeEvent_H
+#define _SupplicantStateChangeEvent_H
+
+#include "SupplicantEvent.h"
+
+class SupplicantStateChangeEvent : public SupplicantEvent {
+private:
+ int mState;
+
+public:
+ SupplicantStateChangeEvent(int level, char *event, size_t len);
+ SupplicantStateChangeEvent(int state);
+ virtual ~SupplicantStateChangeEvent();
+
+ int getState() { return mState; }
+};
+
+#endif
diff --git a/nexus/SupplicantStatus.cpp b/nexus/SupplicantStatus.cpp
new file mode 100644
index 0000000..b3c560a
--- /dev/null
+++ b/nexus/SupplicantStatus.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_TAG "SupplicantStatus"
+#include <cutils/log.h>
+
+#include "SupplicantStatus.h"
+#include "SupplicantState.h"
+
+SupplicantStatus::SupplicantStatus() {
+ mWpaState = SupplicantState::UNKNOWN;
+ mId = -1;
+ mBssid = NULL;
+ mSsid = NULL;
+}
+
+SupplicantStatus::SupplicantStatus(int state, int id, char *bssid, char *ssid) :
+ mWpaState(state), mId(id), mBssid(bssid), mSsid(ssid) {
+
+LOGD("state %d, id %d, bssid %p, ssid %p\n", mWpaState, mId, mBssid, mSsid);
+}
+
+SupplicantStatus::~SupplicantStatus() {
+ if (mBssid)
+ free(mBssid);
+ if (mSsid)
+ free(mSsid);
+}
+
+SupplicantStatus *SupplicantStatus::createStatus(char *data, int len) {
+ char *bssid = NULL;
+ char *ssid = NULL;
+ int id = -1;
+ int state = SupplicantState::UNKNOWN;
+
+ char *next = data;
+ char *line;
+ while((line = strsep(&next, "\n"))) {
+ char *line_next = line;
+ char *token = strsep(&line_next, "=");
+ char *value = strsep(&line_next, "=");
+ if (!strcmp(token, "bssid"))
+ bssid = strdup(value);
+ else if (!strcmp(token, "ssid"))
+ ssid = strdup(value);
+ else if (!strcmp(token, "id"))
+ id = atoi(value);
+ else if (!strcmp(token, "wpa_state")) {
+ if (!strcmp(value, "DISCONNECTED"))
+ state = SupplicantState::DISCONNECTED;
+ else if (!strcmp(value, "INACTIVE"))
+ state = SupplicantState::INACTIVE;
+ else if (!strcmp(value, "SCANNING"))
+ state = SupplicantState::SCANNING;
+ else if (!strcmp(value, "ASSOCIATING"))
+ state = SupplicantState::ASSOCIATING;
+ else if (!strcmp(value, "ASSOCIATED"))
+ state = SupplicantState::ASSOCIATED;
+ else if (!strcmp(value, "FOURWAY_HANDSHAKE"))
+ state = SupplicantState::FOURWAY_HANDSHAKE;
+ else if (!strcmp(value, "GROUP_HANDSHAKE"))
+ state = SupplicantState::GROUP_HANDSHAKE;
+ else if (!strcmp(value, "COMPLETED"))
+ state = SupplicantState::COMPLETED;
+ else if (!strcmp(value, "IDLE"))
+ state = SupplicantState::IDLE;
+ else
+ LOGE("Unknown supplicant state '%s'", value);
+ } else
+ LOGD("Ignoring unsupported status token '%s'", token);
+ }
+
+ return new SupplicantStatus(state, id, bssid, ssid);
+
+}
diff --git a/nexus/SupplicantStatus.h b/nexus/SupplicantStatus.h
new file mode 100644
index 0000000..ef01841
--- /dev/null
+++ b/nexus/SupplicantStatus.h
@@ -0,0 +1,42 @@
+/*
+ * 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 _SupplicantStatus_H
+#define _SupplicantStatus_H
+
+class SupplicantStatus {
+private:
+ int mWpaState;
+ int mId;
+ char *mBssid;
+ char *mSsid;
+
+private:
+ SupplicantStatus();
+ SupplicantStatus(int state, int id, char *bssid, char *ssid);
+
+public:
+ virtual ~SupplicantStatus();
+ static SupplicantStatus *createStatus(char *data, int len);
+
+ int getWpaState() { return mWpaState; }
+ int getId() { return mId; }
+ const char *getBssid() { return mBssid; }
+ const char *getSsid() { return mSsid; }
+
+};
+
+#endif
diff --git a/nexus/TiwlanEventListener.cpp b/nexus/TiwlanEventListener.cpp
new file mode 100644
index 0000000..15e6930
--- /dev/null
+++ b/nexus/TiwlanEventListener.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#define LOG_TAG "TiwlanEventListener"
+#include <cutils/log.h>
+
+#include "TiwlanEventListener.h"
+
+TiwlanEventListener::TiwlanEventListener(int socket) :
+ SocketListener(socket, false) {
+}
+
+bool TiwlanEventListener::onDataAvailable(SocketClient *cli) {
+ struct ipc_ev_data *data;
+
+ if (!(data = (struct ipc_ev_data *) malloc(sizeof(struct ipc_ev_data)))) {
+ LOGE("Failed to allocate packet (out of memory)");
+ return true;
+ }
+
+ if (recv(cli->getSocket(), data, sizeof(struct ipc_ev_data), 0) < 0) {
+ LOGE("recv failed (%s)", strerror(errno));
+ goto out;
+ }
+
+ if (data->event_type == IPC_EVENT_LINK_SPEED) {
+ uint32_t *spd = (uint32_t *) data->buffer;
+ *spd /= 2;
+// LOGD("Link speed = %u MB/s", *spd);
+ } else if (data->event_type == IPC_EVENT_LOW_SNR) {
+ LOGW("Low signal/noise ratio");
+ } else if (data->event_type == IPC_EVENT_LOW_RSSI) {
+ LOGW("Low RSSI");
+ } else {
+// LOGD("Dropping unhandled driver event %d", data->event_type);
+ }
+
+ // TODO: Tell WifiController about the event
+out:
+ free(data);
+ return true;
+}
diff --git a/nexus/TiwlanEventListener.h b/nexus/TiwlanEventListener.h
new file mode 100644
index 0000000..052d6b1
--- /dev/null
+++ b/nexus/TiwlanEventListener.h
@@ -0,0 +1,55 @@
+/*
+ * 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 _TIWLAN_EVENT_LISTENER_H__
+#define _TIWLAN_EVENT_LISTENER_H__
+
+#include <sysutils/SocketListener.h>
+
+struct wpa_ctrl;
+class SocketClient;
+class ITiwlanEventHandler;
+class TiwlanEventFactory;
+
+class TiwlanEventListener: public SocketListener {
+
+public:
+ TiwlanEventListener(int sock);
+ virtual ~TiwlanEventListener() {}
+
+protected:
+ virtual bool onDataAvailable(SocketClient *c);
+};
+
+// TODO: Move all this crap into a factory
+#define TI_DRIVER_MSG_PORT 9001
+
+#define IPC_EVENT_LINK_SPEED 2
+#define IPC_EVENT_LOW_SNR 13
+#define IPC_EVENT_LOW_RSSI 14
+
+struct ipc_ev_data {
+ uint32_t event_type;
+ void *event_id;
+ uint32_t process_id;
+ uint32_t delivery_type;
+ uint32_t user_param;
+ void *event_callback;
+ uint32_t bufferSize;
+ uint8_t buffer[2048];
+};
+
+#endif
diff --git a/nexus/TiwlanWifiController.cpp b/nexus/TiwlanWifiController.cpp
new file mode 100644
index 0000000..61535c3
--- /dev/null
+++ b/nexus/TiwlanWifiController.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <cutils/properties.h>
+#define LOG_TAG "TiwlanWifiController"
+#include <cutils/log.h>
+
+#include "PropertyManager.h"
+#include "TiwlanWifiController.h"
+#include "TiwlanEventListener.h"
+
+#define DRIVER_PROP_NAME "wlan.driver.status"
+
+extern "C" int sched_yield(void);
+
+TiwlanWifiController::TiwlanWifiController(PropertyManager *propmngr,
+ IControllerHandler *handlers,
+ char *modpath, char *modname,
+ char *modargs) :
+ WifiController(propmngr, handlers, modpath, modname,
+ modargs) {
+ mEventListener = NULL;
+ mListenerSock = -1;
+}
+
+int TiwlanWifiController::powerUp() {
+ return 0; // Powerup is currently done when the driver is loaded
+}
+
+int TiwlanWifiController::powerDown() {
+ if (mEventListener) {
+ delete mEventListener;
+ close(mListenerSock);
+ mListenerSock = -1;
+ mEventListener = NULL;
+ }
+
+ return 0; // Powerdown is currently done when the driver is unloaded
+}
+
+bool TiwlanWifiController::isPoweredUp() {
+ return isKernelModuleLoaded(getModuleName());
+}
+
+int TiwlanWifiController::loadFirmware() {
+ char driver_status[PROPERTY_VALUE_MAX];
+ int count = 100;
+
+ property_set("ctl.start", "wlan_loader");
+ sched_yield();
+
+ // Wait for driver to be ready
+ while (count-- > 0) {
+ if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
+ if (!strcmp(driver_status, "ok")) {
+ LOGD("Firmware loaded OK");
+
+ if (startDriverEventListener()) {
+ LOGW("Failed to start driver event listener");
+ }
+
+ return 0;
+ } else if (!strcmp(DRIVER_PROP_NAME, "failed")) {
+ LOGE("Firmware load failed");
+ return -1;
+ }
+ }
+ usleep(200000);
+ }
+ property_set(DRIVER_PROP_NAME, "timeout");
+ LOGE("Firmware load timed out");
+ return -1;
+}
+
+int TiwlanWifiController::startDriverEventListener() {
+ struct sockaddr_in addr;
+ int s;
+
+ if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ return -1;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_port = htons(TI_DRIVER_MSG_PORT);
+
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ close(s);
+ return -1;
+ }
+
+ mEventListener = new TiwlanEventListener(s);
+
+ if (mEventListener->startListener()) {
+ LOGE("Error starting driver listener (%s)", strerror(errno));
+ delete mEventListener;
+ mEventListener = NULL;
+ close(s);
+ return -1;
+ }
+ mListenerSock = s;
+ return 0;
+}
+
+bool TiwlanWifiController::isFirmwareLoaded() {
+ // Always load the firmware
+ return false;
+}
diff --git a/nexus/TiwlanWifiController.h b/nexus/TiwlanWifiController.h
new file mode 100644
index 0000000..583be71
--- /dev/null
+++ b/nexus/TiwlanWifiController.h
@@ -0,0 +1,43 @@
+/*
+ * 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 _TIWLAN_WIFI_CONTROLLER_H
+#define _TIWLAN_WIFI_CONTROLLER_H
+
+#include "PropertyManager.h"
+#include "WifiController.h"
+
+class IControllerHandler;
+class TiwlanEventListener;
+
+class TiwlanWifiController : public WifiController {
+ int mListenerSock;
+ TiwlanEventListener *mEventListener;
+
+public:
+ TiwlanWifiController(PropertyManager *propmngr, IControllerHandler *handlers, char *modpath, char *modname, char *modargs);
+ virtual ~TiwlanWifiController() {}
+
+ virtual int powerUp();
+ virtual int powerDown();
+ virtual bool isPoweredUp();
+ virtual int loadFirmware();
+ virtual bool isFirmwareLoaded();
+
+private:
+ int startDriverEventListener();
+};
+#endif
diff --git a/nexus/VpnController.cpp b/nexus/VpnController.cpp
new file mode 100644
index 0000000..add4dc3
--- /dev/null
+++ b/nexus/VpnController.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "PropertyManager.h"
+#include "VpnController.h"
+
+VpnController::VpnController(PropertyManager *propmngr,
+ IControllerHandler *handlers) :
+ Controller("VPN", propmngr, handlers) {
+ mEnabled = false;
+}
+
+int VpnController::start() {
+ mPropMngr->registerProperty("vpn.enabled", this);
+ return 0;
+}
+
+int VpnController::stop() {
+ mPropMngr->unregisterProperty("vpn.enabled");
+ return 0;
+}
+
+int VpnController::set(const char *name, const char *value) {
+ if (!strcmp(name, "vpn.enabled")) {
+ int en = atoi(value);
+ int rc;
+
+ if (en == mEnabled)
+ return 0;
+ rc = (en ? enable() : disable());
+
+ if (!rc) {
+ mEnabled = en;
+ if (en)
+ mPropMngr->unregisterProperty("vpn.gateway");
+ else
+ mPropMngr->unregisterProperty("vpn.gateway");
+ }
+ return rc;
+ } if (!strcmp(name, "vpn.gateway")) {
+ if (!inet_aton(value, &mVpnGateway)) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+ }
+
+ return Controller::set(name, value);
+}
+
+const char *VpnController::get(const char *name, char *buffer, size_t maxsize) {
+ if (!strcmp(name, "vpn.enabled")) {
+ snprintf(buffer, maxsize, "%d", mEnabled);
+ return buffer;
+ } if (!strcmp(name, "vpn.gateway")) {
+ snprintf(buffer, maxsize, "%s", inet_ntoa(mVpnGateway));
+ return buffer;
+ }
+
+ return Controller::get(name, buffer, maxsize);
+}
diff --git a/nexus/VpnController.h b/nexus/VpnController.h
new file mode 100644
index 0000000..1af4d9f
--- /dev/null
+++ b/nexus/VpnController.h
@@ -0,0 +1,49 @@
+/*
+ * 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 _VPN_CONTROLLER_H
+#define _VPN_CONTROLLER_H
+
+#include <netinet/in.h>
+
+#include "Controller.h"
+
+class IControllerHandler;
+
+class VpnController : public Controller {
+ bool mEnabled;
+ /*
+ * Gateway of the VPN server to connect to
+ */
+ struct in_addr mVpnGateway;
+
+public:
+ VpnController(PropertyManager *propmngr, IControllerHandler *handlers);
+ virtual ~VpnController() {}
+
+ virtual int start();
+ virtual int stop();
+
+ virtual int set(const char *name, const char *value);
+ virtual const char *get(const char *name, char *buffer, size_t maxlen);
+
+protected:
+ virtual int enable() = 0;
+ virtual int disable() = 0;
+
+};
+
+#endif
diff --git a/nexus/WifiController.cpp b/nexus/WifiController.cpp
new file mode 100644
index 0000000..ef5ecae
--- /dev/null
+++ b/nexus/WifiController.cpp
@@ -0,0 +1,413 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define LOG_TAG "WifiController"
+#include <cutils/log.h>
+
+#include "Supplicant.h"
+#include "WifiController.h"
+#include "WifiScanner.h"
+#include "NetworkManager.h"
+#include "ErrorCode.h"
+#include "WifiNetwork.h"
+#include "ISupplicantEventHandler.h"
+#include "SupplicantState.h"
+#include "SupplicantStatus.h"
+#include "SupplicantAssociatingEvent.h"
+#include "SupplicantAssociatedEvent.h"
+#include "SupplicantConnectedEvent.h"
+#include "SupplicantScanResultsEvent.h"
+#include "SupplicantStateChangeEvent.h"
+#include "SupplicantConnectionTimeoutEvent.h"
+#include "SupplicantDisconnectedEvent.h"
+
+WifiController::WifiController(PropertyManager *mPropMngr,
+ IControllerHandler *handlers,
+ char *modpath, char *modname, char *modargs) :
+ Controller("WIFI", mPropMngr, handlers) {
+ strncpy(mModulePath, modpath, sizeof(mModulePath));
+ strncpy(mModuleName, modname, sizeof(mModuleName));
+ strncpy(mModuleArgs, modargs, sizeof(mModuleArgs));
+
+ mLatestScanResults = new ScanResultCollection();
+ pthread_mutex_init(&mLatestScanResultsLock, NULL);
+
+ mSupplicant = new Supplicant(this, this);
+ mScanner = new WifiScanner(mSupplicant, 10);
+ mCurrentScanMode = 0;
+
+ mEnabled = false;
+
+ mSupplicantState = SupplicantState::UNKNOWN;
+}
+
+int WifiController::start() {
+ mPropMngr->registerProperty("wifi.enabled", this);
+ return 0;
+}
+
+int WifiController::stop() {
+ mPropMngr->unregisterProperty("wifi.enabled");
+ return 0;
+}
+
+int WifiController::enable() {
+
+ if (!isPoweredUp()) {
+ LOGI("Powering up");
+ sendStatusBroadcast("Powering up WiFi hardware");
+ if (powerUp()) {
+ LOGE("Powerup failed (%s)", strerror(errno));
+ return -1;
+ }
+ }
+
+ if (mModuleName[0] != '\0' && !isKernelModuleLoaded(mModuleName)) {
+ LOGI("Loading driver");
+ sendStatusBroadcast("Loading WiFi driver");
+ if (loadKernelModule(mModulePath, mModuleArgs)) {
+ LOGE("Kernel module load failed (%s)", strerror(errno));
+ goto out_powerdown;
+ }
+ }
+
+ if (!isFirmwareLoaded()) {
+ LOGI("Loading firmware");
+ sendStatusBroadcast("Loading WiFI firmware");
+ if (loadFirmware()) {
+ LOGE("Firmware load failed (%s)", strerror(errno));
+ goto out_powerdown;
+ }
+ }
+
+ if (!mSupplicant->isStarted()) {
+ LOGI("Starting WPA Supplicant");
+ sendStatusBroadcast("Starting WPA Supplicant");
+ if (mSupplicant->start()) {
+ LOGE("Supplicant start failed (%s)", strerror(errno));
+ goto out_unloadmodule;
+ }
+ }
+
+ if (Controller::bindInterface(mSupplicant->getInterfaceName())) {
+ LOGE("Error binding interface (%s)", strerror(errno));
+ goto out_unloadmodule;
+ }
+
+ if (mSupplicant->refreshNetworkList())
+ LOGW("Error getting list of networks (%s)", strerror(errno));
+
+ mPropMngr->registerProperty("wifi.supplicant.state", this);
+ mPropMngr->registerProperty("wifi.scanmode", this);
+ mPropMngr->registerProperty("wifi.interface", this);
+
+ LOGI("Enabled successfully");
+ return 0;
+
+out_unloadmodule:
+ if (mModuleName[0] != '\0' && !isKernelModuleLoaded(mModuleName)) {
+ if (unloadKernelModule(mModuleName)) {
+ LOGE("Unable to unload module after failure!");
+ }
+ }
+
+out_powerdown:
+ if (powerDown()) {
+ LOGE("Unable to powerdown after failure!");
+ }
+ return -1;
+}
+
+void WifiController::sendStatusBroadcast(const char *msg) {
+ NetworkManager::Instance()->
+ getBroadcaster()->
+ sendBroadcast(ErrorCode::UnsolicitedInformational, msg, false);
+}
+
+int WifiController::disable() {
+
+ mPropMngr->unregisterProperty("wifi.scanmode");
+ mPropMngr->unregisterProperty("wifi.supplicant.state");
+ mPropMngr->unregisterProperty("wifi.scanmode");
+
+ if (mSupplicant->isStarted()) {
+ sendStatusBroadcast("Stopping WPA Supplicant");
+ if (mSupplicant->stop()) {
+ LOGE("Supplicant stop failed (%s)", strerror(errno));
+ return -1;
+ }
+ } else
+ LOGW("disable(): Supplicant not running?");
+
+ if (mModuleName[0] != '\0' && isKernelModuleLoaded(mModuleName)) {
+ sendStatusBroadcast("Unloading WiFi driver");
+ if (unloadKernelModule(mModuleName)) {
+ LOGE("Unable to unload module (%s)", strerror(errno));
+ return -1;
+ }
+ }
+
+ if (isPoweredUp()) {
+ sendStatusBroadcast("Powering down WiFi hardware");
+ if (powerDown()) {
+ LOGE("Powerdown failed (%s)", strerror(errno));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int WifiController::loadFirmware() {
+ return 0;
+}
+
+int WifiController::setScanMode(uint32_t mode) {
+ int rc = 0;
+
+ if (mCurrentScanMode == mode)
+ return 0;
+
+ if (!(mode & SCAN_ENABLE_MASK)) {
+ if (mCurrentScanMode & SCAN_REPEAT_MASK)
+ mScanner->stop();
+ } else if (mode & SCAN_REPEAT_MASK)
+ rc = mScanner->start(mode & SCAN_ACTIVE_MASK);
+ else
+ rc = mSupplicant->triggerScan(mode & SCAN_ACTIVE_MASK);
+
+ mCurrentScanMode = mode;
+ return rc;
+}
+
+WifiNetwork *WifiController::createNetwork() {
+ WifiNetwork *wn = mSupplicant->createNetwork();
+ return wn;
+}
+
+int WifiController::removeNetwork(int networkId) {
+ WifiNetwork *wn = mSupplicant->lookupNetwork(networkId);
+
+ if (!wn)
+ return -1;
+ return mSupplicant->removeNetwork(wn);
+}
+
+ScanResultCollection *WifiController::createScanResults() {
+ ScanResultCollection *d = new ScanResultCollection();
+ ScanResultCollection::iterator i;
+
+ pthread_mutex_lock(&mLatestScanResultsLock);
+ for (i = mLatestScanResults->begin(); i != mLatestScanResults->end(); ++i)
+ d->push_back((*i)->clone());
+
+ pthread_mutex_unlock(&mLatestScanResultsLock);
+ return d;
+}
+
+WifiNetworkCollection *WifiController::createNetworkList() {
+ return mSupplicant->createNetworkList();
+}
+
+int WifiController::set(const char *name, const char *value) {
+ int rc;
+
+ if (!strcmp(name, "wifi.enabled")) {
+ int en = atoi(value);
+
+ if (en == mEnabled)
+ return 0;
+ rc = (en ? enable() : disable());
+ if (!rc)
+ mEnabled = en;
+ } else if (!strcmp(name, "wifi.interface")) {
+ errno = EROFS;
+ return -1;
+ } else if (!strcmp(name, "wifi.scanmode"))
+ return setScanMode((uint32_t) strtoul(value, NULL, 0));
+ else if (!strcmp(name, "wifi.supplicant.state")) {
+ errno = EROFS;
+ return -1;
+ } else
+ return Controller::set(name, value);
+ return rc;
+}
+
+const char *WifiController::get(const char *name, char *buffer, size_t maxsize) {
+
+ if (!strcmp(name, "wifi.enabled"))
+ snprintf(buffer, maxsize, "%d", mEnabled);
+ else if (!strcmp(name, "wifi.interface")) {
+ snprintf(buffer, maxsize, "%s",
+ (getBoundInterface() ? getBoundInterface() : "none"));
+ } else if (!strcmp(name, "wifi.scanmode"))
+ snprintf(buffer, maxsize, "0x%.8x", mCurrentScanMode);
+ else if (!strcmp(name, "wifi.supplicant.state"))
+ return SupplicantState::toString(mSupplicantState, buffer, maxsize);
+ else
+ return Controller::get(name, buffer, maxsize);
+
+ return buffer;
+}
+
+void WifiController::onAssociatingEvent(SupplicantAssociatingEvent *evt) {
+ LOGD("onAssociatingEvent(%s, %s, %d)",
+ (evt->getBssid() ? evt->getBssid() : "n/a"),
+ (evt->getSsid() ? evt->getSsid() : "n/a"),
+ evt->getFreq());
+}
+
+void WifiController::onAssociatedEvent(SupplicantAssociatedEvent *evt) {
+ LOGD("onAssociatedEvent(%s)", evt->getBssid());
+}
+
+void WifiController::onConnectedEvent(SupplicantConnectedEvent *evt) {
+ LOGD("onConnectedEvent(%s, %d)", evt->getBssid(), evt->getReassociated());
+ SupplicantStatus *ss = mSupplicant->getStatus();
+ WifiNetwork *wn;
+
+ if (ss->getWpaState() != SupplicantState::COMPLETED) {
+ char tmp[32];
+
+ LOGW("onConnected() with SupplicantState = %s!",
+ SupplicantState::toString(ss->getWpaState(), tmp,
+ sizeof(tmp)));
+ return;
+ }
+
+ if (ss->getId() == -1) {
+ LOGW("onConnected() with id = -1!");
+ return;
+ }
+
+ if (!(wn = mSupplicant->lookupNetwork(ss->getId()))) {
+ LOGW("Error looking up connected network id %d (%s)",
+ ss->getId(), strerror(errno));
+ return;
+ }
+
+ delete ss;
+ mHandlers->onInterfaceConnected(this, wn->getIfaceCfg());
+}
+
+void WifiController::onScanResultsEvent(SupplicantScanResultsEvent *evt) {
+ char *reply;
+
+ if (!(reply = (char *) malloc(4096))) {
+ LOGE("Out of memory");
+ return;
+ }
+
+ size_t len = 4096;
+
+ if (mSupplicant->sendCommand("SCAN_RESULTS", reply, &len)) {
+ LOGW("onScanResultsEvent: Error getting scan results (%s)",
+ strerror(errno));
+ free(reply);
+ return;
+ }
+
+ pthread_mutex_lock(&mLatestScanResultsLock);
+ if (!mLatestScanResults->empty()) {
+ ScanResultCollection::iterator i;
+
+ for (i = mLatestScanResults->begin();
+ i !=mLatestScanResults->end(); ++i) {
+ delete *i;
+ }
+ mLatestScanResults->clear();
+ }
+
+ char *linep;
+ char *linep_next = NULL;
+
+ if (!strtok_r(reply, "\n", &linep_next)) {
+ free(reply);
+ pthread_mutex_unlock(&mLatestScanResultsLock);
+ return;
+ }
+
+ while((linep = strtok_r(NULL, "\n", &linep_next)))
+ mLatestScanResults->push_back(new ScanResult(linep));
+
+ char *tmp;
+ asprintf(&tmp, "Scan results ready (%d)", mLatestScanResults->size());
+ NetworkManager::Instance()->getBroadcaster()->
+ sendBroadcast(ErrorCode::UnsolicitedInformational, tmp, false);
+ free(tmp);
+ pthread_mutex_unlock(&mLatestScanResultsLock);
+ free(reply);
+}
+
+void WifiController::onStateChangeEvent(SupplicantStateChangeEvent *evt) {
+ char tmp[32];
+ char tmp2[32];
+
+ LOGD("onStateChangeEvent(%s -> %s)",
+ SupplicantState::toString(mSupplicantState, tmp, sizeof(tmp)),
+ SupplicantState::toString(evt->getState(), tmp2, sizeof(tmp2)));
+
+ mSupplicantState = evt->getState();
+}
+
+void WifiController::onConnectionTimeoutEvent(SupplicantConnectionTimeoutEvent *evt) {
+ LOGD("onConnectionTimeoutEvent(%s)", evt->getBssid());
+}
+
+void WifiController::onDisconnectedEvent(SupplicantDisconnectedEvent *evt) {
+ mHandlers->onInterfaceDisconnected(this, getBoundInterface());
+}
+
+#if 0
+void WifiController::onTerminatingEvent(SupplicantEvent *evt) {
+ LOGD("onTerminatingEvent(%s)", evt->getEvent());
+}
+
+void WifiController::onPasswordChangedEvent(SupplicantEvent *evt) {
+ LOGD("onPasswordChangedEvent(%s)", evt->getEvent());
+}
+
+void WifiController::onEapNotificationEvent(SupplicantEvent *evt) {
+ LOGD("onEapNotificationEvent(%s)", evt->getEvent());
+}
+
+void WifiController::onEapStartedEvent(SupplicantEvent *evt) {
+ LOGD("onEapStartedEvent(%s)", evt->getEvent());
+}
+
+void WifiController::onEapMethodEvent(SupplicantEvent *evt) {
+ LOGD("onEapMethodEvent(%s)", evt->getEvent());
+}
+
+void WifiController::onEapSuccessEvent(SupplicantEvent *evt) {
+ LOGD("onEapSuccessEvent(%s)", evt->getEvent());
+}
+
+void WifiController::onEapFailureEvent(SupplicantEvent *evt) {
+ LOGD("onEapFailureEvent(%s)", evt->getEvent());
+}
+
+void WifiController::onLinkSpeedEvent(SupplicantEvent *evt) {
+ LOGD("onLinkSpeedEvent(%s)", evt->getEvent());
+}
+
+void WifiController::onDriverStateEvent(SupplicantEvent *evt) {
+ LOGD("onDriverStateEvent(%s)", evt->getEvent());
+}
+#endif
diff --git a/nexus/WifiController.h b/nexus/WifiController.h
new file mode 100644
index 0000000..c61d97a
--- /dev/null
+++ b/nexus/WifiController.h
@@ -0,0 +1,123 @@
+/*
+ * 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 _WIFI_CONTROLLER_H
+#define _WIFI_CONTROLLER_H
+
+#include <sys/types.h>
+
+#include "Controller.h"
+#include "ScanResult.h"
+#include "WifiNetwork.h"
+#include "ISupplicantEventHandler.h"
+
+class NetInterface;
+class Supplicant;
+class WifiScanner;
+class SupplicantAssociatingEvent;
+class SupplicantAssociatedEvent;
+class SupplicantConnectedEvent;
+class SupplicantScanResultsEvent;
+class SupplicantStateChangeEvent;
+class SupplicantDisconnectedEvent;
+
+class WifiController : public Controller, public ISupplicantEventHandler {
+public:
+ static const uint32_t SCAN_ENABLE_MASK = 0x01;
+ static const uint32_t SCAN_ACTIVE_MASK = 0x02;
+ static const uint32_t SCAN_REPEAT_MASK = 0x04;
+
+ static const uint32_t SCANMODE_NONE = 0;
+ static const uint32_t SCANMODE_PASSIVE_ONESHOT = SCAN_ENABLE_MASK;
+ static const uint32_t SCANMODE_PASSIVE_CONTINUOUS = SCAN_ENABLE_MASK | SCAN_REPEAT_MASK;
+ static const uint32_t SCANMODE_ACTIVE_ONESHOT = SCAN_ENABLE_MASK | SCAN_ACTIVE_MASK;
+ static const uint32_t SCANMODE_ACTIVE_CONTINUOUS = SCAN_ENABLE_MASK | SCAN_ACTIVE_MASK | SCAN_REPEAT_MASK;
+
+private:
+ Supplicant *mSupplicant;
+ char mModulePath[255];
+ char mModuleName[64];
+ char mModuleArgs[255];
+
+ uint32_t mCurrentScanMode;
+ WifiScanner *mScanner;
+ int mSupplicantState;
+
+ ScanResultCollection *mLatestScanResults;
+ pthread_mutex_t mLatestScanResultsLock;
+
+ bool mEnabled;
+
+public:
+ WifiController(PropertyManager *propmngr, IControllerHandler *handlers, char *modpath, char *modname, char *modargs);
+ virtual ~WifiController() {}
+
+ int start();
+ int stop();
+
+ WifiNetwork *createNetwork();
+ int removeNetwork(int networkId);
+ WifiNetworkCollection *createNetworkList();
+
+ virtual int set(const char *name, const char *value);
+ virtual const char *get(const char *name, char *buffer, size_t maxlen);
+
+ ScanResultCollection *createScanResults();
+
+ char *getModulePath() { return mModulePath; }
+ char *getModuleName() { return mModuleName; }
+ char *getModuleArgs() { return mModuleArgs; }
+
+ Supplicant *getSupplicant() { return mSupplicant; }
+
+protected:
+ // Move this crap into a 'driver'
+ virtual int powerUp() = 0;
+ virtual int powerDown() = 0;
+ virtual int loadFirmware();
+
+ virtual bool isFirmwareLoaded() = 0;
+ virtual bool isPoweredUp() = 0;
+
+private:
+ void sendStatusBroadcast(const char *msg);
+ int setScanMode(uint32_t mode);
+ int enable();
+ int disable();
+
+ // ISupplicantEventHandler methods
+ virtual void onAssociatingEvent(SupplicantAssociatingEvent *evt);
+ virtual void onAssociatedEvent(SupplicantAssociatedEvent *evt);
+ virtual void onConnectedEvent(SupplicantConnectedEvent *evt);
+ virtual void onScanResultsEvent(SupplicantScanResultsEvent *evt);
+ virtual void onStateChangeEvent(SupplicantStateChangeEvent *evt);
+ virtual void onConnectionTimeoutEvent(SupplicantConnectionTimeoutEvent *evt);
+ virtual void onDisconnectedEvent(SupplicantDisconnectedEvent *evt);
+#if 0
+ virtual void onTerminatingEvent(SupplicantEvent *evt);
+ virtual void onPasswordChangedEvent(SupplicantEvent *evt);
+ virtual void onEapNotificationEvent(SupplicantEvent *evt);
+ virtual void onEapStartedEvent(SupplicantEvent *evt);
+ virtual void onEapMethodEvent(SupplicantEvent *evt);
+ virtual void onEapSuccessEvent(SupplicantEvent *evt);
+ virtual void onEapFailureEvent(SupplicantEvent *evt);
+ virtual void onLinkSpeedEvent(SupplicantEvent *evt);
+ virtual void onDriverStateEvent(SupplicantEvent *evt);
+#endif
+
+};
+
+#endif
diff --git a/nexus/WifiNetwork.cpp b/nexus/WifiNetwork.cpp
new file mode 100644
index 0000000..7059bd0
--- /dev/null
+++ b/nexus/WifiNetwork.cpp
@@ -0,0 +1,636 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#define LOG_TAG "WifiNetwork"
+#include <cutils/log.h>
+
+#include "NetworkManager.h"
+#include "WifiNetwork.h"
+#include "Supplicant.h"
+#include "WifiController.h"
+#include "InterfaceConfig.h"
+
+const char *WifiNetwork::PropertyNames[] = { "ssid", "bssid", "psk", "wepkey.1",
+ "wepkey.2", "wepkey.3", "wepkey.4",
+ "defkeyidx", "pri", "hiddenssid",
+ "AllowedKeyManagement",
+ "AllowedProtocols",
+ "AllowedAuthAlgorithms",
+ "AllowedPairwiseCiphers",
+ "AllowedGroupCiphers",
+ "enabled", '\0' };
+WifiNetwork::WifiNetwork() {
+ // This is private to restrict copy constructors
+}
+
+WifiNetwork::WifiNetwork(WifiController *c, Supplicant *suppl, const char *data) {
+ mController = c;
+ mSuppl = suppl;
+
+ char *tmp = strdup(data);
+ char *next = tmp;
+ char *id;
+ char *ssid;
+ char *bssid;
+ char *flags;
+
+ if (!(id = strsep(&next, "\t")))
+ LOGE("Failed to extract network id");
+ if (!(ssid = strsep(&next, "\t")))
+ LOGE("Failed to extract ssid");
+ if (!(bssid = strsep(&next, "\t")))
+ LOGE("Failed to extract bssid");
+ if (!(flags = strsep(&next, "\t")))
+ LOGE("Failed to extract flags");
+
+ // LOGD("id '%s', ssid '%s', bssid '%s', flags '%s'", id, ssid, bssid,
+ // flags ? flags :"null");
+
+ if (id)
+ mNetid = atoi(id);
+ if (ssid)
+ mSsid = strdup(ssid);
+ if (bssid)
+ mBssid = strdup(bssid);
+
+ mPsk = NULL;
+ memset(mWepKeys, 0, sizeof(mWepKeys));
+ mDefaultKeyIndex = -1;
+ mPriority = -1;
+ mHiddenSsid = NULL;
+ mAllowedKeyManagement = KeyManagementMask::UNKNOWN;
+ mAllowedProtocols = 0;
+ mAllowedAuthAlgorithms = 0;
+ mAllowedPairwiseCiphers = 0;
+ mAllowedGroupCiphers = 0;
+ mEnabled = true;
+
+ if (flags && flags[0] != '\0') {
+ if (!strcmp(flags, "[DISABLED]"))
+ mEnabled = false;
+ else
+ LOGW("Unsupported flags '%s'", flags);
+ }
+
+ char *tmp2;
+ asprintf(&tmp2, "wifi.net.%d", mNetid);
+ mIfaceCfg = new InterfaceConfig(tmp2);
+ free(tmp2);
+ free(tmp);
+}
+
+WifiNetwork::WifiNetwork(WifiController *c, Supplicant *suppl, int networkId) {
+ mController = c;
+ mSuppl = suppl;
+ mNetid = networkId;
+ mSsid = NULL;
+ mBssid = NULL;
+ mPsk = NULL;
+ memset(mWepKeys, 0, sizeof(mWepKeys));
+ mDefaultKeyIndex = -1;
+ mPriority = -1;
+ mHiddenSsid = NULL;
+ mAllowedKeyManagement = 0;
+ mAllowedProtocols = 0;
+ mAllowedAuthAlgorithms = 0;
+ mAllowedPairwiseCiphers = 0;
+ mAllowedGroupCiphers = 0;
+ mEnabled = false;
+
+ char *tmp2;
+ asprintf(&tmp2, "wifi.net.%d", mNetid);
+ mIfaceCfg = new InterfaceConfig(tmp2);
+ free(tmp2);
+}
+
+WifiNetwork *WifiNetwork::clone() {
+ WifiNetwork *r = new WifiNetwork();
+
+ r->mSuppl = mSuppl;
+ r->mNetid = mNetid;
+
+ if (mSsid)
+ r->mSsid = strdup(mSsid);
+ if (mBssid)
+ r->mBssid = strdup(mBssid);
+ if (mPsk)
+ r->mPsk = strdup(mPsk);
+
+ r->mController = mController;
+ memcpy(r->mWepKeys, mWepKeys, sizeof(mWepKeys));
+ r->mDefaultKeyIndex = mDefaultKeyIndex;
+ r->mPriority = mPriority;
+ if (mHiddenSsid)
+ r->mHiddenSsid = strdup(mHiddenSsid);
+ r->mAllowedKeyManagement = mAllowedKeyManagement;
+ r->mAllowedProtocols = mAllowedProtocols;
+ r->mAllowedAuthAlgorithms = mAllowedAuthAlgorithms;
+ r->mAllowedPairwiseCiphers = mAllowedPairwiseCiphers;
+ r->mAllowedGroupCiphers = mAllowedGroupCiphers;
+ return r;
+}
+
+WifiNetwork::~WifiNetwork() {
+ if (mSsid)
+ free(mSsid);
+ if (mBssid)
+ free(mBssid);
+ if (mPsk)
+ free(mPsk);
+ for (int i = 0; i < 4; i++) {
+ if (mWepKeys[i])
+ free(mWepKeys[i]);
+ }
+
+ if (mHiddenSsid)
+ free(mHiddenSsid);
+ if (mIfaceCfg)
+ delete(mIfaceCfg);
+}
+
+int WifiNetwork::refresh() {
+ char buffer[255];
+ size_t len;
+
+ len = sizeof(buffer);
+ if (mSuppl->getNetworkVar(mNetid, "psk", buffer, len))
+ mPsk = strdup(buffer);
+
+ for (int i = 0; i < 4; i++) {
+ char *name;
+
+ asprintf(&name, "wep_key%d", i);
+ len = sizeof(buffer);
+ if (mSuppl->getNetworkVar(mNetid, name, buffer, len))
+ mWepKeys[i] = strdup(buffer);
+ free(name);
+ }
+
+ len = sizeof(buffer);
+ if (mSuppl->getNetworkVar(mNetid, "wep_tx_keyidx", buffer, len))
+ mDefaultKeyIndex = atoi(buffer);
+
+ len = sizeof(buffer);
+ if (mSuppl->getNetworkVar(mNetid, "priority", buffer, len))
+ mPriority = atoi(buffer);
+
+ len = sizeof(buffer);
+ if (mSuppl->getNetworkVar(mNetid, "scan_ssid", buffer, len))
+ mHiddenSsid = strdup(buffer);
+
+ len = sizeof(buffer);
+ if (mSuppl->getNetworkVar(mNetid, "key_mgmt", buffer, len)) {
+ if (!strcmp(buffer, "NONE"))
+ setAllowedKeyManagement(KeyManagementMask::NONE);
+ else if (index(buffer, ' ')) {
+ char *next = buffer;
+ char *token;
+ uint32_t mask = 0;
+
+ while((token = strsep(&next, " "))) {
+ if (!strcmp(token, "WPA-PSK"))
+ mask |= KeyManagementMask::WPA_PSK;
+ else if (!strcmp(token, "WPA-EAP"))
+ mask |= KeyManagementMask::WPA_EAP;
+ else if (!strcmp(token, "IEE8021X"))
+ mask |= KeyManagementMask::IEEE8021X;
+ else
+ LOGW("Unsupported key management scheme '%s'" , token);
+ }
+ setAllowedKeyManagement(mask);
+ } else
+ LOGE("Unsupported key management '%s'", buffer);
+ }
+
+ len = sizeof(buffer);
+ if (mSuppl->getNetworkVar(mNetid, "proto", buffer, len)) {
+ // TODO
+ }
+
+ len = sizeof(buffer);
+ if (mSuppl->getNetworkVar(mNetid, "auth_alg", buffer, len)) {
+ // TODO
+ }
+
+ len = sizeof(buffer);
+ if (mSuppl->getNetworkVar(mNetid, "pairwise", buffer, len)) {
+ // TODO
+ }
+
+ len = sizeof(buffer);
+ if (mSuppl->getNetworkVar(mNetid, "group", buffer, len)) {
+ // TODO
+ }
+
+ return 0;
+out_err:
+ LOGE("Refresh failed (%s)",strerror(errno));
+ return -1;
+}
+
+int WifiNetwork::set(const char *name, const char *value) {
+ char *n_tmp = strdup(name + strlen("wifi.net."));
+ char *n_next = n_tmp;
+ char *n_local;
+ char *n_rest;
+ int rc = 0;
+
+ if (!strsep(&n_next, ".")) // skip net id
+ goto out_inval;
+
+ if (!(n_local = strsep(&n_next, ".")))
+ goto out_inval;
+
+ n_rest = n_next;
+
+// LOGD("set(): var '%s'(%s / %s) = %s", name, n_local, n_rest, value);
+ if (!strcasecmp(n_local, "enabled"))
+ rc = setEnabled(atoi(value));
+ else if (!strcmp(n_local, "ssid"))
+ rc = setSsid(value);
+ else if (!strcasecmp(n_local, "bssid"))
+ rc = setBssid(value);
+ else if (!strcasecmp(n_local, "psk"))
+ rc = setPsk(value);
+ else if (!strcasecmp(n_local, "wepkey"))
+ rc = setWepKey(atoi(n_rest) -1, value);
+ else if (!strcasecmp(n_local, "defkeyidx"))
+ rc = setDefaultKeyIndex(atoi(value));
+ else if (!strcasecmp(n_local, "pri"))
+ rc = setPriority(atoi(value));
+ else if (!strcasecmp(n_local, "hiddenssid"))
+ rc = setHiddenSsid(value);
+ else if (!strcasecmp(n_local, "AllowedKeyManagement")) {
+ uint32_t mask = 0;
+ bool none = false;
+ char *v_tmp = strdup(value);
+ char *v_next = v_tmp;
+ char *v_token;
+
+ while((v_token = strsep(&v_next, " "))) {
+ if (!strcasecmp(v_token, "NONE")) {
+ mask = KeyManagementMask::NONE;
+ none = true;
+ } else if (!none) {
+ if (!strcasecmp(v_token, "WPA_PSK"))
+ mask |= KeyManagementMask::WPA_PSK;
+ else if (!strcasecmp(v_token, "WPA_EAP"))
+ mask |= KeyManagementMask::WPA_EAP;
+ else if (!strcasecmp(v_token, "IEEE8021X"))
+ mask |= KeyManagementMask::IEEE8021X;
+ else {
+ errno = EINVAL;
+ rc = -1;
+ free(v_tmp);
+ goto out;
+ }
+ } else {
+ errno = EINVAL;
+ rc = -1;
+ free(v_tmp);
+ goto out;
+ }
+ }
+ free(v_tmp);
+ } else if (!strcasecmp(n_local, "AllowedProtocols")) {
+ // TODO
+ } else if (!strcasecmp(n_local, "AllowedPairwiseCiphers")) {
+ // TODO
+ } else if (!strcasecmp(n_local, "AllowedAuthAlgorithms")) {
+ // TODO
+ } else if (!strcasecmp(n_local, "AllowedGroupCiphers")) {
+ // TODO
+ } else {
+ errno = ENOENT;
+ free(n_tmp);
+ return -1;
+ }
+
+out:
+ free(n_tmp);
+ return rc;
+
+out_inval:
+ errno = EINVAL;
+ free(n_tmp);
+ return -1;
+}
+
+const char *WifiNetwork::get(const char *name, char *buffer, size_t maxsize) {
+ char *n_tmp = strdup(name + strlen("wifi.net."));
+ char *n_next = n_tmp;
+ char *n_local;
+ char fc[64];
+ char rc[128];
+
+ if (!strsep(&n_next, ".")) // skip net id
+ goto out_inval;
+
+ if (!(n_local = strsep(&n_next, ".")))
+ goto out_inval;
+
+
+ strncpy(fc, n_local, sizeof(fc));
+ rc[0] = '\0';
+ if (n_next)
+ strncpy(rc, n_next, sizeof(rc));
+
+ free(n_tmp);
+
+ if (!strcasecmp(fc, "enabled"))
+ snprintf(buffer, maxsize, "%d", getEnabled());
+ else if (!strcasecmp(fc, "ssid")) {
+ strncpy(buffer,
+ getSsid() ? getSsid() : "none",
+ maxsize);
+ } else if (!strcasecmp(fc, "bssid")) {
+ strncpy(buffer,
+ getBssid() ? getBssid() : "none",
+ maxsize);
+ } else if (!strcasecmp(fc, "psk")) {
+ strncpy(buffer,
+ getPsk() ? getPsk() : "none",
+ maxsize);
+ } else if (!strcasecmp(fc, "wepkey")) {
+ strncpy(buffer,
+ getWepKey(atoi(rc)-1) ? getWepKey(atoi(rc)-1) : "none",
+ maxsize);
+ } else if (!strcasecmp(fc, "defkeyidx"))
+ snprintf(buffer, maxsize, "%d", getDefaultKeyIndex());
+ else if (!strcasecmp(fc, "pri"))
+ snprintf(buffer, maxsize, "%d", getPriority());
+ else if (!strcasecmp(fc, "AllowedKeyManagement")) {
+ if (getAllowedKeyManagement() == KeyManagementMask::NONE)
+ strncpy(buffer, "NONE", maxsize);
+ else {
+ char tmp[80] = { '\0' };
+
+ if (getAllowedKeyManagement() & KeyManagementMask::WPA_PSK)
+ strcat(tmp, "WPA_PSK ");
+ if (getAllowedKeyManagement() & KeyManagementMask::WPA_EAP)
+ strcat(tmp, "WPA_EAP ");
+ if (getAllowedKeyManagement() & KeyManagementMask::IEEE8021X)
+ strcat(tmp, "IEEE8021X");
+ if (tmp[0] == '\0') {
+ strncpy(buffer, "(internal error)", maxsize);
+ errno = ENOENT;
+ return NULL;
+ }
+ if (tmp[strlen(tmp)] == ' ')
+ tmp[strlen(tmp)] = '\0';
+
+ strncpy(buffer, tmp, maxsize);
+ }
+ } else if (!strcasecmp(fc, "hiddenssid")) {
+ strncpy(buffer,
+ getHiddenSsid() ? getHiddenSsid() : "none",
+ maxsize);
+ } else {
+ strncpy(buffer, "(internal error)", maxsize);
+ errno = ENOENT;
+ return NULL;
+ }
+
+ return buffer;
+
+out_inval:
+ errno = EINVAL;
+ free(n_tmp);
+ return NULL;
+}
+
+int WifiNetwork::setSsid(const char *ssid) {
+ if (mSuppl->setNetworkVar(mNetid, "ssid", ssid))
+ return -1;
+ if (mSsid)
+ free(mSsid);
+ mSsid = strdup(ssid);
+ return 0;
+}
+
+int WifiNetwork::setBssid(const char *bssid) {
+ if (mSuppl->setNetworkVar(mNetid, "bssid", bssid))
+ return -1;
+ if (mBssid)
+ free(mBssid);
+ mBssid = strdup(bssid);
+ return 0;
+}
+
+int WifiNetwork::setPsk(const char *psk) {
+ if (mSuppl->setNetworkVar(mNetid, "psk", psk))
+ return -1;
+
+ if (mPsk)
+ free(mPsk);
+ mPsk = strdup(psk);
+ return 0;
+}
+
+int WifiNetwork::setWepKey(int idx, const char *key) {
+ char *name;
+
+ asprintf(&name, "wep_key%d", idx);
+ int rc = mSuppl->setNetworkVar(mNetid, name, key);
+ free(name);
+
+ if (rc)
+ return -1;
+
+ if (mWepKeys[idx])
+ free(mWepKeys[idx]);
+ mWepKeys[idx] = strdup(key);
+ return 0;
+}
+
+int WifiNetwork::setDefaultKeyIndex(int idx) {
+ char val[16];
+ sprintf(val, "%d", idx);
+ if (mSuppl->setNetworkVar(mNetid, "wep_tx_keyidx", val))
+ return -1;
+
+ mDefaultKeyIndex = idx;
+ return 0;
+}
+
+int WifiNetwork::setPriority(int priority) {
+ char val[16];
+ sprintf(val, "%d", priority);
+ if (mSuppl->setNetworkVar(mNetid, "priority", val))
+ return -1;
+
+ mPriority = priority;
+ return 0;
+}
+
+int WifiNetwork::setHiddenSsid(const char *ssid) {
+ if (mSuppl->setNetworkVar(mNetid, "scan_ssid", ssid))
+ return -1;
+
+ if (mHiddenSsid)
+ free(mHiddenSsid);
+ mHiddenSsid = strdup(ssid);
+ return 0;
+}
+
+int WifiNetwork::setAllowedKeyManagement(uint32_t mask) {
+ char accum[255];
+
+ if (mask == KeyManagementMask::NONE)
+ strcpy(accum, "NONE");
+ else {
+ if (mask & KeyManagementMask::WPA_PSK)
+ strcat(accum, "WPA_PSK ");
+ if (mask & KeyManagementMask::WPA_EAP)
+ strcat(accum, "WPA_EAP ");
+ if (mask & KeyManagementMask::IEEE8021X)
+ strcat(accum, "IEEE8021X ");
+ }
+
+ if (mSuppl->setNetworkVar(mNetid, "key_mgmt", accum))
+ return -1;
+ mAllowedKeyManagement = mask;
+ return 0;
+}
+
+int WifiNetwork::setAllowedProtocols(uint32_t mask) {
+ char accum[255];
+
+ accum[0] = '\0';
+
+ if (mask & SecurityProtocolMask::WPA)
+ strcpy(accum, "WPA ");
+
+ if (mask & SecurityProtocolMask::RSN)
+ strcat(accum, "RSN");
+
+ if (mSuppl->setNetworkVar(mNetid, "proto", accum))
+ return -1;
+ mAllowedProtocols = mask;
+ return 0;
+}
+
+int WifiNetwork::setAllowedAuthAlgorithms(uint32_t mask) {
+ char accum[255];
+
+ accum[0] = '\0';
+
+ if (mask & AuthenticationAlgorithmMask::OPEN)
+ strcpy(accum, "OPEN ");
+
+ if (mask & AuthenticationAlgorithmMask::SHARED)
+ strcat(accum, "SHARED ");
+
+ if (mask & AuthenticationAlgorithmMask::LEAP)
+ strcat(accum, "LEAP ");
+
+ if (mSuppl->setNetworkVar(mNetid, "auth_alg", accum))
+ return -1;
+
+ mAllowedAuthAlgorithms = mask;
+ return 0;
+}
+
+int WifiNetwork::setAllowedPairwiseCiphers(uint32_t mask) {
+ char accum[255];
+
+ if (mask == PairwiseCiphersMask::NONE)
+ strcpy(accum, "NONE");
+ else {
+ if (mask & PairwiseCiphersMask::TKIP)
+ strcat(accum, "TKIP ");
+ if (mask & PairwiseCiphersMask::CCMP)
+ strcat(accum, "CCMP ");
+ }
+
+ if (mSuppl->setNetworkVar(mNetid, "pairwise", accum))
+ return -1;
+
+ mAllowedPairwiseCiphers = mask;
+ return 0;
+}
+
+int WifiNetwork::setAllowedGroupCiphers(uint32_t mask) {
+ char accum[255];
+
+ if (mask & GroupCiphersMask::WEP40)
+ strcat(accum, "WEP40 ");
+ if (mask & GroupCiphersMask::WEP104)
+ strcat(accum, "WEP104 ");
+ if (mask & GroupCiphersMask::TKIP)
+ strcat(accum, "TKIP ");
+ if (mask & GroupCiphersMask::CCMP)
+ strcat(accum, "CCMP ");
+
+ if (mSuppl->setNetworkVar(mNetid, "group", accum))
+ return -1;
+ mAllowedGroupCiphers = mask;
+ return 0;
+}
+
+int WifiNetwork::setEnabled(bool enabled) {
+
+ if (enabled) {
+ if (getPriority() == -1) {
+ LOGE("Cannot enable network when priority is not set");
+ errno = EAGAIN;
+ return -1;
+ }
+ if (getAllowedKeyManagement() == KeyManagementMask::UNKNOWN) {
+ LOGE("Cannot enable network when KeyManagement is not set");
+ errno = EAGAIN;
+ return -1;
+ }
+ }
+
+ if (mSuppl->enableNetwork(mNetid, enabled))
+ return -1;
+
+ mEnabled = enabled;
+ return 0;
+}
+
+int WifiNetwork::registerProperties() {
+ for (const char **p = WifiNetwork::PropertyNames; *p != '\0'; p++) {
+ char *tmp;
+ asprintf(&tmp, "wifi.net.%d.%s", mNetid, *p);
+
+ if (NetworkManager::Instance()->getPropMngr()->registerProperty(tmp,
+ this)) {
+ free(tmp);
+ return -1;
+ }
+ free(tmp);
+ }
+ return 0;
+}
+
+int WifiNetwork::unregisterProperties() {
+ for (const char **p = WifiNetwork::PropertyNames; *p != '\0'; p++) {
+ char *tmp;
+ asprintf(&tmp, "wifi.net.%d.%s", mNetid, *p);
+
+ if (NetworkManager::Instance()->getPropMngr()->unregisterProperty(tmp))
+ LOGW("Unable to remove property '%s' (%s)", tmp, strerror(errno));
+ free(tmp);
+ }
+ return 0;
+}
diff --git a/nexus/WifiNetwork.h b/nexus/WifiNetwork.h
new file mode 100644
index 0000000..c2f5d23
--- /dev/null
+++ b/nexus/WifiNetwork.h
@@ -0,0 +1,212 @@
+/*
+ * 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 _WIFI_NETWORK_H
+#define _WIFI_NETWORK_H
+
+#include <sys/types.h>
+
+#include <utils/List.h>
+
+class KeyManagementMask {
+public:
+ static const uint32_t UNKNOWN = 0;
+ static const uint32_t NONE = 0x01;
+ static const uint32_t WPA_PSK = 0x02;
+ static const uint32_t WPA_EAP = 0x04;
+ static const uint32_t IEEE8021X = 0x08;
+ static const uint32_t ALL = WPA_PSK | WPA_EAP | IEEE8021X;
+};
+
+class SecurityProtocolMask {
+public:
+ static const uint32_t WPA = 0x01;
+ static const uint32_t RSN = 0x02;
+};
+
+class AuthenticationAlgorithmMask {
+public:
+ static const uint32_t OPEN = 0x01;
+ static const uint32_t SHARED = 0x02;
+ static const uint32_t LEAP = 0x04;
+};
+
+class PairwiseCiphersMask {
+public:
+ static const uint32_t NONE = 0x00;
+ static const uint32_t TKIP = 0x01;
+ static const uint32_t CCMP = 0x02;
+};
+
+class GroupCiphersMask {
+public:
+ static const uint32_t WEP40 = 0x01;
+ static const uint32_t WEP104 = 0x02;
+ static const uint32_t TKIP = 0x04;
+ static const uint32_t CCMP = 0x08;
+};
+
+class Supplicant;
+class InterfaceConfig;
+class Controller;
+class WifiController;
+
+#include "IPropertyProvider.h"
+
+class WifiNetwork : public IPropertyProvider{
+public:
+ static const char *PropertyNames[];
+
+private:
+ Supplicant *mSuppl;
+ InterfaceConfig *mIfaceCfg;
+ WifiController *mController;
+
+ /*
+ * Unique network id - normally provided by supplicant
+ */
+ int mNetid;
+
+ /*
+ * The networks' SSID. Can either be an ASCII string,
+ * which must be enclosed in double quotation marks
+ * (ie: "MyNetwork"), or a string of hex digits which
+ * are not enclosed in quotes (ie: 01ab7893)
+ */
+ char *mSsid;
+
+ /*
+ * When set, this entry should only be used
+ * when associating with the AP having the specified
+ * BSSID. The value is a string in the format of an
+ * Ethernet MAC address
+ */
+ char *mBssid;
+
+ /*
+ * Pre-shared key for use with WPA-PSK
+ */
+ char *mPsk;
+
+ /*
+ * Up to four WEP keys. Either in ASCII string enclosed in
+ * double quotes, or a string of hex digits
+ */
+ char *mWepKeys[4];
+
+ /*
+ * Default WEP key index, ranging from 0 -> NUM_WEP_KEYS -1
+ */
+ int mDefaultKeyIndex;
+
+ /*
+ * Priority determines the preference given to a network by
+ * supplicant when choosing an access point with which
+ * to associate
+ */
+ int mPriority;
+
+ /*
+ * This is a network that does not broadcast it's SSID, so an
+ * SSID-specific probe request must be used for scans.
+ */
+ char *mHiddenSsid;
+
+ /*
+ * The set of key management protocols supported by this configuration.
+ */
+ uint32_t mAllowedKeyManagement;
+
+ /*
+ * The set of security protocols supported by this configuration.
+ */
+ uint32_t mAllowedProtocols;
+
+ /*
+ * The set of authentication protocols supported by this configuration.
+ */
+ uint32_t mAllowedAuthAlgorithms;
+
+ /*
+ * The set of pairwise ciphers for WPA supported by this configuration.
+ */
+ uint32_t mAllowedPairwiseCiphers;
+
+ /*
+ * The set of group ciphers for WPA supported by this configuration.
+ */
+ uint32_t mAllowedGroupCiphers;
+
+ /*
+ * Set if this Network is enabled
+ */
+ bool mEnabled;
+
+private:
+ WifiNetwork();
+
+public:
+ WifiNetwork(WifiController *c, Supplicant *suppl, int networkId);
+ WifiNetwork(WifiController *c, Supplicant *suppl, const char *data);
+
+ virtual ~WifiNetwork();
+
+ WifiNetwork *clone();
+ int registerProperties();
+ int unregisterProperties();
+
+ int getNetworkId() { return mNetid; }
+ const char *getSsid() { return mSsid; }
+ const char *getBssid() { return mBssid; }
+ const char *getPsk() { return mPsk; }
+ const char *getWepKey(int idx) { return mWepKeys[idx]; }
+ int getDefaultKeyIndex() { return mDefaultKeyIndex; }
+ int getPriority() { return mPriority; }
+ const char *getHiddenSsid() { return mHiddenSsid; }
+ uint32_t getAllowedKeyManagement() { return mAllowedKeyManagement; }
+ uint32_t getAllowedProtocols() { return mAllowedProtocols; }
+ uint32_t getAllowedAuthAlgorithms() { return mAllowedAuthAlgorithms; }
+ uint32_t getAllowedPairwiseCiphers() { return mAllowedPairwiseCiphers; }
+ uint32_t getAllowedGroupCiphers() { return mAllowedGroupCiphers; }
+ bool getEnabled() { return mEnabled; }
+ Controller *getController() { return (Controller *) mController; }
+
+ int set(const char *name, const char *value);
+ const char *get(const char *name, char *buffer, size_t maxsize);
+
+ InterfaceConfig *getIfaceCfg() { return mIfaceCfg; }
+
+ int setEnabled(bool enabled);
+ int setSsid(const char *ssid);
+ int setBssid(const char *bssid);
+ int setPsk(const char *psk);
+ int setWepKey(int idx, const char *key);
+ int setDefaultKeyIndex(int idx);
+ int setPriority(int pri);
+ int setHiddenSsid(const char *ssid);
+ int setAllowedKeyManagement(uint32_t mask);
+ int setAllowedProtocols(uint32_t mask);
+ int setAllowedAuthAlgorithms(uint32_t mask);
+ int setAllowedPairwiseCiphers(uint32_t mask);
+ int setAllowedGroupCiphers(uint32_t mask);
+
+ // XXX:Should this really be exposed?.. meh
+ int refresh();
+};
+
+typedef android::List<WifiNetwork *> WifiNetworkCollection;
+
+#endif
diff --git a/nexus/WifiScanner.cpp b/nexus/WifiScanner.cpp
new file mode 100644
index 0000000..bdfa497
--- /dev/null
+++ b/nexus/WifiScanner.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <pthread.h>
+
+#define LOG_TAG "WifiScanner"
+#include <cutils/log.h>
+
+#include "WifiScanner.h"
+#include "Supplicant.h"
+
+extern "C" int pthread_cancel(pthread_t thread);
+
+WifiScanner::WifiScanner(Supplicant *suppl, int period) {
+ mSuppl = suppl;
+ mPeriod = period;
+ mActive = false;
+}
+
+int WifiScanner::start(bool active) {
+ mActive = active;
+
+ if(pipe(mCtrlPipe))
+ return -1;
+
+ if (pthread_create(&mThread, NULL, WifiScanner::threadStart, this))
+ return -1;
+ return 0;
+}
+
+void *WifiScanner::threadStart(void *obj) {
+ WifiScanner *me = reinterpret_cast<WifiScanner *>(obj);
+ me->run();
+ pthread_exit(NULL);
+ return NULL;
+}
+
+int WifiScanner::stop() {
+ char c = 0;
+
+ if (write(mCtrlPipe[1], &c, 1) != 1) {
+ LOGE("Error writing to control pipe (%s)", strerror(errno));
+ return -1;
+ }
+
+ void *ret;
+ if (pthread_join(mThread, &ret)) {
+ LOGE("Error joining to scanner thread (%s)", strerror(errno));
+ return -1;
+ }
+
+ close(mCtrlPipe[0]);
+ close(mCtrlPipe[1]);
+ return 0;
+}
+
+void WifiScanner::run() {
+ LOGD("Starting wifi scanner (active = %d)", mActive);
+
+ while(1) {
+ fd_set read_fds;
+ struct timeval to;
+ int rc = 0;
+
+ to.tv_usec = 0;
+ to.tv_sec = mPeriod;
+
+ FD_ZERO(&read_fds);
+ FD_SET(mCtrlPipe[0], &read_fds);
+
+ if (mSuppl->triggerScan(mActive)) {
+ LOGW("Error triggering scan (%s)", strerror(errno));
+ }
+
+ if ((rc = select(mCtrlPipe[0] + 1, &read_fds, NULL, NULL, &to)) < 0) {
+ LOGE("select failed (%s) - sleeping for one scanner period", strerror(errno));
+ sleep(mPeriod);
+ continue;
+ } else if (!rc) {
+ } else if (FD_ISSET(mCtrlPipe[0], &read_fds))
+ break;
+ } // while
+ LOGD("Stopping wifi scanner");
+}
diff --git a/nexus/WifiScanner.h b/nexus/WifiScanner.h
new file mode 100644
index 0000000..92822e9
--- /dev/null
+++ b/nexus/WifiScanner.h
@@ -0,0 +1,47 @@
+/*
+ * 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 _WIFISCANNER_H
+#define _WIFISCANNER_H
+
+#include <pthread.h>
+
+class Supplicant;
+
+class WifiScanner {
+ pthread_t mThread;
+ int mCtrlPipe[2];
+ Supplicant *mSuppl;
+ int mPeriod;
+ bool mActive;
+
+
+public:
+ WifiScanner(Supplicant *suppl, int period);
+ virtual ~WifiScanner() {}
+
+ int getPeriod() { return mPeriod; }
+
+ int start(bool active);
+ int stop();
+
+private:
+ static void *threadStart(void *obj);
+
+ void run();
+};
+
+#endif
diff --git a/nexus/main.cpp b/nexus/main.cpp
new file mode 100644
index 0000000..936d33f
--- /dev/null
+++ b/nexus/main.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+
+#define LOG_TAG "Nexus"
+
+#include "cutils/log.h"
+#include "NetworkManager.h"
+#include "CommandListener.h"
+
+#include "LoopController.h"
+#include "OpenVpnController.h"
+#include "TiwlanWifiController.h"
+
+int main() {
+ LOGI("Nexus version 0.1 firing up");
+
+ CommandListener *cl = new CommandListener();
+
+ NetworkManager *nm;
+ if (!(nm = NetworkManager::Instance())) {
+ LOGE("Unable to create NetworkManager");
+ exit (-1);
+ };
+
+ nm->setBroadcaster((SocketListener *) cl);
+
+ nm->attachController(new LoopController(nm->getPropMngr(), nm));
+ nm->attachController(new TiwlanWifiController(nm->getPropMngr(), nm, "/system/lib/modules/wlan.ko", "wlan", ""));
+// nm->attachController(new AndroidL2TPVpnController(nm->getPropMngr(), nm));
+ nm->attachController(new OpenVpnController(nm->getPropMngr(), nm));
+
+
+ if (NetworkManager::Instance()->run()) {
+ LOGE("Unable to Run NetworkManager (%s)", strerror(errno));
+ exit (1);
+ }
+
+ if (cl->startListener()) {
+ LOGE("Unable to start CommandListener (%s)", strerror(errno));
+ exit (1);
+ }
+
+ // XXX: we'll use the main thread for the NetworkManager eventually
+
+ while(1) {
+ sleep(1000);
+ }
+
+ LOGI("Nexus exiting");
+ exit(0);
+}
diff --git a/nexus/nexctl.c b/nexus/nexctl.c
new file mode 100644
index 0000000..8e1d90c
--- /dev/null
+++ b/nexus/nexctl.c
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include <cutils/sockets.h>
+#include <private/android_filesystem_config.h>
+
+static void usage(char *progname);
+static int do_monitor(int sock, int stop_after_cmd);
+static int do_cmd(int sock, int argc, char **argv);
+
+int main(int argc, char **argv) {
+ int sock;
+
+ if (argc < 2)
+ usage(argv[0]);
+
+ if ((sock = socket_local_client("nexus",
+ ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM)) < 0) {
+ fprintf(stderr, "Error connecting (%s)\n", strerror(errno));
+ exit(4);
+ }
+
+ if (!strcmp(argv[1], "monitor"))
+ exit(do_monitor(sock, 0));
+ exit(do_cmd(sock, argc, argv));
+}
+
+static int do_cmd(int sock, int argc, char **argv) {
+ char final_cmd[255] = { '\0' };
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ char *cmp;
+
+ if (!index(argv[i], ' '))
+ asprintf(&cmp, "%s%s", argv[i], (i == (argc -1)) ? "" : " ");
+ else
+ asprintf(&cmp, "\"%s\"%s", argv[i], (i == (argc -1)) ? "" : " ");
+
+ strcat(final_cmd, cmp);
+ free(cmp);
+ }
+
+ if (write(sock, final_cmd, strlen(final_cmd) + 1) < 0) {
+ perror("write");
+ return errno;
+ }
+
+ return do_monitor(sock, 1);
+}
+
+static int do_monitor(int sock, int stop_after_cmd) {
+ char *buffer = malloc(4096);
+
+ if (!stop_after_cmd)
+ printf("[Connected to Nexus]\n");
+
+ while(1) {
+ fd_set read_fds;
+ struct timeval to;
+ int rc = 0;
+
+ to.tv_sec = 10;
+ to.tv_usec = 0;
+
+ FD_ZERO(&read_fds);
+ FD_SET(sock, &read_fds);
+
+ if ((rc = select(sock +1, &read_fds, NULL, NULL, &to)) < 0) {
+ fprintf(stderr, "Error in select (%s)\n", strerror(errno));
+ free(buffer);
+ return errno;
+ } else if (!rc) {
+ continue;
+ fprintf(stderr, "[TIMEOUT]\n");
+ return ETIMEDOUT;
+ } else if (FD_ISSET(sock, &read_fds)) {
+ memset(buffer, 0, 4096);
+ if ((rc = read(sock, buffer, 4096)) <= 0) {
+ if (rc == 0)
+ fprintf(stderr, "Lost connection to Nexus - did it crash?\n");
+ else
+ fprintf(stderr, "Error reading data (%s)\n", strerror(errno));
+ free(buffer);
+ if (rc == 0)
+ return ECONNRESET;
+ return errno;
+ }
+
+ int offset = 0;
+ int i = 0;
+
+ for (i = 0; i < rc; i++) {
+ if (buffer[i] == '\0') {
+ int code;
+ char tmp[4];
+
+ strncpy(tmp, buffer + offset, 3);
+ tmp[3] = '\0';
+ code = atoi(tmp);
+
+ printf("%s\n", buffer + offset);
+ if (stop_after_cmd) {
+ if (code >= 200 && code < 600)
+ return 0;
+ }
+ offset = i + 1;
+ }
+ }
+ }
+ }
+ free(buffer);
+ return 0;
+}
+
+static void usage(char *progname) {
+ fprintf(stderr, "Usage: %s <monitor>|<cmd> [arg1] [arg2...]\n", progname);
+ exit(1);
+}
+
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index b2fe8cf..e66b1c3 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -6,14 +6,9 @@
copy_from := \
etc/dbus.conf \
etc/init.goldfish.sh \
+ etc/ppp/ip-up-vpn \
etc/hosts
-dont_copy := \
- etc/init.gprs-pppd \
- etc/ppp/chap-secrets \
- etc/ppp/ip-down \
- etc/ppp/ip-up
-
copy_to := $(addprefix $(TARGET_OUT)/,$(copy_from))
copy_from := $(addprefix $(LOCAL_PATH)/,$(copy_from))
diff --git a/rootdir/etc/init.goldfish.sh b/rootdir/etc/init.goldfish.sh
index 0eb0154..f1b801d 100755
--- a/rootdir/etc/init.goldfish.sh
+++ b/rootdir/etc/init.goldfish.sh
@@ -34,6 +34,10 @@
;;
esac
+# call 'qemu-props' to set system properties from the emulator.
+#
+/system/bin/qemu-props
+
# 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
diff --git a/rootdir/etc/init.gprs-pppd b/rootdir/etc/init.gprs-pppd
deleted file mode 100755
index 521eec9..0000000
--- a/rootdir/etc/init.gprs-pppd
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/system/bin/sh
-# An unforunate wrapper script
-# so that the exit code of pppd may be retrieved
-
-
-# this is a workaround for issue #651747
-#trap "/system/bin/sleep 1;exit 0" TERM
-
-
-PPPD_PID=
-
-/system/bin/setprop "net.gprs.ppp-exit" ""
-
-/system/bin/log -t pppd "Starting pppd"
-
-/system/bin/pppd $*
-
-PPPD_EXIT=$?
-PPPD_PID=$!
-
-/system/bin/log -t pppd "pppd exited with $PPPD_EXIT"
-
-/system/bin/setprop "net.gprs.ppp-exit" "$PPPD_EXIT"
diff --git a/rootdir/etc/ppp/chap-secrets b/rootdir/etc/ppp/chap-secrets
deleted file mode 100644
index 6546b0f..0000000
--- a/rootdir/etc/ppp/chap-secrets
+++ /dev/null
@@ -1,2 +0,0 @@
-* * bogus
-
diff --git a/rootdir/etc/ppp/ip-down b/rootdir/etc/ppp/ip-down
deleted file mode 100755
index 672fa1e..0000000
--- a/rootdir/etc/ppp/ip-down
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/system/bin/sh
-case $1 in
- ppp1)
- echo 0 > /proc/sys/net/ipv4/ip_forward;
- ;;
-esac
-
-# Use interface name if linkname is not available
-NAME=${LINKNAME:-"$1"}
-
-/system/bin/setprop "net.$NAME.dns1" "$DNS1"
-/system/bin/setprop "net.$NAME.dns2" "$DNS2"
-/system/bin/setprop "net.$NAME.local-ip" "$IPLOCAL"
-/system/bin/setprop "net.$NAME.remote-ip" "$IPREMOTE"
diff --git a/rootdir/etc/ppp/ip-up b/rootdir/etc/ppp/ip-up
deleted file mode 100755
index cb2d577..0000000
--- a/rootdir/etc/ppp/ip-up
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/system/bin/sh
-case $1 in
- ppp1)
- /android/bin/iptables --flush;
- /android/bin/iptables --table nat --flush;
- /android/bin/iptables --delete-chain;
- /android/bin/iptables --table nat --append POSTROUTING --out-interface ppp0 -j MASQUERADE;
- /android/bin/iptables --append FORWARD --in-interface ppp1 -j ACCEPT;
- echo 0 > /proc/sys/net/ipv4/ip_forward;
- echo 1 > /proc/sys/net/ipv4/ip_forward;
- ;;
- ppp0)
- /system/bin/setprop "net.interfaces.defaultroute" "gprs"
- ;;
-esac
-
-# Use interface name if linkname is not available
-NAME=${LINKNAME:-"$1"}
-
-/system/bin/setprop "net.$NAME.dns1" "$DNS1"
-/system/bin/setprop "net.$NAME.dns2" "$DNS2"
-/system/bin/setprop "net.$NAME.local-ip" "$IPLOCAL"
-/system/bin/setprop "net.$NAME.remote-ip" "$IPREMOTE"
-
diff --git a/rootdir/etc/ppp/ip-up-vpn b/rootdir/etc/ppp/ip-up-vpn
new file mode 100755
index 0000000..5d6b611
--- /dev/null
+++ b/rootdir/etc/ppp/ip-up-vpn
@@ -0,0 +1,18 @@
+#!/system/bin/sh
+
+/system/bin/setprop "vpn.dns1" "$DNS1"
+/system/bin/setprop "vpn.dns2" "$DNS2"
+
+GATEWAY=${6#*@}
+VPNSERVER=${6%@*}
+
+# Protect the route to vpn server
+/system/bin/route add -net "$VPNSERVER" netmask 255.255.255.255 gw "$GATEWAY"
+
+if (exp $?) ; then exit $?; fi
+
+# Route all traffic to vpn connection
+/system/bin/route add -net 0.0.0.0 netmask 128.0.0.0 gw $IPREMOTE
+/system/bin/route add -net 128.0.0.0 netmask 128.0.0.0 gw $IPREMOTE
+
+/system/bin/setprop "vpn.up" "1"
diff --git a/rootdir/init.rc b/rootdir/init.rc
index bcabecb..d318aa3 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -33,10 +33,29 @@
write /proc/cpu/alignment 4
write /proc/sys/kernel/sched_latency_ns 10000000
write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000
+ write /proc/sys/kernel/sched_compat_yield 1
+
+# Create cgroup mount points for process groups
+ mkdir /dev/cpuctl
+ mount cgroup none /dev/cpuctl cpu
+ chown sytem system /dev/cpuctl
+ chown system system /dev/cpuctl/tasks
+ chmod 0777 /dev/cpuctl/tasks
+ write /dev/cpuctl/cpu.shares 1024
+
+ mkdir /dev/cpuctl/fg_boost
+ chown system system /dev/cpuctl/fg_boost/tasks
+ chmod 0777 /dev/cpuctl/fg_boost/tasks
+ write /dev/cpuctl/fg_boost/cpu.shares 1024
+
+ mkdir /dev/cpuctl/bg_non_interactive
+ chown system system /dev/cpuctl/bg_non_interactive/tasks
+ chmod 0777 /dev/cpuctl/bg_non_interactive/tasks
+ write /dev/cpuctl/bg_non_interactive/cpu.shares 16
# mount mtd partitions
# Mount /system rw first to give the filesystem a chance to save a checkpoint
- mount yaffs2 mtd@system /system
+ mount yaffs2 mtd@system /system
mount yaffs2 mtd@system /system ro remount
# We chown/chmod /data again so because mount is run as root + defaults
@@ -56,6 +75,14 @@
# create basic filesystem structure
mkdir /data/misc 01771 system misc
mkdir /data/misc/hcid 0770 bluetooth bluetooth
+ mkdir /data/misc/keystore 0770 keystore keystore
+ mkdir /data/misc/vpn 0770 system system
+ mkdir /data/misc/vpn/profiles 0770 system system
+ mkdir /data/misc/wifi 0770 wifi system
+ chown wifi system /data/misc/wifi
+ touch /data/misc/wifi/wpa_supplicant.conf
+ chmod 0660 /data/misc/wifi/wpa_supplicant.conf
+ chown wifi system /data/misc/wifi/wpa_supplicant.conf
mkdir /data/local 0771 shell shell
mkdir /data/local/tmp 0771 shell shell
mkdir /data/data 0771 system system
@@ -87,14 +114,12 @@
# set RLIMIT_NICE to allow priorities from 19 to -20
setrlimit 13 40 40
-# Set timeout value for rmnet stats.
- write /sys/devices/virtual/net/rmnet0/timeout_suspend 5000000
-
# Define the oom_adj values for the classes of processes that can be
# killed by the kernel. These are used in ActivityManagerService.
setprop ro.FOREGROUND_APP_ADJ 0
setprop ro.VISIBLE_APP_ADJ 1
setprop ro.SECONDARY_SERVER_ADJ 2
+ setprop ro.BACKUP_APP_ADJ 2
setprop ro.HOME_APP_ADJ 4
setprop ro.HIDDEN_APP_MIN_ADJ 7
setprop ro.CONTENT_PROVIDER_ADJ 14
@@ -105,6 +130,7 @@
setprop ro.FOREGROUND_APP_MEM 1536
setprop ro.VISIBLE_APP_MEM 2048
setprop ro.SECONDARY_SERVER_MEM 4096
+ setprop ro.BACKUP_APP_MEM 4096
setprop ro.HOME_APP_MEM 4096
setprop ro.HIDDEN_APP_MEM 5120
setprop ro.CONTENT_PROVIDER_MEM 5632
@@ -199,6 +225,10 @@
service vold /system/bin/vold
socket vold stream 0660 root mount
+service nexus /system/bin/nexus
+ socket nexus stream 0660 root system
+ disabled
+
#service mountd /system/bin/mountd
# socket mountd stream 0660 root mount
@@ -224,6 +254,12 @@
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
@@ -254,3 +290,23 @@
service flash_recovery /system/bin/flash_image recovery /system/recovery.img
oneshot
+
+service racoon /system/bin/racoon
+ socket racoon stream 600 system system
+ # racoon will setuid to vpn after getting necessary resources.
+ group net_admin keystore
+ disabled
+ oneshot
+
+service mtpd /system/bin/mtpd
+ socket mtpd stream 600 system system
+ user vpn
+ group vpn net_admin net_raw
+ disabled
+ oneshot
+
+service keystore /system/bin/keystore
+ user keystore
+ group keystore
+ socket keystore stream 666
+
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 5a8dc0b..70b13dc 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -42,7 +42,7 @@
smd \
chmod \
chown \
- mkdosfs \
+ newfs_msdos \
netstat \
ioctl \
mv \
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index 14372cb..256720d 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -28,6 +28,7 @@
{
uint8_t *bits = NULL;
ssize_t bits_size = 0;
+ const char* label;
int i, j, k;
int res, res2;
@@ -45,21 +46,48 @@
return 1;
}
}
+ res2 = 0;
switch(i) {
+ case EV_SYN:
+ label = "SYN";
+ break;
case EV_KEY:
res2 = ioctl(fd, EVIOCGKEY(res), bits + bits_size);
+ label = "KEY";
+ break;
+ case EV_REL:
+ label = "REL";
+ break;
+ case EV_ABS:
+ label = "ABS";
+ break;
+ case EV_MSC:
+ label = "MSC";
break;
case EV_LED:
res2 = ioctl(fd, EVIOCGLED(res), bits + bits_size);
+ label = "LED";
break;
case EV_SND:
res2 = ioctl(fd, EVIOCGSND(res), bits + bits_size);
+ label = "SND";
break;
case EV_SW:
res2 = ioctl(fd, EVIOCGSW(bits_size), bits + bits_size);
+ label = "SW ";
+ break;
+ case EV_REP:
+ label = "REP";
+ break;
+ case EV_FF:
+ label = "FF ";
+ break;
+ case EV_PWR:
+ label = "PWR";
break;
default:
res2 = 0;
+ label = "???";
}
for(j = 0; j < res; j++) {
for(k = 0; k < 8; k++)
@@ -70,9 +98,9 @@
else
down = ' ';
if(count == 0)
- printf(" type %04x:", i);
+ printf(" %s (%04x):", label, i);
else if((count & 0x7) == 0 || i == EV_ABS)
- printf("\n ");
+ printf("\n ");
printf(" %04x%c", j * 8 + k, down);
if(i == EV_ABS) {
struct input_absinfo abs;
@@ -264,7 +292,16 @@
static void usage(int argc, char *argv[])
{
- fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-q] [-c count] [-r] [device]\n", argv[0]);
+ fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-p] [-q] [-c count] [-r] [device]\n", argv[0]);
+ fprintf(stderr, " -t: show time stamps\n");
+ fprintf(stderr, " -n: don't print newlines\n");
+ fprintf(stderr, " -s: print switch states for given bits\n");
+ fprintf(stderr, " -S: print all switch states\n");
+ fprintf(stderr, " -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32)\n");
+ fprintf(stderr, " -p: show possible events (errs, dev, name, pos. events)\n");
+ fprintf(stderr, " -q: quiet (clear verbosity mask)\n");
+ fprintf(stderr, " -c: print given number of events then exit\n");
+ fprintf(stderr, " -r: print rate events are received\n");
}
int getevent_main(int argc, char *argv[])
@@ -290,7 +327,7 @@
opterr = 0;
do {
- c = getopt(argc, argv, "tns:Sv::qc:rh");
+ c = getopt(argc, argv, "tns:Sv::pqc:rh");
if (c == EOF)
break;
switch (c) {
@@ -317,6 +354,12 @@
print_flags |= PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_DEVICE_INFO | PRINT_VERSION;
print_flags_set = 1;
break;
+ case 'p':
+ print_flags = PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_POSSIBLE_EVENTS;
+ print_flags_set = 1;
+ if(dont_block == -1)
+ dont_block = 1;
+ break;
case 'q':
print_flags = 0;
print_flags_set = 1;
diff --git a/toolbox/ifconfig.c b/toolbox/ifconfig.c
index e83cd8b..80c0e5c 100644
--- a/toolbox/ifconfig.c
+++ b/toolbox/ifconfig.c
@@ -28,20 +28,32 @@
static inline void init_sockaddr_in(struct sockaddr_in *sin, const char *addr)
{
- sin->sin_family = AF_INET;
- sin->sin_port = 0;
- sin->sin_addr.s_addr = inet_addr(addr);
+ sin->sin_family = AF_INET;
+ sin->sin_port = 0;
+ sin->sin_addr.s_addr = inet_addr(addr);
+}
+
+static void setmtu(int s, struct ifreq *ifr, const char *mtu)
+{
+ int m = atoi(mtu);
+ ifr->ifr_mtu = m;
+ if(ioctl(s, SIOCSIFMTU, ifr) < 0) die("SIOCSIFMTU");
+}
+static void setdstaddr(int s, struct ifreq *ifr, const char *addr)
+{
+ init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_dstaddr, addr);
+ if(ioctl(s, SIOCSIFDSTADDR, ifr) < 0) die("SIOCSIFDSTADDR");
}
static void setnetmask(int s, struct ifreq *ifr, const char *addr)
{
- init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_netmask, addr);
+ init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_netmask, addr);
if(ioctl(s, SIOCSIFNETMASK, ifr) < 0) die("SIOCSIFNETMASK");
}
static void setaddr(int s, struct ifreq *ifr, const char *addr)
{
- init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_addr, addr);
+ init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_addr, addr);
if(ioctl(s, SIOCSIFADDR, ifr) < 0) die("SIOCSIFADDR");
}
@@ -109,31 +121,43 @@
running = (flags & IFF_RUNNING) ? " running" : "";
multi = (flags & IFF_MULTICAST) ? " multicast" : "";
printf("%s%s%s%s%s%s]\n", updown, brdcst, loopbk, ppp, running, multi);
-
-
-
-/* char *updown, *brdcst, *loopbk, *ppp, *running, *multi; */
-
return 0;
}
- while(argc > 0){
- if(!strcmp(argv[0], "up")) {
+ while(argc > 0) {
+ if (!strcmp(argv[0], "up")) {
setflags(s, &ifr, IFF_UP, 0);
- } else if(!strcmp(argv[0], "down")) {
+ } else if (!strcmp(argv[0], "mtu")) {
+ argc--, argv++;
+ if (!argc) {
+ errno = EINVAL;
+ die("expecting a value for parameter \"mtu\"");
+ }
+ setmtu(s, &ifr, argv[0]);
+ } else if (!strcmp(argv[0], "-pointopoint")) {
+ setflags(s, &ifr, IFF_POINTOPOINT, 1);
+ } else if (!strcmp(argv[0], "pointopoint")) {
+ argc--, argv++;
+ if (!argc) {
+ errno = EINVAL;
+ die("expecting an IP address for parameter \"pointtopoint\"");
+ }
+ setdstaddr(s, &ifr, argv[0]);
+ setflags(s, &ifr, IFF_POINTOPOINT, 0);
+ } else if (!strcmp(argv[0], "down")) {
setflags(s, &ifr, 0, IFF_UP);
- } else if(!strcmp(argv[0], "netmask")) {
- argc--, argv++;
- if (0 == argc) {
- errno = EINVAL;
- die("expecting an IP address for parameter \"netmask\"");
- }
- setnetmask(s, &ifr, argv[0]);
- } else if(isdigit(argv[0][0])){
+ } else if (!strcmp(argv[0], "netmask")) {
+ argc--, argv++;
+ if (!argc) {
+ errno = EINVAL;
+ die("expecting an IP address for parameter \"netmask\"");
+ }
+ setnetmask(s, &ifr, argv[0]);
+ } else if (isdigit(argv[0][0])) {
setaddr(s, &ifr, argv[0]);
+ setflags(s, &ifr, IFF_UP, 0);
}
argc--, argv++;
}
-
return 0;
}
diff --git a/toolbox/mkdosfs.c b/toolbox/mkdosfs.c
deleted file mode 100644
index 744aad1..0000000
--- a/toolbox/mkdosfs.c
+++ /dev/null
@@ -1,848 +0,0 @@
-/* $NetBSD: newfs_msdos.c,v 1.18.2.1 2005/05/01 18:44:02 tron Exp $ */
-
-/*
- * Copyright (c) 1998 Robert Nordier
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define __USE_FILE_OFFSET64
-
-#include <sys/cdefs.h>
-
-#include <sys/types.h>
-#include <sys/param.h>
-#ifdef __FreeBSD__
-#include <sys/diskslice.h>
-#endif
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/ioctl.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <paths.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#ifdef __NetBSD__
-#include <disktab.h>
-#include <util.h>
-#endif
-
-#define MAXU16 0xffff /* maximum unsigned 16-bit quantity */
-#define BPN 4 /* bits per nibble */
-#define NPB 2 /* nibbles per byte */
-
-#define DOSMAGIC 0xaa55 /* DOS magic number */
-#define MINBPS 128 /* minimum bytes per sector */
-#define MAXSPC 128 /* maximum sectors per cluster */
-#define MAXNFT 16 /* maximum number of FATs */
-#define DEFBLK 4096 /* default block size */
-#define DEFBLK16 2048 /* default block size FAT16 */
-#define DEFRDE 512 /* default root directory entries */
-#define RESFTE 2 /* reserved FAT entries */
-#define MINCLS12 1 /* minimum FAT12 clusters */
-#define MINCLS16 0x1000 /* minimum FAT16 clusters */
-#define MINCLS32 2 /* minimum FAT32 clusters */
-#define MAXCLS12 0xfed /* maximum FAT12 clusters */
-#define MAXCLS16 0xfff5 /* maximum FAT16 clusters */
-#define MAXCLS32 0xffffff5 /* maximum FAT32 clusters */
-
-#define mincls(fat) ((fat) == 12 ? MINCLS12 : \
- (fat) == 16 ? MINCLS16 : \
- MINCLS32)
-
-#define maxcls(fat) ((fat) == 12 ? MAXCLS12 : \
- (fat) == 16 ? MAXCLS16 : \
- MAXCLS32)
-
-#define mk1(p, x) \
- (p) = (u_int8_t)(x)
-
-#define mk2(p, x) \
- (p)[0] = (u_int8_t)(x), \
- (p)[1] = (u_int8_t)((x) >> 010)
-
-#define mk4(p, x) \
- (p)[0] = (u_int8_t)(x), \
- (p)[1] = (u_int8_t)((x) >> 010), \
- (p)[2] = (u_int8_t)((x) >> 020), \
- (p)[3] = (u_int8_t)((x) >> 030)
-
-#define argto1(arg, lo, msg) argtou(arg, lo, 0xff, msg)
-#define argto2(arg, lo, msg) argtou(arg, lo, 0xffff, msg)
-#define argto4(arg, lo, msg) argtou(arg, lo, 0xffffffff, msg)
-#define argtox(arg, lo, msg) argtou(arg, lo, UINT_MAX, msg)
-
-#ifndef MAX
-#define MAX(x, y) ((x) > (y) ? (x) : (y))
-#endif
-#ifndef MIN
-#define MIN(x, y) ((x) < (y) ? (x) : (y))
-#endif
-
-static int powerof2(int x) {
- int i;
- for (i = 0; i < 32; i++) {
- if (x & 1) {
- x >>= 1;
- // if x is zero, then original x was a power of two
- return (x == 0);
- }
- x >>= 1;
- }
-
- return 0;
-}
-
-#ifndef howmany
-#define howmany(x, y) (((x)+((y)-1))/(y))
-#endif
-
-#pragma pack(push, 1)
-struct bs {
- u_int8_t jmp[3]; /* bootstrap entry point */
- u_int8_t oem[8]; /* OEM name and version */
-};
-#define BS_SIZE 11
-
-struct bsbpb {
- u_int8_t bps[2]; /* bytes per sector */
- u_int8_t spc; /* sectors per cluster */
- u_int8_t res[2]; /* reserved sectors */
- u_int8_t nft; /* number of FATs */
- u_int8_t rde[2]; /* root directory entries */
- u_int8_t sec[2]; /* total sectors */
- u_int8_t mid; /* media descriptor */
- u_int8_t spf[2]; /* sectors per FAT */
- u_int8_t spt[2]; /* sectors per track */
- u_int8_t hds[2]; /* drive heads */
- u_int8_t hid[4]; /* hidden sectors */
- u_int8_t bsec[4]; /* big total sectors */
-};
-#define BSBPB_SIZE 25
-
-struct bsxbpb {
- u_int8_t bspf[4]; /* big sectors per FAT */
- u_int8_t xflg[2]; /* FAT control flags */
- u_int8_t vers[2]; /* file system version */
- u_int8_t rdcl[4]; /* root directory start cluster */
- u_int8_t infs[2]; /* file system info sector */
- u_int8_t bkbs[2]; /* backup boot sector */
- u_int8_t rsvd[12]; /* reserved */
-};
-#define BSXBPB_SIZE 28
-
-struct bsx {
- u_int8_t drv; /* drive number */
- u_int8_t rsvd; /* reserved */
- u_int8_t sig; /* extended boot signature */
- u_int8_t volid[4]; /* volume ID number */
- u_int8_t label[11]; /* volume label */
- u_int8_t type[8]; /* file system type */
-};
-#define BSX_SIZE 26
-
-struct de {
- u_int8_t namext[11]; /* name and extension */
- u_int8_t attr; /* attributes */
- u_int8_t rsvd[10]; /* reserved */
- u_int8_t time[2]; /* creation time */
- u_int8_t date[2]; /* creation date */
- u_int8_t clus[2]; /* starting cluster */
- u_int8_t size[4]; /* size */
-#define DE_SIZE 32
-};
-#pragma pack(pop)
-
-struct bpb {
- u_int bps; /* bytes per sector */
- u_int spc; /* sectors per cluster */
- u_int res; /* reserved sectors */
- u_int nft; /* number of FATs */
- u_int rde; /* root directory entries */
- u_int sec; /* total sectors */
- u_int mid; /* media descriptor */
- u_int spf; /* sectors per FAT */
- u_int spt; /* sectors per track */
- u_int hds; /* drive heads */
- u_int hid; /* hidden sectors */
- u_int bsec; /* big total sectors */
- u_int bspf; /* big sectors per FAT */
- u_int rdcl; /* root directory start cluster */
- u_int infs; /* file system info sector */
- u_int bkbs; /* backup boot sector */
-};
-
-static u_int8_t bootcode[] = {
- 0xfa, /* cli */
- 0x31, 0xc0, /* xor ax,ax */
- 0x8e, 0xd0, /* mov ss,ax */
- 0xbc, 0x00, 0x7c, /* mov sp,7c00h */
- 0xfb, /* sti */
- 0x8e, 0xd8, /* mov ds,ax */
- 0xe8, 0x00, 0x00, /* call $ + 3 */
- 0x5e, /* pop si */
- 0x83, 0xc6, 0x19, /* add si,+19h */
- 0xbb, 0x07, 0x00, /* mov bx,0007h */
- 0xfc, /* cld */
- 0xac, /* lodsb */
- 0x84, 0xc0, /* test al,al */
- 0x74, 0x06, /* jz $ + 8 */
- 0xb4, 0x0e, /* mov ah,0eh */
- 0xcd, 0x10, /* int 10h */
- 0xeb, 0xf5, /* jmp $ - 9 */
- 0x30, 0xe4, /* xor ah,ah */
- 0xcd, 0x16, /* int 16h */
- 0xcd, 0x19, /* int 19h */
- 0x0d, 0x0a,
- 'N', 'o', 'n', '-', 's', 'y', 's', 't',
- 'e', 'm', ' ', 'd', 'i', 's', 'k',
- 0x0d, 0x0a,
- 'P', 'r', 'e', 's', 's', ' ', 'a', 'n',
- 'y', ' ', 'k', 'e', 'y', ' ', 't', 'o',
- ' ', 'r', 'e', 'b', 'o', 'o', 't',
- 0x0d, 0x0a,
- 0
-};
-
-static void print_bpb(struct bpb *);
-static u_int ckgeom(const char *, u_int, const char *);
-static u_int argtou(const char *, u_int, u_int, const char *);
-static int oklabel(const char *);
-static void mklabel(u_int8_t *, const char *);
-static void setstr(u_int8_t *, const char *, size_t);
-static void usage(char* progname);
-
-/*
- * Construct a FAT12, FAT16, or FAT32 file system.
- */
-int
-mkdosfs_main(int argc, char *argv[])
-{
- static char opts[] = "NB:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:";
- static const char *opt_B, *opt_L, *opt_O;
- static u_int opt_F, opt_I, opt_S, opt_a, opt_b, opt_c, opt_e;
- static u_int opt_h, opt_i, opt_k, opt_m, opt_n, opt_o, opt_r;
- static u_int opt_s, opt_u;
- static int opt_N;
- static int Iflag, mflag, oflag;
- char buf[MAXPATHLEN];
- struct stat sb;
- struct timeval tv;
- struct bpb bpb;
- struct tm *tm;
- struct bs *bs;
- struct bsbpb *bsbpb;
- struct bsxbpb *bsxbpb;
- struct bsx *bsx;
- struct de *de;
- u_int8_t *img;
- const char *fname, *dtype, *bname;
- ssize_t n;
- time_t now;
- u_int fat, bss, rds, cls, dir, lsn, x, x1, x2;
- int ch, fd, fd1;
- char* progname = argv[0];
-
- while ((ch = getopt(argc, argv, opts)) != -1)
- switch (ch) {
- case 'N':
- opt_N = 1;
- break;
- case 'B':
- opt_B = optarg;
- break;
- case 'F':
- if (strcmp(optarg, "12") &&
- strcmp(optarg, "16") &&
- strcmp(optarg, "32"))
- fprintf(stderr, "%s: bad FAT type\n", optarg);
- opt_F = atoi(optarg);
- break;
- case 'I':
- opt_I = argto4(optarg, 0, "volume ID");
- Iflag = 1;
- break;
- case 'L':
- if (!oklabel(optarg))
- fprintf(stderr, "%s: bad volume label\n", optarg);
- opt_L = optarg;
- break;
- case 'O':
- if (strlen(optarg) > 8)
- fprintf(stderr, "%s: bad OEM string\n", optarg);
- opt_O = optarg;
- break;
- case 'S':
- opt_S = argto2(optarg, 1, "bytes/sector");
- break;
- case 'a':
- opt_a = argto4(optarg, 1, "sectors/FAT");
- break;
- case 'b':
- opt_b = argtox(optarg, 1, "block size");
- opt_c = 0;
- break;
- case 'c':
- opt_c = argto1(optarg, 1, "sectors/cluster");
- opt_b = 0;
- break;
- case 'e':
- opt_e = argto2(optarg, 1, "directory entries");
- break;
- case 'h':
- opt_h = argto2(optarg, 1, "drive heads");
- break;
- case 'i':
- opt_i = argto2(optarg, 1, "info sector");
- break;
- case 'k':
- opt_k = argto2(optarg, 1, "backup sector");
- break;
- case 'm':
- opt_m = argto1(optarg, 0, "media descriptor");
- mflag = 1;
- break;
- case 'n':
- opt_n = argto1(optarg, 1, "number of FATs");
- break;
- case 'o':
- opt_o = argto4(optarg, 0, "hidden sectors");
- oflag = 1;
- break;
- case 'r':
- opt_r = argto2(optarg, 1, "reserved sectors");
- break;
- case 's':
- opt_s = argto4(optarg, 1, "file system size");
- break;
- case 'u':
- opt_u = argto2(optarg, 1, "sectors/track");
- break;
- default:
- usage(progname);
- }
- argc -= optind;
- argv += optind;
- if (argc < 1 || argc > 2)
- usage(progname);
- fname = *argv++;
- if (!strchr(fname, '/')) {
- snprintf(buf, sizeof(buf), "%sr%s", _PATH_DEV, fname);
- if (!(fname = strdup(buf)))
- fprintf(stderr, NULL);
- }
- dtype = *argv;
- if ((fd = open(fname, opt_N ? O_RDONLY : O_RDWR)) == -1 ||
- fstat(fd, &sb))
- fprintf(stderr, "%s\n", fname);
- memset(&bpb, 0, sizeof(bpb));
-
- if (opt_h)
- bpb.hds = opt_h;
- if (opt_u)
- bpb.spt = opt_u;
- if (opt_S)
- bpb.bps = opt_S;
- if (opt_s)
- bpb.bsec = opt_s;
- if (oflag)
- bpb.hid = opt_o;
-
- bpb.bps = 512; // 512 bytes/sector
- bpb.spc = 8; // 4K clusters
-
-
- fprintf(stderr, "opening %s\n", fname);
- if ((fd1 = open(fname, O_RDONLY)) == -1) {
- fprintf(stderr, "failed to open %s\n", fname);
- exit(1);
- }
-
- lseek64(fd1, 0, SEEK_SET);
- loff_t length = lseek64(fd1, 0, SEEK_END);
- if (length > 0) {
- bpb.bsec = length / bpb.bps;
- bpb.spt = bpb.bsec;
- // use FAT32 for 2 gig or greater
- if (length >= 2 *1024 *1024 *1024) {
- fat = 32;
- } else {
- fat = 16;
- }
- }
- close(fd1);
- fd1 = -1;
-
- if (!powerof2(bpb.bps))
- fprintf(stderr, "bytes/sector (%u) is not a power of 2\n", bpb.bps);
- if (bpb.bps < MINBPS)
- fprintf(stderr, "bytes/sector (%u) is too small; minimum is %u\n",
- bpb.bps, MINBPS);
-
- if (!(fat = opt_F)) {
- if (!opt_e && (opt_i || opt_k))
- fat = 32;
- }
-
- if ((fat == 32 && opt_e) || (fat != 32 && (opt_i || opt_k)))
- fprintf(stderr, "-%c is not a legal FAT%s option\n",
- fat == 32 ? 'e' : opt_i ? 'i' : 'k',
- fat == 32 ? "32" : "12/16");
- if (fat == 32)
- bpb.rde = 0;
- if (opt_b) {
- if (!powerof2(opt_b))
- fprintf(stderr, "block size (%u) is not a power of 2\n", opt_b);
- if (opt_b < bpb.bps)
- fprintf(stderr, "block size (%u) is too small; minimum is %u\n",
- opt_b, bpb.bps);
- if (opt_b > bpb.bps * MAXSPC)
- fprintf(stderr, "block size (%u) is too large; maximum is %u\n",
- opt_b, bpb.bps * MAXSPC);
- bpb.spc = opt_b / bpb.bps;
- }
- if (opt_c) {
- if (!powerof2(opt_c))
- fprintf(stderr, "sectors/cluster (%u) is not a power of 2\n", opt_c);
- bpb.spc = opt_c;
- }
- if (opt_r)
- bpb.res = opt_r;
- if (opt_n) {
- if (opt_n > MAXNFT)
- fprintf(stderr, "number of FATs (%u) is too large; maximum is %u\n",
- opt_n, MAXNFT);
- bpb.nft = opt_n;
- }
- if (opt_e)
- bpb.rde = opt_e;
- if (mflag) {
- if (opt_m < 0xf0)
- fprintf(stderr, "illegal media descriptor (%#x)\n", opt_m);
- bpb.mid = opt_m;
- }
- if (opt_a)
- bpb.bspf = opt_a;
- if (opt_i)
- bpb.infs = opt_i;
- if (opt_k)
- bpb.bkbs = opt_k;
- bss = 1;
- bname = NULL;
- fd1 = -1;
- if (opt_B) {
- bname = opt_B;
- if (!strchr(bname, '/')) {
- snprintf(buf, sizeof(buf), "/boot/%s", bname);
- if (!(bname = strdup(buf)))
- fprintf(stderr, NULL);
- }
- if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb))
- fprintf(stderr, "%s", bname);
- if (!S_ISREG(sb.st_mode) || sb.st_size % bpb.bps ||
- sb.st_size < bpb.bps || sb.st_size > bpb.bps * MAXU16)
- fprintf(stderr, "%s: inappropriate file type or format\n", bname);
- bss = sb.st_size / bpb.bps;
- }
- if (!bpb.nft)
- bpb.nft = 2;
- if (!fat) {
- if (bpb.bsec < (bpb.res ? bpb.res : bss) +
- howmany((RESFTE + (bpb.spc ? MINCLS16 : MAXCLS12 + 1)) *
- ((bpb.spc ? 16 : 12) / BPN), bpb.bps * NPB) *
- bpb.nft +
- howmany(bpb.rde ? bpb.rde : DEFRDE,
- bpb.bps / DE_SIZE) +
- (bpb.spc ? MINCLS16 : MAXCLS12 + 1) *
- (bpb.spc ? bpb.spc : howmany(DEFBLK, bpb.bps)))
- fat = 12;
- else if (bpb.rde || bpb.bsec <
- (bpb.res ? bpb.res : bss) +
- howmany((RESFTE + MAXCLS16) * 2, bpb.bps) * bpb.nft +
- howmany(DEFRDE, bpb.bps / DE_SIZE) +
- (MAXCLS16 + 1) *
- (bpb.spc ? bpb.spc : howmany(8192, bpb.bps)))
- fat = 16;
- else
- fat = 32;
- }
- x = bss;
- if (fat == 32) {
- if (!bpb.infs) {
- if (x == MAXU16 || x == bpb.bkbs)
- fprintf(stderr, "no room for info sector\n");
- bpb.infs = x;
- }
- if (bpb.infs != MAXU16 && x <= bpb.infs)
- x = bpb.infs + 1;
- if (!bpb.bkbs) {
- if (x == MAXU16)
- fprintf(stderr, "no room for backup sector\n");
- bpb.bkbs = x;
- } else if (bpb.bkbs != MAXU16 && bpb.bkbs == bpb.infs)
- fprintf(stderr, "backup sector would overwrite info sector\n");
- if (bpb.bkbs != MAXU16 && x <= bpb.bkbs)
- x = bpb.bkbs + 1;
- }
- if (!bpb.res)
- bpb.res = fat == 32 ? MAX(x, MAX(16384 / bpb.bps, 4)) : x;
- else if (bpb.res < x)
- fprintf(stderr, "too few reserved sectors (need %d have %d)\n", x, bpb.res);
- if (fat != 32 && !bpb.rde)
- bpb.rde = DEFRDE;
- rds = howmany(bpb.rde, bpb.bps / DE_SIZE);
- if (!bpb.spc)
- for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bps);
- bpb.spc < MAXSPC &&
- bpb.res +
- howmany((RESFTE + maxcls(fat)) * (fat / BPN),
- bpb.bps * NPB) * bpb.nft +
- rds +
- (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec;
- bpb.spc <<= 1);
- if (fat != 32 && bpb.bspf > MAXU16)
- fprintf(stderr, "too many sectors/FAT for FAT12/16\n");
- x1 = bpb.res + rds;
- x = bpb.bspf ? bpb.bspf : 1;
- if (x1 + (u_int64_t)x * bpb.nft > bpb.bsec)
- fprintf(stderr, "meta data exceeds file system size\n");
- x1 += x * bpb.nft;
- x = (u_int64_t)(bpb.bsec - x1) * bpb.bps * NPB /
- (bpb.spc * bpb.bps * NPB + fat / BPN * bpb.nft);
- x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN),
- bpb.bps * NPB);
- if (!bpb.bspf) {
- bpb.bspf = x2;
- x1 += (bpb.bspf - 1) * bpb.nft;
- }
- cls = (bpb.bsec - x1) / bpb.spc;
- x = (u_int64_t)bpb.bspf * bpb.bps * NPB / (fat / BPN) - RESFTE;
- if (cls > x)
- cls = x;
- if (bpb.bspf < x2)
- fprintf(stderr, "warning: sectors/FAT limits file system to %u clusters\n",
- cls);
- if (cls < mincls(fat))
- fprintf(stderr, "%u clusters too few clusters for FAT%u, need %u\n", cls, fat,
- mincls(fat));
- if (cls > maxcls(fat)) {
- cls = maxcls(fat);
- bpb.bsec = x1 + (cls + 1) * bpb.spc - 1;
- fprintf(stderr, "warning: FAT type limits file system to %u sectors\n",
- bpb.bsec);
- }
- printf("%s: %u sector%s in %u FAT%u cluster%s "
- "(%u bytes/cluster)\n", fname, cls * bpb.spc,
- cls * bpb.spc == 1 ? "" : "s", cls, fat,
- cls == 1 ? "" : "s", bpb.bps * bpb.spc);
- if (!bpb.mid)
- bpb.mid = !bpb.hid ? 0xf0 : 0xf8;
- if (fat == 32)
- bpb.rdcl = RESFTE;
- if (bpb.hid + bpb.bsec <= MAXU16) {
- bpb.sec = bpb.bsec;
- bpb.bsec = 0;
- }
- if (fat != 32) {
- bpb.spf = bpb.bspf;
- bpb.bspf = 0;
- }
- ch = 0;
- if (fat == 12)
- ch = 1; /* 001 Primary DOS with 12 bit FAT */
- else if (fat == 16) {
- if (bpb.bsec == 0)
- ch = 4; /* 004 Primary DOS with 16 bit FAT <32M */
- else
- ch = 6; /* 006 Primary 'big' DOS, 16-bit FAT (> 32MB) */
- /*
- * XXX: what about:
- * 014 DOS (16-bit FAT) - LBA
- * ?
- */
- } else if (fat == 32) {
- ch = 11; /* 011 Primary DOS with 32 bit FAT */
- /*
- * XXX: what about:
- * 012 Primary DOS with 32 bit FAT - LBA
- * ?
- */
- }
- if (ch != 0)
- printf("MBR type: %d\n", ch);
- print_bpb(&bpb);
- if (!opt_N) {
- gettimeofday(&tv, NULL);
- now = tv.tv_sec;
- tm = localtime(&now);
- if (!(img = malloc(bpb.bps)))
- fprintf(stderr, NULL);
- dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft;
-
- for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) {
- x = lsn;
- if (opt_B &&
- fat == 32 && bpb.bkbs != MAXU16 &&
- bss <= bpb.bkbs && x >= bpb.bkbs) {
- x -= bpb.bkbs;
- if (!x && lseek64(fd1, 0, SEEK_SET))
- fprintf(stderr, "lseek64 failed for %s\n", bname);
- }
- if (opt_B && x < bss) {
- if ((n = read(fd1, img, bpb.bps)) == -1)
- fprintf(stderr, "%s\n", bname);
- if (n != bpb.bps)
- fprintf(stderr, "%s: can't read sector %u\n", bname, x);
- } else
- memset(img, 0, bpb.bps);
- if (!lsn ||
- (fat == 32 && bpb.bkbs != MAXU16 && lsn == bpb.bkbs)) {
- x1 = BS_SIZE;
- bsbpb = (struct bsbpb *)(img + x1);
- mk2(bsbpb->bps, bpb.bps);
- mk1(bsbpb->spc, bpb.spc);
- mk2(bsbpb->res, bpb.res);
- mk1(bsbpb->nft, bpb.nft);
- mk2(bsbpb->rde, bpb.rde);
- mk2(bsbpb->sec, bpb.sec);
- mk1(bsbpb->mid, bpb.mid);
- mk2(bsbpb->spf, bpb.spf);
- mk2(bsbpb->spt, bpb.spt);
- mk2(bsbpb->hds, bpb.hds);
- mk4(bsbpb->hid, bpb.hid);
- mk4(bsbpb->bsec, bpb.bsec);
- x1 += BSBPB_SIZE;
- if (fat == 32) {
- bsxbpb = (struct bsxbpb *)(img + x1);
- mk4(bsxbpb->bspf, bpb.bspf);
- mk2(bsxbpb->xflg, 0);
- mk2(bsxbpb->vers, 0);
- mk4(bsxbpb->rdcl, bpb.rdcl);
- mk2(bsxbpb->infs, bpb.infs);
- mk2(bsxbpb->bkbs, bpb.bkbs);
- x1 += BSXBPB_SIZE;
- }
- bsx = (struct bsx *)(img + x1);
- mk1(bsx->sig, 0x29);
- if (Iflag)
- x = opt_I;
- else
- x = (((u_int)(1 + tm->tm_mon) << 8 |
- (u_int)tm->tm_mday) +
- ((u_int)tm->tm_sec << 8 |
- (u_int)(tv.tv_usec / 10))) << 16 |
- ((u_int)(1900 + tm->tm_year) +
- ((u_int)tm->tm_hour << 8 |
- (u_int)tm->tm_min));
- mk4(bsx->volid, x);
- mklabel(bsx->label, opt_L ? opt_L : "NO_NAME");
- snprintf(buf, sizeof(buf), "FAT%u", fat);
- setstr(bsx->type, buf, sizeof(bsx->type));
- if (!opt_B) {
- x1 += BSX_SIZE;
- bs = (struct bs *)img;
- mk1(bs->jmp[0], 0xeb);
- mk1(bs->jmp[1], x1 - 2);
- mk1(bs->jmp[2], 0x90);
- setstr(bs->oem, opt_O ? opt_O : "NetBSD",
- sizeof(bs->oem));
- memcpy(img + x1, bootcode, sizeof(bootcode));
- mk2(img + bpb.bps - 2, DOSMAGIC);
- }
- } else if (fat == 32 && bpb.infs != MAXU16 &&
- (lsn == bpb.infs ||
- (bpb.bkbs != MAXU16 &&
- lsn == bpb.bkbs + bpb.infs))) {
- mk4(img, 0x41615252);
- mk4(img + bpb.bps - 28, 0x61417272);
- mk4(img + bpb.bps - 24, 0xffffffff);
- mk4(img + bpb.bps - 20, bpb.rdcl);
- mk2(img + bpb.bps - 2, DOSMAGIC);
- } else if (lsn >= bpb.res && lsn < dir &&
- !((lsn - bpb.res) %
- (bpb.spf ? bpb.spf : bpb.bspf))) {
- mk1(img[0], bpb.mid);
- for (x = 1; x < fat * (fat == 32 ? 3 : 2) / 8; x++)
- mk1(img[x], fat == 32 && x % 4 == 3 ? 0x0f : 0xff);
- } else if (lsn == dir && opt_L) {
- de = (struct de *)img;
- mklabel(de->namext, opt_L);
- mk1(de->attr, 050);
- x = (u_int)tm->tm_hour << 11 |
- (u_int)tm->tm_min << 5 |
- (u_int)tm->tm_sec >> 1;
- mk2(de->time, x);
- x = (u_int)(tm->tm_year - 80) << 9 |
- (u_int)(tm->tm_mon + 1) << 5 |
- (u_int)tm->tm_mday;
- mk2(de->date, x);
- }
- if ((n = write(fd, img, bpb.bps)) == -1)
- fprintf(stderr, "%s\n", fname);
- if (n != bpb.bps)
- fprintf(stderr, "%s: can't write sector %u\n", fname, lsn);
- }
- }
- return 0;
-}
-
-/*
- * Print out BPB values.
- */
-static void
-print_bpb(struct bpb *bpb)
-{
- printf("bps=%u spc=%u res=%u nft=%u", bpb->bps, bpb->spc, bpb->res,
- bpb->nft);
- if (bpb->rde)
- printf(" rde=%u", bpb->rde);
- if (bpb->sec)
- printf(" sec=%u", bpb->sec);
- printf(" mid=%#x", bpb->mid);
- if (bpb->spf)
- printf(" spf=%u", bpb->spf);
- printf(" spt=%u hds=%u hid=%u", bpb->spt, bpb->hds, bpb->hid);
- if (bpb->bsec)
- printf(" bsec=%u", bpb->bsec);
- if (!bpb->spf) {
- printf(" bspf=%u rdcl=%u", bpb->bspf, bpb->rdcl);
- printf(" infs=");
- printf(bpb->infs == MAXU16 ? "%#x" : "%u", bpb->infs);
- printf(" bkbs=");
- printf(bpb->bkbs == MAXU16 ? "%#x" : "%u", bpb->bkbs);
- }
- printf("\n");
-}
-
-/*
- * Check a disk geometry value.
- */
-static u_int
-ckgeom(const char *fname, u_int val, const char *msg)
-{
- if (!val)
- fprintf(stderr, "%s: no default %s\n", fname, msg);
- if (val > MAXU16)
- fprintf(stderr, "%s: illegal %s\n", fname, msg);
- return val;
-}
-
-/*
- * Convert and check a numeric option argument.
- */
-static u_int
-argtou(const char *arg, u_int lo, u_int hi, const char *msg)
-{
- char *s;
- u_long x;
-
- errno = 0;
- x = strtoul(arg, &s, 0);
- if (errno || !*arg || *s || x < lo || x > hi)
- fprintf(stderr, "%s: bad %s\n", arg, msg);
- return x;
-}
-
-/*
- * Check a volume label.
- */
-static int
-oklabel(const char *src)
-{
- int c, i;
-
- for (i = 0; i <= 11; i++) {
- c = (u_char)*src++;
- if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c))
- break;
- }
- return i && !c;
-}
-
-/*
- * Make a volume label.
- */
-static void
-mklabel(u_int8_t *dest, const char *src)
-{
- int c, i;
-
- for (i = 0; i < 11; i++) {
- c = *src ? toupper((unsigned char)*src++) : ' ';
- *dest++ = !i && c == '\xe5' ? 5 : c;
- }
-}
-
-/*
- * Copy string, padding with spaces.
- */
-static void
-setstr(u_int8_t *dest, const char *src, size_t len)
-{
- while (len--)
- *dest++ = *src ? *src++ : ' ';
-}
-
-/*
- * Print usage message.
- */
-static void
-usage(char* progname)
-{
- fprintf(stderr,
- "usage: %s [ -options ] special [disktype]\n", progname);
- fprintf(stderr, "where the options are:\n");
- fprintf(stderr, "\t-N don't create file system: "
- "just print out parameters\n");
- fprintf(stderr, "\t-B get bootstrap from file\n");
- fprintf(stderr, "\t-F FAT type (12, 16, or 32)\n");
- fprintf(stderr, "\t-I volume ID\n");
- fprintf(stderr, "\t-L volume label\n");
- fprintf(stderr, "\t-O OEM string\n");
- fprintf(stderr, "\t-S bytes/sector\n");
- fprintf(stderr, "\t-a sectors/FAT\n");
- fprintf(stderr, "\t-b block size\n");
- fprintf(stderr, "\t-c sectors/cluster\n");
- fprintf(stderr, "\t-e root directory entries\n");
- fprintf(stderr, "\t-h drive heads\n");
- fprintf(stderr, "\t-i file system info sector\n");
- fprintf(stderr, "\t-k backup boot sector\n");
- fprintf(stderr, "\t-m media descriptor\n");
- fprintf(stderr, "\t-n number of FATs\n");
- fprintf(stderr, "\t-o hidden sectors\n");
- fprintf(stderr, "\t-r reserved sectors\n");
- fprintf(stderr, "\t-s file system size (sectors)\n");
- fprintf(stderr, "\t-u sectors/track\n");
- exit(1);
-}
-
-
diff --git a/toolbox/mount.c b/toolbox/mount.c
index 395c943..472c952 100644
--- a/toolbox/mount.c
+++ b/toolbox/mount.c
@@ -226,7 +226,7 @@
{
char *type = NULL;
int c;
- int loop;
+ int loop = 0;
progname = argv[0];
rwflag = MS_VERBOSE;
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
new file mode 100644
index 0000000..4483cc0
--- /dev/null
+++ b/toolbox/newfs_msdos.c
@@ -0,0 +1,1098 @@
+/*
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: src/sbin/newfs_msdos/newfs_msdos.c,v 1.33 2009/04/11 14:56:29 ed Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#ifndef ANDROID
+ #include <sys/fdcio.h>
+ #include <sys/disk.h>
+ #include <sys/disklabel.h>
+ #include <sys/mount.h>
+#else
+ #include <stdarg.h>
+ #include <linux/fs.h>
+ #include <linux/hdreg.h>
+#endif
+
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define MAXU16 0xffff /* maximum unsigned 16-bit quantity */
+#define BPN 4 /* bits per nibble */
+#define NPB 2 /* nibbles per byte */
+
+#define DOSMAGIC 0xaa55 /* DOS magic number */
+#define MINBPS 512 /* minimum bytes per sector */
+#define MAXSPC 128 /* maximum sectors per cluster */
+#define MAXNFT 16 /* maximum number of FATs */
+#define DEFBLK 4096 /* default block size */
+#define DEFBLK16 2048 /* default block size FAT16 */
+#define DEFRDE 512 /* default root directory entries */
+#define RESFTE 2 /* reserved FAT entries */
+#define MINCLS12 1 /* minimum FAT12 clusters */
+#define MINCLS16 0x1000 /* minimum FAT16 clusters */
+#define MINCLS32 2 /* minimum FAT32 clusters */
+#define MAXCLS12 0xfed /* maximum FAT12 clusters */
+#define MAXCLS16 0xfff5 /* maximum FAT16 clusters */
+#define MAXCLS32 0xffffff5 /* maximum FAT32 clusters */
+
+#define mincls(fat) ((fat) == 12 ? MINCLS12 : \
+ (fat) == 16 ? MINCLS16 : \
+ MINCLS32)
+
+#define maxcls(fat) ((fat) == 12 ? MAXCLS12 : \
+ (fat) == 16 ? MAXCLS16 : \
+ MAXCLS32)
+
+#define mk1(p, x) \
+ (p) = (u_int8_t)(x)
+
+#define mk2(p, x) \
+ (p)[0] = (u_int8_t)(x), \
+ (p)[1] = (u_int8_t)((x) >> 010)
+
+#define mk4(p, x) \
+ (p)[0] = (u_int8_t)(x), \
+ (p)[1] = (u_int8_t)((x) >> 010), \
+ (p)[2] = (u_int8_t)((x) >> 020), \
+ (p)[3] = (u_int8_t)((x) >> 030)
+
+#define argto1(arg, lo, msg) argtou(arg, lo, 0xff, msg)
+#define argto2(arg, lo, msg) argtou(arg, lo, 0xffff, msg)
+#define argto4(arg, lo, msg) argtou(arg, lo, 0xffffffff, msg)
+#define argtox(arg, lo, msg) argtou(arg, lo, UINT_MAX, msg)
+
+struct bs {
+ u_int8_t jmp[3]; /* bootstrap entry point */
+ u_int8_t oem[8]; /* OEM name and version */
+};
+
+struct bsbpb {
+ u_int8_t bps[2]; /* bytes per sector */
+ u_int8_t spc; /* sectors per cluster */
+ u_int8_t res[2]; /* reserved sectors */
+ u_int8_t nft; /* number of FATs */
+ u_int8_t rde[2]; /* root directory entries */
+ u_int8_t sec[2]; /* total sectors */
+ u_int8_t mid; /* media descriptor */
+ u_int8_t spf[2]; /* sectors per FAT */
+ u_int8_t spt[2]; /* sectors per track */
+ u_int8_t hds[2]; /* drive heads */
+ u_int8_t hid[4]; /* hidden sectors */
+ u_int8_t bsec[4]; /* big total sectors */
+};
+
+struct bsxbpb {
+ u_int8_t bspf[4]; /* big sectors per FAT */
+ u_int8_t xflg[2]; /* FAT control flags */
+ u_int8_t vers[2]; /* file system version */
+ u_int8_t rdcl[4]; /* root directory start cluster */
+ u_int8_t infs[2]; /* file system info sector */
+ u_int8_t bkbs[2]; /* backup boot sector */
+ u_int8_t rsvd[12]; /* reserved */
+};
+
+struct bsx {
+ u_int8_t drv; /* drive number */
+ u_int8_t rsvd; /* reserved */
+ u_int8_t sig; /* extended boot signature */
+ u_int8_t volid[4]; /* volume ID number */
+ u_int8_t label[11]; /* volume label */
+ u_int8_t type[8]; /* file system type */
+};
+
+struct de {
+ u_int8_t namext[11]; /* name and extension */
+ u_int8_t attr; /* attributes */
+ u_int8_t rsvd[10]; /* reserved */
+ u_int8_t time[2]; /* creation time */
+ u_int8_t date[2]; /* creation date */
+ u_int8_t clus[2]; /* starting cluster */
+ u_int8_t size[4]; /* size */
+};
+
+struct bpb {
+ u_int bps; /* bytes per sector */
+ u_int spc; /* sectors per cluster */
+ u_int res; /* reserved sectors */
+ u_int nft; /* number of FATs */
+ u_int rde; /* root directory entries */
+ u_int sec; /* total sectors */
+ u_int mid; /* media descriptor */
+ u_int spf; /* sectors per FAT */
+ u_int spt; /* sectors per track */
+ u_int hds; /* drive heads */
+ u_int hid; /* hidden sectors */
+ u_int bsec; /* big total sectors */
+ u_int bspf; /* big sectors per FAT */
+ u_int rdcl; /* root directory start cluster */
+ u_int infs; /* file system info sector */
+ u_int bkbs; /* backup boot sector */
+};
+
+#define BPBGAP 0, 0, 0, 0, 0, 0
+
+static struct {
+ const char *name;
+ struct bpb bpb;
+} const stdfmt[] = {
+ {"160", {512, 1, 1, 2, 64, 320, 0xfe, 1, 8, 1, BPBGAP}},
+ {"180", {512, 1, 1, 2, 64, 360, 0xfc, 2, 9, 1, BPBGAP}},
+ {"320", {512, 2, 1, 2, 112, 640, 0xff, 1, 8, 2, BPBGAP}},
+ {"360", {512, 2, 1, 2, 112, 720, 0xfd, 2, 9, 2, BPBGAP}},
+ {"640", {512, 2, 1, 2, 112, 1280, 0xfb, 2, 8, 2, BPBGAP}},
+ {"720", {512, 2, 1, 2, 112, 1440, 0xf9, 3, 9, 2, BPBGAP}},
+ {"1200", {512, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2, BPBGAP}},
+ {"1232", {1024,1, 1, 2, 192, 1232, 0xfe, 2, 8, 2, BPBGAP}},
+ {"1440", {512, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2, BPBGAP}},
+ {"2880", {512, 2, 1, 2, 240, 5760, 0xf0, 9, 36, 2, BPBGAP}}
+};
+
+static const u_int8_t bootcode[] = {
+ 0xfa, /* cli */
+ 0x31, 0xc0, /* xor ax,ax */
+ 0x8e, 0xd0, /* mov ss,ax */
+ 0xbc, 0x00, 0x7c, /* mov sp,7c00h */
+ 0xfb, /* sti */
+ 0x8e, 0xd8, /* mov ds,ax */
+ 0xe8, 0x00, 0x00, /* call $ + 3 */
+ 0x5e, /* pop si */
+ 0x83, 0xc6, 0x19, /* add si,+19h */
+ 0xbb, 0x07, 0x00, /* mov bx,0007h */
+ 0xfc, /* cld */
+ 0xac, /* lodsb */
+ 0x84, 0xc0, /* test al,al */
+ 0x74, 0x06, /* jz $ + 8 */
+ 0xb4, 0x0e, /* mov ah,0eh */
+ 0xcd, 0x10, /* int 10h */
+ 0xeb, 0xf5, /* jmp $ - 9 */
+ 0x30, 0xe4, /* xor ah,ah */
+ 0xcd, 0x16, /* int 16h */
+ 0xcd, 0x19, /* int 19h */
+ 0x0d, 0x0a,
+ 'N', 'o', 'n', '-', 's', 'y', 's', 't',
+ 'e', 'm', ' ', 'd', 'i', 's', 'k',
+ 0x0d, 0x0a,
+ 'P', 'r', 'e', 's', 's', ' ', 'a', 'n',
+ 'y', ' ', 'k', 'e', 'y', ' ', 't', 'o',
+ ' ', 'r', 'e', 'b', 'o', 'o', 't',
+ 0x0d, 0x0a,
+ 0
+};
+
+static void check_mounted(const char *, mode_t);
+static void getstdfmt(const char *, struct bpb *);
+static void getdiskinfo(int, const char *, const char *, int,
+ struct bpb *);
+static void print_bpb(struct bpb *);
+static u_int ckgeom(const char *, u_int, const char *);
+static u_int argtou(const char *, u_int, u_int, const char *);
+static off_t argtooff(const char *, const char *);
+static int oklabel(const char *);
+static void mklabel(u_int8_t *, const char *);
+static void setstr(u_int8_t *, const char *, size_t);
+static void usage(void);
+
+#ifdef ANDROID
+static void err(int val, const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ char *fmt2;
+ asprintf(&fmt2, "%s\n", fmt);
+ vfprintf(stderr, fmt2, ap);
+ free(fmt2);
+ va_end(ap);
+}
+
+static void errx(int val, const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ char *fmt2;
+ asprintf(&fmt2, "%s\n", fmt);
+ vfprintf(stderr, fmt2, ap);
+ free(fmt2);
+ va_end(ap);
+}
+
+static void warnx(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ char *fmt2;
+ asprintf(&fmt2, "%s\n", fmt);
+ vfprintf(stderr, fmt2, ap);
+ free(fmt2);
+ va_end(ap);
+}
+#define powerof2(x) ((((x) - 1) & (x)) == 0)
+#define howmany(x, y) (((x) + ((y) - 1)) / (y))
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+#endif
+/*
+ * Construct a FAT12, FAT16, or FAT32 file system.
+ */
+int
+newfs_msdos_main(int argc, char *argv[])
+{
+ static const char opts[] = "@:NB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:";
+ const char *opt_B = NULL, *opt_L = NULL, *opt_O = NULL, *opt_f = NULL;
+ u_int opt_F = 0, opt_I = 0, opt_S = 0, opt_a = 0, opt_b = 0, opt_c = 0;
+ u_int opt_e = 0, opt_h = 0, opt_i = 0, opt_k = 0, opt_m = 0, opt_n = 0;
+ u_int opt_o = 0, opt_r = 0, opt_s = 0, opt_u = 0;
+ int opt_N = 0;
+ int Iflag = 0, mflag = 0, oflag = 0;
+ char buf[MAXPATHLEN];
+ struct stat sb;
+ struct timeval tv;
+ struct bpb bpb;
+ struct tm *tm;
+ struct bs *bs;
+ struct bsbpb *bsbpb;
+ struct bsxbpb *bsxbpb;
+ struct bsx *bsx;
+ struct de *de;
+ u_int8_t *img;
+ const char *fname, *dtype, *bname;
+ ssize_t n;
+ time_t now;
+ u_int fat, bss, rds, cls, dir, lsn, x, x1, x2;
+ int ch, fd, fd1;
+ off_t opt_create = 0, opt_ofs = 0;
+
+ while ((ch = getopt(argc, argv, opts)) != -1)
+ switch (ch) {
+ case '@':
+ opt_ofs = argtooff(optarg, "offset");
+ break;
+ case 'N':
+ opt_N = 1;
+ break;
+ case 'B':
+ opt_B = optarg;
+ break;
+ case 'C':
+ opt_create = argtooff(optarg, "create size");
+ break;
+ case 'F':
+ if (strcmp(optarg, "12") &&
+ strcmp(optarg, "16") &&
+ strcmp(optarg, "32"))
+ errx(1, "%s: bad FAT type", optarg);
+ opt_F = atoi(optarg);
+ break;
+ case 'I':
+ opt_I = argto4(optarg, 0, "volume ID");
+ Iflag = 1;
+ break;
+ case 'L':
+ if (!oklabel(optarg))
+ errx(1, "%s: bad volume label", optarg);
+ opt_L = optarg;
+ break;
+ case 'O':
+ if (strlen(optarg) > 8)
+ errx(1, "%s: bad OEM string", optarg);
+ opt_O = optarg;
+ break;
+ case 'S':
+ opt_S = argto2(optarg, 1, "bytes/sector");
+ break;
+ case 'a':
+ opt_a = argto4(optarg, 1, "sectors/FAT");
+ break;
+ case 'b':
+ opt_b = argtox(optarg, 1, "block size");
+ opt_c = 0;
+ break;
+ case 'c':
+ opt_c = argto1(optarg, 1, "sectors/cluster");
+ opt_b = 0;
+ break;
+ case 'e':
+ opt_e = argto2(optarg, 1, "directory entries");
+ break;
+ case 'f':
+ opt_f = optarg;
+ break;
+ case 'h':
+ opt_h = argto2(optarg, 1, "drive heads");
+ break;
+ case 'i':
+ opt_i = argto2(optarg, 1, "info sector");
+ break;
+ case 'k':
+ opt_k = argto2(optarg, 1, "backup sector");
+ break;
+ case 'm':
+ opt_m = argto1(optarg, 0, "media descriptor");
+ mflag = 1;
+ break;
+ case 'n':
+ opt_n = argto1(optarg, 1, "number of FATs");
+ break;
+ case 'o':
+ opt_o = argto4(optarg, 0, "hidden sectors");
+ oflag = 1;
+ break;
+ case 'r':
+ opt_r = argto2(optarg, 1, "reserved sectors");
+ break;
+ case 's':
+ opt_s = argto4(optarg, 1, "file system size");
+ break;
+ case 'u':
+ opt_u = argto2(optarg, 1, "sectors/track");
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc < 1 || argc > 2)
+ usage();
+ fname = *argv++;
+ if (!opt_create && !strchr(fname, '/')) {
+ snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
+ if (!(fname = strdup(buf)))
+ err(1, NULL);
+ }
+ dtype = *argv;
+ if (opt_create) {
+ if (opt_N)
+ errx(1, "create (-C) is incompatible with -N");
+ fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1)
+ errx(1, "failed to create %s", fname);
+ if (ftruncate(fd, opt_create))
+ errx(1, "failed to initialize %jd bytes", (intmax_t)opt_create);
+ } else if ((fd = open(fname, opt_N ? O_RDONLY : O_RDWR)) == -1)
+ err(1, "%s", fname);
+ if (fstat(fd, &sb))
+ err(1, "%s", fname);
+ if (opt_create) {
+ if (!S_ISREG(sb.st_mode))
+ warnx("warning, %s is not a regular file", fname);
+ } else {
+ if (!S_ISCHR(sb.st_mode))
+ warnx("warning, %s is not a character device", fname);
+ }
+ if (!opt_N)
+ check_mounted(fname, sb.st_mode);
+ if (opt_ofs && opt_ofs != lseek(fd, opt_ofs, SEEK_SET))
+ errx(1, "cannot seek to %jd", (intmax_t)opt_ofs);
+ memset(&bpb, 0, sizeof(bpb));
+ if (opt_f) {
+ getstdfmt(opt_f, &bpb);
+ bpb.bsec = bpb.sec;
+ bpb.sec = 0;
+ bpb.bspf = bpb.spf;
+ bpb.spf = 0;
+ }
+ if (opt_h)
+ bpb.hds = opt_h;
+ if (opt_u)
+ bpb.spt = opt_u;
+ if (opt_S)
+ bpb.bps = opt_S;
+ if (opt_s)
+ bpb.bsec = opt_s;
+ if (oflag)
+ bpb.hid = opt_o;
+ if (!(opt_f || (opt_h && opt_u && opt_S && opt_s && oflag))) {
+ off_t delta;
+ getdiskinfo(fd, fname, dtype, oflag, &bpb);
+ bpb.bsec -= (opt_ofs / bpb.bps);
+ delta = bpb.bsec % bpb.spt;
+ if (delta != 0) {
+ warnx("trim %d sectors to adjust to a multiple of %d",
+ (int)delta, bpb.spt);
+ bpb.bsec -= delta;
+ }
+ if (bpb.spc == 0) { /* set defaults */
+ if (bpb.bsec <= 6000) /* about 3MB -> 512 bytes */
+ bpb.spc = 1;
+ else if (bpb.bsec <= (1<<17)) /* 64M -> 4k */
+ bpb.spc = 8;
+ else if (bpb.bsec <= (1<<19)) /* 256M -> 8k */
+ bpb.spc = 16;
+ else if (bpb.bsec <= (1<<21)) /* 1G -> 16k */
+ bpb.spc = 32;
+ else
+ bpb.spc = 64; /* otherwise 32k */
+ }
+ }
+ if (!powerof2(bpb.bps))
+ errx(1, "bytes/sector (%u) is not a power of 2", bpb.bps);
+ if (bpb.bps < MINBPS)
+ errx(1, "bytes/sector (%u) is too small; minimum is %u",
+ bpb.bps, MINBPS);
+ if (!(fat = opt_F)) {
+ if (opt_f)
+ fat = 12;
+ else if (!opt_e && (opt_i || opt_k))
+ fat = 32;
+ }
+ if ((fat == 32 && opt_e) || (fat != 32 && (opt_i || opt_k)))
+ errx(1, "-%c is not a legal FAT%s option",
+ fat == 32 ? 'e' : opt_i ? 'i' : 'k',
+ fat == 32 ? "32" : "12/16");
+ if (opt_f && fat == 32)
+ bpb.rde = 0;
+ if (opt_b) {
+ if (!powerof2(opt_b))
+ errx(1, "block size (%u) is not a power of 2", opt_b);
+ if (opt_b < bpb.bps)
+ errx(1, "block size (%u) is too small; minimum is %u",
+ opt_b, bpb.bps);
+ if (opt_b > bpb.bps * MAXSPC)
+ errx(1, "block size (%u) is too large; maximum is %u",
+ opt_b, bpb.bps * MAXSPC);
+ bpb.spc = opt_b / bpb.bps;
+ }
+ if (opt_c) {
+ if (!powerof2(opt_c))
+ errx(1, "sectors/cluster (%u) is not a power of 2", opt_c);
+ bpb.spc = opt_c;
+ }
+ if (opt_r)
+ bpb.res = opt_r;
+ if (opt_n) {
+ if (opt_n > MAXNFT)
+ errx(1, "number of FATs (%u) is too large; maximum is %u",
+ opt_n, MAXNFT);
+ bpb.nft = opt_n;
+ }
+ if (opt_e)
+ bpb.rde = opt_e;
+ if (mflag) {
+ if (opt_m < 0xf0)
+ errx(1, "illegal media descriptor (%#x)", opt_m);
+ bpb.mid = opt_m;
+ }
+ if (opt_a)
+ bpb.bspf = opt_a;
+ if (opt_i)
+ bpb.infs = opt_i;
+ if (opt_k)
+ bpb.bkbs = opt_k;
+ bss = 1;
+ bname = NULL;
+ fd1 = -1;
+ if (opt_B) {
+ bname = opt_B;
+ if (!strchr(bname, '/')) {
+ snprintf(buf, sizeof(buf), "/boot/%s", bname);
+ if (!(bname = strdup(buf)))
+ err(1, NULL);
+ }
+ if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb))
+ err(1, "%s", bname);
+ if (!S_ISREG(sb.st_mode) || sb.st_size % bpb.bps ||
+ sb.st_size < bpb.bps || sb.st_size > bpb.bps * MAXU16)
+ errx(1, "%s: inappropriate file type or format", bname);
+ bss = sb.st_size / bpb.bps;
+ }
+ if (!bpb.nft)
+ bpb.nft = 2;
+ if (!fat) {
+ if (bpb.bsec < (bpb.res ? bpb.res : bss) +
+ howmany((RESFTE + (bpb.spc ? MINCLS16 : MAXCLS12 + 1)) *
+ ((bpb.spc ? 16 : 12) / BPN), bpb.bps * NPB) *
+ bpb.nft +
+ howmany(bpb.rde ? bpb.rde : DEFRDE,
+ bpb.bps / sizeof(struct de)) +
+ (bpb.spc ? MINCLS16 : MAXCLS12 + 1) *
+ (bpb.spc ? bpb.spc : howmany(DEFBLK, bpb.bps)))
+ fat = 12;
+ else if (bpb.rde || bpb.bsec <
+ (bpb.res ? bpb.res : bss) +
+ howmany((RESFTE + MAXCLS16) * 2, bpb.bps) * bpb.nft +
+ howmany(DEFRDE, bpb.bps / sizeof(struct de)) +
+ (MAXCLS16 + 1) *
+ (bpb.spc ? bpb.spc : howmany(8192, bpb.bps)))
+ fat = 16;
+ else
+ fat = 32;
+ }
+ x = bss;
+ if (fat == 32) {
+ if (!bpb.infs) {
+ if (x == MAXU16 || x == bpb.bkbs)
+ errx(1, "no room for info sector");
+ bpb.infs = x;
+ }
+ if (bpb.infs != MAXU16 && x <= bpb.infs)
+ x = bpb.infs + 1;
+ if (!bpb.bkbs) {
+ if (x == MAXU16)
+ errx(1, "no room for backup sector");
+ bpb.bkbs = x;
+ } else if (bpb.bkbs != MAXU16 && bpb.bkbs == bpb.infs)
+ errx(1, "backup sector would overwrite info sector");
+ if (bpb.bkbs != MAXU16 && x <= bpb.bkbs)
+ x = bpb.bkbs + 1;
+ }
+ if (!bpb.res)
+ bpb.res = fat == 32 ? MAX(x, MAX(16384 / bpb.bps, 4)) : x;
+ else if (bpb.res < x)
+ errx(1, "too few reserved sectors");
+ if (fat != 32 && !bpb.rde)
+ bpb.rde = DEFRDE;
+ rds = howmany(bpb.rde, bpb.bps / sizeof(struct de));
+ if (!bpb.spc)
+ for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bps);
+ bpb.spc < MAXSPC &&
+ bpb.res +
+ howmany((RESFTE + maxcls(fat)) * (fat / BPN),
+ bpb.bps * NPB) * bpb.nft +
+ rds +
+ (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec;
+ bpb.spc <<= 1);
+ if (fat != 32 && bpb.bspf > MAXU16)
+ errx(1, "too many sectors/FAT for FAT12/16");
+ x1 = bpb.res + rds;
+ x = bpb.bspf ? bpb.bspf : 1;
+ if (x1 + (u_int64_t)x * bpb.nft > bpb.bsec)
+ errx(1, "meta data exceeds file system size");
+ x1 += x * bpb.nft;
+ x = (u_int64_t)(bpb.bsec - x1) * bpb.bps * NPB /
+ (bpb.spc * bpb.bps * NPB + fat / BPN * bpb.nft);
+ x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN),
+ bpb.bps * NPB);
+ if (!bpb.bspf) {
+ bpb.bspf = x2;
+ x1 += (bpb.bspf - 1) * bpb.nft;
+ }
+ cls = (bpb.bsec - x1) / bpb.spc;
+ x = (u_int64_t)bpb.bspf * bpb.bps * NPB / (fat / BPN) - RESFTE;
+ if (cls > x)
+ cls = x;
+ if (bpb.bspf < x2)
+ warnx("warning: sectors/FAT limits file system to %u clusters",
+ cls);
+ if (cls < mincls(fat))
+ errx(1, "%u clusters too few clusters for FAT%u, need %u", cls, fat,
+ mincls(fat));
+ if (cls > maxcls(fat)) {
+ cls = maxcls(fat);
+ bpb.bsec = x1 + (cls + 1) * bpb.spc - 1;
+ warnx("warning: FAT type limits file system to %u sectors",
+ bpb.bsec);
+ }
+ printf("%s: %u sector%s in %u FAT%u cluster%s "
+ "(%u bytes/cluster)\n", fname, cls * bpb.spc,
+ cls * bpb.spc == 1 ? "" : "s", cls, fat,
+ cls == 1 ? "" : "s", bpb.bps * bpb.spc);
+ if (!bpb.mid)
+ bpb.mid = !bpb.hid ? 0xf0 : 0xf8;
+ if (fat == 32)
+ bpb.rdcl = RESFTE;
+ if (bpb.hid + bpb.bsec <= MAXU16) {
+ bpb.sec = bpb.bsec;
+ bpb.bsec = 0;
+ }
+ if (fat != 32) {
+ bpb.spf = bpb.bspf;
+ bpb.bspf = 0;
+ }
+ print_bpb(&bpb);
+ if (!opt_N) {
+ gettimeofday(&tv, NULL);
+ now = tv.tv_sec;
+ tm = localtime(&now);
+ if (!(img = malloc(bpb.bps)))
+ err(1, NULL);
+ dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft;
+ for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) {
+ x = lsn;
+ if (opt_B &&
+ fat == 32 && bpb.bkbs != MAXU16 &&
+ bss <= bpb.bkbs && x >= bpb.bkbs) {
+ x -= bpb.bkbs;
+ if (!x && lseek(fd1, opt_ofs, SEEK_SET))
+ err(1, "%s", bname);
+ }
+ if (opt_B && x < bss) {
+ if ((n = read(fd1, img, bpb.bps)) == -1)
+ err(1, "%s", bname);
+ if ((unsigned)n != bpb.bps)
+ errx(1, "%s: can't read sector %u", bname, x);
+ } else
+ memset(img, 0, bpb.bps);
+ if (!lsn ||
+ (fat == 32 && bpb.bkbs != MAXU16 && lsn == bpb.bkbs)) {
+ x1 = sizeof(struct bs);
+ bsbpb = (struct bsbpb *)(img + x1);
+ mk2(bsbpb->bps, bpb.bps);
+ mk1(bsbpb->spc, bpb.spc);
+ mk2(bsbpb->res, bpb.res);
+ mk1(bsbpb->nft, bpb.nft);
+ mk2(bsbpb->rde, bpb.rde);
+ mk2(bsbpb->sec, bpb.sec);
+ mk1(bsbpb->mid, bpb.mid);
+ mk2(bsbpb->spf, bpb.spf);
+ mk2(bsbpb->spt, bpb.spt);
+ mk2(bsbpb->hds, bpb.hds);
+ mk4(bsbpb->hid, bpb.hid);
+ mk4(bsbpb->bsec, bpb.bsec);
+ x1 += sizeof(struct bsbpb);
+ if (fat == 32) {
+ bsxbpb = (struct bsxbpb *)(img + x1);
+ mk4(bsxbpb->bspf, bpb.bspf);
+ mk2(bsxbpb->xflg, 0);
+ mk2(bsxbpb->vers, 0);
+ mk4(bsxbpb->rdcl, bpb.rdcl);
+ mk2(bsxbpb->infs, bpb.infs);
+ mk2(bsxbpb->bkbs, bpb.bkbs);
+ x1 += sizeof(struct bsxbpb);
+ }
+ bsx = (struct bsx *)(img + x1);
+ mk1(bsx->sig, 0x29);
+ if (Iflag)
+ x = opt_I;
+ else
+ x = (((u_int)(1 + tm->tm_mon) << 8 |
+ (u_int)tm->tm_mday) +
+ ((u_int)tm->tm_sec << 8 |
+ (u_int)(tv.tv_usec / 10))) << 16 |
+ ((u_int)(1900 + tm->tm_year) +
+ ((u_int)tm->tm_hour << 8 |
+ (u_int)tm->tm_min));
+ mk4(bsx->volid, x);
+ mklabel(bsx->label, opt_L ? opt_L : "NO NAME");
+ sprintf(buf, "FAT%u", fat);
+ setstr(bsx->type, buf, sizeof(bsx->type));
+ if (!opt_B) {
+ x1 += sizeof(struct bsx);
+ bs = (struct bs *)img;
+ mk1(bs->jmp[0], 0xeb);
+ mk1(bs->jmp[1], x1 - 2);
+ mk1(bs->jmp[2], 0x90);
+ setstr(bs->oem, opt_O ? opt_O : "BSD 4.4",
+ sizeof(bs->oem));
+ memcpy(img + x1, bootcode, sizeof(bootcode));
+ mk2(img + MINBPS - 2, DOSMAGIC);
+ }
+ } else if (fat == 32 && bpb.infs != MAXU16 &&
+ (lsn == bpb.infs ||
+ (bpb.bkbs != MAXU16 &&
+ lsn == bpb.bkbs + bpb.infs))) {
+ mk4(img, 0x41615252);
+ mk4(img + MINBPS - 28, 0x61417272);
+ mk4(img + MINBPS - 24, 0xffffffff);
+ mk4(img + MINBPS - 20, bpb.rdcl);
+ mk2(img + MINBPS - 2, DOSMAGIC);
+ } else if (lsn >= bpb.res && lsn < dir &&
+ !((lsn - bpb.res) %
+ (bpb.spf ? bpb.spf : bpb.bspf))) {
+ mk1(img[0], bpb.mid);
+ for (x = 1; x < fat * (fat == 32 ? 3 : 2) / 8; x++)
+ mk1(img[x], fat == 32 && x % 4 == 3 ? 0x0f : 0xff);
+ } else if (lsn == dir && opt_L) {
+ de = (struct de *)img;
+ mklabel(de->namext, opt_L);
+ mk1(de->attr, 050);
+ x = (u_int)tm->tm_hour << 11 |
+ (u_int)tm->tm_min << 5 |
+ (u_int)tm->tm_sec >> 1;
+ mk2(de->time, x);
+ x = (u_int)(tm->tm_year - 80) << 9 |
+ (u_int)(tm->tm_mon + 1) << 5 |
+ (u_int)tm->tm_mday;
+ mk2(de->date, x);
+ }
+ if ((n = write(fd, img, bpb.bps)) == -1)
+ err(1, "%s", fname);
+ if ((unsigned)n != bpb.bps)
+ errx(1, "%s: can't write sector %u", fname, lsn);
+ }
+ }
+ return 0;
+}
+
+/*
+ * Exit with error if file system is mounted.
+ */
+static void
+check_mounted(const char *fname, mode_t mode)
+{
+ struct statfs *mp;
+ const char *s1, *s2;
+ size_t len;
+ int n, r;
+
+#ifdef ANDROID
+ warnx("Skipping mount checks");
+#else
+ if (!(n = getmntinfo(&mp, MNT_NOWAIT)))
+ err(1, "getmntinfo");
+ len = strlen(_PATH_DEV);
+ s1 = fname;
+ if (!strncmp(s1, _PATH_DEV, len))
+ s1 += len;
+ r = S_ISCHR(mode) && s1 != fname && *s1 == 'r';
+ for (; n--; mp++) {
+ s2 = mp->f_mntfromname;
+ if (!strncmp(s2, _PATH_DEV, len))
+ s2 += len;
+ if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) ||
+ !strcmp(s1, s2))
+ errx(1, "%s is mounted on %s", fname, mp->f_mntonname);
+ }
+#endif
+}
+
+/*
+ * Get a standard format.
+ */
+static void
+getstdfmt(const char *fmt, struct bpb *bpb)
+{
+ u_int x, i;
+
+ x = sizeof(stdfmt) / sizeof(stdfmt[0]);
+ for (i = 0; i < x && strcmp(fmt, stdfmt[i].name); i++);
+ if (i == x)
+ errx(1, "%s: unknown standard format", fmt);
+ *bpb = stdfmt[i].bpb;
+}
+
+/*
+ * Get disk slice, partition, and geometry information.
+ */
+
+#ifdef ANDROID
+static void
+getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag,
+ struct bpb *bpb)
+{
+ struct hd_geometry geom;
+
+ if (ioctl(fd, BLKSSZGET, &bpb->bps)) {
+ fprintf(stderr, "Error getting bytes / sector (%s)", strerror(errno));
+ exit(1);
+ }
+
+ ckgeom(fname, bpb->bps, "bytes/sector");
+
+ if (ioctl(fd, BLKGETSIZE, &bpb->bsec)) {
+ fprintf(stderr, "Error getting blocksize (%s)", strerror(errno));
+ exit(1);
+ }
+
+ if (ioctl(fd, HDIO_GETGEO, &geom)) {
+ fprintf(stderr, "Error getting gemoetry (%s)", strerror(errno));
+ exit(1);
+ }
+
+ bpb->spt = geom.sectors;
+ ckgeom(fname, bpb->spt, "sectors/track");
+
+ bpb->hds = geom.heads;
+ ckgeom(fname, bpb->hds, "drive heads");
+}
+
+#else
+
+static void
+getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag,
+ struct bpb *bpb)
+{
+ struct disklabel *lp, dlp;
+ struct fd_type type;
+ off_t ms, hs = 0;
+
+ lp = NULL;
+
+ /* If the user specified a disk type, try to use that */
+ if (dtype != NULL) {
+ lp = getdiskbyname(dtype);
+ }
+
+ /* Maybe it's a floppy drive */
+ if (lp == NULL) {
+ if (ioctl(fd, DIOCGMEDIASIZE, &ms) == -1) {
+ struct stat st;
+
+ if (fstat(fd, &st))
+ err(1, "Cannot get disk size");
+ /* create a fake geometry for a file image */
+ ms = st.st_size;
+ dlp.d_secsize = 512;
+ dlp.d_nsectors = 63;
+ dlp.d_ntracks = 255;
+ dlp.d_secperunit = ms / dlp.d_secsize;
+ lp = &dlp;
+ } else if (ioctl(fd, FD_GTYPE, &type) != -1) {
+ dlp.d_secsize = 128 << type.secsize;
+ dlp.d_nsectors = type.sectrac;
+ dlp.d_ntracks = type.heads;
+ dlp.d_secperunit = ms / dlp.d_secsize;
+ lp = &dlp;
+ }
+ }
+
+ /* Maybe it's a fixed drive */
+ if (lp == NULL) {
+ if (ioctl(fd, DIOCGDINFO, &dlp) == -1) {
+ if (bpb->bps == 0 && ioctl(fd, DIOCGSECTORSIZE, &dlp.d_secsize) == -1)
+ errx(1, "Cannot get sector size, %s", strerror(errno));
+
+ /* XXX Should we use bpb->bps if it's set? */
+ dlp.d_secperunit = ms / dlp.d_secsize;
+
+ if (bpb->spt == 0 && ioctl(fd, DIOCGFWSECTORS, &dlp.d_nsectors) == -1) {
+ warnx("Cannot get number of sectors per track, %s", strerror(errno));
+ dlp.d_nsectors = 63;
+ }
+ if (bpb->hds == 0 && ioctl(fd, DIOCGFWHEADS, &dlp.d_ntracks) == -1) {
+ warnx("Cannot get number of heads, %s", strerror(errno));
+ if (dlp.d_secperunit <= 63*1*1024)
+ dlp.d_ntracks = 1;
+ else if (dlp.d_secperunit <= 63*16*1024)
+ dlp.d_ntracks = 16;
+ else
+ dlp.d_ntracks = 255;
+ }
+ }
+
+ hs = (ms / dlp.d_secsize) - dlp.d_secperunit;
+ lp = &dlp;
+ }
+
+ if (bpb->bps == 0)
+ bpb->bps = ckgeom(fname, lp->d_secsize, "bytes/sector");
+ if (bpb->spt == 0)
+ bpb->spt = ckgeom(fname, lp->d_nsectors, "sectors/track");
+ if (bpb->hds == 0)
+ bpb->hds = ckgeom(fname, lp->d_ntracks, "drive heads");
+ if (bpb->bsec == 0)
+ bpb->bsec = lp->d_secperunit;
+ if (bpb->hid == 0)
+ bpb->hid = hs;
+}
+#endif
+
+/*
+ * Print out BPB values.
+ */
+static void
+print_bpb(struct bpb *bpb)
+{
+ printf("bps=%u spc=%u res=%u nft=%u", bpb->bps, bpb->spc, bpb->res,
+ bpb->nft);
+ if (bpb->rde)
+ printf(" rde=%u", bpb->rde);
+ if (bpb->sec)
+ printf(" sec=%u", bpb->sec);
+ printf(" mid=%#x", bpb->mid);
+ if (bpb->spf)
+ printf(" spf=%u", bpb->spf);
+ printf(" spt=%u hds=%u hid=%u", bpb->spt, bpb->hds, bpb->hid);
+ if (bpb->bsec)
+ printf(" bsec=%u", bpb->bsec);
+ if (!bpb->spf) {
+ printf(" bspf=%u rdcl=%u", bpb->bspf, bpb->rdcl);
+ printf(" infs=");
+ printf(bpb->infs == MAXU16 ? "%#x" : "%u", bpb->infs);
+ printf(" bkbs=");
+ printf(bpb->bkbs == MAXU16 ? "%#x" : "%u", bpb->bkbs);
+ }
+ printf("\n");
+}
+
+/*
+ * Check a disk geometry value.
+ */
+static u_int
+ckgeom(const char *fname, u_int val, const char *msg)
+{
+ if (!val)
+ errx(1, "%s: no default %s", fname, msg);
+ if (val > MAXU16)
+ errx(1, "%s: illegal %s %d", fname, msg, val);
+ return val;
+}
+
+/*
+ * Convert and check a numeric option argument.
+ */
+static u_int
+argtou(const char *arg, u_int lo, u_int hi, const char *msg)
+{
+ char *s;
+ u_long x;
+
+ errno = 0;
+ x = strtoul(arg, &s, 0);
+ if (errno || !*arg || *s || x < lo || x > hi)
+ errx(1, "%s: bad %s", arg, msg);
+ return x;
+}
+
+/*
+ * Same for off_t, with optional skmgpP suffix
+ */
+static off_t
+argtooff(const char *arg, const char *msg)
+{
+ char *s;
+ off_t x;
+
+ x = strtoll(arg, &s, 0);
+ /* allow at most one extra char */
+ if (errno || x < 0 || (s[0] && s[1]) )
+ errx(1, "%s: bad %s", arg, msg);
+ if (*s) { /* the extra char is the multiplier */
+ switch (*s) {
+ default:
+ errx(1, "%s: bad %s", arg, msg);
+ /* notreached */
+
+ case 's': /* sector */
+ case 'S':
+ x <<= 9; /* times 512 */
+ break;
+
+ case 'k': /* kilobyte */
+ case 'K':
+ x <<= 10; /* times 1024 */
+ break;
+
+ case 'm': /* megabyte */
+ case 'M':
+ x <<= 20; /* times 1024*1024 */
+ break;
+
+ case 'g': /* gigabyte */
+ case 'G':
+ x <<= 30; /* times 1024*1024*1024 */
+ break;
+
+ case 'p': /* partition start */
+ case 'P': /* partition start */
+ case 'l': /* partition length */
+ case 'L': /* partition length */
+ errx(1, "%s: not supported yet %s", arg, msg);
+ /* notreached */
+ }
+ }
+ return x;
+}
+
+/*
+ * Check a volume label.
+ */
+static int
+oklabel(const char *src)
+{
+ int c, i;
+
+ for (i = 0; i <= 11; i++) {
+ c = (u_char)*src++;
+ if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c))
+ break;
+ }
+ return i && !c;
+}
+
+/*
+ * Make a volume label.
+ */
+static void
+mklabel(u_int8_t *dest, const char *src)
+{
+ int c, i;
+
+ for (i = 0; i < 11; i++) {
+ c = *src ? toupper(*src++) : ' ';
+ *dest++ = !i && c == '\xe5' ? 5 : c;
+ }
+}
+
+/*
+ * Copy string, padding with spaces.
+ */
+static void
+setstr(u_int8_t *dest, const char *src, size_t len)
+{
+ while (len--)
+ *dest++ = *src ? *src++ : ' ';
+}
+
+/*
+ * Print usage message.
+ */
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "usage: newfs_msdos [ -options ] special [disktype]\n"
+ "where the options are:\n"
+ "\t-@ create file system at specified offset\n"
+ "\t-B get bootstrap from file\n"
+ "\t-C create image file with specified size\n"
+ "\t-F FAT type (12, 16, or 32)\n"
+ "\t-I volume ID\n"
+ "\t-L volume label\n"
+ "\t-N don't create file system: just print out parameters\n"
+ "\t-O OEM string\n"
+ "\t-S bytes/sector\n"
+ "\t-a sectors/FAT\n"
+ "\t-b block size\n"
+ "\t-c sectors/cluster\n"
+ "\t-e root directory entries\n"
+ "\t-f standard format\n"
+ "\t-h drive heads\n"
+ "\t-i file system info sector\n"
+ "\t-k backup boot sector\n"
+ "\t-m media descriptor\n"
+ "\t-n number of FATs\n"
+ "\t-o hidden sectors\n"
+ "\t-r reserved sectors\n"
+ "\t-s file system size (sectors)\n"
+ "\t-u sectors/track\n");
+ exit(1);
+}
diff --git a/toolbox/route.c b/toolbox/route.c
index adf5c69..4f66201 100644
--- a/toolbox/route.c
+++ b/toolbox/route.c
@@ -1,97 +1,103 @@
+/*
+ * Copyright (c) 2009, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <errno.h>
#include <string.h>
-#include <ctype.h>
-
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
-#include <linux/if.h>
-#include <linux/sockios.h>
#include <arpa/inet.h>
#include <linux/route.h>
-static void die(const char *s)
-{
- fprintf(stderr,"error: %s (%s)\n", s, strerror(errno));
- exit(-1);
+static inline int set_address(const char *address, struct sockaddr *sa) {
+ return inet_aton(address, &((struct sockaddr_in *)sa)->sin_addr);
}
-static inline void init_sockaddr_in(struct sockaddr_in *sin, const char *addr)
-{
- sin->sin_family = AF_INET;
- sin->sin_port = 0;
- sin->sin_addr.s_addr = inet_addr(addr);
-}
-
-#define ADVANCE(argc, argv) do { argc--, argv++; } while(0)
-#define EXPECT_NEXT(argc, argv) do { \
- ADVANCE(argc, argv); \
- if (0 == argc) { \
- errno = EINVAL; \
- die("expecting one more argument"); \
- } \
-} while(0)
-
-/* current support two kinds of usage */
+/* current support the following routing entries */
/* route add default dev wlan0 */
-/* route add default gw 192.168.20.1 dev wlan0 */
+/* route add default gw 192.168.1.1 dev wlan0 */
+/* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */
int route_main(int argc, char *argv[])
{
- struct ifreq ifr;
- int s,i;
- struct rtentry rt;
- struct sockaddr_in ina;
-
- if(argc == 0) return 0;
-
- strncpy(ifr.ifr_name, argv[0], IFNAMSIZ);
- ifr.ifr_name[IFNAMSIZ-1] = 0;
- ADVANCE(argc, argv);
+ struct rtentry rt = {
+ .rt_dst = {.sa_family = AF_INET},
+ .rt_genmask = {.sa_family = AF_INET},
+ .rt_gateway = {.sa_family = AF_INET},
+ };
- if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- die("cannot open control socket\n");
- }
+ errno = EINVAL;
+ if (argc > 2 && !strcmp(argv[1], "add")) {
+ if (!strcmp(argv[2], "default")) {
+ /* route add default dev wlan0 */
+ if (argc > 4 && !strcmp(argv[3], "dev")) {
+ rt.rt_flags = RTF_UP | RTF_HOST;
+ rt.rt_dev = argv[4];
+ errno = 0;
+ goto apply;
+ }
- while(argc > 0){
- if(!strcmp(argv[0], "add")) {
- EXPECT_NEXT(argc, argv);
- if(!strcmp(argv[0], "default")) {
- EXPECT_NEXT(argc, argv);
- memset((char *) &rt, 0, sizeof(struct rtentry));
- rt.rt_dst.sa_family = AF_INET;
- if(!strcmp(argv[0], "dev")) {
- EXPECT_NEXT(argc, argv);
- rt.rt_flags = RTF_UP | RTF_HOST;
- rt.rt_dev = argv[0];
- if (ioctl(s, SIOCADDRT, &rt) < 0) die("SIOCADDRT");
- }else if(!strcmp(argv[0], "gw")) {
- EXPECT_NEXT(argc, argv);
- rt.rt_flags = RTF_UP | RTF_GATEWAY;
- init_sockaddr_in((struct sockaddr_in *)&(rt.rt_genmask), "0.0.0.0");
- if(isdigit(argv[0][0])){
- init_sockaddr_in((struct sockaddr_in *)&(rt.rt_gateway), argv[0]);
- }else{
- die("expecting an IP address for parameter \"gw\"");
- }
- EXPECT_NEXT(argc, argv);
- if(!strcmp(argv[0], "dev")) {
- EXPECT_NEXT(argc, argv);
- rt.rt_dev = argv[0];
- if (ioctl(s, SIOCADDRT, &rt) < 0){
- die("SIOCADDRT");
- }
- }
- }
- }
+ /* route add default gw 192.168.1.1 dev wlan0 */
+ if (argc > 6 && !strcmp(argv[3], "gw") && !strcmp(argv[5], "dev")) {
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+ rt.rt_dev = argv[6];
+ if (set_address(argv[4], &rt.rt_gateway)) {
+ errno = 0;
+ }
+ goto apply;
+ }
}
- ADVANCE(argc, 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;
+ }
+ goto apply;
+ }
}
- return 0;
+apply:
+ if (!errno) {
+ int s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s != -1 && (ioctl(s, SIOCADDRT, &rt) != -1 || errno == EEXIST)) {
+ return 0;
+ }
+ }
+ puts(strerror(errno));
+ return errno;
}
-
diff --git a/vold/format.c b/vold/format.c
index 3383949..cd40197 100755
--- a/vold/format.c
+++ b/vold/format.c
@@ -26,7 +26,7 @@
#include "diskmbr.h"
#include "logwrapper.h"
-static char MKDOSFS_PATH[] = "/system/bin/mkdosfs";
+static char MKDOSFS_PATH[] = "/system/bin/newfs_msdos";
static char MKE2FS_PATH[] = "/system/bin/mke2fs";
int format_partition(blkdev_t *part, char *type)
@@ -37,14 +37,17 @@
devpath = blkdev_get_devpath(part);
if (!strcmp(type, FORMAT_TYPE_FAT32)) {
- char *args[6];
+ char *args[9];
args[0] = MKDOSFS_PATH;
- args[1] = "-c 32";
- args[2] = "-n 2";
- args[3] = "-O android";
- args[4] = devpath;
- args[5] = NULL;
- rc = logwrap(5, args);
+ args[1] = "-F";
+ args[2] = "32";
+ args[3] = "-c";
+ args[4] = "16";
+ args[5] = "-O";
+ args[6] = "android";
+ args[7] = devpath;
+ args[8] = NULL;
+ rc = logwrap(8, args, 1);
} else {
char *args[7];
args[0] = MKE2FS_PATH;
@@ -54,7 +57,7 @@
args[4] = "-v";
args[5] = devpath;
args[6] = NULL;
- rc = logwrap(6, args);
+ rc = logwrap(6, args, 1);
}
free(devpath);
diff --git a/vold/logwrapper.c b/vold/logwrapper.c
index 2900f2e..8da4892 100644
--- a/vold/logwrapper.c
+++ b/vold/logwrapper.c
@@ -42,7 +42,8 @@
buffer[b] = '\0';
} else if (buffer[b] == '\n') {
buffer[b] = '\0';
- LOG(LOG_INFO, tag, &buffer[a]);
+
+ LOG(LOG_INFO, tag, "%s", &buffer[a]);
a = b + 1;
}
}
@@ -100,7 +101,7 @@
}
}
-int logwrap(int argc, char* argv[], pid_t *childPid)
+int logwrap(int argc, char* argv[], pid_t *childPid, int background)
{
pid_t pid;
@@ -138,6 +139,25 @@
dup2(child_ptty, 2);
close(child_ptty);
+ if (background) {
+ int fd = open("/dev/cpuctl/bg_non_interactive/tasks", O_WRONLY);
+
+ if (fd >=0 ) {
+ char text[64];
+
+ sprintf(text, "%d", getpid());
+ if (write(fd, text, strlen(text)) < 0) {
+ LOG(LOG_WARN, "logwrapper",
+ "Unable to background process (%s)", strerror(errno));
+ close(fd);
+ }
+ close(fd);
+ } else {
+ LOG(LOG_WARN, "logwrapper",
+ "Unable to background process (%s)", strerror(errno));
+ }
+ }
+
child(argc, argv);
} else {
return parent(argv[0], parent_ptty);
diff --git a/vold/logwrapper.h b/vold/logwrapper.h
index 602e24c..bf28aae 100644
--- a/vold/logwrapper.h
+++ b/vold/logwrapper.h
@@ -19,5 +19,5 @@
#define _LOGWRAPPER_H
#include <stdlib.h>
-int logwrap(int argc, char* argv[]);
+int logwrap(int argc, char* argv[], int background);
#endif
diff --git a/vold/uevent.c b/vold/uevent.c
index cfb5786..66e70c5 100644
--- a/vold/uevent.c
+++ b/vold/uevent.c
@@ -272,8 +272,7 @@
else
door_open = false;
volmgr_safe_mode(low_batt || door_open);
- } else
- LOG_VOL("handle_switch_event(): Ignoring switch '%s'", name);
+ }
return 0;
}
diff --git a/vold/volmgr_ext3.c b/vold/volmgr_ext3.c
index 680be21..fe3b2bb 100644
--- a/vold/volmgr_ext3.c
+++ b/vold/volmgr_ext3.c
@@ -107,7 +107,7 @@
args[3] = devpath;
args[4] = NULL;
- int rc = logwrap(4, args);
+ int rc = logwrap(4, args, 1);
if (rc == 0) {
LOG_VOL("filesystem '%s' had no errors", devpath);
diff --git a/vold/volmgr_vfat.c b/vold/volmgr_vfat.c
index 344a166..7a4e12f 100644
--- a/vold/volmgr_vfat.c
+++ b/vold/volmgr_vfat.c
@@ -26,7 +26,7 @@
#define VFAT_DEBUG 0
-static char FSCK_MSDOS_PATH[] = "/system/bin/dosfsck";
+static char FSCK_MSDOS_PATH[] = "/system/bin/fsck_msdos";
int vfat_identify(blkdev_t *dev)
{
@@ -39,6 +39,7 @@
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,43 +51,24 @@
return 0;
}
-#ifdef VERIFY_PASS
- char *args[7];
+ char *args[5];
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
+ args[1] = "-p";
+ args[2] = "-f";
+ args[3] = blkdev_get_devpath(dev);
+ args[4] = NULL;
+ rc = logwrap(4, args, 1);
+ 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 == 8) {
LOG_VOL("Filesystem check failed (not a FAT filesystem)");
return -ENODATA;
+ } else if (rc == -11) {
+ LOG_VOL("Filesystem check crashed");
+ return -EIO;
} else {
LOG_VOL("Filesystem check failed (unknown exit code %d)", rc);
return -EIO;
@@ -113,15 +95,22 @@
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