Merge "Document the SELinux extensions to the Android init language."
diff --git a/adb/Android.mk b/adb/Android.mk
index 1a25106..bc8315e 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -33,16 +33,16 @@
ifeq ($(HOST_OS),windows)
USB_SRCS := usb_windows.c
- EXTRA_SRCS := get_my_path_windows.c
+ EXTRA_SRCS := get_my_path_windows.c ../libcutils/list.c
EXTRA_STATIC_LIBS := AdbWinApi
ifneq ($(strip $(USE_CYGWIN)),)
# Pure cygwin case
- LOCAL_LDLIBS += -lpthread
+ LOCAL_LDLIBS += -lpthread -lgdi32
LOCAL_C_INCLUDES += /usr/include/w32api/ddk
endif
ifneq ($(strip $(USE_MINGW)),)
# MinGW under Linux case
- LOCAL_LDLIBS += -lws2_32
+ LOCAL_LDLIBS += -lws2_32 -lgdi32
USE_SYSDEPS_WIN32 := 1
LOCAL_C_INCLUDES += /usr/i586-mingw32msvc/include/ddk
endif
@@ -57,6 +57,7 @@
transport_usb.c \
commandline.c \
adb_client.c \
+ adb_auth_host.c \
sockets.c \
services.c \
file_sync_client.c \
@@ -65,6 +66,7 @@
utils.c \
usb_vendors.c
+LOCAL_C_INCLUDES += external/openssl/include
ifneq ($(USE_SYSDEPS_WIN32),)
LOCAL_SRC_FILES += sysdeps_win32.c
@@ -76,14 +78,14 @@
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
LOCAL_MODULE := adb
-LOCAL_STATIC_LIBRARIES := libzipfile libunz $(EXTRA_STATIC_LIBS)
+LOCAL_STATIC_LIBRARIES := libzipfile libunz libcrypto_static $(EXTRA_STATIC_LIBS)
ifeq ($(USE_SYSDEPS_WIN32),)
LOCAL_STATIC_LIBRARIES += libcutils
endif
include $(BUILD_HOST_EXECUTABLE)
-$(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE))
+$(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
ifeq ($(HOST_OS),windows)
$(LOCAL_INSTALLED_MODULE): \
@@ -104,6 +106,7 @@
transport.c \
transport_local.c \
transport_usb.c \
+ adb_auth_client.c \
sockets.c \
services.c \
file_sync_service.c \
@@ -127,7 +130,7 @@
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
-LOCAL_STATIC_LIBRARIES := libcutils libc
+LOCAL_STATIC_LIBRARIES := libcutils libc libmincrypt
include $(BUILD_EXECUTABLE)
@@ -146,6 +149,7 @@
transport_usb.c \
commandline.c \
adb_client.c \
+ adb_auth_host.c \
sockets.c \
services.c \
file_sync_client.c \
@@ -165,9 +169,13 @@
-D_XOPEN_SOURCE \
-D_GNU_SOURCE
+LOCAL_C_INCLUDES += external/openssl/include
+
LOCAL_MODULE := adb
LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils
+LOCAL_SHARED_LIBRARIES := libcrypto
+
include $(BUILD_EXECUTABLE)
endif
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT
index be4d50b..d9aa09c 100644
--- a/adb/SERVICES.TXT
+++ b/adb/SERVICES.TXT
@@ -17,8 +17,10 @@
upgrade.
host:devices
+host:devices-l
Ask to return the list of available Android devices and their
- state. After the OKAY, this is followed by a 4-byte hex len,
+ state. devices-l includes the device paths in the state.
+ After the OKAY, this is followed by a 4-byte hex len,
and a string that will be dumped as-is by the client, then
the connection is closed
@@ -88,6 +90,9 @@
Returns the serial number of the corresponding device/emulator.
Note that emulator serial numbers are of the form "emulator-5554"
+<host-prefix>:get-devpath
+ Returns the device path of the corresponding device/emulator.
+
<host-prefix>:get-state
Returns the state of a given device as a string.
diff --git a/adb/adb.c b/adb/adb.c
index 229f3ef..07bfbe5 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -21,17 +21,22 @@
#include <ctype.h>
#include <stdarg.h>
#include <errno.h>
+#include <stddef.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include "sysdeps.h"
#include "adb.h"
+#include "adb_auth.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#if !ADB_HOST
#include <private/android_filesystem_config.h>
#include <linux/capability.h>
#include <linux/prctl.h>
+#include <sys/mount.h>
#else
#include "usb_vendors.h"
#endif
@@ -42,7 +47,11 @@
int HOST = 0;
+static int auth_enabled = 0;
+
+#if !ADB_HOST
static const char *adb_device_banner = "device";
+#endif
void fatal(const char *fmt, ...)
{
@@ -94,6 +103,7 @@
{ "transport", TRACE_TRANSPORT },
{ "jdwp", TRACE_JDWP },
{ "services", TRACE_SERVICES },
+ { "auth", TRACE_AUTH },
{ NULL, 0 }
};
@@ -197,19 +207,21 @@
free(p);
}
-void handle_online(void)
+void handle_online(atransport *t)
{
D("adb: online\n");
+ t->online = 1;
}
void handle_offline(atransport *t)
{
D("adb: offline\n");
//Close the associated usb
+ t->online = 0;
run_transport_disconnects(t);
}
-#if TRACE_PACKETS
+#if DEBUG_PACKETS
#define DUMPMAX 32
void print_packet(const char *label, apacket *p)
{
@@ -224,6 +236,7 @@
case A_OKAY: tag = "OKAY"; break;
case A_CLSE: tag = "CLSE"; break;
case A_WRTE: tag = "WRTE"; break;
+ case A_AUTH: tag = "AUTH"; break;
default: tag = "????"; break;
}
@@ -245,7 +258,7 @@
}
x++;
}
- fprintf(stderr, tag);
+ fputs(tag, stderr);
}
#endif
@@ -269,6 +282,36 @@
send_packet(p, t);
}
+static size_t fill_connect_data(char *buf, size_t bufsize)
+{
+#if ADB_HOST
+ return snprintf(buf, bufsize, "host::") + 1;
+#else
+ static const char *cnxn_props[] = {
+ "ro.product.name",
+ "ro.product.model",
+ "ro.product.device",
+ };
+ static const int num_cnxn_props = ARRAY_SIZE(cnxn_props);
+ int i;
+ size_t remaining = bufsize;
+ size_t len;
+
+ len = snprintf(buf, remaining, "%s::", adb_device_banner);
+ remaining -= len;
+ buf += len;
+ for (i = 0; i < num_cnxn_props; i++) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get(cnxn_props[i], value, "");
+ len = snprintf(buf, remaining, "%s=%s;", cnxn_props[i], value);
+ remaining -= len;
+ buf += len;
+ }
+
+ return bufsize - remaining + 1;
+#endif
+}
+
static void send_connect(atransport *t)
{
D("Calling send_connect \n");
@@ -276,15 +319,73 @@
cp->msg.command = A_CNXN;
cp->msg.arg0 = A_VERSION;
cp->msg.arg1 = MAX_PAYLOAD;
- snprintf((char*) cp->data, sizeof cp->data, "%s::",
- HOST ? "host" : adb_device_banner);
- cp->msg.data_length = strlen((char*) cp->data) + 1;
+ cp->msg.data_length = fill_connect_data((char *)cp->data,
+ sizeof(cp->data));
send_packet(cp, t);
-#if ADB_HOST
- /* XXX why sleep here? */
- // allow the device some time to respond to the connect message
- adb_sleep_ms(1000);
-#endif
+}
+
+static void send_auth_request(atransport *t)
+{
+ D("Calling send_auth_request\n");
+ apacket *p;
+ int ret;
+
+ ret = adb_auth_generate_token(t->token, sizeof(t->token));
+ if (ret != sizeof(t->token)) {
+ D("Error generating token ret=%d\n", ret);
+ return;
+ }
+
+ p = get_apacket();
+ memcpy(p->data, t->token, ret);
+ p->msg.command = A_AUTH;
+ p->msg.arg0 = ADB_AUTH_TOKEN;
+ p->msg.data_length = ret;
+ send_packet(p, t);
+}
+
+static void send_auth_response(uint8_t *token, size_t token_size, atransport *t)
+{
+ D("Calling send_auth_response\n");
+ apacket *p = get_apacket();
+ int ret;
+
+ ret = adb_auth_sign(t->key, token, token_size, p->data);
+ if (!ret) {
+ D("Error signing the token\n");
+ put_apacket(p);
+ return;
+ }
+
+ p->msg.command = A_AUTH;
+ p->msg.arg0 = ADB_AUTH_SIGNATURE;
+ p->msg.data_length = ret;
+ send_packet(p, t);
+}
+
+static void send_auth_publickey(atransport *t)
+{
+ D("Calling send_auth_publickey\n");
+ apacket *p = get_apacket();
+ int ret;
+
+ ret = adb_auth_get_userkey(p->data, sizeof(p->data));
+ if (!ret) {
+ D("Failed to get user public key\n");
+ put_apacket(p);
+ return;
+ }
+
+ p->msg.command = A_AUTH;
+ p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
+ p->msg.data_length = ret;
+ send_packet(p, t);
+}
+
+void adb_auth_verified(atransport *t)
+{
+ handle_online(t);
+ send_connect(t);
}
static char *connection_state_name(atransport *t)
@@ -305,29 +406,56 @@
}
}
+/* qual_overwrite is used to overwrite a qualifier string. dst is a
+ * pointer to a char pointer. It is assumed that if *dst is non-NULL, it
+ * was malloc'ed and needs to freed. *dst will be set to a dup of src.
+ */
+static void qual_overwrite(char **dst, const char *src)
+{
+ if (!dst)
+ return;
+
+ free(*dst);
+ *dst = NULL;
+
+ if (!src || !*src)
+ return;
+
+ *dst = strdup(src);
+}
+
void parse_banner(char *banner, atransport *t)
{
- char *type, *product, *end;
+ static const char *prop_seps = ";";
+ static const char key_val_sep = '=';
+ char *cp;
+ char *type;
D("parse_banner: %s\n", banner);
type = banner;
- product = strchr(type, ':');
- if(product) {
- *product++ = 0;
- } else {
- product = "";
- }
-
- /* remove trailing ':' */
- end = strchr(product, ':');
- if(end) *end = 0;
-
- /* save product name in device structure */
- if (t->product == NULL) {
- t->product = strdup(product);
- } else if (strcmp(product, t->product) != 0) {
- free(t->product);
- t->product = strdup(product);
+ cp = strchr(type, ':');
+ if (cp) {
+ *cp++ = 0;
+ /* Nothing is done with second field. */
+ cp = strchr(cp, ':');
+ if (cp) {
+ char *save;
+ char *key;
+ key = adb_strtok_r(cp + 1, prop_seps, &save);
+ while (key) {
+ cp = strchr(key, key_val_sep);
+ if (cp) {
+ *cp++ = '\0';
+ if (!strcmp(key, "ro.product.name"))
+ qual_overwrite(&t->product, cp);
+ else if (!strcmp(key, "ro.product.model"))
+ qual_overwrite(&t->model, cp);
+ else if (!strcmp(key, "ro.product.device"))
+ qual_overwrite(&t->device, cp);
+ }
+ key = adb_strtok_r(NULL, prop_seps, &save);
+ }
+ }
}
if(!strcmp(type, "bootloader")){
@@ -389,13 +517,42 @@
t->connection_state = CS_OFFLINE;
handle_offline(t);
}
+
parse_banner((char*) p->data, t);
- handle_online();
- if(!HOST) send_connect(t);
+
+ if (HOST || !auth_enabled) {
+ handle_online(t);
+ if(!HOST) send_connect(t);
+ } else {
+ send_auth_request(t);
+ }
+ break;
+
+ case A_AUTH:
+ if (p->msg.arg0 == ADB_AUTH_TOKEN) {
+ t->key = adb_auth_nextkey(t->key);
+ if (t->key) {
+ send_auth_response(p->data, p->msg.data_length, t);
+ } else {
+ /* No more private keys to try, send the public key */
+ send_auth_publickey(t);
+ }
+ } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
+ if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
+ adb_auth_verified(t);
+ t->failed_auth_attempts = 0;
+ } else {
+ if (t->failed_auth_attempts++ > 10)
+ adb_sleep_ms(1000);
+ send_auth_request(t);
+ }
+ } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
+ adb_auth_confirm_key(p->data, p->msg.data_length, t);
+ }
break;
case A_OPEN: /* OPEN(local-id, 0, "destination") */
- if(t->connection_state != CS_OFFLINE) {
+ if (t->online) {
char *name = (char*) p->data;
name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
s = create_local_service_socket(name);
@@ -411,7 +568,7 @@
break;
case A_OKAY: /* READY(local-id, remote-id, "") */
- if(t->connection_state != CS_OFFLINE) {
+ if (t->online) {
if((s = find_local_socket(p->msg.arg1))) {
if(s->peer == 0) {
s->peer = create_remote_socket(p->msg.arg0, t);
@@ -423,7 +580,7 @@
break;
case A_CLSE: /* CLOSE(local-id, remote-id, "") */
- if(t->connection_state != CS_OFFLINE) {
+ if (t->online) {
if((s = find_local_socket(p->msg.arg1))) {
s->close(s);
}
@@ -431,7 +588,7 @@
break;
case A_WRTE:
- if(t->connection_state != CS_OFFLINE) {
+ if (t->online) {
if((s = find_local_socket(p->msg.arg1))) {
unsigned rid = p->msg.arg0;
p->len = p->msg.data_length;
@@ -947,12 +1104,12 @@
init_transport_registration();
-
#if ADB_HOST
HOST = 1;
usb_vendors_init();
usb_init();
local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+ adb_auth_init();
char local_name[30];
build_local_name(local_name, sizeof(local_name), server_port);
@@ -960,6 +1117,20 @@
exit(1);
}
#else
+ property_get("ro.adb.secure", value, "0");
+ auth_enabled = !strcmp(value, "1");
+ if (auth_enabled)
+ adb_auth_init();
+
+ // Our external storage path may be different than apps, since
+ // we aren't able to bind mount after dropping root.
+ const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
+ if (NULL != adb_external_storage) {
+ setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
+ } else {
+ D("Warning: ADB_EXTERNAL_STORAGE is not set. Leaving EXTERNAL_STORAGE"
+ " unchanged.\n");
+ }
/* don't listen on a port (default 5037) if running in secure mode */
/* don't run as root if we are running in secure mode */
@@ -1014,24 +1185,29 @@
}
}
- /* for the device, start the usb transport if the
- ** android usb device exists and the "service.adb.tcp.port" and
- ** "persist.adb.tcp.port" properties are not set.
- ** Otherwise start the network transport.
- */
- property_get("service.adb.tcp.port", value, "");
- if (!value[0])
- property_get("persist.adb.tcp.port", value, "");
- if (sscanf(value, "%d", &port) == 1 && port > 0) {
- // listen on TCP port specified by service.adb.tcp.port property
- local_init(port);
- } else if (access("/dev/android_adb", F_OK) == 0) {
+ int usb = 0;
+ if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {
// listen on USB
usb_init();
- } else {
+ usb = 1;
+ }
+
+ // If one of these properties is set, also listen on that port
+ // If one of the properties isn't set and we couldn't listen on usb,
+ // listen on the default port.
+ property_get("service.adb.tcp.port", value, "");
+ if (!value[0]) {
+ property_get("persist.adb.tcp.port", value, "");
+ }
+ if (sscanf(value, "%d", &port) == 1 && port > 0) {
+ printf("using port=%d\n", port);
+ // listen on TCP port specified by service.adb.tcp.port property
+ local_init(port);
+ } else if (!usb) {
// listen on default port
local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
}
+
D("adb_main(): pre init_jdwp()\n");
init_jdwp();
D("adb_main(): post init_jdwp()\n");
@@ -1067,7 +1243,7 @@
strncpy(hostbuf, host, sizeof(hostbuf) - 1);
if (portstr) {
- if ((unsigned int)(portstr - host) >= sizeof(hostbuf)) {
+ if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) {
snprintf(buffer, buffer_size, "bad host name %s", host);
return;
}
@@ -1201,16 +1377,19 @@
}
// return a list of all connected devices
- if (!strcmp(service, "devices")) {
+ if (!strncmp(service, "devices", 7)) {
char buffer[4096];
- memset(buf, 0, sizeof(buf));
- memset(buffer, 0, sizeof(buffer));
- D("Getting device list \n");
- list_transports(buffer, sizeof(buffer));
- snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
- D("Wrote device list \n");
- writex(reply_fd, buf, strlen(buf));
- return 0;
+ int use_long = !strcmp(service+7, "-l");
+ if (use_long || service[7] == 0) {
+ memset(buf, 0, sizeof(buf));
+ memset(buffer, 0, sizeof(buffer));
+ D("Getting device list \n");
+ list_transports(buffer, sizeof(buffer), use_long);
+ snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
+ D("Wrote device list \n");
+ writex(reply_fd, buf, strlen(buf));
+ return 0;
+ }
}
// add a new TCP transport, device or emulator
@@ -1276,6 +1455,16 @@
writex(reply_fd, buf, strlen(buf));
return 0;
}
+ if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
+ char *out = "unknown";
+ transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+ if (transport && transport->devpath) {
+ out = transport->devpath;
+ }
+ snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
+ writex(reply_fd, buf, strlen(buf));
+ return 0;
+ }
// indicates a new emulator instance has started
if (!strncmp(service,"emulator:",9)) {
int port = atoi(service+9);
diff --git a/adb/adb.h b/adb/adb.h
index 03a7393..9da8af8 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -29,13 +29,14 @@
#define A_OKAY 0x59414b4f
#define A_CLSE 0x45534c43
#define A_WRTE 0x45545257
+#define A_AUTH 0x48545541
#define A_VERSION 0x01000000 // ADB protocol version
#define ADB_VERSION_MAJOR 1 // Used for help/version information
#define ADB_VERSION_MINOR 0 // Used for help/version information
-#define ADB_SERVER_VERSION 29 // Increment this when we want to force users to start a new adb server
+#define ADB_SERVER_VERSION 31 // Increment this when we want to force users to start a new adb server
typedef struct amessage amessage;
typedef struct apacket apacket;
@@ -165,6 +166,8 @@
kTransportHost,
} transport_type;
+#define TOKEN_SIZE 20
+
struct atransport
{
atransport *next;
@@ -181,6 +184,7 @@
int ref_count;
unsigned sync_token;
int connection_state;
+ int online;
transport_type type;
/* usb handle or socket fd as needed */
@@ -190,11 +194,19 @@
/* used to identify transports for clients */
char *serial;
char *product;
+ char *model;
+ char *device;
+ char *devpath;
int adb_port; // Use for emulators (local transport)
/* a list of adisconnect callbacks called when the transport is kicked */
int kicked;
adisconnect disconnects;
+
+ void *key;
+ unsigned char token[TOKEN_SIZE];
+ fdevent auth_fde;
+ unsigned failed_auth_attempts;
};
@@ -253,7 +265,7 @@
** get_device_transport does an acquire on your behalf before returning
*/
void init_transport_registration(void);
-int list_transports(char *buf, size_t bufsize);
+int list_transports(char *buf, size_t bufsize, int long_listing);
void update_transports(void);
asocket* create_device_tracker(void);
@@ -286,7 +298,7 @@
void unregister_transport(atransport *t);
void unregister_all_tcp_transports();
-void register_usb_transport(usb_handle *h, const char *serial, unsigned writeable);
+void register_usb_transport(usb_handle *h, const char *serial, const char *devpath, unsigned writeable);
/* this should only be used for transports with connection_state == CS_NOPERM */
void unregister_usb_transport(usb_handle *usb);
@@ -346,6 +358,7 @@
TRACE_SYSDEPS,
TRACE_JDWP, /* 0x100 */
TRACE_SERVICES,
+ TRACE_AUTH,
} AdbTrace;
#if ADB_TRACE
@@ -405,7 +418,7 @@
#endif
-#if !TRACE_PACKETS
+#if !DEBUG_PACKETS
#define print_packet(tag,p) do {} while (0)
#endif
@@ -461,6 +474,17 @@
#define CHUNK_SIZE (64*1024)
+#if !ADB_HOST
+#define USB_ADB_PATH "/dev/android_adb"
+
+#define USB_FFS_ADB_PATH "/dev/usb-ffs/adb/"
+#define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH#x
+
+#define USB_FFS_ADB_EP0 USB_FFS_ADB_EP(ep0)
+#define USB_FFS_ADB_OUT USB_FFS_ADB_EP(ep1)
+#define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2)
+#endif
+
int sendfailmsg(int fd, const char *reason);
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
new file mode 100644
index 0000000..1fffa49
--- /dev/null
+++ b/adb/adb_auth.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ADB_AUTH_H
+#define __ADB_AUTH_H
+
+void adb_auth_init(void);
+void adb_auth_verified(atransport *t);
+
+/* AUTH packets first argument */
+/* Request */
+#define ADB_AUTH_TOKEN 1
+/* Response */
+#define ADB_AUTH_SIGNATURE 2
+#define ADB_AUTH_RSAPUBLICKEY 3
+
+#if ADB_HOST
+
+int adb_auth_sign(void *key, void *token, size_t token_size, void *sig);
+void *adb_auth_nextkey(void *current);
+int adb_auth_get_userkey(unsigned char *data, size_t len);
+
+static inline int adb_auth_generate_token(void *token, size_t token_size) { return 0; }
+static inline int adb_auth_verify(void *token, void *sig, int siglen) { return 0; }
+static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t) { }
+static inline void adb_auth_reload_keys(void) { }
+
+#else // !ADB_HOST
+
+static inline int adb_auth_sign(void* key, void *token, size_t token_size, void *sig) { return 0; }
+static inline void *adb_auth_nextkey(void *current) { return NULL; }
+static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return 0; }
+
+int adb_auth_generate_token(void *token, size_t token_size);
+int adb_auth_verify(void *token, void *sig, int siglen);
+void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t);
+void adb_auth_reload_keys(void);
+
+#endif // ADB_HOST
+
+#endif // __ADB_AUTH_H
diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.c
new file mode 100644
index 0000000..0b4913e
--- /dev/null
+++ b/adb/adb_auth_client.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <resolv.h>
+#include <cutils/list.h>
+#include <cutils/sockets.h>
+
+#include "sysdeps.h"
+#include "adb.h"
+#include "adb_auth.h"
+#include "fdevent.h"
+#include "mincrypt/rsa.h"
+
+#define TRACE_TAG TRACE_AUTH
+
+
+struct adb_public_key {
+ struct listnode node;
+ RSAPublicKey key;
+};
+
+static struct listnode key_list;
+
+static char *key_paths[] = {
+ "/adb_keys",
+ "/data/misc/adb/adb_keys",
+ NULL
+};
+
+static fdevent listener_fde;
+static int framework_fd = -1;
+
+
+static void read_keys(const char *file, struct listnode *list)
+{
+ struct adb_public_key *key;
+ FILE *f;
+ char buf[MAX_PAYLOAD];
+ char *sep;
+ int ret;
+
+ f = fopen(file, "r");
+ if (!f) {
+ D("Can't open '%s'\n", file);
+ return;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ /* Allocate 4 extra bytes to decode the base64 data in-place */
+ key = calloc(1, sizeof(*key) + 4);
+ if (!key) {
+ D("Can't malloc key\n");
+ break;
+ }
+
+ sep = strpbrk(buf, " \t");
+ if (sep)
+ *sep = '\0';
+
+ ret = __b64_pton(buf, (u_char *)&key->key, sizeof(key->key) + 4);
+ if (ret != sizeof(key->key)) {
+ D("%s: Invalid base64 data ret=%d\n", file, ret);
+ free(key);
+ continue;
+ }
+
+ if (key->key.len != RSANUMWORDS) {
+ D("%s: Invalid key len %d\n", file, key->key.len);
+ free(key);
+ continue;
+ }
+
+ list_add_tail(list, &key->node);
+ }
+
+ fclose(f);
+}
+
+static void free_keys(struct listnode *list)
+{
+ struct listnode *item;
+
+ while (!list_empty(list)) {
+ item = list_head(list);
+ list_remove(item);
+ free(node_to_item(item, struct adb_public_key, node));
+ }
+}
+
+void adb_auth_reload_keys(void)
+{
+ char *path;
+ char **paths = key_paths;
+ struct stat buf;
+
+ free_keys(&key_list);
+
+ while ((path = *paths++)) {
+ if (!stat(path, &buf)) {
+ D("Loading keys from '%s'\n", path);
+ read_keys(path, &key_list);
+ }
+ }
+}
+
+int adb_auth_generate_token(void *token, size_t token_size)
+{
+ FILE *f;
+ int ret;
+
+ f = fopen("/dev/urandom", "r");
+ if (!f)
+ return 0;
+
+ ret = fread(token, token_size, 1, f);
+
+ fclose(f);
+ return ret * token_size;
+}
+
+int adb_auth_verify(void *token, void *sig, int siglen)
+{
+ struct listnode *item;
+ struct adb_public_key *key;
+ int ret;
+
+ if (siglen != RSANUMBYTES)
+ return 0;
+
+ list_for_each(item, &key_list) {
+ key = node_to_item(item, struct adb_public_key, node);
+ ret = RSA_verify(&key->key, sig, siglen, token);
+ if (ret)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void adb_auth_event(int fd, unsigned events, void *data)
+{
+ atransport *t = data;
+ char response[2];
+ int ret;
+
+ if (events & FDE_READ) {
+ ret = unix_read(fd, response, sizeof(response));
+ if (ret < 0) {
+ D("Disconnect");
+ fdevent_remove(&t->auth_fde);
+ framework_fd = -1;
+ }
+ else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
+ adb_auth_reload_keys();
+ adb_auth_verified(t);
+ }
+ }
+}
+
+void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t)
+{
+ char msg[MAX_PAYLOAD];
+ int ret;
+
+ if (framework_fd < 0) {
+ D("Client not connected\n");
+ return;
+ }
+
+ if (key[len - 1] != '\0') {
+ D("Key must be a null-terminated string\n");
+ return;
+ }
+
+ ret = snprintf(msg, sizeof(msg), "PK%s", key);
+ if (ret >= (signed)sizeof(msg)) {
+ D("Key too long. ret=%d", ret);
+ return;
+ }
+ D("Sending '%s'\n", msg);
+
+ ret = unix_write(framework_fd, msg, ret);
+ if (ret < 0) {
+ D("Failed to write PK, errno=%d\n", errno);
+ return;
+ }
+
+ fdevent_install(&t->auth_fde, framework_fd, adb_auth_event, t);
+ fdevent_add(&t->auth_fde, FDE_READ);
+}
+
+static void adb_auth_listener(int fd, unsigned events, void *data)
+{
+ struct sockaddr addr;
+ socklen_t alen;
+ int s;
+
+ alen = sizeof(addr);
+
+ s = adb_socket_accept(fd, &addr, &alen);
+ if (s < 0) {
+ D("Failed to accept: errno=%d\n", errno);
+ return;
+ }
+
+ framework_fd = s;
+}
+
+void adb_auth_init(void)
+{
+ int fd, ret;
+
+ list_init(&key_list);
+ adb_auth_reload_keys();
+
+ fd = android_get_control_socket("adbd");
+ if (fd < 0) {
+ D("Failed to get adbd socket\n");
+ return;
+ }
+
+ ret = listen(fd, 4);
+ if (ret < 0) {
+ D("Failed to listen on '%d'\n", fd);
+ return;
+ }
+
+ fdevent_install(&listener_fde, fd, adb_auth_listener, NULL);
+ fdevent_add(&listener_fde, FDE_READ);
+}
diff --git a/adb/adb_auth_host.c b/adb/adb_auth_host.c
new file mode 100644
index 0000000..9039d42
--- /dev/null
+++ b/adb/adb_auth_host.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
+# include "windows.h"
+# include "shlobj.h"
+#else
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <unistd.h>
+#endif
+#include <string.h>
+
+#include "sysdeps.h"
+#include "adb.h"
+#include "adb_auth.h"
+
+/* HACK: we need the RSAPublicKey struct
+ * but RSA_verify conflits with openssl */
+#define RSA_verify RSA_verify_mincrypt
+#include "mincrypt/rsa.h"
+#undef RSA_verify
+
+#include <cutils/list.h>
+
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+
+#define TRACE_TAG TRACE_AUTH
+
+#define ANDROID_PATH ".android"
+#define ADB_KEY_FILE "adbkey"
+
+
+struct adb_private_key {
+ struct listnode node;
+ RSA *rsa;
+};
+
+static struct listnode key_list;
+
+
+/* Convert OpenSSL RSA private key to android pre-computed RSAPublicKey format */
+static int RSA_to_RSAPublicKey(RSA *rsa, RSAPublicKey *pkey)
+{
+ int ret = 1;
+ unsigned int i;
+
+ BN_CTX* ctx = BN_CTX_new();
+ BIGNUM* r32 = BN_new();
+ BIGNUM* rr = BN_new();
+ BIGNUM* r = BN_new();
+ BIGNUM* rem = BN_new();
+ BIGNUM* n = BN_new();
+ BIGNUM* n0inv = BN_new();
+
+ if (RSA_size(rsa) != RSANUMBYTES) {
+ ret = 0;
+ goto out;
+ }
+
+ BN_set_bit(r32, 32);
+ BN_copy(n, rsa->n);
+ BN_set_bit(r, RSANUMWORDS * 32);
+ BN_mod_sqr(rr, r, n, ctx);
+ BN_div(NULL, rem, n, r32, ctx);
+ BN_mod_inverse(n0inv, rem, r32, ctx);
+
+ pkey->len = RSANUMWORDS;
+ pkey->n0inv = 0 - BN_get_word(n0inv);
+ for (i = 0; i < RSANUMWORDS; i++) {
+ BN_div(rr, rem, rr, r32, ctx);
+ pkey->rr[i] = BN_get_word(rem);
+ BN_div(n, rem, n, r32, ctx);
+ pkey->n[i] = BN_get_word(rem);
+ }
+ pkey->exponent = BN_get_word(rsa->e);
+
+out:
+ BN_free(n0inv);
+ BN_free(n);
+ BN_free(rem);
+ BN_free(r);
+ BN_free(rr);
+ BN_free(r32);
+ BN_CTX_free(ctx);
+
+ return ret;
+}
+
+static void get_user_info(char *buf, size_t len)
+{
+ char hostname[1024], username[1024];
+ int ret;
+
+#ifndef _WIN32
+ ret = gethostname(hostname, sizeof(hostname));
+ if (ret < 0)
+#endif
+ strcpy(hostname, "unknown");
+
+#if !defined _WIN32 && !defined ADB_HOST_ON_TARGET
+ ret = getlogin_r(username, sizeof(username));
+ if (ret < 0)
+#endif
+ strcpy(username, "unknown");
+
+ ret = snprintf(buf, len, " %s@%s", username, hostname);
+ if (ret >= (signed)len)
+ buf[len - 1] = '\0';
+}
+
+static int write_public_keyfile(RSA *private_key, const char *private_key_path)
+{
+ RSAPublicKey pkey;
+ BIO *bio, *b64, *bfile;
+ char path[PATH_MAX], info[MAX_PAYLOAD];
+ int ret;
+
+ ret = snprintf(path, sizeof(path), "%s.pub", private_key_path);
+ if (ret >= (signed)sizeof(path))
+ return 0;
+
+ ret = RSA_to_RSAPublicKey(private_key, &pkey);
+ if (!ret) {
+ D("Failed to convert to publickey\n");
+ return 0;
+ }
+
+ bfile = BIO_new_file(path, "w");
+ if (!bfile) {
+ D("Failed to open '%s'\n", path);
+ return 0;
+ }
+
+ D("Writing public key to '%s'\n", path);
+
+ b64 = BIO_new(BIO_f_base64());
+ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+
+ bio = BIO_push(b64, bfile);
+ BIO_write(bio, &pkey, sizeof(pkey));
+ BIO_flush(bio);
+ BIO_pop(b64);
+ BIO_free(b64);
+
+ get_user_info(info, sizeof(info));
+ BIO_write(bfile, info, strlen(info));
+ BIO_flush(bfile);
+ BIO_free_all(bfile);
+
+ return 1;
+}
+
+static int generate_key(const char *file)
+{
+ EVP_PKEY* pkey = EVP_PKEY_new();
+ BIGNUM* exponent = BN_new();
+ RSA* rsa = RSA_new();
+ mode_t old_mask;
+ FILE *f = NULL;
+ int ret = 0;
+
+ D("generate_key '%s'\n", file);
+
+ if (!pkey || !exponent || !rsa) {
+ D("Failed to allocate key\n");
+ goto out;
+ }
+
+ BN_set_word(exponent, RSA_F4);
+ RSA_generate_key_ex(rsa, 2048, exponent, NULL);
+ EVP_PKEY_set1_RSA(pkey, rsa);
+
+ old_mask = umask(077);
+
+ f = fopen(file, "w");
+ if (!f) {
+ D("Failed to open '%s'\n", file);
+ umask(old_mask);
+ goto out;
+ }
+
+ umask(old_mask);
+
+ if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
+ D("Failed to write key\n");
+ goto out;
+ }
+
+ if (!write_public_keyfile(rsa, file)) {
+ D("Failed to write public key\n");
+ goto out;
+ }
+
+ ret = 1;
+
+out:
+ if (f)
+ fclose(f);
+ EVP_PKEY_free(pkey);
+ RSA_free(rsa);
+ BN_free(exponent);
+ return ret;
+}
+
+static int read_key(const char *file, struct listnode *list)
+{
+ struct adb_private_key *key;
+ FILE *f;
+
+ D("read_key '%s'\n", file);
+
+ f = fopen(file, "r");
+ if (!f) {
+ D("Failed to open '%s'\n", file);
+ return 0;
+ }
+
+ key = malloc(sizeof(*key));
+ if (!key) {
+ D("Failed to alloc key\n");
+ fclose(f);
+ return 0;
+ }
+ key->rsa = RSA_new();
+
+ if (!PEM_read_RSAPrivateKey(f, &key->rsa, NULL, NULL)) {
+ D("Failed to read key\n");
+ fclose(f);
+ RSA_free(key->rsa);
+ free(key);
+ return 0;
+ }
+
+ fclose(f);
+ list_add_tail(list, &key->node);
+ return 1;
+}
+
+static int get_user_keyfilepath(char *filename, size_t len)
+{
+ const char *format, *home;
+ char android_dir[PATH_MAX];
+ struct stat buf;
+#ifdef _WIN32
+ char path[PATH_MAX];
+ home = getenv("ANDROID_SDK_HOME");
+ if (!home) {
+ SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, path);
+ home = path;
+ }
+ format = "%s\\%s";
+#else
+ home = getenv("HOME");
+ if (!home)
+ return -1;
+ format = "%s/%s";
+#endif
+
+ D("home '%s'\n", home);
+
+ if (snprintf(android_dir, sizeof(android_dir), format, home,
+ ANDROID_PATH) >= (int)sizeof(android_dir))
+ return -1;
+
+ if (stat(android_dir, &buf)) {
+ if (adb_mkdir(android_dir, 0750) < 0) {
+ D("Cannot mkdir '%s'", android_dir);
+ return -1;
+ }
+ }
+
+ return snprintf(filename, len, format, android_dir, ADB_KEY_FILE);
+}
+
+static int get_user_key(struct listnode *list)
+{
+ struct stat buf;
+ char path[PATH_MAX];
+ int ret;
+
+ ret = get_user_keyfilepath(path, sizeof(path));
+ if (ret < 0 || ret >= (signed)sizeof(path)) {
+ D("Error getting user key filename");
+ return 0;
+ }
+
+ D("user key '%s'\n", path);
+
+ if (stat(path, &buf) == -1) {
+ if (!generate_key(path)) {
+ D("Failed to generate new key\n");
+ return 0;
+ }
+ }
+
+ return read_key(path, list);
+}
+
+static void get_vendor_keys(struct listnode *list)
+{
+ const char *adb_keys_path;
+ char keys_path[MAX_PAYLOAD];
+ char *path;
+ char *save;
+ struct stat buf;
+
+ adb_keys_path = getenv("ADB_VENDOR_KEYS");
+ if (!adb_keys_path)
+ return;
+ strncpy(keys_path, adb_keys_path, sizeof(keys_path));
+
+ path = adb_strtok_r(keys_path, ENV_PATH_SEPARATOR_STR, &save);
+ while (path) {
+ D("Reading: '%s'\n", path);
+
+ if (stat(path, &buf))
+ D("Can't read '%s'\n", path);
+ else if (!read_key(path, list))
+ D("Failed to read '%s'\n", path);
+
+ path = adb_strtok_r(NULL, ENV_PATH_SEPARATOR_STR, &save);
+ }
+}
+
+int adb_auth_sign(void *node, void *token, size_t token_size, void *sig)
+{
+ unsigned int len;
+ struct adb_private_key *key = node_to_item(node, struct adb_private_key, node);
+
+ if (!RSA_sign(NID_sha1, token, token_size, sig, &len, key->rsa)) {
+ return 0;
+ }
+
+ D("adb_auth_sign len=%d\n", len);
+ return (int)len;
+}
+
+void *adb_auth_nextkey(void *current)
+{
+ struct listnode *item;
+
+ if (list_empty(&key_list))
+ return NULL;
+
+ if (!current)
+ return list_head(&key_list);
+
+ list_for_each(item, &key_list) {
+ if (item == current) {
+ /* current is the last item, we tried all the keys */
+ if (item->next == &key_list)
+ return NULL;
+ return item->next;
+ }
+ }
+
+ return NULL;
+}
+
+int adb_auth_get_userkey(unsigned char *data, size_t len)
+{
+ char path[PATH_MAX];
+ char *file;
+ int ret;
+
+ ret = get_user_keyfilepath(path, sizeof(path) - 4);
+ if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) {
+ D("Error getting user key filename");
+ return 0;
+ }
+ strcat(path, ".pub");
+
+ file = load_file(path, (unsigned*)&ret);
+ if (!file) {
+ D("Can't load '%s'\n", path);
+ return 0;
+ }
+
+ if (len < (size_t)(ret + 1)) {
+ D("%s: Content too large ret=%d\n", path, ret);
+ return 0;
+ }
+
+ memcpy(data, file, ret);
+ data[ret] = '\0';
+
+ return ret + 1;
+}
+
+void adb_auth_init(void)
+{
+ int ret;
+
+ D("adb_auth_init\n");
+
+ list_init(&key_list);
+
+ ret = get_user_key(&key_list);
+ if (!ret) {
+ D("Failed to get user key\n");
+ return;
+ }
+
+ get_vendor_keys(&key_list);
+}
diff --git a/adb/commandline.c b/adb/commandline.c
index d2b8166..24cbb5a 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -84,8 +84,8 @@
" returns an error if more than one USB device is present.\n"
" -e - directs command to the only running emulator.\n"
" returns an error if more than one emulator is running.\n"
- " -s <serial number> - directs command to the USB device or emulator with\n"
- " the given serial number. Overrides ANDROID_SERIAL\n"
+ " -s <specific device> - directs command to the device or emulator with the given\n"
+ " serial number or qualifier. Overrides ANDROID_SERIAL\n"
" environment variable.\n"
" -p <product name or path> - simple product name like 'sooner', or\n"
" a relative/absolute path to a product\n"
@@ -93,7 +93,8 @@
" If -p is not specified, the ANDROID_PRODUCT_OUT\n"
" environment variable is used, which must\n"
" be an absolute path.\n"
- " devices - list all connected devices\n"
+ " devices [-l] - list all connected devices\n"
+ " ('-l' will also list device qualifiers)\n"
" connect <host>[:<port>] - connect to a device via TCP/IP\n"
" Port 5555 is used by default if no port number is specified.\n"
" disconnect [<host>[:<port>]] - disconnect from a TCP/IP device.\n"
@@ -159,6 +160,7 @@
" adb kill-server - kill the server if it is running\n"
" adb get-state - prints: offline | bootloader | device\n"
" adb get-serialno - prints: <serial-number>\n"
+ " adb get-devpath - prints: <device-path>\n"
" adb status-window - continuously print device status for a specified device\n"
" adb remount - remounts the /system partition on the device read-write\n"
" adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
@@ -1016,7 +1018,16 @@
if(!strcmp(argv[0], "devices")) {
char *tmp;
- snprintf(buf, sizeof buf, "host:%s", argv[0]);
+ char *listopt;
+ if (argc < 2)
+ listopt = "";
+ else if (argc == 2 && !strcmp(argv[1], "-l"))
+ listopt = argv[1];
+ else {
+ fprintf(stderr, "Usage: adb devices [-l]\n");
+ return 1;
+ }
+ snprintf(buf, sizeof buf, "host:%s%s", argv[0], listopt);
tmp = adb_query(buf);
if(tmp) {
printf("List of devices attached \n");
@@ -1298,7 +1309,8 @@
/* passthrough commands */
if(!strcmp(argv[0],"get-state") ||
- !strcmp(argv[0],"get-serialno"))
+ !strcmp(argv[0],"get-serialno") ||
+ !strcmp(argv[0],"get-devpath"))
{
char *tmp;
diff --git a/adb/protocol.txt b/adb/protocol.txt
index 398d042..c9d3c24 100644
--- a/adb/protocol.txt
+++ b/adb/protocol.txt
@@ -72,7 +72,25 @@
The system identity string should be "<systemtype>:<serialno>:<banner>"
where systemtype is "bootloader", "device", or "host", serialno is some
kind of unique ID (or empty), and banner is a human-readable version
-or identifier string (informational only).
+or identifier string. The banner is used to transmit useful properties.
+
+
+--- AUTH(type, 0, "data") ----------------------------------------------
+
+The AUTH message informs the recipient that authentication is required to
+connect to the sender. If type is TOKEN(1), data is a random token that
+the recipient can sign with a private key. The recipient replies with an
+AUTH packet where type is SIGNATURE(2) and data is the signature. If the
+signature verification succeeds, the sender replies with a CONNECT packet.
+
+If the signature verification fails, the sender replies with a new AUTH
+packet and a new random token, so that the recipient can retry signing
+with a different private key.
+
+Once the recipient has tried all its private keys, it can reply with an
+AUTH packet where type is RSAPUBLICKEY(3) and data is the public key. If
+possible, an on-screen confirmation may be displayed for the user to
+confirm they want to install the public key on the device.
--- OPEN(local-id, 0, "destination") -----------------------------------
@@ -166,6 +184,7 @@
#define A_SYNC 0x434e5953
#define A_CNXN 0x4e584e43
+#define A_AUTH 0x48545541
#define A_OPEN 0x4e45504f
#define A_OKAY 0x59414b4f
#define A_CLSE 0x45534c43
diff --git a/adb/sockets.c b/adb/sockets.c
index cd31b23..305cb44 100644
--- a/adb/sockets.c
+++ b/adb/sockets.c
@@ -608,12 +608,30 @@
return n;
}
+#define PREFIX(str) { str, sizeof(str) - 1 }
+static const struct prefix_struct {
+ const char *str;
+ const size_t len;
+} prefixes[] = {
+ PREFIX("usb:"),
+ PREFIX("product:"),
+ PREFIX("model:"),
+ PREFIX("device:"),
+};
+static const int num_prefixes = (sizeof(prefixes) / sizeof(prefixes[0]));
+
/* skip_host_serial return the position in a string
skipping over the 'serial' parameter in the ADB protocol,
where parameter string may be a host:port string containing
the protocol delimiter (colon). */
char *skip_host_serial(char *service) {
char *first_colon, *serial_end;
+ int i;
+
+ for (i = 0; i < num_prefixes; i++) {
+ if (!strncmp(service, prefixes[i].str, prefixes[i].len))
+ return strchr(service + prefixes[i].len, ':');
+ }
first_colon = strchr(service, ':');
if (!first_colon) {
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index e883557..0252ef3 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -38,6 +38,7 @@
#define OS_PATH_SEPARATOR '\\'
#define OS_PATH_SEPARATOR_STR "\\"
+#define ENV_PATH_SEPARATOR_STR ";"
typedef CRITICAL_SECTION adb_mutex_t;
@@ -254,6 +255,8 @@
return isalpha(path[0]) && path[1] == ':' && path[2] == '\\';
}
+extern char* adb_strtok_r(char *str, const char *delim, char **saveptr);
+
#else /* !_WIN32 a.k.a. Unix */
#include "fdevent.h"
@@ -291,6 +294,7 @@
#define OS_PATH_SEPARATOR '/'
#define OS_PATH_SEPARATOR_STR "/"
+#define ENV_PATH_SEPARATOR_STR ":"
typedef pthread_mutex_t adb_mutex_t;
@@ -506,6 +510,13 @@
return path[0] == '/';
}
+static __inline__ char* adb_strtok_r(char *str, const char *delim, char **saveptr)
+{
+ return strtok_r(str, delim, saveptr);
+}
+#undef strtok_r
+#define strtok_r ___xxx_strtok_r
+
#endif /* !_WIN32 */
#endif /* _ADB_SYSDEPS_H */
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index c426718..d41c42c 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -2140,3 +2140,81 @@
InitializeCriticalSection( &_win32_lock );
}
+/* Windows doesn't have strtok_r. Use the one from bionic. */
+
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+char *
+adb_strtok_r(char *s, const char *delim, char **last)
+{
+ char *spanp;
+ int c, sc;
+ char *tok;
+
+
+ if (s == NULL && (s = *last) == NULL)
+ return (NULL);
+
+ /*
+ * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
+ */
+cont:
+ c = *s++;
+ for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
+ if (c == sc)
+ goto cont;
+ }
+
+ if (c == 0) { /* no non-delimiter characters */
+ *last = NULL;
+ return (NULL);
+ }
+ tok = s - 1;
+
+ /*
+ * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
+ * Note that delim must have one NUL; we stop if we see that, too.
+ */
+ for (;;) {
+ c = *s++;
+ spanp = (char *)delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *last = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+}
diff --git a/adb/transport.c b/adb/transport.c
index 2f7bd27..9fd6cc2 100644
--- a/adb/transport.c
+++ b/adb/transport.c
@@ -370,7 +370,7 @@
char head[5];
int len;
- len = list_transports(buffer+4, bufferlen-4);
+ len = list_transports(buffer+4, bufferlen-4, 0);
snprintf(head, sizeof(head), "%04x", len);
memcpy(buffer, head, 4);
len += 4;
@@ -601,6 +601,12 @@
free(t->product);
if (t->serial)
free(t->serial);
+ if (t->model)
+ free(t->model);
+ if (t->device)
+ free(t->device);
+ if (t->devpath)
+ free(t->devpath);
memset(t,0xee,sizeof(atransport));
free(t);
@@ -737,6 +743,45 @@
dis->next = dis->prev = dis;
}
+static int qual_char_is_invalid(char ch)
+{
+ if ('A' <= ch && ch <= 'Z')
+ return 0;
+ if ('a' <= ch && ch <= 'z')
+ return 0;
+ if ('0' <= ch && ch <= '9')
+ return 0;
+ return 1;
+}
+
+static int qual_match(const char *to_test,
+ const char *prefix, const char *qual, int sanitize_qual)
+{
+ if (!to_test || !*to_test)
+ /* Return true if both the qual and to_test are null strings. */
+ return !qual || !*qual;
+
+ if (!qual)
+ return 0;
+
+ if (prefix) {
+ while (*prefix) {
+ if (*prefix++ != *to_test++)
+ return 0;
+ }
+ }
+
+ while (*qual) {
+ char ch = *qual++;
+ if (sanitize_qual && qual_char_is_invalid(ch))
+ ch = '_';
+ if (ch != *to_test++)
+ return 0;
+ }
+
+ /* Everything matched so far. Return true if *to_test is a NUL. */
+ return !*to_test;
+}
atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out)
{
@@ -758,9 +803,19 @@
/* check for matching serial number */
if (serial) {
- if (t->serial && !strcmp(serial, t->serial)) {
+ if ((t->serial && !strcmp(serial, t->serial)) ||
+ (t->devpath && !strcmp(serial, t->devpath)) ||
+ qual_match(serial, "product:", t->product, 0) ||
+ qual_match(serial, "model:", t->model, 1) ||
+ qual_match(serial, "device:", t->device, 0)) {
+ if (result) {
+ if (error_out)
+ *error_out = "more than one device";
+ ambiguous = 1;
+ result = NULL;
+ break;
+ }
result = t;
- break;
}
} else {
if (ttype == kTransportUsb && t->type == kTransportUsb) {
@@ -837,7 +892,58 @@
}
}
-int list_transports(char *buf, size_t bufsize)
+static void add_qual(char **buf, size_t *buf_size,
+ const char *prefix, const char *qual, int sanitize_qual)
+{
+ size_t len;
+ int prefix_len;
+
+ if (!buf || !*buf || !buf_size || !*buf_size || !qual || !*qual)
+ return;
+
+ len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual);
+
+ if (sanitize_qual) {
+ char *cp;
+ for (cp = *buf + prefix_len; cp < *buf + len; cp++) {
+ if (qual_char_is_invalid(*cp))
+ *cp = '_';
+ }
+ }
+
+ *buf_size -= len;
+ *buf += len;
+}
+
+static size_t format_transport(atransport *t, char *buf, size_t bufsize,
+ int long_listing)
+{
+ const char* serial = t->serial;
+ if (!serial || !serial[0])
+ serial = "????????????";
+
+ if (!long_listing) {
+ return snprintf(buf, bufsize, "%s\t%s\n", serial, statename(t));
+ } else {
+ size_t len, remaining = bufsize;
+
+ len = snprintf(buf, remaining, "%-22s %s", serial, statename(t));
+ remaining -= len;
+ buf += len;
+
+ add_qual(&buf, &remaining, " ", t->devpath, 0);
+ add_qual(&buf, &remaining, " product:", t->product, 0);
+ add_qual(&buf, &remaining, " model:", t->model, 1);
+ add_qual(&buf, &remaining, " device:", t->device, 0);
+
+ len = snprintf(buf, remaining, "\n");
+ remaining -= len;
+
+ return bufsize - remaining;
+ }
+}
+
+int list_transports(char *buf, size_t bufsize, int long_listing)
{
char* p = buf;
char* end = buf + bufsize;
@@ -847,11 +953,7 @@
/* XXX OVERRUN PROBLEMS XXX */
adb_mutex_lock(&transport_lock);
for(t = transport_list.next; t != &transport_list; t = t->next) {
- const char* serial = t->serial;
- if (!serial || !serial[0])
- serial = "????????????";
- len = snprintf(p, end - p, "%s\t%s\n", serial, statename(t));
-
+ len = format_transport(t, p, end - p, long_listing);
if (p + len >= end) {
/* discard last line if buffer is too short */
break;
@@ -956,7 +1058,7 @@
#endif
-void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable)
+void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable)
{
atransport *t = calloc(1, sizeof(atransport));
D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
@@ -965,6 +1067,9 @@
if(serial) {
t->serial = strdup(serial);
}
+ if(devpath) {
+ t->devpath = strdup(devpath);
+ }
register_transport(t);
}
diff --git a/adb/usb_libusb.c b/adb/usb_libusb.c
index 8c75266..06ff5dc 100644
--- a/adb/usb_libusb.c
+++ b/adb/usb_libusb.c
@@ -347,7 +347,7 @@
adb_mutex_unlock(&usb_lock);
- register_usb_transport(usb, serial, 1);
+ register_usb_transport(usb, serial, NULL, 1);
return (1);
}
diff --git a/adb/usb_linux.c b/adb/usb_linux.c
index 4d55b74..7bf2057 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.c
@@ -116,7 +116,8 @@
}
-static void register_device(const char *dev_name, unsigned char ep_in, unsigned char ep_out,
+static void register_device(const char *dev_name, const char *devpath,
+ unsigned char ep_in, unsigned char ep_out,
int ifc, int serial_index, unsigned zero_mask);
static inline int badname(const char *name)
@@ -129,7 +130,7 @@
static void find_usb_device(const char *base,
void (*register_device_callback)
- (const char *, unsigned char, unsigned char, int, int, unsigned))
+ (const char *, const char *, unsigned char, unsigned char, int, int, unsigned))
{
char busname[32], devname[32];
unsigned char local_ep_in, local_ep_out;
@@ -227,6 +228,11 @@
is_adb_interface(vid, pid, interface->bInterfaceClass,
interface->bInterfaceSubClass, interface->bInterfaceProtocol)) {
+ struct stat st;
+ char pathbuf[128];
+ char link[256];
+ char *devpath = NULL;
+
DBGX("looking for bulk endpoints\n");
// looks like ADB...
ep1 = (struct usb_endpoint_descriptor *)bufptr;
@@ -263,7 +269,26 @@
local_ep_out = ep1->bEndpointAddress;
}
- register_device_callback(devname, local_ep_in, local_ep_out,
+ // Determine the device path
+ if (!fstat(fd, &st) && S_ISCHR(st.st_mode)) {
+ char *slash;
+ ssize_t link_len;
+ snprintf(pathbuf, sizeof(pathbuf), "/sys/dev/char/%d:%d",
+ major(st.st_rdev), minor(st.st_rdev));
+ link_len = readlink(pathbuf, link, sizeof(link) - 1);
+ if (link_len > 0) {
+ link[link_len] = '\0';
+ slash = strrchr(link, '/');
+ if (slash) {
+ snprintf(pathbuf, sizeof(pathbuf),
+ "usb:%s", slash + 1);
+ devpath = pathbuf;
+ }
+ }
+ }
+
+ register_device_callback(devname, devpath,
+ local_ep_in, local_ep_out,
interface->bInterfaceNumber, device->iSerialNumber, zero_mask);
break;
}
@@ -532,7 +557,7 @@
return 0;
}
-static void register_device(const char *dev_name,
+static void register_device(const char *dev_name, const char *devpath,
unsigned char ep_in, unsigned char ep_out,
int interface, int serial_index, unsigned zero_mask)
{
@@ -644,7 +669,7 @@
usb->next->prev = usb;
adb_mutex_unlock(&usb_lock);
- register_usb_transport(usb, serial, usb->writeable);
+ register_usb_transport(usb, serial, devpath, usb->writeable);
return;
fail:
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c
index 635fa4b..fb1dad0 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.c
@@ -19,6 +19,8 @@
#include <unistd.h>
#include <string.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/functionfs.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <dirent.h>
@@ -29,20 +31,122 @@
#define TRACE_TAG TRACE_USB
#include "adb.h"
+#define MAX_PACKET_SIZE_FS 64
+#define MAX_PACKET_SIZE_HS 512
+
+#define cpu_to_le16(x) htole16(x)
+#define cpu_to_le32(x) htole32(x)
struct usb_handle
{
- int fd;
adb_cond_t notify;
adb_mutex_t lock;
+
+ int (*write)(usb_handle *h, const void *data, int len);
+ int (*read)(usb_handle *h, void *data, int len);
+ void (*kick)(usb_handle *h);
+
+ // Legacy f_adb
+ int fd;
+
+ // FunctionFS
+ int control;
+ int bulk_out; /* "out" from the host's perspective => source for adbd */
+ int bulk_in; /* "in" from the host's perspective => sink for adbd */
};
-void usb_cleanup()
-{
- // nothing to do here
-}
+static const struct {
+ struct usb_functionfs_descs_head header;
+ struct {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio source;
+ struct usb_endpoint_descriptor_no_audio sink;
+ } __attribute__((packed)) fs_descs, hs_descs;
+} __attribute__((packed)) descriptors = {
+ .header = {
+ .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+ .length = cpu_to_le32(sizeof(descriptors)),
+ .fs_count = 3,
+ .hs_count = 3,
+ },
+ .fs_descs = {
+ .intf = {
+ .bLength = sizeof(descriptors.fs_descs.intf),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = ADB_CLASS,
+ .bInterfaceSubClass = ADB_SUBCLASS,
+ .bInterfaceProtocol = ADB_PROTOCOL,
+ .iInterface = 1, /* first string from the provided table */
+ },
+ .source = {
+ .bLength = sizeof(descriptors.fs_descs.source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+ },
+ .sink = {
+ .bLength = sizeof(descriptors.fs_descs.sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+ },
+ },
+ .hs_descs = {
+ .intf = {
+ .bLength = sizeof(descriptors.hs_descs.intf),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = ADB_CLASS,
+ .bInterfaceSubClass = ADB_SUBCLASS,
+ .bInterfaceProtocol = ADB_PROTOCOL,
+ .iInterface = 1, /* first string from the provided table */
+ },
+ .source = {
+ .bLength = sizeof(descriptors.hs_descs.source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+ },
+ .sink = {
+ .bLength = sizeof(descriptors.hs_descs.sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+ },
+ },
+};
-static void *usb_open_thread(void *x)
+#define STR_INTERFACE_ "ADB Interface"
+
+static const struct {
+ struct usb_functionfs_strings_head header;
+ struct {
+ __le16 code;
+ const char str1[sizeof(STR_INTERFACE_)];
+ } __attribute__((packed)) lang0;
+} __attribute__((packed)) strings = {
+ .header = {
+ .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
+ .length = cpu_to_le32(sizeof(strings)),
+ .str_count = cpu_to_le32(1),
+ .lang_count = cpu_to_le32(1),
+ },
+ .lang0 = {
+ cpu_to_le16(0x0409), /* en-us */
+ STR_INTERFACE_,
+ },
+};
+
+
+
+static void *usb_adb_open_thread(void *x)
{
struct usb_handle *usb = (struct usb_handle *)x;
int fd;
@@ -72,14 +176,14 @@
usb->fd = fd;
D("[ usb_thread - registering device ]\n");
- register_usb_transport(usb, 0, 1);
+ register_usb_transport(usb, 0, 0, 1);
}
// never gets here
return 0;
}
-int usb_write(usb_handle *h, const void *data, int len)
+static int usb_adb_write(usb_handle *h, const void *data, int len)
{
int n;
@@ -94,7 +198,7 @@
return 0;
}
-int usb_read(usb_handle *h, void *data, int len)
+static int usb_adb_read(usb_handle *h, void *data, int len)
{
int n;
@@ -109,14 +213,31 @@
return 0;
}
-void usb_init()
+static void usb_adb_kick(usb_handle *h)
+{
+ D("usb_kick\n");
+ adb_mutex_lock(&h->lock);
+ adb_close(h->fd);
+ h->fd = -1;
+
+ // notify usb_adb_open_thread that we are disconnected
+ adb_cond_signal(&h->notify);
+ adb_mutex_unlock(&h->lock);
+}
+
+static void usb_adb_init()
{
usb_handle *h;
adb_thread_t tid;
int fd;
h = calloc(1, sizeof(usb_handle));
+
+ h->write = usb_adb_write;
+ h->read = usb_adb_read;
+ h->kick = usb_adb_kick;
h->fd = -1;
+
adb_cond_init(&h->notify, 0);
adb_mutex_init(&h->lock, 0);
@@ -133,25 +254,239 @@
}
D("[ usb_init - starting thread ]\n");
- if(adb_thread_create(&tid, usb_open_thread, h)){
+ if(adb_thread_create(&tid, usb_adb_open_thread, h)){
fatal_errno("cannot create usb thread");
}
}
-void usb_kick(usb_handle *h)
-{
- D("usb_kick\n");
- adb_mutex_lock(&h->lock);
- adb_close(h->fd);
- h->fd = -1;
- // notify usb_open_thread that we are disconnected
+static void init_functionfs(struct usb_handle *h)
+{
+ ssize_t ret;
+
+ D("OPENING %s\n", USB_FFS_ADB_EP0);
+ h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR);
+ if (h->control < 0) {
+ D("[ %s: cannot open control endpoint: errno=%d]\n", USB_FFS_ADB_EP0, errno);
+ goto err;
+ }
+
+ ret = adb_write(h->control, &descriptors, sizeof(descriptors));
+ if (ret < 0) {
+ D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno);
+ goto err;
+ }
+
+ ret = adb_write(h->control, &strings, sizeof(strings));
+ if (ret < 0) {
+ D("[ %s: writing strings failed: errno=%d]\n", USB_FFS_ADB_EP0, errno);
+ goto err;
+ }
+
+ h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDWR);
+ if (h->bulk_out < 0) {
+ D("[ %s: cannot open bulk-out ep: errno=%d ]\n", USB_FFS_ADB_OUT, errno);
+ goto err;
+ }
+
+ h->bulk_in = adb_open(USB_FFS_ADB_IN, O_RDWR);
+ if (h->bulk_in < 0) {
+ D("[ %s: cannot open bulk-in ep: errno=%d ]\n", USB_FFS_ADB_IN, errno);
+ goto err;
+ }
+
+ return;
+
+err:
+ if (h->bulk_in > 0) {
+ adb_close(h->bulk_in);
+ h->bulk_in = -1;
+ }
+ if (h->bulk_out > 0) {
+ adb_close(h->bulk_out);
+ h->bulk_out = -1;
+ }
+ if (h->control > 0) {
+ adb_close(h->control);
+ h->control = -1;
+ }
+ return;
+}
+
+static void *usb_ffs_open_thread(void *x)
+{
+ struct usb_handle *usb = (struct usb_handle *)x;
+
+ while (1) {
+ // wait until the USB device needs opening
+ adb_mutex_lock(&usb->lock);
+ while (usb->control != -1)
+ adb_cond_wait(&usb->notify, &usb->lock);
+ adb_mutex_unlock(&usb->lock);
+
+ while (1) {
+ init_functionfs(usb);
+
+ if (usb->control >= 0)
+ break;
+
+ adb_sleep_ms(1000);
+ }
+
+ D("[ usb_thread - registering device ]\n");
+ register_usb_transport(usb, 0, 0, 1);
+ }
+
+ // never gets here
+ return 0;
+}
+
+static int bulk_write(int bulk_in, const char *buf, size_t length)
+{
+ size_t count = 0;
+ int ret;
+
+ do {
+ ret = adb_write(bulk_in, buf + count, length - count);
+ if (ret < 0) {
+ if (errno != EINTR)
+ return ret;
+ } else {
+ count += ret;
+ }
+ } while (count < length);
+
+ D("[ bulk_write done fd=%d ]\n", bulk_in);
+ return count;
+}
+
+static int usb_ffs_write(usb_handle *h, const void *data, int len)
+{
+ int n;
+
+ D("about to write (fd=%d, len=%d)\n", h->bulk_in, len);
+ n = bulk_write(h->bulk_in, data, len);
+ if (n != len) {
+ D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
+ h->bulk_in, n, errno, strerror(errno));
+ return -1;
+ }
+ D("[ done fd=%d ]\n", h->bulk_in);
+ return 0;
+}
+
+static int bulk_read(int bulk_out, char *buf, size_t length)
+{
+ size_t count = 0;
+ int ret;
+
+ do {
+ ret = adb_read(bulk_out, buf + count, length - count);
+ if (ret < 0) {
+ if (errno != EINTR) {
+ D("[ bulk_read failed fd=%d length=%d count=%d ]\n",
+ bulk_out, length, count);
+ return ret;
+ }
+ } else {
+ count += ret;
+ }
+ } while (count < length);
+
+ return count;
+}
+
+static int usb_ffs_read(usb_handle *h, void *data, int len)
+{
+ int n;
+
+ D("about to read (fd=%d, len=%d)\n", h->bulk_out, len);
+ n = bulk_read(h->bulk_out, data, len);
+ if (n != len) {
+ D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
+ h->bulk_out, n, errno, strerror(errno));
+ return -1;
+ }
+ D("[ done fd=%d ]\n", h->bulk_out);
+ return 0;
+}
+
+static void usb_ffs_kick(usb_handle *h)
+{
+ int err;
+
+ err = ioctl(h->bulk_in, FUNCTIONFS_CLEAR_HALT);
+ if (err < 0)
+ D("[ kick: source (fd=%d) clear halt failed (%d) ]", h->bulk_in, errno);
+
+ err = ioctl(h->bulk_out, FUNCTIONFS_CLEAR_HALT);
+ if (err < 0)
+ D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out, errno);
+
+ adb_mutex_lock(&h->lock);
+ adb_close(h->control);
+ adb_close(h->bulk_out);
+ adb_close(h->bulk_in);
+ h->control = h->bulk_out = h->bulk_in = -1;
+
+ // notify usb_ffs_open_thread that we are disconnected
adb_cond_signal(&h->notify);
adb_mutex_unlock(&h->lock);
}
+static void usb_ffs_init()
+{
+ usb_handle *h;
+ adb_thread_t tid;
+
+ D("[ usb_init - using FunctionFS ]\n");
+
+ h = calloc(1, sizeof(usb_handle));
+
+ h->write = usb_ffs_write;
+ h->read = usb_ffs_read;
+ h->kick = usb_ffs_kick;
+
+ h->control = -1;
+ h->bulk_out = -1;
+ h->bulk_out = -1;
+
+ adb_cond_init(&h->notify, 0);
+ adb_mutex_init(&h->lock, 0);
+
+ D("[ usb_init - starting thread ]\n");
+ if (adb_thread_create(&tid, usb_ffs_open_thread, h)){
+ fatal_errno("[ cannot create usb thread ]\n");
+ }
+}
+
+void usb_init()
+{
+ if (access(USB_FFS_ADB_EP0, F_OK) == 0)
+ usb_ffs_init();
+ else
+ usb_adb_init();
+}
+
+void usb_cleanup()
+{
+}
+
+int usb_write(usb_handle *h, const void *data, int len)
+{
+ return h->write(h, data, len);
+}
+
+int usb_read(usb_handle *h, void *data, int len)
+{
+ return h->read(h, data, len);
+}
int usb_close(usb_handle *h)
{
- // nothing to do here
return 0;
}
+
+void usb_kick(usb_handle *h)
+{
+ h->kick(h);
+}
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index 00d02da..45ce444 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -125,10 +125,13 @@
IOUSBDeviceInterface197 **dev = NULL;
HRESULT result;
SInt32 score;
+ UInt32 locationId;
UInt16 vendor;
UInt16 product;
UInt8 serialIndex;
char serial[256];
+ char devpathBuf[64];
+ char *devpath = NULL;
while ((usbInterface = IOIteratorNext(iterator))) {
//* Create an intermediate interface plugin
@@ -192,6 +195,11 @@
kr = (*dev)->GetDeviceVendor(dev, &vendor);
kr = (*dev)->GetDeviceProduct(dev, &product);
+ kr = (*dev)->GetLocationID(dev, &locationId);
+ if (kr == 0) {
+ snprintf(devpathBuf, sizeof(devpathBuf), "usb:%lX", locationId);
+ devpath = devpathBuf;
+ }
kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
if (serialIndex > 0) {
@@ -256,7 +264,7 @@
}
DBG("AndroidDeviceAdded calling register_usb_transport\n");
- register_usb_transport(handle, (serial[0] ? serial : NULL), 1);
+ register_usb_transport(handle, (serial[0] ? serial : NULL), devpath, 1);
// Register for an interest notification of this device being removed.
// Pass the reference to our private data as the refCon for the
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index b988115..1c09b84 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -127,6 +127,11 @@
#define VENDOR_ID_LAB126 0x1949
// Yulong Coolpad's USB Vendor ID
#define VENDOR_ID_YULONG_COOLPAD 0x1EBF
+// Kobo's USB Vendor ID
+#define VENDOR_ID_KOBO 0x2237
+// Teleepoch's USB Vendor ID
+#define VENDOR_ID_TELEEPOCH 0x2340
+
/** built-in vendor list */
int builtInVendorIds[] = {
@@ -176,6 +181,8 @@
VENDOR_ID_SONY,
VENDOR_ID_LAB126,
VENDOR_ID_YULONG_COOLPAD,
+ VENDOR_ID_KOBO,
+ VENDOR_ID_TELEEPOCH,
};
#define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index 251bf17..4936b77 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -490,7 +490,7 @@
true)) {
// Lets make sure that we don't duplicate this device
if (register_new_device(handle)) {
- register_usb_transport(handle, serial_number, 1);
+ register_usb_transport(handle, serial_number, NULL, 1);
} else {
D("register_new_device failed for %s\n", interf_name);
usb_cleanup_handle(handle);
diff --git a/charger/Android.mk b/charger/Android.mk
index 5367a98..fe0c91d 100644
--- a/charger/Android.mk
+++ b/charger/Android.mk
@@ -8,6 +8,10 @@
LOCAL_SRC_FILES := \
charger.c
+ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
+LOCAL_CFLAGS := -DCHARGER_DISABLE_INIT_BLANK
+endif
+
LOCAL_MODULE := charger
LOCAL_MODULE_TAGS := optional
LOCAL_FORCE_STATIC_EXECUTABLE := true
@@ -17,7 +21,7 @@
LOCAL_C_INCLUDES := bootable/recovery
LOCAL_STATIC_LIBRARIES := libminui libpixelflinger_static libpng
-LOCAL_STATIC_LIBRARIES += libz libstdc++ libcutils libc
+LOCAL_STATIC_LIBRARIES += libz libstdc++ libcutils libm libc
include $(BUILD_EXECUTABLE)
diff --git a/charger/charger.c b/charger/charger.c
index 76be076..c5e4ec2 100644
--- a/charger/charger.c
+++ b/charger/charger.c
@@ -975,7 +975,9 @@
ev_sync_key_state(set_key_callback, charger);
+#ifndef CHARGER_DISABLE_INIT_BLANK
gr_fb_blank(true);
+#endif
charger->next_screen_transition = now - 1;
charger->next_key_check = -1;
diff --git a/debuggerd/arm/machine.c b/debuggerd/arm/machine.c
index 1c2e13f..160db7b 100644
--- a/debuggerd/arm/machine.c
+++ b/debuggerd/arm/machine.c
@@ -53,7 +53,8 @@
/* catch underflow */
p = 0;
}
- end = p + 80;
+ /* Dump more memory content for the crashing thread. */
+ end = p + 256;
/* catch overflow; 'end - p' has to be multiples of 16 */
while (end < p)
end -= 16;
@@ -81,6 +82,8 @@
long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL);
sprintf(code_buffer + strlen(code_buffer), "%08lx ", data);
+ /* Enable the following code blob to dump ASCII values */
+#if 0
int j;
for (j = 0; j < 4; j++) {
/*
@@ -95,6 +98,7 @@
*asc_out++ = '.';
}
}
+#endif
p += 4;
}
*asc_out = '\0';
diff --git a/debuggerd/tombstone.c b/debuggerd/tombstone.c
index 47a1bf5..5f2db43 100644
--- a/debuggerd/tombstone.c
+++ b/debuggerd/tombstone.c
@@ -126,6 +126,15 @@
return "?";
}
+static void dump_revision_info(log_t* log)
+{
+ char revision[PROPERTY_VALUE_MAX];
+
+ property_get("ro.revision", revision, "unknown");
+
+ _LOG(log, false, "Revision: '%s'\n", revision);
+}
+
static void dump_build_info(log_t* log)
{
char fingerprint[PROPERTY_VALUE_MAX];
@@ -596,6 +605,7 @@
_LOG(log, false,
"*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
dump_build_info(log);
+ dump_revision_info(log);
dump_thread_info(log, pid, tid, true);
if(signal) {
dump_fault_addr(log, tid, signal);
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 3d582b2..5025dae 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -63,7 +63,7 @@
include $(BUILD_HOST_EXECUTABLE)
-$(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE))
+$(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
ifeq ($(HOST_OS),linux)
diff --git a/fastboot/engine.c b/fastboot/engine.c
index 93be3de..7a55260 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.c
@@ -144,6 +144,39 @@
{ "ext4", generate_ext4_image, cleanup_image }
};
+/* Return true if this partition is supported by the fastboot format command.
+ * It is also used to determine if we should first erase a partition before
+ * flashing it with an ext4 filesystem. See needs_erase()
+ *
+ * Not all devices report the filesystem type, so don't report any errors,
+ * just return false.
+ */
+int fb_format_supported(usb_handle *usb, const char *partition)
+{
+ char response[FB_RESPONSE_SZ+1];
+ struct generator *generator = NULL;
+ int status;
+ unsigned int i;
+
+ status = fb_getvar(usb, response, "partition-type:%s", partition);
+ if (status) {
+ return 0;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(generators); i++) {
+ if (!strncmp(generators[i].fs_type, response, FB_RESPONSE_SZ)) {
+ generator = &generators[i];
+ break;
+ }
+ }
+
+ if (generator) {
+ return 1;
+ }
+
+ return 0;
+}
+
static int cb_default(Action *a, int status, char *resp)
{
if (status) {
@@ -565,6 +598,8 @@
int status = 0;
a = action_list;
+ if (!a)
+ return status;
resp[FB_RESPONSE_SZ] = 0;
double start = -1;
@@ -605,3 +640,8 @@
fprintf(stderr,"finished. total time: %.3fs\n", (now() - start));
return status;
}
+
+int fb_queue_is_empty(void)
+{
+ return (action_list == NULL);
+}
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index c9def7b..3de6d7d 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -70,6 +70,7 @@
static const char *cmdline = 0;
static int wipe_data = 0;
static unsigned short vendor_id = 0;
+static int long_listing = 0;
static int64_t sparse_limit = -1;
static int64_t target_sparse_limit = -1;
@@ -187,6 +188,11 @@
int match_fastboot(usb_ifc_info *info)
{
+ return match_fastboot_with_serial(info, serial);
+}
+
+int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial)
+{
if(!(vendor_id && (info->dev_vendor == vendor_id)) &&
(info->dev_vendor != 0x18d1) && // Google
(info->dev_vendor != 0x8087) && // Intel
@@ -204,15 +210,16 @@
if(info->ifc_class != 0xff) return -1;
if(info->ifc_subclass != 0x42) return -1;
if(info->ifc_protocol != 0x03) return -1;
- // require matching serial number if a serial number is specified
+ // require matching serial number or device path if requested
// at the command line with the -s option.
- if (serial && strcmp(serial, info->serial_number) != 0) return -1;
+ if (local_serial && (strcmp(local_serial, info->serial_number) != 0 &&
+ strcmp(local_serial, info->device_path) != 0)) return -1;
return 0;
}
int list_devices_callback(usb_ifc_info *info)
{
- if (match_fastboot(info) == 0) {
+ if (match_fastboot_with_serial(info, NULL) == 0) {
char* serial = info->serial_number;
if (!info->writable) {
serial = "no permissions"; // like "adb devices"
@@ -221,7 +228,13 @@
serial = "????????????";
}
// output compatible with "adb devices"
- printf("%s\tfastboot\n", serial);
+ if (!long_listing) {
+ printf("%s\tfastboot\n", serial);
+ } else if (!info->device_path) {
+ printf("%-22s fastboot\n", serial);
+ } else {
+ printf("%-22s fastboot %s\n", serial, info->device_path);
+ }
}
return -1;
@@ -274,8 +287,13 @@
" help show this help message\n"
"\n"
"options:\n"
- " -w erase userdata and cache\n"
- " -s <serial number> specify device serial number\n"
+ " -w erase userdata and cache (and format\n"
+ " if supported by partition type)\n"
+ " -u do not first erase partition before\n"
+ " formatting\n"
+ " -s <specific device> specify device serial number\n"
+ " or path to device port\n"
+ " -l with \"devices\", lists device paths\n"
" -p <product> specify product name\n"
" -c <cmdline> override kernel commandline\n"
" -i <vendor id> specify a custom USB vendor id\n"
@@ -547,6 +565,18 @@
return 0;
}
+/* Until we get lazy inode table init working in make_ext4fs, we need to
+ * erase partitions of type ext4 before flashing a filesystem so no stale
+ * inodes are left lying around. Otherwise, e2fsck gets very upset.
+ */
+static int needs_erase(const char *part)
+{
+ /* The function fb_format_supported() currently returns the value
+ * we want, so just call it.
+ */
+ return fb_format_supported(usb, part);
+}
+
void do_flash(usb_handle *usb, const char *pname, const char *fname)
{
int64_t sz64;
@@ -582,7 +612,7 @@
fb_queue_command("signature", "installing signature");
}
-void do_update(char *fn)
+void do_update(char *fn, int erase_first)
{
void *zdata;
unsigned zsize;
@@ -620,17 +650,26 @@
data = unzip_file(zip, "boot.img", &sz);
if (data == 0) die("update package missing boot.img");
do_update_signature(zip, "boot.sig");
+ if (erase_first && needs_erase("boot")) {
+ fb_queue_erase("boot");
+ }
fb_queue_flash("boot", data, sz);
data = unzip_file(zip, "recovery.img", &sz);
if (data != 0) {
do_update_signature(zip, "recovery.sig");
+ if (erase_first && needs_erase("recovery")) {
+ fb_queue_erase("recovery");
+ }
fb_queue_flash("recovery", data, sz);
}
data = unzip_file(zip, "system.img", &sz);
if (data == 0) die("update package missing system.img");
do_update_signature(zip, "system.sig");
+ if (erase_first && needs_erase("system")) {
+ fb_queue_erase("system");
+ }
fb_queue_flash("system", data, sz);
}
@@ -652,7 +691,7 @@
fb_queue_command("signature", "installing signature");
}
-void do_flashall(void)
+void do_flashall(int erase_first)
{
char *fname;
void *data;
@@ -672,12 +711,18 @@
data = load_file(fname, &sz);
if (data == 0) die("could not load boot.img: %s", strerror(errno));
do_send_signature(fname);
+ if (erase_first && needs_erase("boot")) {
+ fb_queue_erase("boot");
+ }
fb_queue_flash("boot", data, sz);
fname = find_item("recovery", product);
data = load_file(fname, &sz);
if (data != 0) {
do_send_signature(fname);
+ if (erase_first && needs_erase("recovery")) {
+ fb_queue_erase("recovery");
+ }
fb_queue_flash("recovery", data, sz);
}
@@ -685,6 +730,9 @@
data = load_file(fname, &sz);
if (data == 0) die("could not load system.img: %s", strerror(errno));
do_send_signature(fname);
+ if (erase_first && needs_erase("system")) {
+ fb_queue_erase("system");
+ }
fb_queue_flash("system", data, sz);
}
@@ -755,6 +803,7 @@
int wants_wipe = 0;
int wants_reboot = 0;
int wants_reboot_bootloader = 0;
+ int erase_first = 1;
void *data;
unsigned sz;
unsigned page_size = 2048;
@@ -767,7 +816,7 @@
serial = getenv("ANDROID_SERIAL");
while (1) {
- c = getopt_long(argc, argv, "wb:n:s:S:p:c:i:m:h", &longopts, NULL);
+ c = getopt_long(argc, argv, "wub:n:s:S:lp:c:i:m:h", &longopts, NULL);
if (c < 0) {
break;
}
@@ -776,6 +825,9 @@
case 'w':
wants_wipe = 1;
break;
+ case 'u':
+ erase_first = 0;
+ break;
case 'b':
base_addr = strtoul(optarg, 0, 16);
break;
@@ -792,6 +844,9 @@
die("invalid sparse limit");
}
break;
+ case 'l':
+ long_listing = 1;
+ break;
case 'p':
product = optarg;
break;
@@ -846,10 +901,18 @@
skip(2);
} else if(!strcmp(*argv, "erase")) {
require(2);
+
+ if (fb_format_supported(usb, argv[1])) {
+ fprintf(stderr, "******** Did you mean to fastboot format this partition?\n");
+ }
+
fb_queue_erase(argv[1]);
skip(2);
} else if(!strcmp(*argv, "format")) {
require(2);
+ if (erase_first && needs_erase(argv[1])) {
+ fb_queue_erase(argv[1]);
+ }
fb_queue_format(argv[1], 0);
skip(2);
} else if(!strcmp(*argv, "signature")) {
@@ -897,6 +960,9 @@
skip(2);
}
if (fname == 0) die("cannot determine image filename for '%s'", pname);
+ if (erase_first && needs_erase(pname)) {
+ fb_queue_erase(pname);
+ }
do_flash(usb, pname, fname);
} else if(!strcmp(*argv, "flash:raw")) {
char *pname = argv[1];
@@ -914,14 +980,14 @@
fb_queue_flash(pname, data, sz);
} else if(!strcmp(*argv, "flashall")) {
skip(1);
- do_flashall();
+ do_flashall(erase_first);
wants_reboot = 1;
} else if(!strcmp(*argv, "update")) {
if (argc > 1) {
- do_update(argv[1]);
+ do_update(argv[1], erase_first);
skip(2);
} else {
- do_update("update.zip");
+ do_update("update.zip", erase_first);
skip(1);
}
wants_reboot = 1;
@@ -945,6 +1011,9 @@
fb_queue_command("reboot-bootloader", "rebooting into bootloader");
}
+ if (fb_queue_is_empty())
+ return 0;
+
status = fb_execute_queue(usb);
return (status) ? 1 : 0;
}
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 9177932..c1b2964 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -45,7 +45,8 @@
/* engine.c - high level command queue engine */
int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...);
-void fb_queue_flash(const char *ptn, void *data, unsigned sz);;
+int fb_format_supported(usb_handle *usb, const char *partition);
+void fb_queue_flash(const char *ptn, void *data, unsigned sz);
void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz);
void fb_queue_erase(const char *ptn);
void fb_queue_format(const char *ptn, int skip_if_not_supported);
@@ -58,6 +59,7 @@
void fb_queue_download(const char *name, void *data, unsigned size);
void fb_queue_notice(const char *notice);
int fb_execute_queue(usb_handle *usb);
+int fb_queue_is_empty(void);
/* util stuff */
void die(const char *fmt, ...);
diff --git a/fastboot/usb.h b/fastboot/usb.h
index df9efde..d504ee2 100644
--- a/fastboot/usb.h
+++ b/fastboot/usb.h
@@ -53,6 +53,7 @@
unsigned char writable;
char serial_number[256];
+ char device_path[256];
};
typedef int (*ifc_match_func)(usb_ifc_info *ifc);
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c
index 83c6de9..b7a9ca3 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.c
@@ -32,6 +32,7 @@
#include <string.h>
#include <sys/ioctl.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
@@ -107,6 +108,9 @@
int in, out;
unsigned i;
unsigned e;
+
+ struct stat st;
+ int result;
if(check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE))
return -1;
@@ -134,7 +138,6 @@
// Keep it short enough because some bootloaders are borked if the URB len is > 255
// 128 is too big by 1.
__u16 buffer[127];
- int result;
memset(buffer, 0, sizeof(buffer));
@@ -158,6 +161,42 @@
}
}
+ /* We need to get a path that represents a particular port on a particular
+ * hub. We are passed an fd that was obtained by opening an entry under
+ * /dev/bus/usb. Unfortunately, the names of those entries change each
+ * time devices are plugged and unplugged. So how to get a repeatable
+ * path? udevadm provided the inspiration. We can get the major and
+ * minor of the device file, read the symlink that can be found here:
+ * /sys/dev/char/<major>:<minor>
+ * and then use the last element of that path. As a concrete example, I
+ * have an Android device at /dev/bus/usb/001/027 so working with bash:
+ * $ ls -l /dev/bus/usb/001/027
+ * crw-rw-r-- 1 root plugdev 189, 26 Apr 9 11:03 /dev/bus/usb/001/027
+ * $ ls -l /sys/dev/char/189:26
+ * lrwxrwxrwx 1 root root 0 Apr 9 11:03 /sys/dev/char/189:26 ->
+ * ../../devices/pci0000:00/0000:00:1a.7/usb1/1-4/1-4.2/1-4.2.3
+ * So our device_path would be 1-4.2.3 which says my device is connected
+ * to port 3 of a hub on port 2 of a hub on port 4 of bus 1 (per
+ * http://www.linux-usb.org/FAQ.html).
+ */
+ info.device_path[0] = '\0';
+ result = fstat(fd, &st);
+ if (!result && S_ISCHR(st.st_mode)) {
+ char cdev[128];
+ char link[256];
+ char *slash;
+ ssize_t link_len;
+ snprintf(cdev, sizeof(cdev), "/sys/dev/char/%d:%d",
+ major(st.st_rdev), minor(st.st_rdev));
+ link_len = readlink(cdev, link, sizeof(link) - 1);
+ if (link_len > 0) {
+ link[link_len] = '\0';
+ slash = strrchr(link, '/');
+ if (slash)
+ snprintf(info.device_path, sizeof(info.device_path), "usb:%s", slash+1);
+ }
+ }
+
for(i = 0; i < cfg->bNumInterfaces; i++) {
if(check(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE))
return -1;
diff --git a/fastboot/usb_osx.c b/fastboot/usb_osx.c
index cbce9bd..1548ba8 100644
--- a/fastboot/usb_osx.c
+++ b/fastboot/usb_osx.c
@@ -264,6 +264,7 @@
SInt32 score;
HRESULT result;
UInt8 serialIndex;
+ UInt32 locationId;
// Create an intermediate plugin.
kr = IOCreatePlugInInterfaceForService(device,
@@ -322,6 +323,13 @@
goto error;
}
+ kr = (*dev)->GetLocationID(dev, &locationId);
+ if (kr != 0) {
+ ERR("GetLocationId");
+ goto error;
+ }
+ snprintf(handle->info.device_path, sizeof(handle->info.device_path), "usb:%lX", locationId);
+
kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
if (serialIndex > 0) {
diff --git a/fastboot/usb_windows.c b/fastboot/usb_windows.c
index 99027cc..7aa36b2 100644
--- a/fastboot/usb_windows.c
+++ b/fastboot/usb_windows.c
@@ -311,6 +311,8 @@
info.serial_number[0] = 0;
}
+ info.device_path[0] = 0;
+
if (callback(&info) == 0) {
return 1;
}
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 2661b02..2bcc9c4 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -58,6 +58,12 @@
{ "ro", MS_RDONLY },
{ "rw", 0 },
{ "remount", MS_REMOUNT },
+ { "bind", MS_BIND },
+ { "rec", MS_REC },
+ { "unbindable", MS_UNBINDABLE },
+ { "private", MS_PRIVATE },
+ { "slave", MS_SLAVE },
+ { "shared", MS_SHARED },
{ "defaults", 0 },
{ 0, 0 },
};
diff --git a/include/arch/darwin-x86/AndroidConfig.h b/include/arch/darwin-x86/AndroidConfig.h
deleted file mode 100644
index 48f8d9a..0000000
--- a/include/arch/darwin-x86/AndroidConfig.h
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Android config -- "Darwin". Used for X86 Mac OS X.
- */
-#ifndef _ANDROID_CONFIG_H
-#define _ANDROID_CONFIG_H
-
-/*
- * ===========================================================================
- * !!! IMPORTANT !!!
- * ===========================================================================
- *
- * This file is included by ALL C/C++ source files. Don't put anything in
- * here unless you are absolutely certain it can't go anywhere else.
- *
- * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//"
- * comments.
- */
-
-/*
- * Threading model. Choose one:
- *
- * HAVE_PTHREADS - use the pthreads library.
- * HAVE_WIN32_THREADS - use Win32 thread primitives.
- * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX
- */
-#define HAVE_PTHREADS
-
-/*
- * Do we have the futex syscall?
- */
-
-/* #define HAVE_FUTEX */
-
-/*
- * Process creation model. Choose one:
- *
- * HAVE_FORKEXEC - use fork() and exec()
- * HAVE_WIN32_PROC - use CreateProcess()
- */
-#define HAVE_FORKEXEC
-
-/*
- * Process out-of-memory adjustment. Set if running on Linux,
- * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
- * badness adjustment.
- */
-/* #define HAVE_OOM_ADJ */
-
-/*
- * IPC model. Choose one:
- *
- * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
- * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
- * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
- * HAVE_ANDROID_IPC - use Android versions (?, mmap).
- */
-#define HAVE_MACOSX_IPC
-
-/*
- * Memory-mapping model. Choose one:
- *
- * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
- * HAVE_WIN32_FILEMAP - use Win32 filemaps
- */
-#define HAVE_POSIX_FILEMAP
-
-/*
- * Define this if you have <termio.h>
- */
-#define HAVE_TERMIO_H
-
-/*
- * Define this if you have <sys/sendfile.h>
- */
-/* #define HAVE_SYS_SENDFILE_H 1 */
-
-/*
- * Define this if you build against MSVCRT.DLL
- */
-/* #define HAVE_MS_C_RUNTIME */
-
-/*
- * Define this if you have sys/uio.h
- */
-#define HAVE_SYS_UIO_H
-
-/*
- * Define this if your platforms implements symbolic links
- * in its filesystems
- */
-#define HAVE_SYMLINKS
-
-/*
- * Define this if we have localtime_r().
- */
-#define HAVE_LOCALTIME_R 1
-
-/*
- * Define this if we have gethostbyname_r().
- */
-/* #define HAVE_GETHOSTBYNAME_R */
-
-/*
- * Define this if we have ioctl().
- */
-/* #define HAVE_IOCTL */
-
-/*
- * Define this if we want to use WinSock.
- */
-/* #define HAVE_WINSOCK */
-
-/*
- * Define this if have clock_gettime() and friends
- */
-/* #define HAVE_POSIX_CLOCKS */
-
-/*
- * Define this if we have pthread_cond_timedwait_monotonic() and
- * clock_gettime(CLOCK_MONOTONIC).
- */
-/* #define HAVE_TIMEDWAIT_MONOTONIC */
-
-/*
- * Endianness of the target machine. Choose one:
- *
- * HAVE_ENDIAN_H -- have endian.h header we can include.
- * HAVE_LITTLE_ENDIAN -- we are little endian.
- * HAVE_BIG_ENDIAN -- we are big endian.
- */
-#if (defined(__ppc__) || defined(__ppc64__))
-# define HAVE_BIG_ENDIAN
-#elif (defined(__i386__) || defined(__x86_64__))
-# define HAVE_LITTLE_ENDIAN
-#endif
-
-/*
- * We need to choose between 32-bit and 64-bit off_t. All of our code should
- * agree on the same size. For desktop systems, use 64-bit values,
- * because some of our libraries (e.g. wxWidgets) expect to be built that way.
- */
-#define _FILE_OFFSET_BITS 64
-#define _LARGEFILE_SOURCE 1
-
-/*
- * Define if platform has off64_t (and lseek64 and other xxx64 functions)
- */
-/* #define HAVE_OFF64_T */
-
-/*
- * Defined if we have the backtrace() call for retrieving a stack trace.
- * Needed for CallStack to operate; if not defined, CallStack is
- * non-functional.
- */
-#define HAVE_BACKTRACE 0
-
-/*
- * Defined if we have the dladdr() call for retrieving the symbol associated
- * with a memory address. If not defined, stack crawls will not have symbolic
- * information.
- */
-#define HAVE_DLADDR 0
-
-/*
- * Defined if we have the cxxabi.h header for demangling C++ symbols. If
- * not defined, stack crawls will be displayed with raw mangled symbols
- */
-#define HAVE_CXXABI 0
-
-/*
- * Defined if we have the gettid() system call.
- */
-/* #define HAVE_GETTID */
-
-
-/*
- * Add any extra platform-specific defines here.
- */
-#define _THREAD_SAFE
-
-/*
- * Define if we have <malloc.h> header
- */
-/* #define HAVE_MALLOC_H */
-
-/*
- * Define if tm struct has tm_gmtoff field
- */
-#define HAVE_TM_GMTOFF 1
-
-/*
- * Define if dirent struct has d_type field
- */
-#define HAVE_DIRENT_D_TYPE 1
-
-/*
- * Define if we have madvise() in <sys/mman.h>
- */
-#define HAVE_MADVISE 1
-
-/*
- * Define if we include <sys/mount.h> for statfs()
- */
-#define INCLUDE_SYS_MOUNT_FOR_STATFS 1
-
-/*
- * What CPU architecture does this platform use?
- */
-#if (defined(__ppc__) || defined(__ppc64__))
-# define ARCH_PPC
-#elif (defined(__i386__) || defined(__x86_64__))
-# define ARCH_X86
-#endif
-
-/*
- * sprintf() format string for shared library naming.
- */
-#define OS_SHARED_LIB_FORMAT_STR "lib%s.dylib"
-
-/*
- * type for the third argument to mincore().
- */
-#define MINCORE_POINTER_TYPE char *
-
-/*
- * The default path separator for the platform
- */
-#define OS_PATH_SEPARATOR '/'
-
-/*
- * Is the filesystem case sensitive?
- *
- * For tools apps, we'll treat is as not case sensitive.
- */
-/* #define OS_CASE_SENSITIVE */
-
-/*
- * Define if <sys/socket.h> exists.
- */
-#define HAVE_SYS_SOCKET_H 1
-
-/*
- * Define if the strlcpy() function exists on the system.
- */
-#define HAVE_STRLCPY 1
-
-/*
- * Define if the open_memstream() function exists on the system.
- */
-/* #define HAVE_OPEN_MEMSTREAM 1 */
-
-/*
- * Define if the BSD funopen() function exists on the system.
- */
-#define HAVE_FUNOPEN 1
-
-/*
- * Define if writev() exists
- */
-#define HAVE_WRITEV 1
-
-/*
- * Define if <stdint.h> exists.
- */
-#define HAVE_STDINT_H 1
-
-/*
- * Define if <stdbool.h> exists.
- */
-#define HAVE_STDBOOL_H 1
-
-/*
- * Define if <sched.h> exists.
- */
-#define HAVE_SCHED_H 1
-
-/*
- * Define if pread() exists
- */
-#define HAVE_PREAD 1
-
-/*
- * Define if we have st_mtim in struct stat
- */
-#define HAVE_STAT_ST_MTIM 1
-
-/*
- * Define if printf() supports %zd for size_t arguments
- */
-#define HAVE_PRINTF_ZD 1
-
-/*
- * Define to 1 if <stdlib.h> provides qsort_r() with a BSD style function prototype.
- */
-#define HAVE_BSD_QSORT_R 1
-
-/*
- * Define to 1 if <stdlib.h> provides qsort_r() with a GNU style function prototype.
- */
-#define HAVE_GNU_QSORT_R 0
-
-#endif /*_ANDROID_CONFIG_H*/
diff --git a/include/arch/freebsd-x86/AndroidConfig.h b/include/arch/freebsd-x86/AndroidConfig.h
deleted file mode 100644
index 4bc5559..0000000
--- a/include/arch/freebsd-x86/AndroidConfig.h
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Android config -- "FreeBSD". Used for desktop x86 FreeBSD.
- */
-#ifndef _ANDROID_CONFIG_H
-#define _ANDROID_CONFIG_H
-
-/*
- * make sure we are building for FreeBSD
- */
-#ifndef OS_FREEBSD
-#define OS_FREEBSD
-#endif
-/*
- * ===========================================================================
- * !!! IMPORTANT !!!
- * ===========================================================================
- *
- * This file is included by ALL C/C++ source files. Don't put anything in
- * here unless you are absolutely certain it can't go anywhere else.
- *
- * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//"
- * comments.
- */
-
-/*
- * Threading model. Choose one:
- *
- * HAVE_PTHREADS - use the pthreads library.
- * HAVE_WIN32_THREADS - use Win32 thread primitives.
- * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX
- */
-#define HAVE_PTHREADS
-
-/*
- * Do we have the futex syscall?
- */
-/* #define HAVE_FUTEX */
-
-/*
- * Process creation model. Choose one:
- *
- * HAVE_FORKEXEC - use fork() and exec()
- * HAVE_WIN32_PROC - use CreateProcess()
- */
-#define HAVE_FORKEXEC
-
-/*
- * Process out-of-memory adjustment. Set if running on Linux,
- * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
- * badness adjustment.
- */
-/* #define HAVE_OOM_ADJ */
-
-/*
- * IPC model. Choose one:
- *
- * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
- * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
- * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
- * HAVE_ANDROID_IPC - use Android versions (?, mmap).
- */
-#define HAVE_SYSV_IPC
-
-/*
- * Memory-mapping model. Choose one:
- *
- * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
- * HAVE_WIN32_FILEMAP - use Win32 filemaps
- */
-#define HAVE_POSIX_FILEMAP
-
-/*
- * Define this if you have <termio.h>
- */
-/* #define HAVE_TERMIO_H */
-
-/*
- * Define this if you have <sys/sendfile.h>
- */
-/* #define HAVE_SYS_SENDFILE_H 1 */
-
-/*
- * Define this if you build against MSVCRT.DLL
- */
-/* #define HAVE_MS_C_RUNTIME */
-
-/*
- * Define this if you have sys/uio.h
- */
-#define HAVE_SYS_UIO_H
-
-/*
- * Define this if your platforms implements symbolic links
- * in its filesystems
- */
-#define HAVE_SYMLINKS
-
-/*
- * Define this if we have localtime_r().
- */
-#define HAVE_LOCALTIME_R 1
-
-/*
- * Define this if we have gethostbyname_r().
- */
-/* #define HAVE_GETHOSTBYNAME_R */
-
-/*
- * Define this if we have ioctl().
- */
-#define HAVE_IOCTL
-
-/*
- * Define this if we want to use WinSock.
- */
-/* #define HAVE_WINSOCK */
-
-/*
- * Define this if have clock_gettime() and friends
- *
- * Desktop Linux has this in librt, but it's broken in goobuntu, yielding
- * mildly or wildly inaccurate results.
- */
-#define HAVE_POSIX_CLOCKS
-
-/*
- * Define this if we have pthread_cond_timedwait_monotonic() and
- * clock_gettime(CLOCK_MONOTONIC).
- */
-/* #define HAVE_TIMEDWAIT_MONOTONIC */
-
-/*
- * Define this if we have linux style epoll()
- */
-/* #define HAVE_EPOLL */
-
-/*
- * Endianness of the target machine. Choose one:
- *
- * HAVE_ENDIAN_H -- have endian.h header we can include.
- * HAVE_LITTLE_ENDIAN -- we are little endian.
- * HAVE_BIG_ENDIAN -- we are big endian.
- */
-/* #define HAVE_ENDIAN_H */
-#define HAVE_LITTLE_ENDIAN
-
-/*
- * Define this if you have sys/endian.h
- * NOTE: mutually exclusive with HAVE_ENDIAN_H
- */
-#define HAVE_SYS_ENDIAN_H
-
-/*
- * We need to choose between 32-bit and 64-bit off_t. All of our code should
- * agree on the same size. For desktop systems, use 64-bit values,
- * because some of our libraries (e.g. wxWidgets) expect to be built that way.
- */
-#define _FILE_OFFSET_BITS 64
-#define _LARGEFILE_SOURCE 1
-
-/*
- * Define if platform has off64_t (and lseek64 and other xxx64 functions)
- */
-/* #define HAVE_OFF64_T */
-
-/*
- * Defined if we have the backtrace() call for retrieving a stack trace.
- * Needed for CallStack to operate; if not defined, CallStack is
- * non-functional.
- */
-#define HAVE_BACKTRACE 0
-
-/*
- * Defined if we have the dladdr() call for retrieving the symbol associated
- * with a memory address. If not defined, stack crawls will not have symbolic
- * information.
- */
-#define HAVE_DLADDR 1
-
-/*
- * Defined if we have the cxxabi.h header for demangling C++ symbols. If
- * not defined, stack crawls will be displayed with raw mangled symbols
- */
-#define HAVE_CXXABI 0
-
-/*
- * Defined if we have the gettid() system call.
- */
-/* #define HAVE_GETTID */
-
-/*
- * Defined if we have the sched_setscheduler() call
- */
-#define HAVE_SCHED_SETSCHEDULER
-
-/*
- * Add any extra platform-specific defines here.
- */
-
-/*
- * Define if we have <malloc.h> header
- */
-#define HAVE_MALLOC_H
-
-/*
- * Define if we have Linux-style non-filesystem Unix Domain Sockets
- */
-
-/*
- * What CPU architecture does this platform use?
- */
-#define ARCH_X86
-
-
-/*
- * Define if we have Linux's inotify in <sys/inotify.h>.
- */
-/*#define HAVE_INOTIFY 1*/
-
-/*
- * Define if we have madvise() in <sys/mman.h>
- */
-#define HAVE_MADVISE 1
-
-/*
- * Define if tm struct has tm_gmtoff field
- */
-#define HAVE_TM_GMTOFF 1
-
-/*
- * Define if dirent struct has d_type field
- */
-#define HAVE_DIRENT_D_TYPE 1
-
-/*
- * Define if libc includes Android system properties implementation.
- */
-/* #define HAVE_LIBC_SYSTEM_PROPERTIES */
-
-/*
- * Define if system provides a system property server (should be
- * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
- */
-#define HAVE_SYSTEM_PROPERTY_SERVER
-
-/*
- * sprintf() format string for shared library naming.
- */
-#define OS_SHARED_LIB_FORMAT_STR "lib%s.so"
-
-/*
- * type for the third argument to mincore().
- */
-#define MINCORE_POINTER_TYPE char *
-
-/*
- * Do we have the sigaction flag SA_NOCLDWAIT?
- */
-#define HAVE_SA_NOCLDWAIT
-
-/*
- * Define if we include <sys/mount.h> for statfs()
- */
-#define INCLUDE_SYS_MOUNT_FOR_STATFS 1
-
-/*
- * The default path separator for the platform
- */
-#define OS_PATH_SEPARATOR '/'
-
-/*
- * Is the filesystem case sensitive?
- */
-#define OS_CASE_SENSITIVE
-
-/*
- * Define if <sys/socket.h> exists.
- */
-#define HAVE_SYS_SOCKET_H 1
-
-/*
- * Define if the strlcpy() function exists on the system.
- */
-#define HAVE_STRLCPY 1
-
-/*
- * Define if the open_memstream() function exists on the system.
- */
-/* #define HAVE_OPEN_MEMSTREAM 1 */
-
-/*
- * Define if the BSD funopen() function exists on the system.
- */
-#define HAVE_FUNOPEN 1
-
-/*
- * Define if prctl() exists
- */
-/* #define HAVE_PRCTL 1 */
-
-/*
- * Define if writev() exists
- */
-#define HAVE_WRITEV 1
-
-/*
- * Define if <alloca.h> does not exist
- * NOTE: <alloca.h> defines alloca() which
- * on FreeBSD is defined in <stdlib.h>
- */
-#define HAVE_NO_ALLOCA_H
-
-/*
- * Defines CLOCK_PROCESS_CPUTIME_ID for clock_gettime()
- * XXX: CLOCK_PROF seems to be commonly used replacement
- */
-#ifndef CLOCK_PROCESS_CPUTIME_ID
-#define CLOCK_PROCESS_CPUTIME_ID CLOCK_PROF
-#endif
-
-/*
- * Define if <stdint.h> exists.
- */
-/* #define HAVE_STDINT_H */
-
-/*
- * Define if <stdbool.h> exists.
- */
-/* #define HAVE_STDBOOL_H */
-
-/*
- * Define if <sched.h> exists.
- */
-#define HAVE_SCHED_H 1
-
-/*
- * Define if pread() exists
- */
-#define HAVE_PREAD 1
-/*
- * Define if we have st_mtim in struct stat
- */
-#define HAVE_STAT_ST_MTIM 1
-
-/*
- * Define if printf() supports %zd for size_t arguments
- */
-#define HAVE_PRINTF_ZD 1
-
-/*
- * Define to 1 if <stdlib.h> provides qsort_r() with a BSD style function prototype.
- */
-#define HAVE_BSD_QSORT_R 1
-
-/*
- * Define to 1 if <stdlib.h> provides qsort_r() with a GNU style function prototype.
- */
-#define HAVE_GNU_QSORT_R 0
-
-#endif /*_ANDROID_CONFIG_H*/
diff --git a/include/arch/linux-arm/AndroidConfig.h b/include/arch/linux-arm/AndroidConfig.h
deleted file mode 100644
index 233752b..0000000
--- a/include/arch/linux-arm/AndroidConfig.h
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Android config -- "android-arm". Used for ARM device builds.
- */
-#ifndef _ANDROID_CONFIG_H
-#define _ANDROID_CONFIG_H
-
-/*
- * ===========================================================================
- * !!! IMPORTANT !!!
- * ===========================================================================
- *
- * This file is included by ALL C/C++ source files. Don't put anything in
- * here unless you are absolutely certain it can't go anywhere else.
- *
- * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//"
- * comments.
- */
-
-/*
- * Threading model. Choose one:
- *
- * HAVE_PTHREADS - use the pthreads library.
- * HAVE_WIN32_THREADS - use Win32 thread primitives.
- * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX
- */
-#define HAVE_PTHREADS
-
-/*
- * Do we have pthread_setname_np()?
- *
- * (HAVE_PTHREAD_SETNAME_NP is used by WebKit to enable a function with
- * the same name but different parameters, so we can't use that here.)
- */
-#define HAVE_ANDROID_PTHREAD_SETNAME_NP
-
-/*
- * Do we have the futex syscall?
- */
-#define HAVE_FUTEX
-
-/*
- * Define if we already have the futex wrapper functions defined. Yes if
- * compiling against bionic.
- */
-#define HAVE_FUTEX_WRAPPERS 1
-
-/*
- * Process creation model. Choose one:
- *
- * HAVE_FORKEXEC - use fork() and exec()
- * HAVE_WIN32_PROC - use CreateProcess()
- */
-#define HAVE_FORKEXEC
-
-/*
- * Process out-of-memory adjustment. Set if running on Linux,
- * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
- * badness adjustment.
- */
-#define HAVE_OOM_ADJ
-
-/*
- * IPC model. Choose one:
- *
- * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
- * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
- * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
- * HAVE_ANDROID_IPC - use Android versions (?, mmap).
- */
-#define HAVE_ANDROID_IPC
-
-/*
- * Memory-mapping model. Choose one:
- *
- * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
- * HAVE_WIN32_FILEMAP - use Win32 filemaps
- */
-#define HAVE_POSIX_FILEMAP
-
-/*
- * Define this if you have <termio.h>
- */
-#define HAVE_TERMIO_H 1
-
-/*
- * Define this if you have <sys/sendfile.h>
- */
-#define HAVE_SYS_SENDFILE_H 1
-
-/*
- * Define this if you build against MSVCRT.DLL
- */
-/* #define HAVE_MS_C_RUNTIME */
-
-/*
- * Define this if you have sys/uio.h
- */
-#define HAVE_SYS_UIO_H 1
-
-/*
- * Define this if your platforms implements symbolic links
- * in its filesystems
- */
-#define HAVE_SYMLINKS
-
-/*
- * Define this if we have localtime_r().
- */
-/* #define HAVE_LOCALTIME_R 1 */
-
-/*
- * Define this if we have gethostbyname_r().
- */
-/* #define HAVE_GETHOSTBYNAME_R */
-
-/*
- * Define this if we have ioctl().
- */
-#define HAVE_IOCTL
-
-/*
- * Define this if we want to use WinSock.
- */
-/* #define HAVE_WINSOCK */
-
-/*
- * Define this if have clock_gettime() and friends
- */
-#define HAVE_POSIX_CLOCKS
-
-/*
- * Define this if we have pthread_cond_timedwait_monotonic() and
- * clock_gettime(CLOCK_MONOTONIC).
- */
-#define HAVE_TIMEDWAIT_MONOTONIC
-
-/*
- * Define this if we have linux style epoll()
- */
-#define HAVE_EPOLL
-
-/*
- * Endianness of the target machine. Choose one:
- *
- * HAVE_ENDIAN_H -- have endian.h header we can include.
- * HAVE_LITTLE_ENDIAN -- we are little endian.
- * HAVE_BIG_ENDIAN -- we are big endian.
- */
-#define HAVE_ENDIAN_H
-#define HAVE_LITTLE_ENDIAN
-
-/*
- * We need to choose between 32-bit and 64-bit off_t. All of our code should
- * agree on the same size. For desktop systems, use 64-bit values,
- * because some of our libraries (e.g. wxWidgets) expect to be built that way.
- */
-/* #define _FILE_OFFSET_BITS 64 */
-/* #define _LARGEFILE_SOURCE 1 */
-
-/*
- * Define if platform has off64_t (and lseek64 and other xxx64 functions)
- */
-#define HAVE_OFF64_T
-
-/*
- * Defined if we have the backtrace() call for retrieving a stack trace.
- * Needed for CallStack to operate; if not defined, CallStack is
- * non-functional.
- */
-#define HAVE_BACKTRACE 0
-
-/*
- * Defined if we have the dladdr() call for retrieving the symbol associated
- * with a memory address. If not defined, stack crawls will not have symbolic
- * information.
- */
-#define HAVE_DLADDR 1
-
-/*
- * Defined if we have the cxxabi.h header for demangling C++ symbols. If
- * not defined, stack crawls will be displayed with raw mangled symbols
- */
-#define HAVE_CXXABI 0
-
-/*
- * Defined if we have the gettid() system call.
- */
-#define HAVE_GETTID
-
-/*
- * Defined if we have the sched_setscheduler() call
- */
-#define HAVE_SCHED_SETSCHEDULER
-
-/*
- * Add any extra platform-specific defines here.
- */
-#ifndef __linux__
-#define __linux__
-#endif
-
-/*
- * Define if we have <malloc.h> header
- */
-#define HAVE_MALLOC_H
-
-/*
- * Define if we're running on *our* linux on device or emulator.
- */
-#define HAVE_ANDROID_OS 1
-
-/*
- * Define if we have Linux-style non-filesystem Unix Domain Sockets
- */
-#define HAVE_LINUX_LOCAL_SOCKET_NAMESPACE 1
-
-/*
- * Define if we have Linux's inotify in <sys/inotify.h>.
- */
-#define HAVE_INOTIFY 1
-
-/*
- * Define if we have madvise() in <sys/mman.h>
- */
-#define HAVE_MADVISE 1
-
-/*
- * Define if tm struct has tm_gmtoff field
- */
-#define HAVE_TM_GMTOFF 1
-
-/*
- * Define if dirent struct has d_type field
- */
-#define HAVE_DIRENT_D_TYPE 1
-
-/*
- * Define if libc includes Android system properties implementation.
- */
-#define HAVE_LIBC_SYSTEM_PROPERTIES 1
-
-/*
- * Define if system provides a system property server (should be
- * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
- */
-/* #define HAVE_SYSTEM_PROPERTY_SERVER */
-
-/*
- * What CPU architecture does this platform use?
- */
-#define ARCH_ARM
-
-/*
- * Define if the size of enums is as short as possible,
- */
-/* #define HAVE_SHORT_ENUMS */
-
-/*
- * sprintf() format string for shared library naming.
- */
-#define OS_SHARED_LIB_FORMAT_STR "lib%s.so"
-
-/*
- * Do we have __memcmp16()?
- */
-#define HAVE__MEMCMP16 1
-
-/*
- * type for the third argument to mincore().
- */
-#define MINCORE_POINTER_TYPE unsigned char *
-
-/*
- * Do we have the sigaction flag SA_NOCLDWAIT?
- */
-#define HAVE_SA_NOCLDWAIT
-
-/*
- * The default path separator for the platform
- */
-#define OS_PATH_SEPARATOR '/'
-
-/*
- * Is the filesystem case sensitive?
- */
-#define OS_CASE_SENSITIVE
-
-/*
- * Define if <sys/socket.h> exists.
- */
-#define HAVE_SYS_SOCKET_H 1
-
-/*
- * Define if the strlcpy() function exists on the system.
- */
-#define HAVE_STRLCPY 1
-
-/*
- * Define if the open_memstream() function exists on the system.
- */
-/* #define HAVE_OPEN_MEMSTREAM 1 */
-
-/*
- * Define if the BSD funopen() function exists on the system.
- */
-#define HAVE_FUNOPEN 1
-
-/*
- * Define if prctl() exists
- */
-#define HAVE_PRCTL 1
-
-/*
- * Define if writev() exists
- */
-#define HAVE_WRITEV 1
-
-/*
- * Define if <stdint.h> exists.
- */
-#define HAVE_STDINT_H 1
-
-/*
- * Define if <stdbool.h> exists.
- */
-#define HAVE_STDBOOL_H 1
-
-/*
- * Define if <sched.h> exists.
- */
-#define HAVE_SCHED_H 1
-
-/*
- * Define if pread() exists
- */
-#define HAVE_PREAD 1
-
-/*
- * Define if we have st_mtim in struct stat
- */
-#define HAVE_STAT_ST_MTIM 1
-
-/*
- * Define if printf() supports %zd for size_t arguments
- */
-#define HAVE_PRINTF_ZD 1
-
-/*
- * Define to 1 if <stdlib.h> provides qsort_r() with a BSD style function prototype.
- */
-#define HAVE_BSD_QSORT_R 0
-
-/*
- * Define to 1 if <stdlib.h> provides qsort_r() with a GNU style function prototype.
- */
-#define HAVE_GNU_QSORT_R 0
-
-#endif /* _ANDROID_CONFIG_H */
diff --git a/include/arch/linux-mips/AndroidConfig.h b/include/arch/linux-mips/AndroidConfig.h
deleted file mode 100644
index 2d51dc7..0000000
--- a/include/arch/linux-mips/AndroidConfig.h
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Android config -- "android-mips". Used for MIPS device builds.
- */
-#ifndef _ANDROID_CONFIG_H
-#define _ANDROID_CONFIG_H
-
-/*
- * ===========================================================================
- * !!! IMPORTANT !!!
- * ===========================================================================
- *
- * This file is included by ALL C/C++ source files. Don't put anything in
- * here unless you are absolutely certain it can't go anywhere else.
- *
- * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//"
- * comments.
- */
-
-/*
- * Threading model. Choose one:
- *
- * HAVE_PTHREADS - use the pthreads library.
- * HAVE_WIN32_THREADS - use Win32 thread primitives.
- * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX
- */
-#define HAVE_PTHREADS
-
-/*
- * Do we have pthread_setname_np()?
- *
- * (HAVE_PTHREAD_SETNAME_NP is used by WebKit to enable a function with
- * the same name but different parameters, so we can't use that here.)
- */
-#define HAVE_ANDROID_PTHREAD_SETNAME_NP
-
-/*
- * Do we have the futex syscall?
- */
-#define HAVE_FUTEX
-
-/*
- * Define if we already have the futex wrapper functions defined. Yes if
- * compiling against bionic.
- */
-#define HAVE_FUTEX_WRAPPERS 1
-
-/*
- * Process creation model. Choose one:
- *
- * HAVE_FORKEXEC - use fork() and exec()
- * HAVE_WIN32_PROC - use CreateProcess()
- */
-#define HAVE_FORKEXEC
-
-/*
- * Process out-of-memory adjustment. Set if running on Linux,
- * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
- * badness adjustment.
- */
-#define HAVE_OOM_ADJ
-
-/*
- * IPC model. Choose one:
- *
- * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
- * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
- * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
- * HAVE_ANDROID_IPC - use Android versions (?, mmap).
- */
-#define HAVE_ANDROID_IPC
-
-/*
- * Memory-mapping model. Choose one:
- *
- * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
- * HAVE_WIN32_FILEMAP - use Win32 filemaps
- */
-#define HAVE_POSIX_FILEMAP
-
-/*
- * Define this if you have <termio.h>
- */
-#define HAVE_TERMIO_H 1
-
-/*
- * Define this if you have <sys/sendfile.h>
- */
-#define HAVE_SYS_SENDFILE_H 1
-
-/*
- * Define this if you build against MSVCRT.DLL
- */
-/* #define HAVE_MS_C_RUNTIME */
-
-/*
- * Define this if you have sys/uio.h
- */
-#define HAVE_SYS_UIO_H 1
-
-/*
- * Define this if your platforms implements symbolic links
- * in its filesystems
- */
-#define HAVE_SYMLINKS
-
-/*
- * Define this if we have localtime_r().
- */
-/* #define HAVE_LOCALTIME_R */
-
-/*
- * Define this if we have gethostbyname_r().
- */
-/* #define HAVE_GETHOSTBYNAME_R */
-
-/*
- * Define this if we have ioctl().
- */
-#define HAVE_IOCTL
-
-/*
- * Define this if we want to use WinSock.
- */
-/* #define HAVE_WINSOCK */
-
-/*
- * Define this if have clock_gettime() and friends
- */
-#define HAVE_POSIX_CLOCKS
-
-/*
- * Define this if we have pthread_cond_timedwait_monotonic() and
- * clock_gettime(CLOCK_MONOTONIC).
- */
-#define HAVE_TIMEDWAIT_MONOTONIC
-
-/*
- * Define this if we have linux style epoll()
- */
-#define HAVE_EPOLL
-
-/*
- * Endianness of the target machine. Choose one:
- *
- * HAVE_ENDIAN_H -- have endian.h header we can include.
- * HAVE_LITTLE_ENDIAN -- we are little endian.
- * HAVE_BIG_ENDIAN -- we are big endian.
- */
-#define HAVE_ENDIAN_H
-#if defined(__MIPSEB__)
-#define HAVE_BIG_ENDIAN
-#endif
-#if defined(__MIPSEL__)
-#define HAVE_LITTLE_ENDIAN
-#endif
-
-/*
- * We need to choose between 32-bit and 64-bit off_t. All of our code should
- * agree on the same size. For desktop systems, use 64-bit values,
- * because some of our libraries (e.g. wxWidgets) expect to be built that way.
- */
-/* #define _FILE_OFFSET_BITS 64 */
-/* #define _LARGEFILE_SOURCE 1 */
-
-/*
- * Define if platform has off64_t (and lseek64 and other xxx64 functions)
- */
-#define HAVE_OFF64_T
-
-/*
- * Defined if we have the backtrace() call for retrieving a stack trace.
- * Needed for CallStack to operate; if not defined, CallStack is
- * non-functional.
- */
-#define HAVE_BACKTRACE 0
-
-/*
- * Defined if we have the dladdr() call for retrieving the symbol associated
- * with a memory address. If not defined, stack crawls will not have symbolic
- * information.
- */
-#define HAVE_DLADDR 1
-
-/*
- * Defined if we have the cxxabi.h header for demangling C++ symbols. If
- * not defined, stack crawls will be displayed with raw mangled symbols
- */
-#define HAVE_CXXABI 0
-
-/*
- * Defined if we have the gettid() system call.
- */
-#define HAVE_GETTID
-
-/*
- * Defined if we have the sched_setscheduler() call
- */
-#define HAVE_SCHED_SETSCHEDULER
-
-/*
- * Add any extra platform-specific defines here.
- */
-#ifndef __linux__
-#define __linux__ 1
-#endif
-
-#ifndef __linux
-#define __linux 1
-#endif
-
-#ifdef __unix__
-#undef __unix__
-#endif
-
-#ifdef __unix
-#undef __unix
-#endif
-
-/*
- * Define if we have <malloc.h> header
- */
-#define HAVE_MALLOC_H
-
-/*
- * Define if we're running on *our* linux on device or emulator.
- */
-#define HAVE_ANDROID_OS 1
-
-/*
- * Define if we have Linux-style non-filesystem Unix Domain Sockets
- */
-#define HAVE_LINUX_LOCAL_SOCKET_NAMESPACE 1
-
-/*
- * Define if we have Linux's inotify in <sys/inotify.h>.
- */
-#define HAVE_INOTIFY 1
-
-/*
- * Define if we have madvise() in <sys/mman.h>
- */
-#define HAVE_MADVISE 1
-
-/*
- * Define if tm struct has tm_gmtoff field
- */
-#define HAVE_TM_GMTOFF 1
-
-/*
- * Define if dirent struct has d_type field
- */
-#define HAVE_DIRENT_D_TYPE 1
-
-/*
- * Define if libc includes Android system properties implementation.
- */
-#define HAVE_LIBC_SYSTEM_PROPERTIES 1
-
-/*
- * Define if system provides a system property server (should be
- * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
- */
-/* #define HAVE_SYSTEM_PROPERTY_SERVER */
-
-/*
- * What CPU architecture does this platform use?
- */
-#define ARCH_MIPS 1
-
-/*
- * Define if the size of enums is as short as possible,
- */
-/* #define HAVE_SHORT_ENUMS */
-
-/*
- * sprintf() format string for shared library naming.
- */
-#define OS_SHARED_LIB_FORMAT_STR "lib%s.so"
-
-/*
- * Do we have __memcmp16()?
- */
-#define HAVE__MEMCMP16 1
-
-/*
- * type for the third argument to mincore().
- */
-#define MINCORE_POINTER_TYPE unsigned char *
-
-/*
- * Do we have the sigaction flag SA_NOCLDWAIT?
- */
-#define HAVE_SA_NOCLDWAIT
-
-/*
- * The default path separator for the platform
- */
-#define OS_PATH_SEPARATOR '/'
-
-/*
- * Is the filesystem case sensitive?
- */
-#define OS_CASE_SENSITIVE
-
-/*
- * Define if <sys/socket.h> exists.
- */
-#define HAVE_SYS_SOCKET_H 1
-
-/*
- * Define if the strlcpy() function exists on the system.
- */
-#define HAVE_STRLCPY 1
-
-/*
- * Define if the open_memstream() function exists on the system.
- */
-/* #define HAVE_OPEN_MEMSTREAM 1 */
-
-/*
- * Define if the BSD funopen() function exists on the system.
- */
-#define HAVE_FUNOPEN 1
-
-/*
- * Define if prctl() exists
- */
-#define HAVE_PRCTL 1
-
-/*
- * Define if writev() exists
- */
-#define HAVE_WRITEV 1
-
-/*
- * Define if <stdint.h> exists.
- */
-#define HAVE_STDINT_H 1
-
-/*
- * Define if <stdbool.h> exists.
- */
-#define HAVE_STDBOOL_H 1
-
-/*
- * Define if <sched.h> exists.
- */
-#define HAVE_SCHED_H 1
-
-/*
- * Define if pread() exists
- */
-#define HAVE_PREAD 1
-
-/*
- * Define if we have st_mtim in struct stat
- */
-#define HAVE_STAT_ST_MTIM 1
-
-/*
- * Define if printf() supports %zd for size_t arguments
- */
-#define HAVE_PRINTF_ZD 1
-
-/*
- * Whether or not _Unwind_Context is defined as a struct.
- */
-#define HAVE_UNWIND_CONTEXT_STRUCT 1
-
-#endif /* _ANDROID_CONFIG_H */
diff --git a/include/arch/linux-ppc/AndroidConfig.h b/include/arch/linux-ppc/AndroidConfig.h
deleted file mode 100644
index ae2569b..0000000
--- a/include/arch/linux-ppc/AndroidConfig.h
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Android config -- "Linux". Used for desktop ppc Linux.
- */
-#ifndef _ANDROID_CONFIG_H
-#define _ANDROID_CONFIG_H
-
-/*
- * ===========================================================================
- * !!! IMPORTANT !!!
- * ===========================================================================
- *
- * This file is included by ALL C/C++ source files. Don't put anything in
- * here unless you are absolutely certain it can't go anywhere else.
- *
- * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//"
- * comments.
- */
-
-/*
- * Threading model. Choose one:
- *
- * HAVE_PTHREADS - use the pthreads library.
- * HAVE_WIN32_THREADS - use Win32 thread primitives.
- * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX
- */
-#define HAVE_PTHREADS
-
-/*
- * Do we have the futex syscall?
- */
-
-#define HAVE_FUTEX
-
-/*
- * Process creation model. Choose one:
- *
- * HAVE_FORKEXEC - use fork() and exec()
- * HAVE_WIN32_PROC - use CreateProcess()
- */
-#define HAVE_FORKEXEC
-
-/*
- * Process out-of-memory adjustment. Set if running on Linux,
- * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
- * badness adjustment.
- */
-#define HAVE_OOM_ADJ
-
-/*
- * IPC model. Choose one:
- *
- * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
- * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
- * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
- * HAVE_ANDROID_IPC - use Android versions (?, mmap).
- */
-#define HAVE_SYSV_IPC
-
-/*
- * Memory-mapping model. Choose one:
- *
- * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
- * HAVE_WIN32_FILEMAP - use Win32 filemaps
- */
-#define HAVE_POSIX_FILEMAP
-
-/*
- * Define this if you have <termio.h>
- */
-#define HAVE_TERMIO_H 1
-
-/*
- * Define this if you have <sys/sendfile.h>
- */
-#define HAVE_SYS_SENDFILE_H 1
-
-/*
- * Define this if you build against MSVCRT.DLL
- */
-/* #define HAVE_MS_C_RUNTIME */
-
-/*
- * Define this if you have sys/uio.h
- */
-#define HAVE_SYS_UIO_H 1
-
-/*
- * Define this if your platforms implements symbolic links
- * in its filesystems
- */
-#define HAVE_SYMLINKS
-
-/*
- * Define this if we have localtime_r().
- */
-#define HAVE_LOCALTIME_R 1
-
-/*
- * Define this if we have gethostbyname_r().
- */
-#define HAVE_GETHOSTBYNAME_R
-
-/*
- * Define this if we have ioctl().
- */
-#define HAVE_IOCTL
-
-/*
- * Define this if we want to use WinSock.
- */
-/* #define HAVE_WINSOCK */
-
-/*
- * Define this if have clock_gettime() and friends
- *
- * Desktop Linux has this in librt, but it's broken in goobuntu, yielding
- * mildly or wildly inaccurate results.
- */
-/*#define HAVE_POSIX_CLOCKS*/
-
-/*
- * Define this if we have pthread_cond_timedwait_monotonic() and
- * clock_gettime(CLOCK_MONOTONIC).
- */
-/* #define HAVE_TIMEDWAIT_MONOTONIC */
-
-/*
- * Define this if we have linux style epoll()
- */
-#define HAVE_EPOLL
-
-/*
- * Endianness of the target machine. Choose one:
- *
- * HAVE_ENDIAN_H -- have endian.h header we can include.
- * HAVE_LITTLE_ENDIAN -- we are little endian.
- * HAVE_BIG_ENDIAN -- we are big endian.
- */
-#define HAVE_ENDIAN_H
-#define HAVE_BIG_ENDIAN
-
-/*
- * We need to choose between 32-bit and 64-bit off_t. All of our code should
- * agree on the same size. For desktop systems, use 64-bit values,
- * because some of our libraries (e.g. wxWidgets) expect to be built that way.
- */
-#define _FILE_OFFSET_BITS 64
-#define _LARGEFILE_SOURCE 1
-
-/*
- * Define if platform has off64_t (and lseek64 and other xxx64 functions)
- */
-#define HAVE_OFF64_T
-
-/*
- * Defined if we have the backtrace() call for retrieving a stack trace.
- * Needed for CallStack to operate; if not defined, CallStack is
- * non-functional.
- */
-#define HAVE_BACKTRACE 1
-
-/*
- * Defined if we have the dladdr() call for retrieving the symbol associated
- * with a memory address. If not defined, stack crawls will not have symbolic
- * information.
- */
-#define HAVE_DLADDR 1
-
-/*
- * Defined if we have the cxxabi.h header for demangling C++ symbols. If
- * not defined, stack crawls will be displayed with raw mangled symbols
- */
-#define HAVE_CXXABI 0
-
-/*
- * Defined if we have the gettid() system call.
- */
-/* #define HAVE_GETTID */
-
-/*
- * Defined if we have the sched_setscheduler() call
- */
-#define HAVE_SCHED_SETSCHEDULER
-
-/*
- * Add any extra platform-specific defines here.
- */
-
-/*
- * Define if we have <malloc.h> header
- */
-#define HAVE_MALLOC_H
-
-/*
- * Define if we have Linux-style non-filesystem Unix Domain Sockets
- */
-
-/*
- * What CPU architecture does this platform use?
- */
-#define ARCH_PPC
-
-
-/*
- * Define if we have Linux's inotify in <sys/inotify.h>.
- */
-/*#define HAVE_INOTIFY 1*/
-
-/*
- * Define if we have madvise() in <sys/mman.h>
- */
-#define HAVE_MADVISE 1
-
-/*
- * Define if tm struct has tm_gmtoff field
- */
-#define HAVE_TM_GMTOFF 1
-
-/*
- * Define if dirent struct has d_type field
- */
-#define HAVE_DIRENT_D_TYPE 1
-
-/*
- * Define if libc includes Android system properties implementation.
- */
-/* #define HAVE_LIBC_SYSTEM_PROPERTIES */
-
-/*
- * Define if system provides a system property server (should be
- * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
- */
-#define HAVE_SYSTEM_PROPERTY_SERVER
-
-/*
- * sprintf() format string for shared library naming.
- */
-#define OS_SHARED_LIB_FORMAT_STR "lib%s.so"
-
-/*
- * type for the third argument to mincore().
- */
-#define MINCORE_POINTER_TYPE unsigned char *
-
-/*
- * Do we have the sigaction flag SA_NOCLDWAIT?
- */
-#define HAVE_SA_NOCLDWAIT
-
-/*
- * The default path separator for the platform
- */
-#define OS_PATH_SEPARATOR '/'
-
-/*
- * Is the filesystem case sensitive?
- */
-#define OS_CASE_SENSITIVE
-
-/*
- * Define if <sys/socket.h> exists.
- */
-#define HAVE_SYS_SOCKET_H 1
-
-/*
- * Define if the strlcpy() function exists on the system.
- */
-/* #define HAVE_STRLCPY 1 */
-
-/*
- * Define if the open_memstream() function exists on the system.
- */
-#define HAVE_OPEN_MEMSTREAM 1
-
-/*
- * Define if the BSD funopen() function exists on the system.
- */
-/* #define HAVE_FUNOPEN 1 */
-
-/*
- * Define if prctl() exists
- */
-#define HAVE_PRCTL 1
-
-/*
- * Define if writev() exists
- */
-#define HAVE_WRITEV 1
-
-/*
- * Define if <stdint.h> exists.
- */
-#define HAVE_STDINT_H 1
-
-/*
- * Define if <stdbool.h> exists.
- */
-#define HAVE_STDBOOL_H 1
-
-/*
- * Define if <sched.h> exists.
- */
-#define HAVE_SCHED_H 1
-
-/*
- * Define if pread() exists
- */
-#define HAVE_PREAD 1
-
-/*
- * Define to 1 if <stdlib.h> provides qsort_r() with a BSD style function prototype.
- */
-#define HAVE_BSD_QSORT_R 0
-
-/*
- * Define to 1 if <stdlib.h> provides qsort_r() with a GNU style function prototype.
- */
-#define HAVE_GNU_QSORT_R 1
-
-#endif /*_ANDROID_CONFIG_H*/
diff --git a/include/arch/linux-x86/AndroidConfig.h b/include/arch/linux-x86/AndroidConfig.h
deleted file mode 100644
index 431a54b..0000000
--- a/include/arch/linux-x86/AndroidConfig.h
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Android config -- "Linux". Used for desktop x86 Linux.
- */
-#ifndef _ANDROID_CONFIG_H
-#define _ANDROID_CONFIG_H
-
-/*
- * ===========================================================================
- * !!! IMPORTANT !!!
- * ===========================================================================
- *
- * This file is included by ALL C/C++ source files. Don't put anything in
- * here unless you are absolutely certain it can't go anywhere else.
- *
- * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//"
- * comments.
- */
-
-/*
- * Threading model. Choose one:
- *
- * HAVE_PTHREADS - use the pthreads library.
- * HAVE_WIN32_THREADS - use Win32 thread primitives.
- * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX
- */
-#define HAVE_PTHREADS
-
-/*
- * Do we have the futex syscall?
- */
-
-#define HAVE_FUTEX
-
-/*
- * Process creation model. Choose one:
- *
- * HAVE_FORKEXEC - use fork() and exec()
- * HAVE_WIN32_PROC - use CreateProcess()
- */
-#define HAVE_FORKEXEC
-
-/*
- * Process out-of-memory adjustment. Set if running on Linux,
- * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
- * badness adjustment.
- */
-#define HAVE_OOM_ADJ
-
-/*
- * IPC model. Choose one:
- *
- * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
- * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
- * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
- * HAVE_ANDROID_IPC - use Android versions (?, mmap).
- */
-#define HAVE_SYSV_IPC
-
-/*
- * Memory-mapping model. Choose one:
- *
- * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
- * HAVE_WIN32_FILEMAP - use Win32 filemaps
- */
-#define HAVE_POSIX_FILEMAP
-
-/*
- * Define this if you have <termio.h>
- */
-#define HAVE_TERMIO_H 1
-
-/*
- * Define this if you have <sys/sendfile.h>
- */
-#define HAVE_SYS_SENDFILE_H 1
-
-/*
- * Define this if you build against MSVCRT.DLL
- */
-/* #define HAVE_MS_C_RUNTIME */
-
-/*
- * Define this if you have sys/uio.h
- */
-#define HAVE_SYS_UIO_H 1
-
-/*
- * Define this if your platforms implements symbolic links
- * in its filesystems
- */
-#define HAVE_SYMLINKS
-
-/*
- * Define this if we have localtime_r().
- */
-#define HAVE_LOCALTIME_R 1
-
-/*
- * Define this if we have gethostbyname_r().
- */
-#define HAVE_GETHOSTBYNAME_R
-
-/*
- * Define this if we have ioctl().
- */
-#define HAVE_IOCTL
-
-/*
- * Define this if we want to use WinSock.
- */
-/* #define HAVE_WINSOCK */
-
-/*
- * Define this if have clock_gettime() and friends
- *
- * Desktop Linux has this in librt, but it's broken in goobuntu, yielding
- * mildly or wildly inaccurate results.
- */
-/*#define HAVE_POSIX_CLOCKS*/
-
-/*
- * Define this if we have pthread_cond_timedwait_monotonic() and
- * clock_gettime(CLOCK_MONOTONIC).
- */
-/* #define HAVE_TIMEDWAIT_MONOTONIC */
-
-/*
- * Define this if we have linux style epoll()
- */
-#define HAVE_EPOLL
-
-/*
- * Endianness of the target machine. Choose one:
- *
- * HAVE_ENDIAN_H -- have endian.h header we can include.
- * HAVE_LITTLE_ENDIAN -- we are little endian.
- * HAVE_BIG_ENDIAN -- we are big endian.
- */
-#define HAVE_ENDIAN_H
-#define HAVE_LITTLE_ENDIAN
-
-/*
- * We need to choose between 32-bit and 64-bit off_t. All of our code should
- * agree on the same size. For desktop systems, use 64-bit values,
- * because some of our libraries (e.g. wxWidgets) expect to be built that way.
- */
-#define _FILE_OFFSET_BITS 64
-#define _LARGEFILE_SOURCE 1
-
-/*
- * Define if platform has off64_t (and lseek64 and other xxx64 functions)
- */
-#define HAVE_OFF64_T
-
-/*
- * Defined if we have the backtrace() call for retrieving a stack trace.
- * Needed for CallStack to operate; if not defined, CallStack is
- * non-functional.
- */
-#define HAVE_BACKTRACE 1
-
-/*
- * Defined if we have the dladdr() call for retrieving the symbol associated
- * with a memory address. If not defined, stack crawls will not have symbolic
- * information.
- */
-#define HAVE_DLADDR 1
-
-/*
- * Defined if we have the cxxabi.h header for demangling C++ symbols. If
- * not defined, stack crawls will be displayed with raw mangled symbols
- */
-#define HAVE_CXXABI 0
-
-/*
- * Defined if we have the gettid() system call.
- */
-/* #define HAVE_GETTID */
-
-/*
- * Defined if we have the sched_setscheduler() call
- */
-#define HAVE_SCHED_SETSCHEDULER
-
-/*
- * Add any extra platform-specific defines here.
- */
-
-/*
- * Define if we have <malloc.h> header
- */
-#define HAVE_MALLOC_H
-
-/*
- * Define if we have Linux-style non-filesystem Unix Domain Sockets
- */
-
-/*
- * What CPU architecture does this platform use?
- */
-#define ARCH_X86
-
-
-/*
- * Define if we have Linux's inotify in <sys/inotify.h>.
- */
-/*#define HAVE_INOTIFY 1*/
-
-/*
- * Define if we have madvise() in <sys/mman.h>
- */
-#define HAVE_MADVISE 1
-
-/*
- * Define if tm struct has tm_gmtoff field
- */
-#define HAVE_TM_GMTOFF 1
-
-/*
- * Define if dirent struct has d_type field
- */
-#define HAVE_DIRENT_D_TYPE 1
-
-/*
- * Define if libc includes Android system properties implementation.
- */
-/* #define HAVE_LIBC_SYSTEM_PROPERTIES */
-
-/*
- * Define if system provides a system property server (should be
- * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
- */
-#define HAVE_SYSTEM_PROPERTY_SERVER
-
-/*
- * sprintf() format string for shared library naming.
- */
-#define OS_SHARED_LIB_FORMAT_STR "lib%s.so"
-
-/*
- * type for the third argument to mincore().
- */
-#define MINCORE_POINTER_TYPE unsigned char *
-
-/*
- * Do we have the sigaction flag SA_NOCLDWAIT?
- */
-#define HAVE_SA_NOCLDWAIT
-
-/*
- * The default path separator for the platform
- */
-#define OS_PATH_SEPARATOR '/'
-
-/*
- * Is the filesystem case sensitive?
- */
-#define OS_CASE_SENSITIVE
-
-/*
- * Define if <sys/socket.h> exists.
- */
-#define HAVE_SYS_SOCKET_H 1
-
-/*
- * Define if the strlcpy() function exists on the system.
- */
-/* #define HAVE_STRLCPY 1 */
-
-/*
- * Define if the open_memstream() function exists on the system.
- */
-#define HAVE_OPEN_MEMSTREAM 1
-
-/*
- * Define if the BSD funopen() function exists on the system.
- */
-/* #define HAVE_FUNOPEN 1 */
-
-/*
- * Define if prctl() exists
- */
-#define HAVE_PRCTL 1
-
-/*
- * Define if writev() exists
- */
-#define HAVE_WRITEV 1
-
-/*
- * Define if <stdint.h> exists.
- */
-#define HAVE_STDINT_H 1
-
-/*
- * Define if <stdbool.h> exists.
- */
-#define HAVE_STDBOOL_H 1
-
-/*
- * Define if <sched.h> exists.
- */
-#define HAVE_SCHED_H 1
-
-/*
- * Define if pread() exists
- */
-#define HAVE_PREAD 1
-
-/*
- * Define if we have st_mtim in struct stat
- */
-#define HAVE_STAT_ST_MTIM 1
-
-/*
- * Define if printf() supports %zd for size_t arguments
- */
-#define HAVE_PRINTF_ZD 1
-
-/*
- * Define to 1 if <stdlib.h> provides qsort_r() with a BSD style function prototype.
- */
-#define HAVE_BSD_QSORT_R 0
-
-/*
- * Define to 1 if <stdlib.h> provides qsort_r() with a GNU style function prototype.
- */
-#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
-#define HAVE_GNU_QSORT_R 1
-#else
-#define HAVE_GNU_QSORT_R 0
-#endif
-
-#endif /*_ANDROID_CONFIG_H*/
diff --git a/include/arch/target_linux-x86/AndroidConfig.h b/include/arch/target_linux-x86/AndroidConfig.h
deleted file mode 100644
index ab53892..0000000
--- a/include/arch/target_linux-x86/AndroidConfig.h
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright 2005 The Android Open Source Project
- *
- * Android config -- "target_linux-x86". Used for x86 linux target devices.
- */
-#ifndef _ANDROID_CONFIG_H
-#define _ANDROID_CONFIG_H
-
-/*
- * ===========================================================================
- * !!! IMPORTANT !!!
- * ===========================================================================
- *
- * This file is included by ALL C/C++ source files. Don't put anything in
- * here unless you are absolutely certain it can't go anywhere else.
- *
- * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//"
- * comments.
- */
-
-/*
- * Threading model. Choose one:
- *
- * HAVE_PTHREADS - use the pthreads library.
- * HAVE_WIN32_THREADS - use Win32 thread primitives.
- * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX
- */
-#define HAVE_PTHREADS
-
-/*
- * Do we have pthread_setname_np()?
- *
- * (HAVE_PTHREAD_SETNAME_NP is used by WebKit to enable a function with
- * the same name but different parameters, so we can't use that here.)
- */
-#define HAVE_ANDROID_PTHREAD_SETNAME_NP
-
-/*
- * Do we have the futex syscall?
- */
-#define HAVE_FUTEX
-
-/*
- * Define if we already have the futex wrapper functions defined. Yes if
- * compiling against bionic.
- */
-#define HAVE_FUTEX_WRAPPERS 1
-
-/*
- * Process creation model. Choose one:
- *
- * HAVE_FORKEXEC - use fork() and exec()
- * HAVE_WIN32_PROC - use CreateProcess()
- */
-#define HAVE_FORKEXEC
-
-/*
- * Process out-of-memory adjustment. Set if running on Linux,
- * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
- * badness adjustment.
- */
-#define HAVE_OOM_ADJ
-
-/*
- * IPC model. Choose one:
- *
- * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
- * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
- * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
- * HAVE_ANDROID_IPC - use Android versions (?, mmap).
- */
-#define HAVE_ANDROID_IPC 1
-
-/*
- * Memory-mapping model. Choose one:
- *
- * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
- * HAVE_WIN32_FILEMAP - use Win32 filemaps
- */
-#define HAVE_POSIX_FILEMAP 1
-
-/*
- * Define this if you have <termio.h>
- */
-#define HAVE_TERMIO_H 1
-
-/*
- * Define this if you have <sys/sendfile.h>
- */
-#define HAVE_SYS_SENDFILE_H 1
-
-/*
- * Define this if you build against have Microsoft C runtime (MSVCRT.DLL)
- */
-/* #define HAVE_MS_C_RUNTIME */
-
-/*
- * Define this if you have sys/uio.h
- */
-#define HAVE_SYS_UIO_H 1
-
-/*
- * Define this if your platforms implements symbolic links
- * in its filesystems
- */
-#define HAVE_SYMLINKS 1
-
-/*
- * Define this if we have localtime_r().
- */
-/* #define HAVE_LOCALTIME_R 1 */
-
-/*
- * Define this if we have gethostbyname_r().
- */
-/* #define HAVE_GETHOSTBYNAME_R */
-
-/*
- * Define this if we have ioctl().
- */
-#define HAVE_IOCTL
-
-/*
- * Define this if we want to use WinSock.
- */
-/* #define HAVE_WINSOCK */
-
-/*
- * Define this if have clock_gettime() and friends
- *
- */
-#define HAVE_POSIX_CLOCKS
-
-/*
- * Define this if we have pthread_cond_timedwait_monotonic() and
- * clock_gettime(CLOCK_MONOTONIC).
- */
-#define HAVE_TIMEDWAIT_MONOTONIC
-
-/*
- * Define this if we have linux style epoll()
- */
-#define HAVE_EPOLL
-
-/*
- * Endianness of the target machine. Choose one:
- *
- * HAVE_ENDIAN_H -- have endian.h header we can include.
- * HAVE_LITTLE_ENDIAN -- we are little endian.
- * HAVE_BIG_ENDIAN -- we are big endian.
- */
-#define HAVE_ENDIAN_H
-#define HAVE_LITTLE_ENDIAN
-
-/*
- * We need to choose between 32-bit and 64-bit off_t. All of our code should
- * agree on the same size. For desktop systems, use 64-bit values,
- * because some of our libraries (e.g. wxWidgets) expect to be built that way.
- */
-/*
- * #define _FILE_OFFSET_BITS 64
- * #define _LARGEFILE_SOURCE 1
- */
-
-/*
- * Define if platform has off64_t (and lseek64 and other xxx64 functions)
- */
-#define HAVE_OFF64_T
-
-/*
- * Defined if we have the backtrace() call for retrieving a stack trace.
- * Needed for CallStack to operate; if not defined, CallStack is
- * non-functional.
- */
-#define HAVE_BACKTRACE 0
-
-/*
- * Defined if we have the dladdr() call for retrieving the symbol associated
- * with a memory address. If not defined, stack crawls will not have symbolic
- * information.
- */
-#define HAVE_DLADDR 0
-
-/*
- * Defined if we have the cxxabi.h header for demangling C++ symbols. If
- * not defined, stack crawls will be displayed with raw mangled symbols
- */
-#define HAVE_CXXABI 0
-
-/*
- * Defined if we have the gettid() system call.
- */
-#define HAVE_GETTID
-
-/*
- * Defined if we have the sched_setscheduler() call
- */
-#define HAVE_SCHED_SETSCHEDULER
-
-/*
- * Add any extra platform-specific defines here.
- */
-#ifndef __linux__
-#define __linux__
-#endif
-
-/*
- * Define if we have <malloc.h> header
- */
-#define HAVE_MALLOC_H
-
-/*
- * Define if we're running on *our* linux on device or emulator.
- */
-#define HAVE_ANDROID_OS 1
-
-/*
- * Define if we have Linux-style non-filesystem Unix Domain Sockets
- */
-#define HAVE_LINUX_LOCAL_SOCKET_NAMESPACE 1
-
-/*
- * Define if we have Linux's inotify in <sys/inotify.h>.
- */
-#define HAVE_INOTIFY 1
-
-/*
- * Define if we have madvise() in <sys/mman.h>
- */
-#define HAVE_MADVISE 1
-
-/*
- * Define if we have Linux's dbus
- */
-/* #define HAVE_DBUS 1 */
-
-/*
- * Define if tm struct has tm_gmtoff field
- */
-#define HAVE_TM_GMTOFF 1
-
-/*
- * Define if dirent struct has d_type field
- */
-#define HAVE_DIRENT_D_TYPE 1
-
-/*
- * Define if libc includes Android system properties implementation.
- */
-#define HAVE_LIBC_SYSTEM_PROPERTIES 1
-
-/*
- * Define if system provides a system property server (should be
- * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
- */
-/* #define HAVE_SYSTEM_PROPERTY_SERVER */
-
-/*
- * What CPU architecture does this platform use?
- */
-#define ARCH_X86
-
-/*
- * sprintf() format string for shared library naming.
- */
-#define OS_SHARED_LIB_FORMAT_STR "lib%s.so"
-
-/*
- * Do we have __memcmp16()?
- */
-/* #define HAVE__MEMCMP16 1 */
-
-/*
- * type for the third argument to mincore().
- */
-#define MINCORE_POINTER_TYPE unsigned char *
-
-/*
- * Do we have the sigaction flag SA_NOCLDWAIT?
- */
-#define HAVE_SA_NOCLDWAIT
-
-/*
- * The default path separator for the platform
- */
-#define OS_PATH_SEPARATOR '/'
-
-/*
- * Is the filesystem case sensitive?
- */
-#define OS_CASE_SENSITIVE
-
-/*
- * Define if <sys/socket.h> exists.
- */
-#define HAVE_SYS_SOCKET_H 1
-
-/*
- * Define if the strlcpy() function exists on the system.
- */
-#define HAVE_STRLCPY 1
-
-/*
- * Define if the open_memstream() function exists on the system.
- */
-/* #define HAVE_OPEN_MEMSTREAM 1 */
-
-/*
- * Define if the BSD funopen() function exists on the system.
- */
-#define HAVE_FUNOPEN 1
-
-/*
- * Define if prctl() exists
- */
-#define HAVE_PRCTL 1
-
-/*
- * Whether or not _Unwind_Context is defined as a struct.
- */
-#define HAVE_UNWIND_CONTEXT_STRUCT
-
-/*
- * Define if <stdint.h> exists.
- */
-#define HAVE_STDINT_H 1
-
-/*
- * Define if <stdbool.h> exists.
- */
-#define HAVE_STDBOOL_H 1
-
-/*
- * Define if <sched.h> exists.
- */
-#define HAVE_SCHED_H 1
-
-/*
- * Define if pread() exists
- */
-#define HAVE_PREAD 1
-
-/*
- * Define if we have st_mtim in struct stat
- */
-#define HAVE_STAT_ST_MTIM 1
-
-/*
- * Define if printf() supports %zd for size_t arguments
- */
-#define HAVE_PRINTF_ZD 1
-
-/*
- * Define to 1 if <stdlib.h> provides qsort_r() with a BSD style function prototype.
- */
-#define HAVE_BSD_QSORT_R 0
-
-/*
- * Define to 1 if <stdlib.h> provides qsort_r() with a GNU style function prototype.
- */
-#define HAVE_GNU_QSORT_R 0
-
-#endif /* _ANDROID_CONFIG_H */
diff --git a/include/arch/windows/AndroidConfig.h b/include/arch/windows/AndroidConfig.h
deleted file mode 100644
index 0274da5..0000000
--- a/include/arch/windows/AndroidConfig.h
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Android config -- "CYGWIN_NT-5.1".
- *
- * Cygwin has pthreads, but GDB seems to get confused if you use it to
- * create threads. By "confused", I mean it freezes up the first time the
- * debugged process creates a thread, even if you use CreateThread. The
- * mere presence of pthreads linkage seems to cause problems.
- */
-#ifndef _ANDROID_CONFIG_H
-#define _ANDROID_CONFIG_H
-
-/*
- * ===========================================================================
- * !!! IMPORTANT !!!
- * ===========================================================================
- *
- * This file is included by ALL C/C++ source files. Don't put anything in
- * here unless you are absolutely certain it can't go anywhere else.
- *
- * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//"
- * comments.
- */
-
-/*
- * Threading model. Choose one:
- *
- * HAVE_PTHREADS - use the pthreads library.
- * HAVE_WIN32_THREADS - use Win32 thread primitives.
- */
-#define HAVE_WIN32_THREADS
-
-/*
- * Do we have the futex syscall?
- */
-
-/* #define HAVE_FUTEX */
-
-
-/*
- * Process creation model. Choose one:
- *
- * HAVE_FORKEXEC - use fork() and exec()
- * HAVE_WIN32_PROC - use CreateProcess()
- */
-#ifdef __CYGWIN__
-# define HAVE_FORKEXEC
-#else
-# define HAVE_WIN32_PROC
-#endif
-
-/*
- * Process out-of-memory adjustment. Set if running on Linux,
- * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
- * badness adjustment.
- */
-/* #define HAVE_OOM_ADJ */
-
-/*
- * IPC model. Choose one:
- *
- * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
- * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
- * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
- * HAVE_ANDROID_IPC - use Android versions (?, mmap).
- */
-#define HAVE_WIN32_IPC
-
-/*
- * Memory-mapping model. Choose one:
- *
- * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
- * HAVE_WIN32_FILEMAP - use Win32 filemaps
- */
-#ifdef __CYGWIN__
-#define HAVE_POSIX_FILEMAP
-#else
-#define HAVE_WIN32_FILEMAP
-#endif
-
-/*
- * Define this if you have <termio.h>
- */
-#ifdef __CYGWIN__
-# define HAVE_TERMIO_H
-#endif
-
-/*
- * Define this if you have <sys/sendfile.h>
- */
-#ifdef __CYGWIN__
-# define HAVE_SYS_SENDFILE_H 1
-#endif
-
-/*
- * Define this if you build against MSVCRT.DLL
- */
-#ifndef __CYGWIN__
-# define HAVE_MS_C_RUNTIME
-#endif
-
-/*
- * Define this if you have sys/uio.h
- */
-#ifdef __CYGWIN__
-#define HAVE_SYS_UIO_H
-#endif
-
-
-/*
- * Define this if we have localtime_r().
- */
-/* #define HAVE_LOCALTIME_R 1 */
-
-/*
- * Define this if we have gethostbyname_r().
- */
-/* #define HAVE_GETHOSTBYNAME_R */
-
-/*
- * Define this if we have ioctl().
- */
-/* #define HAVE_IOCTL */
-
-/*
- * Define this if we want to use WinSock.
- */
-#ifndef __CYGWIN__
-#define HAVE_WINSOCK
-#endif
-
-/*
- * Define this if your platforms implements symbolic links
- * in its filesystems
- */
-/* #define HAVE_SYMLINKS */
-
-/*
- * Define this if have clock_gettime() and friends
- */
-/* #define HAVE_POSIX_CLOCKS */
-
-/*
- * Endianness of the target machine. Choose one:
- *
- * HAVE_ENDIAN_H -- have endian.h header we can include.
- * HAVE_LITTLE_ENDIAN -- we are little endian.
- * HAVE_BIG_ENDIAN -- we are big endian.
- */
-#ifdef __CYGWIN__
-#define HAVE_ENDIAN_H
-#endif
-
-#define HAVE_LITTLE_ENDIAN
-
-/*
- * We need to choose between 32-bit and 64-bit off_t. All of our code should
- * agree on the same size. For desktop systems, use 64-bit values,
- * because some of our libraries (e.g. wxWidgets) expect to be built that way.
- */
-#define _FILE_OFFSET_BITS 64
-#define _LARGEFILE_SOURCE 1
-
-/*
- * Define if platform has off64_t (and lseek64 and other xxx64 functions)
- */
-#define HAVE_OFF64_T
-
-/*
- * Defined if we have the backtrace() call for retrieving a stack trace.
- * Needed for CallStack to operate; if not defined, CallStack is
- * non-functional.
- */
-#define HAVE_BACKTRACE 0
-
-/*
- * Defined if we have the dladdr() call for retrieving the symbol associated
- * with a memory address. If not defined, stack crawls will not have symbolic
- * information.
- */
-#define HAVE_DLADDR 0
-
-/*
- * Defined if we have the cxxabi.h header for demangling C++ symbols. If
- * not defined, stack crawls will be displayed with raw mangled symbols
- */
-#define HAVE_CXXABI 0
-
-/*
- * Define if tm struct has tm_gmtoff field
- */
-/* #define HAVE_TM_GMTOFF 1 */
-
-/*
- * Define if dirent struct has d_type field
- */
-/* #define HAVE_DIRENT_D_TYPE 1 */
-
-/*
- * Define if libc includes Android system properties implementation.
- */
-/* #define HAVE_LIBC_SYSTEM_PROPERTIES */
-
-/*
- * Define if system provides a system property server (should be
- * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
- */
-/* #define HAVE_SYSTEM_PROPERTY_SERVER */
-
-/*
- * Define if we have madvise() in <sys/mman.h>
- */
-/*#define HAVE_MADVISE 1*/
-
-/*
- * Add any extra platform-specific defines here.
- */
-#define WIN32 1 /* stock Cygwin doesn't define these */
-#define _WIN32 1
-#define _WIN32_WINNT 0x0500 /* admit to using >= Win2K */
-
-#define HAVE_WINDOWS_PATHS /* needed by simulator */
-
-/*
- * What CPU architecture does this platform use?
- */
-#define ARCH_X86
-
-/*
- * sprintf() format string for shared library naming.
- */
-#define OS_SHARED_LIB_FORMAT_STR "lib%s.dll"
-
-/*
- * type for the third argument to mincore().
- */
-#define MINCORE_POINTER_TYPE unsigned char *
-
-/*
- * The default path separator for the platform
- */
-#define OS_PATH_SEPARATOR '\\'
-
-/*
- * Is the filesystem case sensitive?
- */
-/* #define OS_CASE_SENSITIVE */
-
-/*
- * Define if <sys/socket.h> exists.
- * Cygwin has it, but not MinGW.
- */
-#ifdef USE_MINGW
-/* #define HAVE_SYS_SOCKET_H */
-#else
-#define HAVE_SYS_SOCKET_H 1
-#endif
-
-/*
- * Define if the strlcpy() function exists on the system.
- */
-/* #define HAVE_STRLCPY 1 */
-
-/*
- * Define if the open_memstream() function exists on the system.
- */
-/* #define HAVE_OPEN_MEMSTREAM 1 */
-
-/*
- * Define if the BSD funopen() function exists on the system.
- */
-/* #define HAVE_FUNOPEN 1 */
-
-/*
- * Define if <winsock2.h> exists.
- * Only MinGW has it.
- */
-#ifdef USE_MINGW
-#define HAVE_WINSOCK2_H 1
-#else
-/* #define HAVE_WINSOCK2_H */
-#endif
-
-/*
- * Various definitions missing in MinGW
- */
-#ifdef USE_MINGW
-#define S_IRGRP 0
-#endif
-
-/*
- * Define if writev() exists.
- */
-/* #define HAVE_WRITEV */
-
-/*
- * Define if <stdint.h> exists.
- */
-/* #define HAVE_STDINT_H */
-
-/*
- * Define if <stdbool.h> exists.
- */
-#define HAVE_STDBOOL_H
-
-/*
- * Define if <sched.h> exists.
- */
-/* #define HAVE_SCHED_H */
-
-/*
- * Define if pread() exists
- */
-/* #define HAVE_PREAD 1 */
-
-/*
- * Define if we have st_mtim in struct stat
- */
-/* #define HAVE_STAT_ST_MTIM 1 */
-
-/*
- * Define if printf() supports %zd for size_t arguments
- */
-/* #define HAVE_PRINTF_ZD 1 */
-
-/*
- * Define to 1 if <stdlib.h> provides qsort_r() with a BSD style function prototype.
- */
-#define HAVE_BSD_QSORT_R 0
-
-/*
- * Define to 1 if <stdlib.h> provides qsort_r() with a GNU style function prototype.
- */
-#define HAVE_GNU_QSORT_R 0
-
-#endif /*_ANDROID_CONFIG_H*/
diff --git a/include/corkscrew/map_info.h b/include/corkscrew/map_info.h
index c5cd8f8..ea1d35f 100644
--- a/include/corkscrew/map_info.h
+++ b/include/corkscrew/map_info.h
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <stdbool.h>
+#include <stdint.h>
#ifdef __cplusplus
extern "C" {
diff --git a/include/corkscrew/ptrace.h b/include/corkscrew/ptrace.h
index 9e0da78..76276d8 100644
--- a/include/corkscrew/ptrace.h
+++ b/include/corkscrew/ptrace.h
@@ -24,6 +24,7 @@
#include <sys/types.h>
#include <stdbool.h>
+#include <stdint.h>
#ifdef __cplusplus
extern "C" {
diff --git a/include/corkscrew/symbol_table.h b/include/corkscrew/symbol_table.h
index 020c8b8..4998750 100644
--- a/include/corkscrew/symbol_table.h
+++ b/include/corkscrew/symbol_table.h
@@ -17,6 +17,7 @@
#ifndef _CORKSCREW_SYMBOL_TABLE_H
#define _CORKSCREW_SYMBOL_TABLE_H
+#include <stdint.h>
#include <sys/types.h>
#ifdef __cplusplus
diff --git a/include/cutils/fs.h b/include/cutils/fs.h
new file mode 100644
index 0000000..fd5296b
--- /dev/null
+++ b/include/cutils/fs.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_FS_H
+#define __CUTILS_FS_H
+
+#include <sys/types.h>
+
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({ \
+ typeof (exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1 && errno == EINTR); \
+ _rc; })
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Ensure that directory exists with given mode and owners.
+ */
+extern int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
+
+/*
+ * Read single plaintext integer from given file, correctly handling files
+ * partially written with fs_write_atomic_int().
+ */
+extern int fs_read_atomic_int(const char* path, int* value);
+
+/*
+ * Write single plaintext integer to given file, creating backup while
+ * in progress.
+ */
+extern int fs_write_atomic_int(const char* path, int value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_FS_H */
diff --git a/include/cutils/multiuser.h b/include/cutils/multiuser.h
new file mode 100644
index 0000000..635ddb1
--- /dev/null
+++ b/include/cutils/multiuser.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_MULTIUSER_H
+#define __CUTILS_MULTIUSER_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// NOTE: keep in sync with android.os.UserId
+
+#define MULTIUSER_APP_PER_USER_RANGE 100000
+
+typedef uid_t userid_t;
+typedef uid_t appid_t;
+
+extern userid_t multiuser_get_user_id(uid_t uid);
+extern appid_t multiuser_get_app_id(uid_t uid);
+extern uid_t multiuser_get_uid(userid_t userId, appid_t appId);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_MULTIUSER_H */
diff --git a/include/cutils/tztime.h b/include/cutils/tztime.h
index dbdbd60..36ac25d 100644
--- a/include/cutils/tztime.h
+++ b/include/cutils/tztime.h
@@ -17,8 +17,45 @@
#ifndef _CUTILS_TZTIME_H
#define _CUTILS_TZTIME_H
-// TODO: fix both callers to just include <bionic_time.h> themselves.
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+time_t mktime_tz(struct tm * const tmp, char const * tz);
+void localtime_tz(const time_t * const timep, struct tm * tmp, const char* tz);
+
+#ifdef HAVE_ANDROID_OS
+
+/* the following is defined in the Bionic C library on Android, but the
+ * declarations are only available through a platform-private header
+ */
#include <bionic_time.h>
+#else /* !HAVE_ANDROID_OS */
+
+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;
+ const char *x_fmt;
+ const char *c_fmt;
+ const char *am;
+ const char *pm;
+ const char *date_fmt;
+};
+
+size_t strftime_tz(char *s, size_t max, const char *format, const struct tm *tm, const struct strftime_locale *locale);
+
+#endif /* !HAVE_ANDROID_OS */
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __CUTILS_TZTIME_H */
diff --git a/include/ion/ion.h b/include/ion/ion.h
index cafead5..018c0a1 100644
--- a/include/ion/ion.h
+++ b/include/ion/ion.h
@@ -27,8 +27,11 @@
int ion_open();
int ion_close(int fd);
-int ion_alloc(int fd, size_t len, size_t align, unsigned int flags,
- struct ion_handle **handle);
+int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask,
+ unsigned int flags, struct ion_handle **handle);
+int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask,
+ unsigned int flags, int *handle_fd);
+int ion_sync_fd(int fd, int handle_fd);
int ion_free(int fd, struct ion_handle *handle);
int ion_map(int fd, struct ion_handle *handle, size_t length, int prot,
int flags, off_t offset, unsigned char **ptr, int *map_fd);
diff --git a/include/mincrypt/rsa.h b/include/mincrypt/rsa.h
index 7d7d571..d7429fc 100644
--- a/include/mincrypt/rsa.h
+++ b/include/mincrypt/rsa.h
@@ -13,14 +13,14 @@
** be used to endorse or promote products derived from this software
** without specific prior written permission.
**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+** THIS SOFTWARE IS PROVIDED BY Google Inc. ``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
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
** EVENT SHALL Google Inc. 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
+** 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.
*/
@@ -42,6 +42,7 @@
uint32_t n0inv; /* -1 / n[0] mod 2^32 */
uint32_t n[RSANUMWORDS]; /* modulus as little endian array */
uint32_t rr[RSANUMWORDS]; /* R^2 as little endian array */
+ int exponent; /* 3 or 65537 */
} RSAPublicKey;
int RSA_verify(const RSAPublicKey *key,
diff --git a/include/netutils/ifc.h b/include/netutils/ifc.h
index 3574f7f..1f5421d 100644
--- a/include/netutils/ifc.h
+++ b/include/netutils/ifc.h
@@ -69,6 +69,8 @@
uint32_t prefixLength, in_addr_t gateway,
in_addr_t dns1, in_addr_t dns2);
+extern in_addr_t prefixLengthToIpv4Netmask(int prefix_length);
+
__END_DECLS
#endif /* _NETUTILS_IFC_H_ */
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 33ecd9a..3a2500e 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -62,6 +62,7 @@
#define AID_DRMRPC 1026 /* group for drm rpc */
#define AID_NFC 1027 /* nfc subsystem */
#define AID_SDCARD_R 1028 /* external storage read access */
+#define AID_CLAT 1029 /* clat part of nat464 */
#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
@@ -76,6 +77,7 @@
#define AID_NET_ADMIN 3005 /* can configure interfaces and routing tables. */
#define AID_NET_BW_STATS 3006 /* read bandwidth statistics */
#define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */
+#define AID_NET_BT_STACK 3008 /* bluetooth: access config files */
#define AID_MISC 9998 /* access to misc storage */
#define AID_NOBODY 9999
@@ -122,6 +124,7 @@
{ "diag", AID_DIAG, },
{ "net_bt_admin", AID_NET_BT_ADMIN, },
{ "net_bt", AID_NET_BT, },
+ { "net_bt_stack", AID_NET_BT_STACK, },
{ "sdcard_r", AID_SDCARD_R, },
{ "sdcard_rw", AID_SDCARD_RW, },
{ "media_rw", AID_MEDIA_RW, },
@@ -137,6 +140,7 @@
{ "net_bw_acct", AID_NET_BW_ACCT, },
{ "misc", AID_MISC, },
{ "nobody", AID_NOBODY, },
+ { "clat", AID_CLAT, },
};
#define android_id_count \
@@ -191,12 +195,6 @@
{ 00550, AID_ROOT, AID_SHELL, "system/etc/init.testmenu" },
{ 00550, AID_DHCP, AID_SHELL, "system/etc/dhcpcd/dhcpcd-run-hooks" },
{ 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/dbus.conf" },
- { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluetooth/main.conf" },
- { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluetooth/input.conf" },
- { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluetooth/audio.conf" },
- { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluetooth/network.conf" },
- { 00444, AID_NET_BT, AID_NET_BT, "system/etc/bluetooth/blacklist.conf" },
- { 00640, AID_SYSTEM, AID_SYSTEM, "system/etc/bluetooth/auto_pairing.conf" },
{ 00444, AID_RADIO, AID_AUDIO, "system/etc/AudioPara4.csv" },
{ 00555, AID_ROOT, AID_ROOT, "system/etc/ppp/*" },
{ 00555, AID_ROOT, AID_ROOT, "system/etc/rc.*" },
diff --git a/include/sync/sync.h b/include/sync/sync.h
index 6aa5f2d..918acf6 100644
--- a/include/sync/sync.h
+++ b/include/sync/sync.h
@@ -19,13 +19,30 @@
#ifndef __SYS_CORE_SYNC_H
#define __SYS_CORE_SYNC_H
-#include <linux/sync.h>
-#include <linux/sw_sync.h>
+#include <sys/cdefs.h>
+#include <stdint.h>
__BEGIN_DECLS
+// XXX: These structs are copied from the header "linux/sync.h".
+struct sync_fence_info_data {
+ uint32_t len;
+ char name[32];
+ int32_t status;
+ uint8_t pt_info[0];
+};
+
+struct sync_pt_info {
+ uint32_t len;
+ char obj_name[32];
+ char driver_name[32];
+ int32_t status;
+ uint64_t timestamp_ns;
+ uint8_t driver_data[0];
+};
+
/* timeout in msecs */
-int sync_wait(int fd, unsigned int timeout);
+int sync_wait(int fd, int timeout);
int sync_merge(const char *name, int fd1, int fd2);
struct sync_fence_info_data *sync_fence_info(int fd);
struct sync_pt_info *sync_pt_info(struct sync_fence_info_data *info,
diff --git a/include/system/audio.h b/include/system/audio.h
index 3807317..d246070 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -63,7 +63,10 @@
AUDIO_SOURCE_CAMCORDER = 5,
AUDIO_SOURCE_VOICE_RECOGNITION = 6,
AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
-
+ AUDIO_SOURCE_REMOTE_SUBMIX = 8, /* Source for the mix to be presented remotely. */
+ /* An example of remote presentation is Wifi Display */
+ /* where a dongle attached to a TV can be used to */
+ /* play the mix captured by this audio source. */
AUDIO_SOURCE_CNT,
AUDIO_SOURCE_MAX = AUDIO_SOURCE_CNT - 1,
} audio_source_t;
@@ -152,7 +155,7 @@
AUDIO_FORMAT_PCM_SUB_8_24_BIT),
} audio_format_t;
-typedef enum {
+enum {
/* output channels */
AUDIO_CHANNEL_OUT_FRONT_LEFT = 0x1,
AUDIO_CHANNEL_OUT_FRONT_RIGHT = 0x2,
@@ -275,7 +278,11 @@
AUDIO_IN_ACOUSTICS_TX_DISABLE = 0,
} audio_in_acoustics_t;
-typedef enum {
+enum {
+ AUDIO_DEVICE_NONE = 0x0,
+ /* reserved bits */
+ AUDIO_DEVICE_BIT_IN = 0x80000000,
+ AUDIO_DEVICE_BIT_DEFAULT = 0x40000000,
/* output devices */
AUDIO_DEVICE_OUT_EARPIECE = 0x1,
AUDIO_DEVICE_OUT_SPEAKER = 0x2,
@@ -292,7 +299,8 @@
AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000,
AUDIO_DEVICE_OUT_USB_ACCESSORY = 0x2000,
AUDIO_DEVICE_OUT_USB_DEVICE = 0x4000,
- AUDIO_DEVICE_OUT_DEFAULT = 0x8000,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX = 0x8000,
+ AUDIO_DEVICE_OUT_DEFAULT = AUDIO_DEVICE_BIT_DEFAULT,
AUDIO_DEVICE_OUT_ALL = (AUDIO_DEVICE_OUT_EARPIECE |
AUDIO_DEVICE_OUT_SPEAKER |
AUDIO_DEVICE_OUT_WIRED_HEADSET |
@@ -308,6 +316,7 @@
AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
AUDIO_DEVICE_OUT_USB_ACCESSORY |
AUDIO_DEVICE_OUT_USB_DEVICE |
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX |
AUDIO_DEVICE_OUT_DEFAULT),
AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
@@ -319,15 +328,20 @@
AUDIO_DEVICE_OUT_USB_DEVICE),
/* input devices */
- AUDIO_DEVICE_IN_COMMUNICATION = 0x10000,
- AUDIO_DEVICE_IN_AMBIENT = 0x20000,
- AUDIO_DEVICE_IN_BUILTIN_MIC = 0x40000,
- AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000,
- AUDIO_DEVICE_IN_WIRED_HEADSET = 0x100000,
- AUDIO_DEVICE_IN_AUX_DIGITAL = 0x200000,
- AUDIO_DEVICE_IN_VOICE_CALL = 0x400000,
- AUDIO_DEVICE_IN_BACK_MIC = 0x800000,
- AUDIO_DEVICE_IN_DEFAULT = 0x80000000,
+ AUDIO_DEVICE_IN_COMMUNICATION = AUDIO_DEVICE_BIT_IN | 0x1,
+ AUDIO_DEVICE_IN_AMBIENT = AUDIO_DEVICE_BIT_IN | 0x2,
+ AUDIO_DEVICE_IN_BUILTIN_MIC = AUDIO_DEVICE_BIT_IN | 0x4,
+ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = AUDIO_DEVICE_BIT_IN | 0x8,
+ AUDIO_DEVICE_IN_WIRED_HEADSET = AUDIO_DEVICE_BIT_IN | 0x10,
+ AUDIO_DEVICE_IN_AUX_DIGITAL = AUDIO_DEVICE_BIT_IN | 0x20,
+ AUDIO_DEVICE_IN_VOICE_CALL = AUDIO_DEVICE_BIT_IN | 0x40,
+ AUDIO_DEVICE_IN_BACK_MIC = AUDIO_DEVICE_BIT_IN | 0x80,
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX = AUDIO_DEVICE_BIT_IN | 0x100,
+ AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x200,
+ AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x400,
+ AUDIO_DEVICE_IN_USB_ACCESSORY = AUDIO_DEVICE_BIT_IN | 0x800,
+ AUDIO_DEVICE_IN_USB_DEVICE = AUDIO_DEVICE_BIT_IN | 0x1000,
+ AUDIO_DEVICE_IN_DEFAULT = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT,
AUDIO_DEVICE_IN_ALL = (AUDIO_DEVICE_IN_COMMUNICATION |
AUDIO_DEVICE_IN_AMBIENT |
@@ -337,9 +351,16 @@
AUDIO_DEVICE_IN_AUX_DIGITAL |
AUDIO_DEVICE_IN_VOICE_CALL |
AUDIO_DEVICE_IN_BACK_MIC |
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX |
+ AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET |
+ AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET |
+ AUDIO_DEVICE_IN_USB_ACCESSORY |
+ AUDIO_DEVICE_IN_USB_DEVICE |
AUDIO_DEVICE_IN_DEFAULT),
AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
-} audio_devices_t;
+};
+
+typedef uint32_t audio_devices_t;
/* the audio output flags serve two purposes:
* - when an AudioTrack is created they indicate a "wish" to be connected to an
@@ -366,7 +387,8 @@
static inline bool audio_is_output_device(audio_devices_t device)
{
- if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL) == 0))
+ if (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
+ (popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL) == 0))
return true;
else
return false;
@@ -374,12 +396,20 @@
static inline bool audio_is_input_device(audio_devices_t device)
{
- if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_IN_ALL) == 0))
- return true;
- else
- return false;
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_IN_ALL) == 0))
+ return true;
+ }
+ return false;
}
+static inline bool audio_is_output_devices(audio_devices_t device)
+{
+ return (device & AUDIO_DEVICE_BIT_IN) == 0;
+}
+
+
static inline bool audio_is_a2dp_device(audio_devices_t device)
{
if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_A2DP))
@@ -390,6 +420,7 @@
static inline bool audio_is_bluetooth_sco_device(audio_devices_t device)
{
+ device &= ~AUDIO_DEVICE_BIT_IN;
if ((popcount(device) == 1) && (device & (AUDIO_DEVICE_OUT_ALL_SCO |
AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)))
return true;
@@ -405,6 +436,14 @@
return false;
}
+static inline bool audio_is_remote_submix_device(audio_devices_t device)
+{
+ if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX))
+ return true;
+ else
+ return false;
+}
+
static inline bool audio_is_input_channel(uint32_t channel)
{
if ((channel & ~AUDIO_CHANNEL_IN_ALL) == 0)
diff --git a/include/system/audio_policy.h b/include/system/audio_policy.h
index 91b8e9c..a6554de 100644
--- a/include/system/audio_policy.h
+++ b/include/system/audio_policy.h
@@ -43,6 +43,7 @@
AUDIO_POLICY_FORCE_ANALOG_DOCK,
AUDIO_POLICY_FORCE_DIGITAL_DOCK,
AUDIO_POLICY_FORCE_NO_BT_A2DP, /* A2DP sink is not preferred to speaker or wired HS */
+ AUDIO_POLICY_FORCE_SYSTEM_ENFORCED,
AUDIO_POLICY_FORCE_CFG_CNT,
AUDIO_POLICY_FORCE_CFG_MAX = AUDIO_POLICY_FORCE_CFG_CNT - 1,
@@ -56,6 +57,7 @@
AUDIO_POLICY_FORCE_FOR_MEDIA,
AUDIO_POLICY_FORCE_FOR_RECORD,
AUDIO_POLICY_FORCE_FOR_DOCK,
+ AUDIO_POLICY_FORCE_FOR_SYSTEM,
AUDIO_POLICY_FORCE_USE_CNT,
AUDIO_POLICY_FORCE_USE_MAX = AUDIO_POLICY_FORCE_USE_CNT - 1,
diff --git a/include/system/camera.h b/include/system/camera.h
index e4cacc5..7a4dd53 100644
--- a/include/system/camera.h
+++ b/include/system/camera.h
@@ -163,6 +163,17 @@
* can silently finish itself or show a dialog.
*/
CAMERA_CMD_PING = 9,
+
+ /**
+ * Configure the number of video buffers used for recording. The intended
+ * video buffer count for recording is passed as arg1, which must be
+ * greater than 0. This command must be sent before recording is started.
+ * This command returns INVALID_OPERATION error if it is sent after video
+ * recording is started, or the command is not supported at all. This
+ * command also returns a BAD_VALUE error if the intended video buffer
+ * count is non-positive or too big to be realized.
+ */
+ CAMERA_CMD_SET_VIDEO_BUFFER_COUNT = 10,
};
/** camera fatal errors */
diff --git a/include/system/graphics.h b/include/system/graphics.h
index 24e2bfb2..82b5fcc 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -109,6 +109,37 @@
*/
HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20,
+ /*
+ * Android binary blob graphics buffer format:
+ *
+ * This format is used to carry task-specific data which does not have a
+ * standard image structure. The details of the format are left to the two
+ * endpoints.
+ *
+ * A typical use case is for transporting JPEG-compressed images from the
+ * Camera HAL to the framework or to applications.
+ *
+ * Buffers of this format must have a height of 1, and width equal to their
+ * size in bytes.
+ */
+ HAL_PIXEL_FORMAT_BLOB = 0x21,
+
+ /*
+ * Android format indicating that the choice of format is entirely up to the
+ * device-specific Gralloc implementation.
+ *
+ * The Gralloc implementation should examine the usage bits passed in when
+ * allocating a buffer with this format, and it should derive the pixel
+ * format from those usage flags. This format will never be used with any
+ * of the GRALLOC_USAGE_SW_* usage flags.
+ *
+ * If a buffer of this format is to be used as an OpenGL ES texture, the
+ * framework will assume that sampling the texture will always return an
+ * alpha value of 1.0 (i.e. the buffer contains only opaque pixel values).
+ *
+ */
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22,
+
/* Legacy formats (deprecated), used by ImageFormat.java */
HAL_PIXEL_FORMAT_YCbCr_422_SP = 0x10, // NV16
HAL_PIXEL_FORMAT_YCrCb_420_SP = 0x11, // NV21
diff --git a/include/system/window.h b/include/system/window.h
index 8e00bcd..4698fb3 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -17,11 +17,15 @@
#ifndef SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H
#define SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H
+#include <cutils/native_handle.h>
+#include <errno.h>
+#include <limits.h>
#include <stdint.h>
#include <string.h>
+#include <sync/sync.h>
#include <sys/cdefs.h>
#include <system/graphics.h>
-#include <cutils/native_handle.h>
+#include <unistd.h>
__BEGIN_DECLS
@@ -38,6 +42,14 @@
// ---------------------------------------------------------------------------
+// This #define may be used to conditionally compile device-specific code to
+// support either the prior ANativeWindow interface, which did not pass libsync
+// fences around, or the new interface that does. This #define is only present
+// when the ANativeWindow interface does include libsync support.
+#define ANDROID_NATIVE_WINDOW_HAS_SYNC 1
+
+// ---------------------------------------------------------------------------
+
typedef const native_handle_t* buffer_handle_t;
// ---------------------------------------------------------------------------
@@ -379,8 +391,12 @@
* allowed if a specific buffer count has been set.
*
* Returns 0 on success or -errno on error.
+ *
+ * XXX: This function is deprecated. It will continue to work for some
+ * time for binary compatibility, but the new dequeueBuffer function that
+ * outputs a fence file descriptor should be used in its place.
*/
- int (*dequeueBuffer)(struct ANativeWindow* window,
+ int (*dequeueBuffer_DEPRECATED)(struct ANativeWindow* window,
struct ANativeWindowBuffer** buffer);
/*
@@ -389,9 +405,14 @@
* dequeueBuffer first.
*
* Returns 0 on success or -errno on error.
+ *
+ * XXX: This function is deprecated. It will continue to work for some
+ * time for binary compatibility, but it is essentially a no-op, and calls
+ * to it should be removed.
*/
- int (*lockBuffer)(struct ANativeWindow* window,
+ int (*lockBuffer_DEPRECATED)(struct ANativeWindow* window,
struct ANativeWindowBuffer* buffer);
+
/*
* Hook called by EGL when modifications to the render buffer are done.
* This unlocks and post the buffer.
@@ -405,8 +426,13 @@
* Buffers MUST be queued in the same order than they were dequeued.
*
* Returns 0 on success or -errno on error.
+ *
+ * XXX: This function is deprecated. It will continue to work for some
+ * time for binary compatibility, but the new queueBuffer function that
+ * takes a fence file descriptor should be used in its place (pass a value
+ * of -1 for the fence file descriptor if there is no valid one to pass).
*/
- int (*queueBuffer)(struct ANativeWindow* window,
+ int (*queueBuffer_DEPRECATED)(struct ANativeWindow* window,
struct ANativeWindowBuffer* buffer);
/*
@@ -463,12 +489,86 @@
* reference if they might use the buffer after queueing or canceling it.
* Holding a reference to a buffer after queueing or canceling it is only
* allowed if a specific buffer count has been set.
+ *
+ * XXX: This function is deprecated. It will continue to work for some
+ * time for binary compatibility, but the new cancelBuffer function that
+ * takes a fence file descriptor should be used in its place (pass a value
+ * of -1 for the fence file descriptor if there is no valid one to pass).
*/
- int (*cancelBuffer)(struct ANativeWindow* window,
+ int (*cancelBuffer_DEPRECATED)(struct ANativeWindow* window,
struct ANativeWindowBuffer* buffer);
+ /*
+ * Hook called by EGL to acquire a buffer. This call may block if no
+ * buffers are available.
+ *
+ * The window holds a reference to the buffer between dequeueBuffer and
+ * either queueBuffer or cancelBuffer, so clients only need their own
+ * reference if they might use the buffer after queueing or canceling it.
+ * Holding a reference to a buffer after queueing or canceling it is only
+ * allowed if a specific buffer count has been set.
+ *
+ * The libsync fence file descriptor returned in the int pointed to by the
+ * fenceFd argument will refer to the fence that must signal before the
+ * dequeued buffer may be written to. A value of -1 indicates that the
+ * caller may access the buffer immediately without waiting on a fence. If
+ * a valid file descriptor is returned (i.e. any value except -1) then the
+ * caller is responsible for closing the file descriptor.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*dequeueBuffer)(struct ANativeWindow* window,
+ struct ANativeWindowBuffer** buffer, int* fenceFd);
- void* reserved_proc[2];
+ /*
+ * Hook called by EGL when modifications to the render buffer are done.
+ * This unlocks and post the buffer.
+ *
+ * The window holds a reference to the buffer between dequeueBuffer and
+ * either queueBuffer or cancelBuffer, so clients only need their own
+ * reference if they might use the buffer after queueing or canceling it.
+ * Holding a reference to a buffer after queueing or canceling it is only
+ * allowed if a specific buffer count has been set.
+ *
+ * The fenceFd argument specifies a libsync fence file descriptor for a
+ * fence that must signal before the buffer can be accessed. If the buffer
+ * can be accessed immediately then a value of -1 should be used. The
+ * caller must not use the file descriptor after it is passed to
+ * queueBuffer, and the ANativeWindow implementation is responsible for
+ * closing it.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*queueBuffer)(struct ANativeWindow* window,
+ struct ANativeWindowBuffer* buffer, int fenceFd);
+
+ /*
+ * Hook used to cancel a buffer that has been dequeued.
+ * No synchronization is performed between dequeue() and cancel(), so
+ * either external synchronization is needed, or these functions must be
+ * called from the same thread.
+ *
+ * The window holds a reference to the buffer between dequeueBuffer and
+ * either queueBuffer or cancelBuffer, so clients only need their own
+ * reference if they might use the buffer after queueing or canceling it.
+ * Holding a reference to a buffer after queueing or canceling it is only
+ * allowed if a specific buffer count has been set.
+ *
+ * The fenceFd argument specifies a libsync fence file decsriptor for a
+ * fence that must signal before the buffer can be accessed. If the buffer
+ * can be accessed immediately then a value of -1 should be used.
+ *
+ * Note that if the client has not waited on the fence that was returned
+ * from dequeueBuffer, that same fence should be passed to cancelBuffer to
+ * ensure that future uses of the buffer are preceded by a wait on that
+ * fence. The caller must not use the file descriptor after it is passed
+ * to cancelBuffer, and the ANativeWindow implementation is responsible for
+ * closing it.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*cancelBuffer)(struct ANativeWindow* window,
+ struct ANativeWindowBuffer* buffer, int fenceFd);
};
/* Backwards compatibility: use ANativeWindow (struct ANativeWindow in C).
@@ -551,7 +651,7 @@
/*
* native_window_set_active_rect(..., active_rect)
*
- * This function is deprectated and will be removed soon. For now it simply
+ * This function is deprecated and will be removed soon. For now it simply
* sets the post-transform crop for compatibility while multi-project commits
* get checked.
*/
@@ -717,6 +817,17 @@
return window->perform(window, NATIVE_WINDOW_API_DISCONNECT, api);
}
+/*
+ * native_window_dequeue_buffer_and_wait(...)
+ * Dequeue a buffer and wait on the fence associated with that buffer. The
+ * buffer may safely be accessed immediately upon this function returning. An
+ * error is returned if either of the dequeue or the wait operations fail.
+ */
+static inline int native_window_dequeue_buffer_and_wait(ANativeWindow *anw,
+ struct ANativeWindowBuffer** anb) {
+ return anw->dequeueBuffer_DEPRECATED(anw, anb);
+}
+
__END_DECLS
diff --git a/init/Android.mk b/init/Android.mk
index f3287a8..00d2144 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -15,7 +15,8 @@
signal_handler.c \
init_parser.c \
ueventd.c \
- ueventd_parser.c
+ ueventd_parser.c \
+ watchdogd.c
ifeq ($(strip $(INIT_BOOTCHART)),true)
LOCAL_SRC_FILES += bootchart.c
@@ -40,8 +41,11 @@
include $(BUILD_EXECUTABLE)
-# Make a symlink from /sbin/ueventd to /init
-SYMLINKS := $(TARGET_ROOT_OUT)/sbin/ueventd
+# Make a symlink from /sbin/ueventd and /sbin/watchdogd to /init
+SYMLINKS := \
+ $(TARGET_ROOT_OUT)/sbin/ueventd \
+ $(TARGET_ROOT_OUT)/sbin/watchdogd
+
$(SYMLINKS): INIT_BINARY := $(LOCAL_MODULE)
$(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk
@echo "Symlink: $@ -> ../$(INIT_BINARY)"
diff --git a/init/builtins.c b/init/builtins.c
index 550be68..baa3e7f 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -320,6 +320,14 @@
if (_chown(args[1], uid, gid) < 0) {
return -errno;
}
+
+ /* chown may have cleared S_ISUID and S_ISGID, chmod again */
+ if (mode & (S_ISUID | S_ISGID)) {
+ ret = _chmod(args[1], mode);
+ if (ret == -1) {
+ return -errno;
+ }
+ }
}
return 0;
@@ -337,6 +345,12 @@
{ "ro", MS_RDONLY },
{ "rw", 0 },
{ "remount", MS_REMOUNT },
+ { "bind", MS_BIND },
+ { "rec", MS_REC },
+ { "unbindable", MS_UNBINDABLE },
+ { "private", MS_PRIVATE },
+ { "slave", MS_SLAVE },
+ { "shared", MS_SHARED },
{ "defaults", 0 },
{ 0, 0 },
};
diff --git a/init/devices.c b/init/devices.c
index 2644623..dd875d6 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -49,6 +49,7 @@
#define SYSFS_PREFIX "/sys"
#define FIRMWARE_DIR1 "/etc/firmware"
#define FIRMWARE_DIR2 "/vendor/firmware"
+#define FIRMWARE_DIR3 "/firmware/image"
extern struct selabel_handle *sehandle;
@@ -631,7 +632,7 @@
static void handle_device_event(struct uevent *uevent)
{
- if (!strcmp(uevent->action,"add"))
+ if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change"))
fixup_sys_perms(uevent->path);
if (!strncmp(uevent->subsystem, "block", 5)) {
@@ -696,7 +697,7 @@
static void process_firmware_event(struct uevent *uevent)
{
- char *root, *loading, *data, *file1 = NULL, *file2 = NULL;
+ char *root, *loading, *data, *file1 = NULL, *file2 = NULL, *file3 = NULL;
int l, loading_fd, data_fd, fw_fd;
int booting = is_booting();
@@ -723,6 +724,10 @@
if (l == -1)
goto data_free_out;
+ l = asprintf(&file3, FIRMWARE_DIR3"/%s", uevent->firmware);
+ if (l == -1)
+ goto data_free_out;
+
loading_fd = open(loading, O_WRONLY);
if(loading_fd < 0)
goto file_free_out;
@@ -736,17 +741,20 @@
if(fw_fd < 0) {
fw_fd = open(file2, O_RDONLY);
if (fw_fd < 0) {
- if (booting) {
- /* If we're not fully booted, we may be missing
- * filesystems needed for firmware, wait and retry.
- */
- usleep(100000);
- booting = is_booting();
- goto try_loading_again;
+ fw_fd = open(file3, O_RDONLY);
+ if (fw_fd < 0) {
+ if (booting) {
+ /* If we're not fully booted, we may be missing
+ * filesystems needed for firmware, wait and retry.
+ */
+ usleep(100000);
+ booting = is_booting();
+ goto try_loading_again;
+ }
+ INFO("firmware: could not open '%s' %d\n", uevent->firmware, errno);
+ write(loading_fd, "-1", 2);
+ goto data_close_out;
}
- INFO("firmware: could not open '%s' %d\n", uevent->firmware, errno);
- write(loading_fd, "-1", 2);
- goto data_close_out;
}
}
diff --git a/init/init.c b/init/init.c
index 1d639dd..b20b434 100755
--- a/init/init.c
+++ b/init/init.c
@@ -31,6 +31,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <sys/personality.h>
#include <selinux/selinux.h>
#include <selinux/label.h>
@@ -56,6 +57,7 @@
#include "init_parser.h"
#include "util.h"
#include "ueventd.h"
+#include "watchdogd.h"
struct selabel_handle *sehandle;
struct selabel_handle *sehandle_prop;
@@ -232,6 +234,21 @@
int fd, sz;
umask(077);
+#ifdef __arm__
+ /*
+ * b/7188322 - Temporarily revert to the compat memory layout
+ * to avoid breaking third party apps.
+ *
+ * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE.
+ *
+ * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466
+ * changes the kernel mapping from bottom up to top-down.
+ * This breaks some programs which improperly embed
+ * an out of date copy of Android's linker.
+ */
+ int current = personality(0xffffFFFF);
+ personality(current | ADDR_COMPAT_LAYOUT);
+#endif
if (properties_inited()) {
get_property_workspace(&fd, &sz);
sprintf(tmp, "%d,%d", dup(fd), sz);
@@ -808,6 +825,9 @@
if (!strcmp(basename(argv[0]), "ueventd"))
return ueventd_main(argc, argv);
+ if (!strcmp(basename(argv[0]), "watchdogd"))
+ return watchdogd_main(argc, argv);
+
/* clear the umask */
umask(0);
diff --git a/init/property_service.c b/init/property_service.c
old mode 100644
new mode 100755
index 31bc55a..61dd86f
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -79,6 +79,7 @@
{ "sys.", AID_SYSTEM, 0 },
{ "service.", AID_SYSTEM, 0 },
{ "wlan.", AID_SYSTEM, 0 },
+ { "bluetooth.", AID_BLUETOOTH, 0 },
{ "dhcp.", AID_SYSTEM, 0 },
{ "dhcp.", AID_DHCP, 0 },
{ "debug.", AID_SYSTEM, 0 },
@@ -89,6 +90,7 @@
{ "persist.sys.", AID_SYSTEM, 0 },
{ "persist.service.", AID_SYSTEM, 0 },
{ "persist.security.", AID_SYSTEM, 0 },
+ { "persist.service.bdroid.", AID_BLUETOOTH, 0 },
{ "selinux." , AID_SYSTEM, 0 },
{ NULL, 0, 0 }
};
@@ -583,6 +585,16 @@
return property_area_inited;
}
+static void load_override_properties() {
+#ifdef ALLOW_LOCAL_PROP_OVERRIDE
+ const char *debuggable = property_get("ro.debuggable");
+ if (debuggable && (strcmp(debuggable, "1") == 0)) {
+ load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
+ }
+#endif /* ALLOW_LOCAL_PROP_OVERRIDE */
+}
+
+
/* When booting an encrypted system, /data is not mounted when the
* property service is started, so any properties stored there are
* not loaded. Vold triggers init to load these properties once it
@@ -590,9 +602,7 @@
*/
void load_persist_props(void)
{
-#ifdef ALLOW_LOCAL_PROP_OVERRIDE
- load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
-#endif /* ALLOW_LOCAL_PROP_OVERRIDE */
+ load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
}
@@ -603,9 +613,7 @@
load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
-#ifdef ALLOW_LOCAL_PROP_OVERRIDE
- load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
-#endif /* ALLOW_LOCAL_PROP_OVERRIDE */
+ load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
diff --git a/init/ueventd.c b/init/ueventd.c
index a89e067..a41c31e 100644
--- a/init/ueventd.c
+++ b/init/ueventd.c
@@ -105,7 +105,7 @@
for (i = 0; i < ARRAY_SIZE(android_ids); i++)
if (!strcmp(id, android_ids[i].name))
return android_ids[i].aid;
- return 0;
+ return -1;
}
void set_device_permission(int nargs, char **args)
diff --git a/init/watchdogd.c b/init/watchdogd.c
new file mode 100644
index 0000000..fb53836
--- /dev/null
+++ b/init/watchdogd.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <linux/watchdog.h>
+
+#include "log.h"
+#include "util.h"
+
+#define DEV_NAME "/dev/watchdog"
+
+int watchdogd_main(int argc, char **argv)
+{
+ int fd;
+ int ret;
+ int interval = 10;
+ int margin = 10;
+ int timeout;
+
+ open_devnull_stdio();
+ klog_init();
+
+ INFO("Starting watchdogd\n");
+
+ if (argc >= 2)
+ interval = atoi(argv[1]);
+
+ if (argc >= 3)
+ margin = atoi(argv[2]);
+
+ timeout = interval + margin;
+
+ fd = open(DEV_NAME, O_RDWR);
+ if (fd < 0) {
+ ERROR("watchdogd: Failed to open %s: %s\n", DEV_NAME, strerror(errno));
+ return 1;
+ }
+
+ ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
+ if (ret) {
+ ERROR("watchdogd: Failed to set timeout to %d: %s\n", timeout, strerror(errno));
+ ret = ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
+ if (ret) {
+ ERROR("watchdogd: Failed to get timeout: %s\n", strerror(errno));
+ } else {
+ if (timeout > margin)
+ interval = timeout - margin;
+ else
+ interval = 1;
+ ERROR("watchdogd: Adjusted interval to timeout returned by driver: timeout %d, interval %d, margin %d\n",
+ timeout, interval, margin);
+ }
+ }
+
+ while(1) {
+ write(fd, "", 1);
+ sleep(interval);
+ }
+}
+
diff --git a/init/watchdogd.h b/init/watchdogd.h
new file mode 100644
index 0000000..8b48ab8
--- /dev/null
+++ b/init/watchdogd.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_WATCHDOGD_H_
+#define _INIT_WATCHDOGD_H_
+
+int watchdogd_main(int argc, char **argv);
+
+#endif
diff --git a/libcorkscrew/Android.mk b/libcorkscrew/Android.mk
index aace5f8..2786d8f 100644
--- a/libcorkscrew/Android.mk
+++ b/libcorkscrew/Android.mk
@@ -14,9 +14,7 @@
LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
+generic_src_files := \
backtrace.c \
backtrace-helper.c \
demangle.c \
@@ -24,16 +22,24 @@
ptrace.c \
symbol_table.c
-ifeq ($(TARGET_ARCH),arm)
-LOCAL_SRC_FILES += \
+arm_src_files := \
arch-arm/backtrace-arm.c \
arch-arm/ptrace-arm.c
+
+x86_src_files := \
+ arch-x86/backtrace-x86.c \
+ arch-x86/ptrace-x86.c
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(generic_src_files)
+
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_SRC_FILES += $(arm_src_files)
LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
endif
ifeq ($(TARGET_ARCH),x86)
-LOCAL_SRC_FILES += \
- arch-x86/backtrace-x86.c \
- arch-x86/ptrace-x86.c
+LOCAL_SRC_FILES += $(x86_src_files)
LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
endif
ifeq ($(TARGET_ARCH),mips)
@@ -50,3 +56,38 @@
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
+
+# Build test.
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := test.c
+LOCAL_CFLAGS += -std=gnu99 -Werror -fno-inline-small-functions
+LOCAL_SHARED_LIBRARIES := libcorkscrew
+LOCAL_MODULE := libcorkscrew_test
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
+
+ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
+
+# Build libcorkscrew.
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES += $(generic_src_files) $(x86_src_files)
+LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
+LOCAL_SHARED_LIBRARIES += libgccdemangle
+LOCAL_STATIC_LIBRARIES += libcutils
+LOCAL_LDLIBS += -ldl -lrt
+LOCAL_CFLAGS += -std=gnu99 -Werror
+LOCAL_MODULE := libcorkscrew
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+# Build test.
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := test.c
+LOCAL_CFLAGS += -std=gnu99 -Werror -fno-inline-small-functions
+LOCAL_SHARED_LIBRARIES := libcorkscrew
+LOCAL_MODULE := libcorkscrew_test
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_HOST_EXECUTABLE)
+
+endif # linux-x86
diff --git a/libcorkscrew/arch-x86/backtrace-x86.c b/libcorkscrew/arch-x86/backtrace-x86.c
index 082f635..fb79a0c 100644
--- a/libcorkscrew/arch-x86/backtrace-x86.c
+++ b/libcorkscrew/arch-x86/backtrace-x86.c
@@ -31,10 +31,19 @@
#include <limits.h>
#include <errno.h>
#include <sys/ptrace.h>
-#include <sys/exec_elf.h>
#include <cutils/log.h>
-#if !defined(__BIONIC_HAVE_UCONTEXT_T)
+#if defined(__BIONIC__)
+
+#if defined(__BIONIC_HAVE_UCONTEXT_T)
+
+// Bionic offers the Linux kernel headers.
+#include <asm/sigcontext.h>
+#include <asm/ucontext.h>
+typedef struct ucontext ucontext_t;
+
+#else /* __BIONIC_HAVE_UCONTEXT_T */
+
/* Old versions of the Android <signal.h> didn't define ucontext_t. */
typedef struct {
@@ -60,7 +69,16 @@
mcontext_t uc_mcontext;
uint32_t uc_sigmask;
} ucontext_t;
-#endif /* !__BIONIC_HAVE_UCONTEXT_T */
+
+#endif /* __BIONIC_HAVE_UCONTEXT_T */
+
+#else /* __BIONIC__ */
+
+// glibc has its own renaming of the Linux kernel's structures.
+#define __USE_GNU // For REG_EBP, REG_ESP, and REG_EIP.
+#include <ucontext.h>
+
+#endif /* __ BIONIC__ */
/* Unwind state. */
typedef struct {
@@ -111,8 +129,8 @@
unwind_state_t state;
state.ebp = uc->uc_mcontext.gregs[REG_EBP];
- state.eip = uc->uc_mcontext.gregs[REG_EIP];
state.esp = uc->uc_mcontext.gregs[REG_ESP];
+ state.eip = uc->uc_mcontext.gregs[REG_EIP];
memory_t memory;
init_memory(&memory, map_info_list);
diff --git a/libcorkscrew/backtrace.c b/libcorkscrew/backtrace.c
index e57f428..3697d18 100644
--- a/libcorkscrew/backtrace.c
+++ b/libcorkscrew/backtrace.c
@@ -27,16 +27,41 @@
#include <unistd.h>
#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
#include <pthread.h>
#include <unwind.h>
-#include <sys/exec_elf.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
+#include <elf.h>
#if HAVE_DLADDR
+#define __USE_GNU // For dladdr(3) in glibc.
#include <dlfcn.h>
#endif
+#if defined(__BIONIC__)
+
+// Bionic implements and exports gettid but only implements tgkill.
+extern int tgkill(int tgid, int tid, int sig);
+
+#else
+
+// glibc doesn't implement or export either gettid or tgkill.
+
+#include <unistd.h>
+#include <sys/syscall.h>
+
+static pid_t gettid() {
+ return syscall(__NR_gettid);
+}
+
+static int tgkill(int tgid, int tid, int sig) {
+ return syscall(__NR_tgkill, tgid, tid, sig);
+}
+
+#endif
+
typedef struct {
backtrace_frame_t* backtrace;
size_t ignore_depth;
@@ -115,8 +140,6 @@
}
#endif
-extern int tgkill(int tgid, int tid, int sig);
-
ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace,
size_t ignore_depth, size_t max_depth) {
if (tid == gettid()) {
diff --git a/libcorkscrew/map_info.c b/libcorkscrew/map_info.c
index f33378f..3c52854 100644
--- a/libcorkscrew/map_info.c
+++ b/libcorkscrew/map_info.c
@@ -21,6 +21,7 @@
#include <ctype.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <pthread.h>
diff --git a/libcorkscrew/ptrace.c b/libcorkscrew/ptrace.c
index cbea8ca..6496d5e 100644
--- a/libcorkscrew/ptrace.c
+++ b/libcorkscrew/ptrace.c
@@ -21,6 +21,7 @@
#include <corkscrew/ptrace.h>
#include <errno.h>
+#include <stdlib.h>
#include <sys/ptrace.h>
#include <cutils/log.h>
diff --git a/libcorkscrew/symbol_table.c b/libcorkscrew/symbol_table.c
index 1b97180..29e4a79 100644
--- a/libcorkscrew/symbol_table.c
+++ b/libcorkscrew/symbol_table.c
@@ -19,14 +19,22 @@
#include <corkscrew/symbol_table.h>
+#include <stdbool.h>
#include <stdlib.h>
+#include <elf.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/mman.h>
-#include <sys/exec_elf.h>
#include <cutils/log.h>
+static bool is_elf(Elf32_Ehdr* e) {
+ return (e->e_ident[EI_MAG0] == ELFMAG0 &&
+ e->e_ident[EI_MAG1] == ELFMAG1 &&
+ e->e_ident[EI_MAG2] == ELFMAG2 &&
+ e->e_ident[EI_MAG3] == ELFMAG3);
+}
+
// Compare function for qsort
static int qcompar(const void *a, const void *b) {
const symbol_t* asym = (const symbol_t*)a;
@@ -67,7 +75,7 @@
// Parse the file header
Elf32_Ehdr *hdr = (Elf32_Ehdr*)base;
- if (!IS_ELF(*hdr)) {
+ if (!is_elf(hdr)) {
goto out_close;
}
Elf32_Shdr *shdr = (Elf32_Shdr*)(base + hdr->e_shoff);
diff --git a/libcorkscrew/test.c b/libcorkscrew/test.c
new file mode 100644
index 0000000..af34c03
--- /dev/null
+++ b/libcorkscrew/test.c
@@ -0,0 +1,64 @@
+#include <corkscrew/backtrace.h>
+#include <corkscrew/symbol_table.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void do_backtrace() {
+ const size_t MAX_DEPTH = 32;
+ backtrace_frame_t* frames = (backtrace_frame_t*) malloc(sizeof(backtrace_frame_t) * MAX_DEPTH);
+ ssize_t frame_count = unwind_backtrace(frames, 0, MAX_DEPTH);
+ fprintf(stderr, "frame_count=%d\n", (int) frame_count);
+
+ backtrace_symbol_t* backtrace_symbols = (backtrace_symbol_t*) malloc(sizeof(backtrace_symbol_t) * frame_count);
+ get_backtrace_symbols(frames, frame_count, backtrace_symbols);
+
+ for (size_t i = 0; i < (size_t) frame_count; ++i) {
+ char line[MAX_BACKTRACE_LINE_LENGTH];
+ format_backtrace_line(i, &frames[i], &backtrace_symbols[i],
+ line, MAX_BACKTRACE_LINE_LENGTH);
+ if (backtrace_symbols[i].symbol_name != NULL) {
+ // get_backtrace_symbols found the symbol's name with dladdr(3).
+ fprintf(stderr, " %s\n", line);
+ } else {
+ // We don't have a symbol. Maybe this is a static symbol, and
+ // we can look it up?
+ symbol_table_t* symbols = NULL;
+ if (backtrace_symbols[i].map_name != NULL) {
+ symbols = load_symbol_table(backtrace_symbols[i].map_name);
+ }
+ const symbol_t* symbol = NULL;
+ if (symbols != NULL) {
+ symbol = find_symbol(symbols, frames[i].absolute_pc);
+ }
+ if (symbol != NULL) {
+ uintptr_t offset = frames[i].absolute_pc - symbol->start;
+ fprintf(stderr, " %s (%s%+d)\n", line, symbol->name, offset);
+ } else {
+ fprintf(stderr, " %s (\?\?\?)\n", line);
+ }
+ free_symbol_table(symbols);
+ }
+ }
+
+ free_backtrace_symbols(backtrace_symbols, frame_count);
+ free(backtrace_symbols);
+ free(frames);
+}
+
+__attribute__ ((noinline)) void g() {
+ fprintf(stderr, "g()\n");
+ do_backtrace();
+}
+
+__attribute__ ((noinline)) int f(int i) {
+ fprintf(stderr, "f(%i)\n", i);
+ if (i == 0) {
+ g();
+ return 0;
+ }
+ return f(i - 1);
+}
+
+int main() {
+ return f(5);
+}
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index da8e149..d9bd8d8 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -50,7 +50,7 @@
threads.c \
sched_policy.c \
iosched_policy.c \
- str_parms.c
+ str_parms.c \
commonHostSources := \
ashmem-host.c
@@ -75,8 +75,14 @@
else
commonSources += \
abort_socket.c \
+ fs.c \
selector.c \
+ tztime.c \
+ multiuser.c \
zygote.c
+
+ commonHostSources += \
+ tzstrftime.c
endif
diff --git a/libcutils/fs.c b/libcutils/fs.c
new file mode 100644
index 0000000..1226d44
--- /dev/null
+++ b/libcutils/fs.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "cutils"
+
+#include <cutils/fs.h>
+#include <cutils/log.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+
+#define ALL_PERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
+#define BUF_SIZE 64
+
+int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid) {
+ // Check if path needs to be created
+ struct stat sb;
+ if (TEMP_FAILURE_RETRY(lstat(path, &sb)) == -1) {
+ if (errno == ENOENT) {
+ goto create;
+ } else {
+ ALOGE("Failed to lstat(%s): %s", path, strerror(errno));
+ return -1;
+ }
+ }
+
+ // Exists, verify status
+ if (!S_ISDIR(sb.st_mode)) {
+ ALOGE("Not a directory: %s", path);
+ return -1;
+ }
+ if (((sb.st_mode & ALL_PERMS) == mode) && (sb.st_uid == uid) && (sb.st_gid == gid)) {
+ return 0;
+ } else {
+ goto fixup;
+ }
+
+create:
+ if (TEMP_FAILURE_RETRY(mkdir(path, mode)) == -1) {
+ if (errno != EEXIST) {
+ ALOGE("Failed to mkdir(%s): %s", path, strerror(errno));
+ return -1;
+ }
+ }
+
+fixup:
+ if (TEMP_FAILURE_RETRY(chmod(path, mode)) == -1) {
+ ALOGE("Failed to chmod(%s, %d): %s", path, mode, strerror(errno));
+ return -1;
+ }
+ if (TEMP_FAILURE_RETRY(chown(path, uid, gid)) == -1) {
+ ALOGE("Failed to chown(%s, %d, %d): %s", path, uid, gid, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int fs_read_atomic_int(const char* path, int* out_value) {
+ int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY));
+ if (fd == -1) {
+ ALOGE("Failed to read %s: %s", path, strerror(errno));
+ return -1;
+ }
+
+ char buf[BUF_SIZE];
+ if (TEMP_FAILURE_RETRY(read(fd, buf, BUF_SIZE)) == -1) {
+ ALOGE("Failed to read %s: %s", path, strerror(errno));
+ goto fail;
+ }
+ if (sscanf(buf, "%d", out_value) != 1) {
+ ALOGE("Failed to parse %s: %s", path, strerror(errno));
+ goto fail;
+ }
+ close(fd);
+ return 0;
+
+fail:
+ close(fd);
+ *out_value = -1;
+ return -1;
+}
+
+int fs_write_atomic_int(const char* path, int value) {
+ char temp[PATH_MAX];
+ if (snprintf(temp, PATH_MAX, "%s.XXXXXX", path) >= PATH_MAX) {
+ ALOGE("Path too long");
+ return -1;
+ }
+
+ int fd = TEMP_FAILURE_RETRY(mkstemp(temp));
+ if (fd == -1) {
+ ALOGE("Failed to open %s: %s", temp, strerror(errno));
+ return -1;
+ }
+
+ char buf[BUF_SIZE];
+ int len = snprintf(buf, BUF_SIZE, "%d", value) + 1;
+ if (len > BUF_SIZE) {
+ ALOGE("Value %d too large: %s", value, strerror(errno));
+ goto fail;
+ }
+ if (TEMP_FAILURE_RETRY(write(fd, buf, len)) < len) {
+ ALOGE("Failed to write %s: %s", temp, strerror(errno));
+ goto fail;
+ }
+ if (close(fd) == -1) {
+ ALOGE("Failed to close %s: %s", temp, strerror(errno));
+ goto fail_closed;
+ }
+
+ if (rename(temp, path) == -1) {
+ ALOGE("Failed to rename %s to %s: %s", temp, path, strerror(errno));
+ goto fail_closed;
+ }
+
+ return 0;
+
+fail:
+ close(fd);
+fail_closed:
+ unlink(temp);
+ return -1;
+}
diff --git a/libcutils/multiuser.c b/libcutils/multiuser.c
new file mode 100644
index 0000000..7c74bb8
--- /dev/null
+++ b/libcutils/multiuser.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/multiuser.h>
+
+userid_t multiuser_get_user_id(uid_t uid) {
+ return uid / MULTIUSER_APP_PER_USER_RANGE;
+}
+
+appid_t multiuser_get_app_id(uid_t uid) {
+ return uid % MULTIUSER_APP_PER_USER_RANGE;
+}
+
+uid_t multiuser_get_uid(userid_t userId, appid_t appId) {
+ return userId * MULTIUSER_APP_PER_USER_RANGE + (appId % MULTIUSER_APP_PER_USER_RANGE);
+}
diff --git a/libcutils/private.h b/libcutils/private.h
new file mode 100644
index 0000000..2837b70
--- /dev/null
+++ b/libcutils/private.h
@@ -0,0 +1,368 @@
+#ifndef PRIVATE_H
+
+#define PRIVATE_H
+
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson.
+*/
+
+/*
+** This header is for use ONLY with the time conversion code.
+** There is no guarantee that it will remain unchanged,
+** or that it will remain at all.
+** Do NOT copy it to any system include directory.
+** Thank you!
+*/
+
+/*
+** ID
+*/
+
+#ifndef lint
+#ifndef NOID
+static char privatehid[] = "@(#)private.h 8.2";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+#define GRANDPARENTED "Local time zone must be set--see zic manual page"
+
+/*
+** Defaults for preprocessor symbols.
+** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
+*/
+
+#ifndef HAVE_ADJTIME
+#define HAVE_ADJTIME 1
+#endif /* !defined HAVE_ADJTIME */
+
+#ifndef HAVE_GETTEXT
+#define HAVE_GETTEXT 0
+#endif /* !defined HAVE_GETTEXT */
+
+#ifndef HAVE_INCOMPATIBLE_CTIME_R
+#define HAVE_INCOMPATIBLE_CTIME_R 0
+#endif /* !defined INCOMPATIBLE_CTIME_R */
+
+#ifndef HAVE_SETTIMEOFDAY
+#define HAVE_SETTIMEOFDAY 3
+#endif /* !defined HAVE_SETTIMEOFDAY */
+
+#ifndef HAVE_STRERROR
+#define HAVE_STRERROR 1
+#endif /* !defined HAVE_STRERROR */
+
+#ifndef HAVE_SYMLINK
+#define HAVE_SYMLINK 1
+#endif /* !defined HAVE_SYMLINK */
+
+#ifndef HAVE_SYS_STAT_H
+#define HAVE_SYS_STAT_H 1
+#endif /* !defined HAVE_SYS_STAT_H */
+
+#ifndef HAVE_SYS_WAIT_H
+#define HAVE_SYS_WAIT_H 1
+#endif /* !defined HAVE_SYS_WAIT_H */
+
+#ifndef HAVE_UNISTD_H
+#define HAVE_UNISTD_H 1
+#endif /* !defined HAVE_UNISTD_H */
+
+#ifndef HAVE_UTMPX_H
+#define HAVE_UTMPX_H 0
+#endif /* !defined HAVE_UTMPX_H */
+
+#ifndef LOCALE_HOME
+#define LOCALE_HOME "/usr/lib/locale"
+#endif /* !defined LOCALE_HOME */
+
+#if HAVE_INCOMPATIBLE_CTIME_R
+#define asctime_r _incompatible_asctime_r
+#define ctime_r _incompatible_ctime_r
+#endif /* HAVE_INCOMPATIBLE_CTIME_R */
+
+/*
+** Nested includes
+*/
+
+#include "sys/types.h" /* for time_t */
+#include "stdio.h"
+#include "errno.h"
+#include "string.h"
+#include "limits.h" /* for CHAR_BIT et al. */
+#include "time.h"
+#include "stdlib.h"
+
+#if HAVE_GETTEXT
+#include "libintl.h"
+#endif /* HAVE_GETTEXT */
+
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */
+#endif /* HAVE_SYS_WAIT_H */
+
+#ifndef WIFEXITED
+#define WIFEXITED(status) (((status) & 0xff) == 0)
+#endif /* !defined WIFEXITED */
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(status) (((status) >> 8) & 0xff)
+#endif /* !defined WEXITSTATUS */
+
+#if HAVE_UNISTD_H
+#include "unistd.h" /* for F_OK and R_OK */
+#endif /* HAVE_UNISTD_H */
+
+#if !HAVE_UNISTD_H
+#ifndef F_OK
+#define F_OK 0
+#endif /* !defined F_OK */
+#ifndef R_OK
+#define R_OK 4
+#endif /* !defined R_OK */
+#endif /* !HAVE_UNISTD_H */
+
+/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
+#define is_digit(c) ((unsigned)(c) - '0' <= 9)
+
+/*
+** Define HAVE_STDINT_H's default value here, rather than at the
+** start, since __GLIBC__'s value depends on previously-included
+** files.
+** (glibc 2.1 and later have stdint.h, even with pre-C99 compilers.)
+*/
+#ifndef HAVE_STDINT_H
+#define HAVE_STDINT_H \
+ (199901 <= __STDC_VERSION__ || \
+ 2 < (__GLIBC__ + (0 < __GLIBC_MINOR__)))
+#endif /* !defined HAVE_STDINT_H */
+
+#if HAVE_STDINT_H
+#include "stdint.h"
+#endif /* !HAVE_STDINT_H */
+
+#ifndef INT_FAST64_MAX
+/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */
+#if defined LLONG_MAX || defined __LONG_LONG_MAX__
+typedef long long int_fast64_t;
+#else /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
+#if (LONG_MAX >> 31) < 0xffffffff
+Please use a compiler that supports a 64-bit integer type (or wider);
+you may need to compile with "-DHAVE_STDINT_H".
+#endif /* (LONG_MAX >> 31) < 0xffffffff */
+typedef long int_fast64_t;
+#endif /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
+#endif /* !defined INT_FAST64_MAX */
+
+#ifndef INT32_MAX
+#define INT32_MAX 0x7fffffff
+#endif /* !defined INT32_MAX */
+#ifndef INT32_MIN
+#define INT32_MIN (-1 - INT32_MAX)
+#endif /* !defined INT32_MIN */
+
+/*
+** Workarounds for compilers/systems.
+*/
+
+/*
+** If your compiler lacks prototypes, "#define P(x) ()".
+*/
+
+#ifndef P
+#define P(x) x
+#endif /* !defined P */
+
+/*
+** SunOS 4.1.1 headers lack EXIT_SUCCESS.
+*/
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif /* !defined EXIT_SUCCESS */
+
+/*
+** SunOS 4.1.1 headers lack EXIT_FAILURE.
+*/
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif /* !defined EXIT_FAILURE */
+
+/*
+** SunOS 4.1.1 headers lack FILENAME_MAX.
+*/
+
+#ifndef FILENAME_MAX
+
+#ifndef MAXPATHLEN
+#ifdef unix
+#include "sys/param.h"
+#endif /* defined unix */
+#endif /* !defined MAXPATHLEN */
+
+#ifdef MAXPATHLEN
+#define FILENAME_MAX MAXPATHLEN
+#endif /* defined MAXPATHLEN */
+#ifndef MAXPATHLEN
+#define FILENAME_MAX 1024 /* Pure guesswork */
+#endif /* !defined MAXPATHLEN */
+
+#endif /* !defined FILENAME_MAX */
+
+/*
+** SunOS 4.1.1 libraries lack remove.
+*/
+
+#ifndef remove
+extern int unlink P((const char * filename));
+#define remove unlink
+#endif /* !defined remove */
+
+/*
+** Some ancient errno.h implementations don't declare errno.
+** But some newer errno.h implementations define it as a macro.
+** Fix the former without affecting the latter.
+*/
+
+#ifndef errno
+extern int errno;
+#endif /* !defined errno */
+
+/*
+** Some time.h implementations don't declare asctime_r.
+** Others might define it as a macro.
+** Fix the former without affecting the latter.
+*/
+
+#ifndef asctime_r
+extern char * asctime_r();
+#endif
+
+/*
+** Private function declarations.
+*/
+
+char * icalloc P((int nelem, int elsize));
+char * icatalloc P((char * old, const char * new));
+char * icpyalloc P((const char * string));
+char * imalloc P((int n));
+void * irealloc P((void * pointer, int size));
+void icfree P((char * pointer));
+void ifree P((char * pointer));
+const char * scheck P((const char * string, const char * format));
+
+/*
+** Finally, some convenience items.
+*/
+
+#ifndef TRUE
+#define TRUE 1
+#endif /* !defined TRUE */
+
+#ifndef FALSE
+#define FALSE 0
+#endif /* !defined FALSE */
+
+#ifndef TYPE_BIT
+#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
+#endif /* !defined TYPE_BIT */
+
+#ifndef TYPE_SIGNED
+#define TYPE_SIGNED(type) (((type) -1) < 0)
+#endif /* !defined TYPE_SIGNED */
+
+/*
+** Since the definition of TYPE_INTEGRAL contains floating point numbers,
+** it cannot be used in preprocessor directives.
+*/
+
+#ifndef TYPE_INTEGRAL
+#define TYPE_INTEGRAL(type) (((type) 0.5) != 0.5)
+#endif /* !defined TYPE_INTEGRAL */
+
+#ifndef INT_STRLEN_MAXIMUM
+/*
+** 302 / 1000 is log10(2.0) rounded up.
+** Subtract one for the sign bit if the type is signed;
+** add one for integer division truncation;
+** add one more for a minus sign if the type is signed.
+*/
+#define INT_STRLEN_MAXIMUM(type) \
+ ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
+ 1 + TYPE_SIGNED(type))
+#endif /* !defined INT_STRLEN_MAXIMUM */
+
+/*
+** INITIALIZE(x)
+*/
+
+#ifndef GNUC_or_lint
+#ifdef lint
+#define GNUC_or_lint
+#endif /* defined lint */
+#ifndef lint
+#ifdef __GNUC__
+#define GNUC_or_lint
+#endif /* defined __GNUC__ */
+#endif /* !defined lint */
+#endif /* !defined GNUC_or_lint */
+
+#ifndef INITIALIZE
+#ifdef GNUC_or_lint
+#define INITIALIZE(x) ((x) = 0)
+#endif /* defined GNUC_or_lint */
+#ifndef GNUC_or_lint
+#define INITIALIZE(x)
+#endif /* !defined GNUC_or_lint */
+#endif /* !defined INITIALIZE */
+
+/*
+** For the benefit of GNU folk...
+** `_(MSGID)' uses the current locale's message library string for MSGID.
+** The default is to use gettext if available, and use MSGID otherwise.
+*/
+
+#ifndef _
+#if HAVE_GETTEXT
+#define _(msgid) gettext(msgid)
+#else /* !HAVE_GETTEXT */
+#define _(msgid) msgid
+#endif /* !HAVE_GETTEXT */
+#endif /* !defined _ */
+
+#ifndef TZ_DOMAIN
+#define TZ_DOMAIN "tz"
+#endif /* !defined TZ_DOMAIN */
+
+#if HAVE_INCOMPATIBLE_CTIME_R
+#undef asctime_r
+#undef ctime_r
+char *asctime_r P((struct tm const *, char *));
+char *ctime_r P((time_t const *, char *));
+#endif /* HAVE_INCOMPATIBLE_CTIME_R */
+
+#ifndef YEARSPERREPEAT
+#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
+#endif /* !defined YEARSPERREPEAT */
+
+/*
+** The Gregorian year averages 365.2425 days, which is 31556952 seconds.
+*/
+
+#ifndef AVGSECSPERYEAR
+#define AVGSECSPERYEAR 31556952L
+#endif /* !defined AVGSECSPERYEAR */
+
+#ifndef SECSPERREPEAT
+#define SECSPERREPEAT ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR)
+#endif /* !defined SECSPERREPEAT */
+
+#ifndef SECSPERREPEAT_BITS
+#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
+#endif /* !defined SECSPERREPEAT_BITS */
+
+/*
+** UNIX was a registered trademark of The Open Group in 2003.
+*/
+
+#endif /* !defined PRIVATE_H */
diff --git a/libcutils/tzfile.h b/libcutils/tzfile.h
new file mode 100644
index 0000000..8c70375
--- /dev/null
+++ b/libcutils/tzfile.h
@@ -0,0 +1,180 @@
+#ifndef TZFILE_H
+
+#define TZFILE_H
+
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson.
+*/
+
+/*
+** This header is for use ONLY with the time conversion code.
+** There is no guarantee that it will remain unchanged,
+** or that it will remain at all.
+** Do NOT copy it to any system include directory.
+** Thank you!
+*/
+
+/*
+** ID
+*/
+
+#ifndef lint
+#ifndef NOID
+static char tzfilehid[] = "@(#)tzfile.h 8.1";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*
+** Information about time zone files.
+*/
+
+#ifndef TZDIR
+#define TZDIR "/usr/share/zoneinfo" /* "/android/usr/share/zoneinfo" */ /* Time zone object file directory */
+#endif /* !defined TZDIR */
+
+#ifndef TZDEFAULT
+#define TZDEFAULT "localtime"
+#endif /* !defined TZDEFAULT */
+
+#ifndef TZDEFRULES
+#define TZDEFRULES "posixrules"
+#endif /* !defined TZDEFRULES */
+
+/*
+** Each file begins with. . .
+*/
+
+#define TZ_MAGIC "TZif"
+
+struct tzhead {
+ char tzh_magic[4]; /* TZ_MAGIC */
+ char tzh_version[1]; /* '\0' or '2' as of 2005 */
+ char tzh_reserved[15]; /* reserved--must be zero */
+ char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
+ char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
+ char tzh_leapcnt[4]; /* coded number of leap seconds */
+ char tzh_timecnt[4]; /* coded number of transition times */
+ char tzh_typecnt[4]; /* coded number of local time types */
+ char tzh_charcnt[4]; /* coded number of abbr. chars */
+};
+
+/*
+** . . .followed by. . .
+**
+** tzh_timecnt (char [4])s coded transition times a la time(2)
+** tzh_timecnt (unsigned char)s types of local time starting at above
+** tzh_typecnt repetitions of
+** one (char [4]) coded UTC offset in seconds
+** one (unsigned char) used to set tm_isdst
+** one (unsigned char) that's an abbreviation list index
+** tzh_charcnt (char)s '\0'-terminated zone abbreviations
+** tzh_leapcnt repetitions of
+** one (char [4]) coded leap second transition times
+** one (char [4]) total correction after above
+** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
+** time is standard time, if FALSE,
+** transition time is wall clock time
+** if absent, transition times are
+** assumed to be wall clock time
+** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition
+** time is UTC, if FALSE,
+** transition time is local time
+** if absent, transition times are
+** assumed to be local time
+*/
+
+/*
+** If tzh_version is '2' or greater, the above is followed by a second instance
+** of tzhead and a second instance of the data in which each coded transition
+** time uses 8 rather than 4 chars,
+** then a POSIX-TZ-environment-variable-style string for use in handling
+** instants after the last transition time stored in the file
+** (with nothing between the newlines if there is no POSIX representation for
+** such instants).
+*/
+
+/*
+** In the current implementation, "tzset()" refuses to deal with files that
+** exceed any of the limits below.
+*/
+
+#ifndef TZ_MAX_TIMES
+#define TZ_MAX_TIMES 1200
+#endif /* !defined TZ_MAX_TIMES */
+
+#ifndef TZ_MAX_TYPES
+#ifndef NOSOLAR
+#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
+#endif /* !defined NOSOLAR */
+#ifdef NOSOLAR
+/*
+** Must be at least 14 for Europe/Riga as of Jan 12 1995,
+** as noted by Earl Chew.
+*/
+#define TZ_MAX_TYPES 20 /* Maximum number of local time types */
+#endif /* !defined NOSOLAR */
+#endif /* !defined TZ_MAX_TYPES */
+
+#ifndef TZ_MAX_CHARS
+#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
+ /* (limited by what unsigned chars can hold) */
+#endif /* !defined TZ_MAX_CHARS */
+
+#ifndef TZ_MAX_LEAPS
+#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
+#endif /* !defined TZ_MAX_LEAPS */
+
+#define SECSPERMIN 60
+#define MINSPERHOUR 60
+#define HOURSPERDAY 24
+#define DAYSPERWEEK 7
+#define DAYSPERNYEAR 365
+#define DAYSPERLYEAR 366
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR 12
+
+#define TM_SUNDAY 0
+#define TM_MONDAY 1
+#define TM_TUESDAY 2
+#define TM_WEDNESDAY 3
+#define TM_THURSDAY 4
+#define TM_FRIDAY 5
+#define TM_SATURDAY 6
+
+#define TM_JANUARY 0
+#define TM_FEBRUARY 1
+#define TM_MARCH 2
+#define TM_APRIL 3
+#define TM_MAY 4
+#define TM_JUNE 5
+#define TM_JULY 6
+#define TM_AUGUST 7
+#define TM_SEPTEMBER 8
+#define TM_OCTOBER 9
+#define TM_NOVEMBER 10
+#define TM_DECEMBER 11
+
+#define TM_YEAR_BASE 1900
+
+#define EPOCH_YEAR 1970
+#define EPOCH_WDAY TM_THURSDAY
+
+#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+
+/*
+** Since everything in isleap is modulo 400 (or a factor of 400), we know that
+** isleap(y) == isleap(y % 400)
+** and so
+** isleap(a + b) == isleap((a + b) % 400)
+** or
+** isleap(a + b) == isleap(a % 400 + b % 400)
+** This is true even if % means modulo rather than Fortran remainder
+** (which is allowed by C89 but not C99).
+** We use this to avoid addition overflow problems.
+*/
+
+#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
+
+#endif /* !defined TZFILE_H */
diff --git a/libcutils/tzstrftime.c b/libcutils/tzstrftime.c
new file mode 100644
index 0000000..e4f54df
--- /dev/null
+++ b/libcutils/tzstrftime.c
@@ -0,0 +1,842 @@
+#ifndef lint
+#ifndef NOID
+static char elsieid[] = "@(#)strftime.c 8.1";
+/*
+** Based on the UCB version with the ID appearing below.
+** This is ANSIish only when "multibyte character == plain character".
+*/
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+#include <stdio.h>
+#include <time.h>
+#include <tzfile.h>
+#include <limits.h>
+#include <cutils/tztime.h>
+
+/*
+** Copyright (c) 1989 The Regents of the University of California.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms are permitted
+** provided that the above copyright notice and this paragraph are
+** duplicated in all such forms and that any documentation,
+** advertising materials, and other materials related to such
+** distribution and use acknowledge that the software was developed
+** by the University of California, Berkeley. The name of the
+** University may not be used to endorse or promote products derived
+** from this software without specific prior written permission.
+** THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifndef LIBC_SCCS
+#ifndef lint
+static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89";
+#endif /* !defined lint */
+#endif /* !defined LIBC_SCCS */
+
+#include <ctype.h>
+
+#define P(x) x
+
+static char * _add P((const char *, char *, const char *, int));
+static char * _conv P((int, const char *, char *, const char *));
+static char * _fmt P((const char *, const struct tm *, char *, const char *,
+ int *, const struct strftime_locale *Locale));
+static char * _yconv P((int, int, int, int, char *, const char *, int));
+static char * getformat P((int, char *, char *, char *, char *));
+
+extern char * tzname[];
+
+
+
+
+
+/* from private.h */
+
+#ifndef TYPE_BIT
+#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
+#endif /* !defined TYPE_BIT */
+
+#ifndef TYPE_SIGNED
+#define TYPE_SIGNED(type) (((type) -1) < 0)
+#endif /* !defined TYPE_SIGNED */
+
+#ifndef INT_STRLEN_MAXIMUM
+/*
+ * ** 302 / 1000 is log10(2.0) rounded up.
+ * ** Subtract one for the sign bit if the type is signed;
+ * ** add one for integer division truncation;
+ * ** add one more for a minus sign if the type is signed.
+ * */
+#define INT_STRLEN_MAXIMUM(type) \
+ ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
+ 1 + TYPE_SIGNED(type))
+#endif /* !defined INT_STRLEN_MAXIMUM */
+
+/* end of part from private.h */
+
+
+
+
+#ifndef YEAR_2000_NAME
+#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
+#endif /* !defined YEAR_2000_NAME */
+
+#define IN_NONE 0
+#define IN_SOME 1
+#define IN_THIS 2
+#define IN_ALL 3
+
+#define FORCE_LOWER_CASE 0x100
+
+size_t
+strftime_tz(s, maxsize, format, t, Locale)
+char * const s;
+const size_t maxsize;
+const char * const format;
+const struct tm * const t;
+const struct strftime_locale *Locale;
+{
+ char * p;
+ int warn;
+
+ warn = IN_NONE;
+ p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, Locale);
+#if 0
+ if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
+ (void) fprintf(stderr, "\n");
+ if (format == NULL)
+ (void) fprintf(stderr, "NULL strftime format ");
+ else (void) fprintf(stderr, "strftime format \"%s\" ",
+ format);
+ (void) fprintf(stderr, "yields only two digits of years in ");
+ if (warn == IN_SOME)
+ (void) fprintf(stderr, "some locales");
+ else if (warn == IN_THIS)
+ (void) fprintf(stderr, "the current locale");
+ else (void) fprintf(stderr, "all locales");
+ (void) fprintf(stderr, "\n");
+ }
+#endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
+ if (p == s + maxsize)
+ return 0;
+ *p = '\0';
+ return p - s;
+}
+
+static char *getformat(int modifier, char *normal, char *underscore,
+ char *dash, char *zero) {
+ switch (modifier) {
+ case '_':
+ return underscore;
+
+ case '-':
+ return dash;
+
+ case '0':
+ return zero;
+ }
+
+ return normal;
+}
+
+static char *
+_fmt(format, t, pt, ptlim, warnp, Locale)
+const char * format;
+const struct tm * const t;
+char * pt;
+const char * const ptlim;
+int * warnp;
+const struct strftime_locale *Locale;
+{
+ for ( ; *format; ++format) {
+ if (*format == '%') {
+ int modifier = 0;
+label:
+ switch (*++format) {
+ case '\0':
+ --format;
+ break;
+ case 'A':
+ pt = _add((t->tm_wday < 0 ||
+ t->tm_wday >= DAYSPERWEEK) ?
+ "?" : Locale->weekday[t->tm_wday],
+ pt, ptlim, modifier);
+ continue;
+ case 'a':
+ pt = _add((t->tm_wday < 0 ||
+ t->tm_wday >= DAYSPERWEEK) ?
+ "?" : Locale->wday[t->tm_wday],
+ pt, ptlim, modifier);
+ continue;
+ case 'B':
+ 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':
+ pt = _add((t->tm_mon < 0 ||
+ t->tm_mon >= MONSPERYEAR) ?
+ "?" : Locale->mon[t->tm_mon],
+ pt, ptlim, modifier);
+ continue;
+ case 'C':
+ /*
+ ** %C used to do a...
+ ** _fmt("%a %b %e %X %Y", t);
+ ** ...whereas now POSIX 1003.2 calls for
+ ** something completely different.
+ ** (ado, 1993-05-24)
+ */
+ pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
+ pt, ptlim, modifier);
+ continue;
+ case 'c':
+ {
+ int warn2 = IN_SOME;
+
+ pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp, Locale);
+ if (warn2 == IN_ALL)
+ warn2 = IN_THIS;
+ if (warn2 > *warnp)
+ *warnp = warn2;
+ }
+ continue;
+ case 'D':
+ pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, Locale);
+ continue;
+ case 'd':
+ pt = _conv(t->tm_mday,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'E':
+ case 'O':
+ /*
+ ** C99 locale modifiers.
+ ** The sequences
+ ** %Ec %EC %Ex %EX %Ey %EY
+ ** %Od %oe %OH %OI %Om %OM
+ ** %OS %Ou %OU %OV %Ow %OW %Oy
+ ** are supposed to provide alternate
+ ** representations.
+ */
+ goto label;
+ case '_':
+ case '-':
+ case '0':
+ case '^':
+ case '#':
+ modifier = *format;
+ goto label;
+ case 'e':
+ pt = _conv(t->tm_mday,
+ getformat(modifier, "%2d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'F':
+ pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, Locale);
+ continue;
+ case 'H':
+ pt = _conv(t->tm_hour,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'I':
+ pt = _conv((t->tm_hour % 12) ?
+ (t->tm_hour % 12) : 12,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'j':
+ pt = _conv(t->tm_yday + 1,
+ getformat(modifier, "%03d", "%3d", "%d", "%03d"),
+ pt, ptlim);
+ continue;
+ case 'k':
+ /*
+ ** This used to be...
+ ** _conv(t->tm_hour % 12 ?
+ ** t->tm_hour % 12 : 12, 2, ' ');
+ ** ...and has been changed to the below to
+ ** match SunOS 4.1.1 and Arnold Robbins'
+ ** strftime version 3.0. That is, "%k" and
+ ** "%l" have been swapped.
+ ** (ado, 1993-05-24)
+ */
+ pt = _conv(t->tm_hour,
+ getformat(modifier, "%2d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+#ifdef KITCHEN_SINK
+ case 'K':
+ /*
+ ** After all this time, still unclaimed!
+ */
+ pt = _add("kitchen sink", pt, ptlim, modifier);
+ continue;
+#endif /* defined KITCHEN_SINK */
+ case 'l':
+ /*
+ ** This used to be...
+ ** _conv(t->tm_hour, 2, ' ');
+ ** ...and has been changed to the below to
+ ** match SunOS 4.1.1 and Arnold Robbin's
+ ** strftime version 3.0. That is, "%k" and
+ ** "%l" have been swapped.
+ ** (ado, 1993-05-24)
+ */
+ pt = _conv((t->tm_hour % 12) ?
+ (t->tm_hour % 12) : 12,
+ getformat(modifier, "%2d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'M':
+ pt = _conv(t->tm_min,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'm':
+ pt = _conv(t->tm_mon + 1,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'n':
+ pt = _add("\n", pt, ptlim, modifier);
+ continue;
+ case 'p':
+ pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
+ Locale->pm :
+ Locale->am,
+ pt, ptlim, modifier);
+ continue;
+ case 'P':
+ pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
+ Locale->pm :
+ Locale->am,
+ pt, ptlim, FORCE_LOWER_CASE);
+ continue;
+ case 'R':
+ pt = _fmt("%H:%M", t, pt, ptlim, warnp, Locale);
+ continue;
+ case 'r':
+ pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp, Locale);
+ continue;
+ case 'S':
+ pt = _conv(t->tm_sec,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 's':
+ {
+ struct tm tm;
+ char buf[INT_STRLEN_MAXIMUM(
+ time_t) + 1];
+ time_t mkt;
+
+ tm = *t;
+ mkt = mktime(&tm);
+ if (TYPE_SIGNED(time_t))
+ (void) sprintf(buf, "%ld",
+ (long) mkt);
+ else (void) sprintf(buf, "%lu",
+ (unsigned long) mkt);
+ pt = _add(buf, pt, ptlim, modifier);
+ }
+ continue;
+ case 'T':
+ pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, Locale);
+ continue;
+ case 't':
+ pt = _add("\t", pt, ptlim, modifier);
+ continue;
+ case 'U':
+ pt = _conv((t->tm_yday + DAYSPERWEEK -
+ t->tm_wday) / DAYSPERWEEK,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'u':
+ /*
+ ** From Arnold Robbins' strftime version 3.0:
+ ** "ISO 8601: Weekday as a decimal number
+ ** [1 (Monday) - 7]"
+ ** (ado, 1993-05-24)
+ */
+ pt = _conv((t->tm_wday == 0) ?
+ DAYSPERWEEK : t->tm_wday, "%d", pt, ptlim);
+ continue;
+ case 'V': /* ISO 8601 week number */
+ case 'G': /* ISO 8601 year (four digits) */
+ case 'g': /* ISO 8601 year (two digits) */
+/*
+** From Arnold Robbins' strftime version 3.0: "the week number of the
+** year (the first Monday as the first day of week 1) as a decimal number
+** (01-53)."
+** (ado, 1993-05-24)
+**
+** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
+** "Week 01 of a year is per definition the first week which has the
+** Thursday in this year, which is equivalent to the week which contains
+** the fourth day of January. In other words, the first week of a new year
+** is the week which has the majority of its days in the new year. Week 01
+** might also contain days from the previous year and the week before week
+** 01 of a year is the last week (52 or 53) of the previous year even if
+** it contains days from the new year. A week starts with Monday (day 1)
+** and ends with Sunday (day 7). For example, the first week of the year
+** 1997 lasts from 1996-12-30 to 1997-01-05..."
+** (ado, 1996-01-02)
+*/
+ {
+ int year;
+ int base;
+ int yday;
+ int wday;
+ int w;
+
+ year = t->tm_year;
+ base = TM_YEAR_BASE;
+ yday = t->tm_yday;
+ wday = t->tm_wday;
+ for ( ; ; ) {
+ int len;
+ int bot;
+ int top;
+
+ len = isleap_sum(year, base) ?
+ DAYSPERLYEAR :
+ DAYSPERNYEAR;
+ /*
+ ** What yday (-3 ... 3) does
+ ** the ISO year begin on?
+ */
+ bot = ((yday + 11 - wday) %
+ DAYSPERWEEK) - 3;
+ /*
+ ** What yday does the NEXT
+ ** ISO year begin on?
+ */
+ top = bot -
+ (len % DAYSPERWEEK);
+ if (top < -3)
+ top += DAYSPERWEEK;
+ top += len;
+ if (yday >= top) {
+ ++base;
+ w = 1;
+ break;
+ }
+ if (yday >= bot) {
+ w = 1 + ((yday - bot) /
+ DAYSPERWEEK);
+ break;
+ }
+ --base;
+ yday += isleap_sum(year, base) ?
+ DAYSPERLYEAR :
+ DAYSPERNYEAR;
+ }
+#ifdef XPG4_1994_04_09
+ if ((w == 52 &&
+ t->tm_mon == TM_JANUARY) ||
+ (w == 1 &&
+ t->tm_mon == TM_DECEMBER))
+ w = 53;
+#endif /* defined XPG4_1994_04_09 */
+ if (*format == 'V')
+ pt = _conv(w,
+ getformat(modifier,
+ "%02d",
+ "%2d",
+ "%d",
+ "%02d"),
+ pt, ptlim);
+ else if (*format == 'g') {
+ *warnp = IN_ALL;
+ pt = _yconv(year, base, 0, 1,
+ pt, ptlim, modifier);
+ } else pt = _yconv(year, base, 1, 1,
+ pt, ptlim, modifier);
+ }
+ continue;
+ case 'v':
+ /*
+ ** From Arnold Robbins' strftime version 3.0:
+ ** "date as dd-bbb-YYYY"
+ ** (ado, 1993-05-24)
+ */
+ pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, Locale);
+ continue;
+ case 'W':
+ pt = _conv((t->tm_yday + DAYSPERWEEK -
+ (t->tm_wday ?
+ (t->tm_wday - 1) :
+ (DAYSPERWEEK - 1))) / DAYSPERWEEK,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'w':
+ pt = _conv(t->tm_wday, "%d", pt, ptlim);
+ continue;
+ case 'X':
+ pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp, Locale);
+ continue;
+ case 'x':
+ {
+ int warn2 = IN_SOME;
+
+ pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2, Locale);
+ if (warn2 == IN_ALL)
+ warn2 = IN_THIS;
+ if (warn2 > *warnp)
+ *warnp = warn2;
+ }
+ continue;
+ case 'y':
+ *warnp = IN_ALL;
+ pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
+ pt, ptlim, modifier);
+ continue;
+ case 'Y':
+ pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
+ pt, ptlim, modifier);
+ continue;
+ case 'Z':
+#ifdef TM_ZONE
+ if (t->TM_ZONE != NULL)
+ pt = _add(t->TM_ZONE, pt, ptlim,
+ modifier);
+ else
+#endif /* defined TM_ZONE */
+ if (t->tm_isdst >= 0)
+ pt = _add(tzname[t->tm_isdst != 0],
+ pt, ptlim, modifier);
+ /*
+ ** C99 says that %Z must be replaced by the
+ ** empty string if the time zone is not
+ ** determinable.
+ */
+ continue;
+ case 'z':
+ {
+ int diff;
+ char const * sign;
+
+ if (t->tm_isdst < 0)
+ continue;
+#ifdef TM_GMTOFF
+ diff = t->TM_GMTOFF;
+#else /* !defined TM_GMTOFF */
+ /*
+ ** C99 says that the UTC offset must
+ ** be computed by looking only at
+ ** tm_isdst. This requirement is
+ ** incorrect, since it means the code
+ ** must rely on magic (in this case
+ ** altzone and timezone), and the
+ ** magic might not have the correct
+ ** offset. Doing things correctly is
+ ** tricky and requires disobeying C99;
+ ** see GNU C strftime for details.
+ ** For now, punt and conform to the
+ ** standard, even though it's incorrect.
+ **
+ ** C99 says that %z must be replaced by the
+ ** empty string if the time zone is not
+ ** determinable, so output nothing if the
+ ** appropriate variables are not available.
+ */
+ if (t->tm_isdst == 0)
+#ifdef USG_COMPAT
+ diff = -timezone;
+#else /* !defined USG_COMPAT */
+ continue;
+#endif /* !defined USG_COMPAT */
+ else
+#ifdef ALTZONE
+ diff = -altzone;
+#else /* !defined ALTZONE */
+ continue;
+#endif /* !defined ALTZONE */
+#endif /* !defined TM_GMTOFF */
+ if (diff < 0) {
+ sign = "-";
+ diff = -diff;
+ } else sign = "+";
+ pt = _add(sign, pt, ptlim, modifier);
+ diff /= SECSPERMIN;
+ diff = (diff / MINSPERHOUR) * 100 +
+ (diff % MINSPERHOUR);
+ pt = _conv(diff,
+ getformat(modifier, "%04d",
+ "%4d", "%d", "%04d"),
+ pt, ptlim);
+ }
+ continue;
+ case '+':
+ pt = _fmt(Locale->date_fmt, t, pt, ptlim,
+ warnp, Locale);
+ continue;
+ case '%':
+ /*
+ ** X311J/88-090 (4.12.3.5): if conversion char is
+ ** undefined, behavior is undefined. Print out the
+ ** character itself as printf(3) also does.
+ */
+ default:
+ break;
+ }
+ }
+ if (pt == ptlim)
+ break;
+ *pt++ = *format;
+ }
+ return pt;
+}
+
+static char *
+_conv(n, format, pt, ptlim)
+const int n;
+const char * const format;
+char * const pt;
+const char * const ptlim;
+{
+ char buf[INT_STRLEN_MAXIMUM(int) + 1];
+
+ (void) sprintf(buf, format, n);
+ return _add(buf, pt, ptlim, 0);
+}
+
+static char *
+_add(str, pt, ptlim, modifier)
+const char * str;
+char * pt;
+const char * const ptlim;
+int modifier;
+{
+ int c;
+
+ switch (modifier) {
+ case FORCE_LOWER_CASE:
+ while (pt < ptlim && (*pt = tolower(*str++)) != '\0') {
+ ++pt;
+ }
+ break;
+
+ case '^':
+ while (pt < ptlim && (*pt = toupper(*str++)) != '\0') {
+ ++pt;
+ }
+ break;
+
+ case '#':
+ while (pt < ptlim && (c = *str++) != '\0') {
+ if (isupper(c)) {
+ c = tolower(c);
+ } else if (islower(c)) {
+ c = toupper(c);
+ }
+ *pt = c;
+ ++pt;
+ }
+
+ break;
+
+ default:
+ while (pt < ptlim && (*pt = *str++) != '\0') {
+ ++pt;
+ }
+ }
+
+ return pt;
+}
+
+/*
+** POSIX and the C Standard are unclear or inconsistent about
+** what %C and %y do if the year is negative or exceeds 9999.
+** Use the convention that %C concatenated with %y yields the
+** same output as %Y, and that %Y contains at least 4 bytes,
+** with more only if necessary.
+*/
+
+static char *
+_yconv(a, b, convert_top, convert_yy, pt, ptlim, modifier)
+const int a;
+const int b;
+const int convert_top;
+const int convert_yy;
+char * pt;
+const char * const ptlim;
+int modifier;
+{
+ register int lead;
+ register int trail;
+
+#define DIVISOR 100
+ trail = a % DIVISOR + b % DIVISOR;
+ lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
+ trail %= DIVISOR;
+ if (trail < 0 && lead > 0) {
+ trail += DIVISOR;
+ --lead;
+ } else if (lead < 0 && trail > 0) {
+ trail -= DIVISOR;
+ ++lead;
+ }
+ if (convert_top) {
+ if (lead == 0 && trail < 0)
+ pt = _add("-0", pt, ptlim, modifier);
+ else pt = _conv(lead, getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ }
+ if (convert_yy)
+ pt = _conv(((trail < 0) ? -trail : trail),
+ getformat(modifier, "%02d", "%2d", "%d", "%02d"),
+ pt, ptlim);
+ return pt;
+}
+
+#ifdef LOCALE_HOME
+static struct lc_time_T *
+_loc P((void))
+{
+ static const char locale_home[] = LOCALE_HOME;
+ static const char lc_time[] = "LC_TIME";
+ static char * locale_buf;
+
+ int fd;
+ int oldsun; /* "...ain't got nothin' to do..." */
+ char * lbuf;
+ char * name;
+ char * p;
+ const char ** ap;
+ const char * plim;
+ char filename[FILENAME_MAX];
+ struct stat st;
+ size_t namesize;
+ size_t bufsize;
+
+ /*
+ ** Use localebuf.mon[0] to signal whether locale is already set up.
+ */
+ if (localebuf.mon[0])
+ return &localebuf;
+ name = setlocale(LC_TIME, (char *) NULL);
+ if (name == NULL || *name == '\0')
+ goto no_locale;
+ /*
+ ** If the locale name is the same as our cache, use the cache.
+ */
+ lbuf = locale_buf;
+ if (lbuf != NULL && strcmp(name, lbuf) == 0) {
+ p = lbuf;
+ for (ap = (const char **) &localebuf;
+ ap < (const char **) (&localebuf + 1);
+ ++ap)
+ *ap = p += strlen(p) + 1;
+ return &localebuf;
+ }
+ /*
+ ** Slurp the locale file into the cache.
+ */
+ namesize = strlen(name) + 1;
+ if (sizeof filename <
+ ((sizeof locale_home) + namesize + (sizeof lc_time)))
+ goto no_locale;
+ oldsun = 0;
+ (void) sprintf(filename, "%s/%s/%s", locale_home, name, lc_time);
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ /*
+ ** Old Sun systems have a different naming and data convention.
+ */
+ oldsun = 1;
+ (void) sprintf(filename, "%s/%s/%s", locale_home,
+ lc_time, name);
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ goto no_locale;
+ }
+ if (fstat(fd, &st) != 0)
+ goto bad_locale;
+ if (st.st_size <= 0)
+ goto bad_locale;
+ bufsize = namesize + st.st_size;
+ locale_buf = NULL;
+ lbuf = (lbuf == NULL) ? malloc(bufsize) : realloc(lbuf, bufsize);
+ if (lbuf == NULL)
+ goto bad_locale;
+ (void) strcpy(lbuf, name);
+ p = lbuf + namesize;
+ plim = p + st.st_size;
+ if (read(fd, p, (size_t) st.st_size) != st.st_size)
+ goto bad_lbuf;
+ if (close(fd) != 0)
+ goto bad_lbuf;
+ /*
+ ** Parse the locale file into localebuf.
+ */
+ if (plim[-1] != '\n')
+ goto bad_lbuf;
+ for (ap = (const char **) &localebuf;
+ ap < (const char **) (&localebuf + 1);
+ ++ap) {
+ if (p == plim)
+ goto bad_lbuf;
+ *ap = p;
+ while (*p != '\n')
+ ++p;
+ *p++ = '\0';
+ }
+ if (oldsun) {
+ /*
+ ** SunOS 4 used an obsolescent format; see localdtconv(3).
+ ** c_fmt had the ``short format for dates and times together''
+ ** (SunOS 4 date, "%a %b %e %T %Z %Y" in the C locale);
+ ** date_fmt had the ``long format for dates''
+ ** (SunOS 4 strftime %C, "%A, %B %e, %Y" in the C locale).
+ ** Discard the latter in favor of the former.
+ */
+ localebuf.date_fmt = localebuf.c_fmt;
+ }
+ /*
+ ** Record the successful parse in the cache.
+ */
+ locale_buf = lbuf;
+
+ return &localebuf;
+
+bad_lbuf:
+ free(lbuf);
+bad_locale:
+ (void) close(fd);
+no_locale:
+ localebuf = C_time_locale;
+ locale_buf = NULL;
+ return &localebuf;
+}
+#endif /* defined LOCALE_HOME */
diff --git a/libcutils/tztime.c b/libcutils/tztime.c
new file mode 100644
index 0000000..d6448a1
--- /dev/null
+++ b/libcutils/tztime.c
@@ -0,0 +1,1950 @@
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson.
+*/
+
+#include <stdio.h>
+
+#ifndef lint
+#ifndef NOID
+static char elsieid[] = "@(#)localtime.c 8.3";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*
+** Leap second handling from Bradley White.
+** POSIX-style TZ environment variable handling from Guy Harris.
+*/
+
+/*LINTLIBRARY*/
+
+#include "private.h"
+#include "tzfile.h"
+#include "fcntl.h"
+#include "float.h" /* for FLT_MAX and DBL_MAX */
+
+#ifndef TZ_ABBR_MAX_LEN
+#define TZ_ABBR_MAX_LEN 16
+#endif /* !defined TZ_ABBR_MAX_LEN */
+
+#ifndef TZ_ABBR_CHAR_SET
+#define TZ_ABBR_CHAR_SET \
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
+#endif /* !defined TZ_ABBR_CHAR_SET */
+
+#ifndef TZ_ABBR_ERR_CHAR
+#define TZ_ABBR_ERR_CHAR '_'
+#endif /* !defined TZ_ABBR_ERR_CHAR */
+
+#define INDEXFILE "/system/usr/share/zoneinfo/zoneinfo.idx"
+#define DATAFILE "/system/usr/share/zoneinfo/zoneinfo.dat"
+#define NAMELEN 40
+#define INTLEN 4
+#define READLEN (NAMELEN + 3 * INTLEN)
+
+/*
+** SunOS 4.1.1 headers lack O_BINARY.
+*/
+
+#ifdef O_BINARY
+#define OPEN_MODE (O_RDONLY | O_BINARY)
+#endif /* defined O_BINARY */
+#ifndef O_BINARY
+#define OPEN_MODE O_RDONLY
+#endif /* !defined O_BINARY */
+
+/* Complex computations to determine the min/max of time_t depending
+ * on TYPE_BIT / TYPE_SIGNED / TYPE_INTEGRAL.
+ * These macros cannot be used in pre-processor directives, so we
+ * let the C compiler do the work, which makes things a bit funky.
+ */
+static const time_t TIME_T_MAX =
+ TYPE_INTEGRAL(time_t) ?
+ ( TYPE_SIGNED(time_t) ?
+ ~((time_t)1 << (TYPE_BIT(time_t)-1))
+ :
+ ~(time_t)0
+ )
+ : /* if time_t is a floating point number */
+ ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MAX : (time_t)FLT_MAX );
+
+static const time_t TIME_T_MIN =
+ TYPE_INTEGRAL(time_t) ?
+ ( TYPE_SIGNED(time_t) ?
+ ((time_t)1 << (TYPE_BIT(time_t)-1))
+ :
+ 0
+ )
+ :
+ ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MIN : (time_t)FLT_MIN );
+
+#ifndef WILDABBR
+/*
+** Someone might make incorrect use of a time zone abbreviation:
+** 1. They might reference tzname[0] before calling tzset (explicitly
+** or implicitly).
+** 2. They might reference tzname[1] before calling tzset (explicitly
+** or implicitly).
+** 3. They might reference tzname[1] after setting to a time zone
+** in which Daylight Saving Time is never observed.
+** 4. They might reference tzname[0] after setting to a time zone
+** in which Standard Time is never observed.
+** 5. They might reference tm.TM_ZONE after calling offtime.
+** What's best to do in the above cases is open to debate;
+** for now, we just set things up so that in any of the five cases
+** WILDABBR is used. Another possibility: initialize tzname[0] to the
+** string "tzname[0] used before set", and similarly for the other cases.
+** And another: initialize tzname[0] to "ERA", with an explanation in the
+** manual page of what this "time zone abbreviation" means (doing this so
+** that tzname[0] has the "normal" length of three characters).
+*/
+#define WILDABBR " "
+#endif /* !defined WILDABBR */
+
+static char wildabbr[] = WILDABBR;
+
+static const char gmt[] = "GMT";
+
+/*
+** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
+** We default to US rules as of 1999-08-17.
+** POSIX 1003.1 section 8.1.1 says that the default DST rules are
+** implementation dependent; for historical reasons, US rules are a
+** common default.
+*/
+#ifndef TZDEFRULESTRING
+#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
+#endif /* !defined TZDEFDST */
+
+struct ttinfo { /* time type information */
+ long tt_gmtoff; /* UTC offset in seconds */
+ int tt_isdst; /* used to set tm_isdst */
+ int tt_abbrind; /* abbreviation list index */
+ int tt_ttisstd; /* TRUE if transition is std time */
+ int tt_ttisgmt; /* TRUE if transition is UTC */
+};
+
+struct lsinfo { /* leap second information */
+ time_t ls_trans; /* transition time */
+ long ls_corr; /* correction to apply */
+};
+
+#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
+
+#ifdef TZNAME_MAX
+#define MY_TZNAME_MAX TZNAME_MAX
+#endif /* defined TZNAME_MAX */
+#ifndef TZNAME_MAX
+#define MY_TZNAME_MAX 255
+#endif /* !defined TZNAME_MAX */
+
+struct state {
+ int leapcnt;
+ int timecnt;
+ int typecnt;
+ int charcnt;
+ int goback;
+ int goahead;
+ time_t ats[TZ_MAX_TIMES];
+ unsigned char types[TZ_MAX_TIMES];
+ struct ttinfo ttis[TZ_MAX_TYPES];
+ char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
+ (2 * (MY_TZNAME_MAX + 1)))];
+ struct lsinfo lsis[TZ_MAX_LEAPS];
+};
+
+struct rule {
+ int r_type; /* type of rule--see below */
+ int r_day; /* day number of rule */
+ int r_week; /* week number of rule */
+ int r_mon; /* month number of rule */
+ long r_time; /* transition time of rule */
+};
+
+#define JULIAN_DAY 0 /* Jn - Julian day */
+#define DAY_OF_YEAR 1 /* n - day of year */
+#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
+
+/*
+** Prototypes for static functions.
+*/
+
+static long detzcode P((const char * codep));
+static time_t detzcode64 P((const char * codep));
+static int differ_by_repeat P((time_t t1, time_t t0));
+static const char * getzname P((const char * strp));
+static const char * getqzname P((const char * strp, const int delim));
+static const char * getnum P((const char * strp, int * nump, int min,
+ int max));
+static const char * getsecs P((const char * strp, long * secsp));
+static const char * getoffset P((const char * strp, long * offsetp));
+static const char * getrule P((const char * strp, struct rule * rulep));
+static void gmtload P((struct state * sp));
+static struct tm * gmtsub P((const time_t * timep, long offset,
+ struct tm * tmp));
+static struct tm * localsub P((const time_t * timep, long offset,
+ struct tm * tmp, const struct state *sp));
+static int increment_overflow P((int * number, int delta));
+static int leaps_thru_end_of P((int y));
+static int long_increment_overflow P((long * number, int delta));
+static int long_normalize_overflow P((long * tensptr,
+ int * unitsptr, int base));
+static int normalize_overflow P((int * tensptr, int * unitsptr,
+ int base));
+static void settzname P((void));
+static time_t time1 P((struct tm * tmp,
+ struct tm * (*funcp) P((const time_t *,
+ long, struct tm *, const struct state* sp)),
+ long offset, const struct state * sp));
+static time_t time2 P((struct tm *tmp,
+ struct tm * (*funcp) P((const time_t *,
+ long, struct tm*, const struct state* sp)),
+ long offset, int * okayp, const struct state * sp));
+static time_t time2sub P((struct tm *tmp,
+ struct tm * (*funcp) P((const time_t*, long, struct tm*,const struct state *sp)),
+ long offset, int * okayp, int do_norm_secs,
+ const struct state *sp));
+static struct tm * timesub P((const time_t * timep, long offset,
+ const struct state * sp, struct tm * tmp));
+static int tmcomp P((const struct tm * atmp,
+ const struct tm * btmp));
+static time_t transtime P((time_t janfirst, int year,
+ const struct rule * rulep, long offset));
+static int tzload P((const char * name, struct state * sp,
+ int doextend));
+static int tzload_uncached P((const char * name, struct state * sp,
+ int doextend));
+static int tzparse P((const char * name, struct state * sp,
+ int lastditch));
+
+#ifdef ALL_STATE
+static struct state * gmtptr;
+#endif /* defined ALL_STATE */
+
+#ifndef ALL_STATE
+static struct state gmtmem;
+#define gmtptr (&gmtmem)
+#endif /* State Farm */
+
+#define CACHE_COUNT 4
+static char * g_cacheNames[CACHE_COUNT] = {0,0};
+static struct state g_cacheStates[CACHE_COUNT];
+static int g_lastCache = 0;
+static struct state g_utc;
+unsigned char g_utcSet = 0;
+
+
+#ifndef TZ_STRLEN_MAX
+#define TZ_STRLEN_MAX 255
+#endif /* !defined TZ_STRLEN_MAX */
+
+static char lcl_TZname[TZ_STRLEN_MAX + 1];
+static int lcl_is_set;
+static int gmt_is_set;
+
+char * tzname[2] = {
+ wildabbr,
+ wildabbr
+};
+
+/*
+** Section 4.12.3 of X3.159-1989 requires that
+** Except for the strftime function, these functions [asctime,
+** ctime, gmtime, localtime] return values in one of two static
+** objects: a broken-down time structure and an array of char.
+** Thanks to Paul Eggert for noting this.
+*/
+
+static struct tm tm;
+
+#ifdef USG_COMPAT
+time_t timezone = 0;
+int daylight = 0;
+#endif /* defined USG_COMPAT */
+
+#ifdef ALTZONE
+time_t altzone = 0;
+#endif /* defined ALTZONE */
+
+static long
+detzcode(codep)
+const char * const codep;
+{
+ register long result;
+ register int i;
+
+ result = (codep[0] & 0x80) ? ~0L : 0;
+ for (i = 0; i < 4; ++i)
+ result = (result << 8) | (codep[i] & 0xff);
+ return result;
+}
+
+static time_t
+detzcode64(codep)
+const char * const codep;
+{
+ register time_t result;
+ register int i;
+
+ result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0;
+ for (i = 0; i < 8; ++i)
+ result = result * 256 + (codep[i] & 0xff);
+ return result;
+}
+
+static int
+differ_by_repeat(t1, t0)
+const time_t t1;
+const time_t t0;
+{
+ if (TYPE_INTEGRAL(time_t) &&
+ TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
+ return 0;
+ return t1 - t0 == SECSPERREPEAT;
+}
+
+static int toint(unsigned char *s) {
+ return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
+}
+
+static int
+tzload(const char *name, struct state * const sp, const int doextend)
+{
+ if (name) {
+ int i, err;
+ if (0 == strcmp(name, "UTC")) {
+ if (!g_utcSet) {
+ tzload_uncached(name, &g_utc, 1);
+ g_utcSet = 1;
+ }
+ //printf("tzload: utc\n");
+ *sp = g_utc;
+ return 0;
+ }
+ for (i=0; i<CACHE_COUNT; i++) {
+ if (g_cacheNames[i] && 0 == strcmp(name, g_cacheNames[i])) {
+ *sp = g_cacheStates[i];
+ //printf("tzload: hit: %s\n", name);
+ return 0;
+ }
+ }
+ //printf("tzload: miss: %s\n", name);
+ g_lastCache++;
+ if (g_lastCache >= CACHE_COUNT) {
+ g_lastCache = 0;
+ }
+ i = g_lastCache;
+ if (g_cacheNames[i]) {
+ free(g_cacheNames[i]);
+ }
+ err = tzload_uncached(name, &(g_cacheStates[i]), 1);
+ if (err == 0) {
+ g_cacheNames[i] = strdup(name);
+ *sp = g_cacheStates[i];
+ return 0;
+ } else {
+ g_cacheNames[i] = NULL;
+ return err;
+ }
+ }
+ return tzload_uncached(name, sp, doextend);
+}
+
+static int
+tzload_uncached(name, sp, doextend)
+register const char * name;
+register struct state * const sp;
+register const int doextend;
+{
+ register const char * p;
+ register int i;
+ register int fid;
+ register int stored;
+ register int nread;
+ union {
+ struct tzhead tzhead;
+ char buf[2 * sizeof(struct tzhead) +
+ 2 * sizeof *sp +
+ 4 * TZ_MAX_TIMES];
+ } u;
+ int toread = sizeof u.buf;
+
+ if (name == NULL && (name = TZDEFAULT) == NULL)
+ return -1;
+ {
+ register int doaccess;
+ /*
+ ** Section 4.9.1 of the C standard says that
+ ** "FILENAME_MAX expands to an integral constant expression
+ ** that is the size needed for an array of char large enough
+ ** to hold the longest file name string that the implementation
+ ** guarantees can be opened."
+ */
+ char fullname[FILENAME_MAX + 1];
+ const char *origname = name;
+
+ if (name[0] == ':')
+ ++name;
+ doaccess = name[0] == '/';
+ if (!doaccess) {
+ if ((p = TZDIR) == NULL)
+ return -1;
+ if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
+ return -1;
+ (void) strcpy(fullname, p);
+ (void) strcat(fullname, "/");
+ (void) strcat(fullname, name);
+ /*
+ ** Set doaccess if '.' (as in "../") shows up in name.
+ */
+ if (strchr(name, '.') != NULL)
+ doaccess = TRUE;
+ name = fullname;
+ }
+ if (doaccess && access(name, R_OK) != 0)
+ return -1;
+ if ((fid = open(name, OPEN_MODE)) == -1) {
+ char buf[READLEN];
+ char name[NAMELEN + 1];
+ int fidix = open(INDEXFILE, OPEN_MODE);
+ int off = -1;
+
+ if (fidix < 0) {
+ return -1;
+ }
+
+ while (read(fidix, buf, sizeof(buf)) == sizeof(buf)) {
+ memcpy(name, buf, NAMELEN);
+ name[NAMELEN] = '\0';
+
+ if (strcmp(name, origname) == 0) {
+ off = toint((unsigned char *) buf + NAMELEN);
+ toread = toint((unsigned char *) buf + NAMELEN + INTLEN);
+ break;
+ }
+ }
+
+ close(fidix);
+
+ if (off < 0)
+ return -1;
+
+ fid = open(DATAFILE, OPEN_MODE);
+
+ if (fid < 0) {
+ return -1;
+ }
+
+ if (lseek(fid, off, SEEK_SET) < 0) {
+ return -1;
+ }
+ }
+ }
+ nread = read(fid, u.buf, toread);
+ if (close(fid) < 0 || nread <= 0)
+ return -1;
+ for (stored = 4; stored <= 8; stored *= 2) {
+ int ttisstdcnt;
+ int ttisgmtcnt;
+
+ ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
+ ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
+ sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
+ sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
+ sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
+ sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
+ p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
+ if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
+ sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
+ sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
+ sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
+ (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
+ (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
+ return -1;
+ if (nread - (p - u.buf) <
+ sp->timecnt * stored + /* ats */
+ sp->timecnt + /* types */
+ sp->typecnt * 6 + /* ttinfos */
+ sp->charcnt + /* chars */
+ sp->leapcnt * (stored + 4) + /* lsinfos */
+ ttisstdcnt + /* ttisstds */
+ ttisgmtcnt) /* ttisgmts */
+ return -1;
+ for (i = 0; i < sp->timecnt; ++i) {
+ sp->ats[i] = (stored == 4) ?
+ detzcode(p) : detzcode64(p);
+ p += stored;
+ }
+ for (i = 0; i < sp->timecnt; ++i) {
+ sp->types[i] = (unsigned char) *p++;
+ if (sp->types[i] >= sp->typecnt)
+ return -1;
+ }
+ for (i = 0; i < sp->typecnt; ++i) {
+ register struct ttinfo * ttisp;
+
+ ttisp = &sp->ttis[i];
+ ttisp->tt_gmtoff = detzcode(p);
+ p += 4;
+ ttisp->tt_isdst = (unsigned char) *p++;
+ if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
+ return -1;
+ ttisp->tt_abbrind = (unsigned char) *p++;
+ if (ttisp->tt_abbrind < 0 ||
+ ttisp->tt_abbrind > sp->charcnt)
+ return -1;
+ }
+ for (i = 0; i < sp->charcnt; ++i)
+ sp->chars[i] = *p++;
+ sp->chars[i] = '\0'; /* ensure '\0' at end */
+ for (i = 0; i < sp->leapcnt; ++i) {
+ register struct lsinfo * lsisp;
+
+ lsisp = &sp->lsis[i];
+ lsisp->ls_trans = (stored == 4) ?
+ detzcode(p) : detzcode64(p);
+ p += stored;
+ lsisp->ls_corr = detzcode(p);
+ p += 4;
+ }
+ for (i = 0; i < sp->typecnt; ++i) {
+ register struct ttinfo * ttisp;
+
+ ttisp = &sp->ttis[i];
+ if (ttisstdcnt == 0)
+ ttisp->tt_ttisstd = FALSE;
+ else {
+ ttisp->tt_ttisstd = *p++;
+ if (ttisp->tt_ttisstd != TRUE &&
+ ttisp->tt_ttisstd != FALSE)
+ return -1;
+ }
+ }
+ for (i = 0; i < sp->typecnt; ++i) {
+ register struct ttinfo * ttisp;
+
+ ttisp = &sp->ttis[i];
+ if (ttisgmtcnt == 0)
+ ttisp->tt_ttisgmt = FALSE;
+ else {
+ ttisp->tt_ttisgmt = *p++;
+ if (ttisp->tt_ttisgmt != TRUE &&
+ ttisp->tt_ttisgmt != FALSE)
+ return -1;
+ }
+ }
+ /*
+ ** Out-of-sort ats should mean we're running on a
+ ** signed time_t system but using a data file with
+ ** unsigned values (or vice versa).
+ */
+ for (i = 0; i < sp->timecnt - 2; ++i)
+ if (sp->ats[i] > sp->ats[i + 1]) {
+ ++i;
+ if (TYPE_SIGNED(time_t)) {
+ /*
+ ** Ignore the end (easy).
+ */
+ sp->timecnt = i;
+ } else {
+ /*
+ ** Ignore the beginning (harder).
+ */
+ register int j;
+
+ for (j = 0; j + i < sp->timecnt; ++j) {
+ sp->ats[j] = sp->ats[j + i];
+ sp->types[j] = sp->types[j + i];
+ }
+ sp->timecnt = j;
+ }
+ break;
+ }
+ /*
+ ** If this is an old file, we're done.
+ */
+ if (u.tzhead.tzh_version[0] == '\0')
+ break;
+ nread -= p - u.buf;
+ for (i = 0; i < nread; ++i)
+ u.buf[i] = p[i];
+ /*
+ ** If this is a narrow integer time_t system, we're done.
+ */
+ if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
+ break;
+ }
+ if (doextend && nread > 2 &&
+ u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
+ sp->typecnt + 2 <= TZ_MAX_TYPES) {
+ struct state ts;
+ register int result;
+
+ u.buf[nread - 1] = '\0';
+ result = tzparse(&u.buf[1], &ts, FALSE);
+ if (result == 0 && ts.typecnt == 2 &&
+ sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
+ for (i = 0; i < 2; ++i)
+ ts.ttis[i].tt_abbrind +=
+ sp->charcnt;
+ for (i = 0; i < ts.charcnt; ++i)
+ sp->chars[sp->charcnt++] =
+ ts.chars[i];
+ i = 0;
+ while (i < ts.timecnt &&
+ ts.ats[i] <=
+ sp->ats[sp->timecnt - 1])
+ ++i;
+ while (i < ts.timecnt &&
+ sp->timecnt < TZ_MAX_TIMES) {
+ sp->ats[sp->timecnt] =
+ ts.ats[i];
+ sp->types[sp->timecnt] =
+ sp->typecnt +
+ ts.types[i];
+ ++sp->timecnt;
+ ++i;
+ }
+ sp->ttis[sp->typecnt++] = ts.ttis[0];
+ sp->ttis[sp->typecnt++] = ts.ttis[1];
+ }
+ }
+ i = 2 * YEARSPERREPEAT;
+ sp->goback = sp->goahead = sp->timecnt > i;
+ sp->goback &= sp->types[i] == sp->types[0] &&
+ differ_by_repeat(sp->ats[i], sp->ats[0]);
+ sp->goahead &=
+ sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
+ differ_by_repeat(sp->ats[sp->timecnt - 1],
+ sp->ats[sp->timecnt - 1 - i]);
+ return 0;
+}
+
+static const int mon_lengths[2][MONSPERYEAR] = {
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+static const int year_lengths[2] = {
+ DAYSPERNYEAR, DAYSPERLYEAR
+};
+
+/*
+** Given a pointer into a time zone string, scan until a character that is not
+** a valid character in a zone name is found. Return a pointer to that
+** character.
+*/
+
+static const char *
+getzname(strp)
+register const char * strp;
+{
+ register char c;
+
+ while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
+ c != '+')
+ ++strp;
+ return strp;
+}
+
+/*
+** Given a pointer into an extended time zone string, scan until the ending
+** delimiter of the zone name is located. Return a pointer to the delimiter.
+**
+** As with getzname above, the legal character set is actually quite
+** restricted, with other characters producing undefined results.
+** We don't do any checking here; checking is done later in common-case code.
+*/
+
+static const char *
+getqzname(register const char *strp, const int delim)
+{
+ register int c;
+
+ while ((c = *strp) != '\0' && c != delim)
+ ++strp;
+ return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract a number from that string.
+** Check that the number is within a specified range; if it is not, return
+** NULL.
+** Otherwise, return a pointer to the first character not part of the number.
+*/
+
+static const char *
+getnum(strp, nump, min, max)
+register const char * strp;
+int * const nump;
+const int min;
+const int max;
+{
+ register char c;
+ register int num;
+
+ if (strp == NULL || !is_digit(c = *strp))
+ return NULL;
+ num = 0;
+ do {
+ num = num * 10 + (c - '0');
+ if (num > max)
+ return NULL; /* illegal value */
+ c = *++strp;
+ } while (is_digit(c));
+ if (num < min)
+ return NULL; /* illegal value */
+ *nump = num;
+ return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract a number of seconds,
+** in hh[:mm[:ss]] form, from the string.
+** If any error occurs, return NULL.
+** Otherwise, return a pointer to the first character not part of the number
+** of seconds.
+*/
+
+static const char *
+getsecs(strp, secsp)
+register const char * strp;
+long * const secsp;
+{
+ int num;
+
+ /*
+ ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
+ ** "M10.4.6/26", which does not conform to Posix,
+ ** but which specifies the equivalent of
+ ** ``02:00 on the first Sunday on or after 23 Oct''.
+ */
+ strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
+ if (strp == NULL)
+ return NULL;
+ *secsp = num * (long) SECSPERHOUR;
+ if (*strp == ':') {
+ ++strp;
+ strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
+ if (strp == NULL)
+ return NULL;
+ *secsp += num * SECSPERMIN;
+ if (*strp == ':') {
+ ++strp;
+ /* `SECSPERMIN' allows for leap seconds. */
+ strp = getnum(strp, &num, 0, SECSPERMIN);
+ if (strp == NULL)
+ return NULL;
+ *secsp += num;
+ }
+ }
+ return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract an offset, in
+** [+-]hh[:mm[:ss]] form, from the string.
+** If any error occurs, return NULL.
+** Otherwise, return a pointer to the first character not part of the time.
+*/
+
+static const char *
+getoffset(strp, offsetp)
+register const char * strp;
+long * const offsetp;
+{
+ register int neg = 0;
+
+ if (*strp == '-') {
+ neg = 1;
+ ++strp;
+ } else if (*strp == '+')
+ ++strp;
+ strp = getsecs(strp, offsetp);
+ if (strp == NULL)
+ return NULL; /* illegal time */
+ if (neg)
+ *offsetp = -*offsetp;
+ return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract a rule in the form
+** date[/time]. See POSIX section 8 for the format of "date" and "time".
+** If a valid rule is not found, return NULL.
+** Otherwise, return a pointer to the first character not part of the rule.
+*/
+
+static const char *
+getrule(strp, rulep)
+const char * strp;
+register struct rule * const rulep;
+{
+ if (*strp == 'J') {
+ /*
+ ** Julian day.
+ */
+ rulep->r_type = JULIAN_DAY;
+ ++strp;
+ strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
+ } else if (*strp == 'M') {
+ /*
+ ** Month, week, day.
+ */
+ rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
+ ++strp;
+ strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
+ if (strp == NULL)
+ return NULL;
+ if (*strp++ != '.')
+ return NULL;
+ strp = getnum(strp, &rulep->r_week, 1, 5);
+ if (strp == NULL)
+ return NULL;
+ if (*strp++ != '.')
+ return NULL;
+ strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
+ } else if (is_digit(*strp)) {
+ /*
+ ** Day of year.
+ */
+ rulep->r_type = DAY_OF_YEAR;
+ strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
+ } else return NULL; /* invalid format */
+ if (strp == NULL)
+ return NULL;
+ if (*strp == '/') {
+ /*
+ ** Time specified.
+ */
+ ++strp;
+ strp = getsecs(strp, &rulep->r_time);
+ } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
+ return strp;
+}
+
+/*
+** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
+** year, a rule, and the offset from UTC at the time that rule takes effect,
+** calculate the Epoch-relative time that rule takes effect.
+*/
+
+static time_t
+transtime(janfirst, year, rulep, offset)
+const time_t janfirst;
+const int year;
+register const struct rule * const rulep;
+const long offset;
+{
+ register int leapyear;
+ register time_t value;
+ register int i;
+ int d, m1, yy0, yy1, yy2, dow;
+
+ INITIALIZE(value);
+ leapyear = isleap(year);
+ switch (rulep->r_type) {
+
+ case JULIAN_DAY:
+ /*
+ ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
+ ** years.
+ ** In non-leap years, or if the day number is 59 or less, just
+ ** add SECSPERDAY times the day number-1 to the time of
+ ** January 1, midnight, to get the day.
+ */
+ value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
+ if (leapyear && rulep->r_day >= 60)
+ value += SECSPERDAY;
+ break;
+
+ case DAY_OF_YEAR:
+ /*
+ ** n - day of year.
+ ** Just add SECSPERDAY times the day number to the time of
+ ** January 1, midnight, to get the day.
+ */
+ value = janfirst + rulep->r_day * SECSPERDAY;
+ break;
+
+ case MONTH_NTH_DAY_OF_WEEK:
+ /*
+ ** Mm.n.d - nth "dth day" of month m.
+ */
+ value = janfirst;
+ for (i = 0; i < rulep->r_mon - 1; ++i)
+ value += mon_lengths[leapyear][i] * SECSPERDAY;
+
+ /*
+ ** Use Zeller's Congruence to get day-of-week of first day of
+ ** month.
+ */
+ m1 = (rulep->r_mon + 9) % 12 + 1;
+ yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
+ yy1 = yy0 / 100;
+ yy2 = yy0 % 100;
+ dow = ((26 * m1 - 2) / 10 +
+ 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
+ if (dow < 0)
+ dow += DAYSPERWEEK;
+
+ /*
+ ** "dow" is the day-of-week of the first day of the month. Get
+ ** the day-of-month (zero-origin) of the first "dow" day of the
+ ** month.
+ */
+ d = rulep->r_day - dow;
+ if (d < 0)
+ d += DAYSPERWEEK;
+ for (i = 1; i < rulep->r_week; ++i) {
+ if (d + DAYSPERWEEK >=
+ mon_lengths[leapyear][rulep->r_mon - 1])
+ break;
+ d += DAYSPERWEEK;
+ }
+
+ /*
+ ** "d" is the day-of-month (zero-origin) of the day we want.
+ */
+ value += d * SECSPERDAY;
+ break;
+ }
+
+ /*
+ ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
+ ** question. To get the Epoch-relative time of the specified local
+ ** time on that day, add the transition time and the current offset
+ ** from UTC.
+ */
+ return value + rulep->r_time + offset;
+}
+
+/*
+** Given a POSIX section 8-style TZ string, fill in the rule tables as
+** appropriate.
+*/
+
+static int
+tzparse(name, sp, lastditch)
+const char * name;
+register struct state * const sp;
+const int lastditch;
+{
+ const char * stdname;
+ const char * dstname;
+ size_t stdlen;
+ size_t dstlen;
+ long stdoffset;
+ long dstoffset;
+ register time_t * atp;
+ register unsigned char * typep;
+ register char * cp;
+ register int load_result;
+
+ INITIALIZE(dstname);
+ stdname = name;
+ if (lastditch) {
+ stdlen = strlen(name); /* length of standard zone name */
+ name += stdlen;
+ if (stdlen >= sizeof sp->chars)
+ stdlen = (sizeof sp->chars) - 1;
+ stdoffset = 0;
+ } else {
+ if (*name == '<') {
+ name++;
+ stdname = name;
+ name = getqzname(name, '>');
+ if (*name != '>')
+ return (-1);
+ stdlen = name - stdname;
+ name++;
+ } else {
+ name = getzname(name);
+ stdlen = name - stdname;
+ }
+ if (*name == '\0')
+ return -1;
+ name = getoffset(name, &stdoffset);
+ if (name == NULL)
+ return -1;
+ }
+ load_result = tzload(TZDEFRULES, sp, FALSE);
+ if (load_result != 0)
+ sp->leapcnt = 0; /* so, we're off a little */
+ sp->timecnt = 0;
+ if (*name != '\0') {
+ if (*name == '<') {
+ dstname = ++name;
+ name = getqzname(name, '>');
+ if (*name != '>')
+ return -1;
+ dstlen = name - dstname;
+ name++;
+ } else {
+ dstname = name;
+ name = getzname(name);
+ dstlen = name - dstname; /* length of DST zone name */
+ }
+ if (*name != '\0' && *name != ',' && *name != ';') {
+ name = getoffset(name, &dstoffset);
+ if (name == NULL)
+ return -1;
+ } else dstoffset = stdoffset - SECSPERHOUR;
+ if (*name == '\0' && load_result != 0)
+ name = TZDEFRULESTRING;
+ if (*name == ',' || *name == ';') {
+ struct rule start;
+ struct rule end;
+ register int year;
+ register time_t janfirst;
+ time_t starttime;
+ time_t endtime;
+
+ ++name;
+ if ((name = getrule(name, &start)) == NULL)
+ return -1;
+ if (*name++ != ',')
+ return -1;
+ if ((name = getrule(name, &end)) == NULL)
+ return -1;
+ if (*name != '\0')
+ return -1;
+ sp->typecnt = 2; /* standard time and DST */
+ /*
+ ** Two transitions per year, from EPOCH_YEAR forward.
+ */
+ sp->ttis[0].tt_gmtoff = -dstoffset;
+ sp->ttis[0].tt_isdst = 1;
+ sp->ttis[0].tt_abbrind = stdlen + 1;
+ sp->ttis[1].tt_gmtoff = -stdoffset;
+ sp->ttis[1].tt_isdst = 0;
+ sp->ttis[1].tt_abbrind = 0;
+ atp = sp->ats;
+ typep = sp->types;
+ janfirst = 0;
+ for (year = EPOCH_YEAR;
+ sp->timecnt + 2 <= TZ_MAX_TIMES;
+ ++year) {
+ time_t newfirst;
+
+ starttime = transtime(janfirst, year, &start,
+ stdoffset);
+ endtime = transtime(janfirst, year, &end,
+ dstoffset);
+ if (starttime > endtime) {
+ *atp++ = endtime;
+ *typep++ = 1; /* DST ends */
+ *atp++ = starttime;
+ *typep++ = 0; /* DST begins */
+ } else {
+ *atp++ = starttime;
+ *typep++ = 0; /* DST begins */
+ *atp++ = endtime;
+ *typep++ = 1; /* DST ends */
+ }
+ sp->timecnt += 2;
+ newfirst = janfirst;
+ newfirst += year_lengths[isleap(year)] *
+ SECSPERDAY;
+ if (newfirst <= janfirst)
+ break;
+ janfirst = newfirst;
+ }
+ } else {
+ register long theirstdoffset;
+ register long theirdstoffset;
+ register long theiroffset;
+ register int isdst;
+ register int i;
+ register int j;
+
+ if (*name != '\0')
+ return -1;
+ /*
+ ** Initial values of theirstdoffset and theirdstoffset.
+ */
+ theirstdoffset = 0;
+ for (i = 0; i < sp->timecnt; ++i) {
+ j = sp->types[i];
+ if (!sp->ttis[j].tt_isdst) {
+ theirstdoffset =
+ -sp->ttis[j].tt_gmtoff;
+ break;
+ }
+ }
+ theirdstoffset = 0;
+ for (i = 0; i < sp->timecnt; ++i) {
+ j = sp->types[i];
+ if (sp->ttis[j].tt_isdst) {
+ theirdstoffset =
+ -sp->ttis[j].tt_gmtoff;
+ break;
+ }
+ }
+ /*
+ ** Initially we're assumed to be in standard time.
+ */
+ isdst = FALSE;
+ theiroffset = theirstdoffset;
+ /*
+ ** Now juggle transition times and types
+ ** tracking offsets as you do.
+ */
+ for (i = 0; i < sp->timecnt; ++i) {
+ j = sp->types[i];
+ sp->types[i] = sp->ttis[j].tt_isdst;
+ if (sp->ttis[j].tt_ttisgmt) {
+ /* No adjustment to transition time */
+ } else {
+ /*
+ ** If summer time is in effect, and the
+ ** transition time was not specified as
+ ** standard time, add the summer time
+ ** offset to the transition time;
+ ** otherwise, add the standard time
+ ** offset to the transition time.
+ */
+ /*
+ ** Transitions from DST to DDST
+ ** will effectively disappear since
+ ** POSIX provides for only one DST
+ ** offset.
+ */
+ if (isdst && !sp->ttis[j].tt_ttisstd) {
+ sp->ats[i] += dstoffset -
+ theirdstoffset;
+ } else {
+ sp->ats[i] += stdoffset -
+ theirstdoffset;
+ }
+ }
+ theiroffset = -sp->ttis[j].tt_gmtoff;
+ if (sp->ttis[j].tt_isdst)
+ theirdstoffset = theiroffset;
+ else theirstdoffset = theiroffset;
+ }
+ /*
+ ** Finally, fill in ttis.
+ ** ttisstd and ttisgmt need not be handled.
+ */
+ sp->ttis[0].tt_gmtoff = -stdoffset;
+ sp->ttis[0].tt_isdst = FALSE;
+ sp->ttis[0].tt_abbrind = 0;
+ sp->ttis[1].tt_gmtoff = -dstoffset;
+ sp->ttis[1].tt_isdst = TRUE;
+ sp->ttis[1].tt_abbrind = stdlen + 1;
+ sp->typecnt = 2;
+ }
+ } else {
+ dstlen = 0;
+ sp->typecnt = 1; /* only standard time */
+ sp->timecnt = 0;
+ sp->ttis[0].tt_gmtoff = -stdoffset;
+ sp->ttis[0].tt_isdst = 0;
+ sp->ttis[0].tt_abbrind = 0;
+ }
+ sp->charcnt = stdlen + 1;
+ if (dstlen != 0)
+ sp->charcnt += dstlen + 1;
+ if ((size_t) sp->charcnt > sizeof sp->chars)
+ return -1;
+ cp = sp->chars;
+ (void) strncpy(cp, stdname, stdlen);
+ cp += stdlen;
+ *cp++ = '\0';
+ if (dstlen != 0) {
+ (void) strncpy(cp, dstname, dstlen);
+ *(cp + dstlen) = '\0';
+ }
+ return 0;
+}
+
+static void
+gmtload(sp)
+struct state * const sp;
+{
+ if (tzload(gmt, sp, TRUE) != 0)
+ (void) tzparse(gmt, sp, TRUE);
+}
+
+/*
+** The easy way to behave "as if no library function calls" localtime
+** is to not call it--so we drop its guts into "localsub", which can be
+** freely called. (And no, the PANS doesn't require the above behavior--
+** but it *is* desirable.)
+**
+** The unused offset argument is for the benefit of mktime variants.
+*/
+
+/*ARGSUSED*/
+static struct tm *
+localsub(timep, offset, tmp, sp)
+const time_t * const timep;
+const long offset;
+struct tm * const tmp;
+const struct state * sp;
+{
+ register const struct ttinfo * ttisp;
+ register int i;
+ register struct tm * result;
+ const time_t t = *timep;
+
+#ifdef ALL_STATE
+ if (sp == NULL)
+ return gmtsub(timep, offset, tmp);
+#endif /* defined ALL_STATE */
+ if ((sp->goback && t < sp->ats[0]) ||
+ (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
+ time_t newt = t;
+ register time_t seconds;
+ register time_t tcycles;
+ register int_fast64_t icycles;
+
+ if (t < sp->ats[0])
+ seconds = sp->ats[0] - t;
+ else seconds = t - sp->ats[sp->timecnt - 1];
+ --seconds;
+ tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
+ ++tcycles;
+ icycles = tcycles;
+ if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
+ return NULL;
+ seconds = icycles;
+ seconds *= YEARSPERREPEAT;
+ seconds *= AVGSECSPERYEAR;
+ if (t < sp->ats[0])
+ newt += seconds;
+ else newt -= seconds;
+ if (newt < sp->ats[0] ||
+ newt > sp->ats[sp->timecnt - 1])
+ return NULL; /* "cannot happen" */
+ result = localsub(&newt, offset, tmp, sp);
+ if (result == tmp) {
+ register time_t newy;
+
+ newy = tmp->tm_year;
+ if (t < sp->ats[0])
+ newy -= icycles * YEARSPERREPEAT;
+ else newy += icycles * YEARSPERREPEAT;
+ tmp->tm_year = newy;
+ if (tmp->tm_year != newy)
+ return NULL;
+ }
+ return result;
+ }
+ if (sp->timecnt == 0 || t < sp->ats[0]) {
+ i = 0;
+ while (sp->ttis[i].tt_isdst)
+ if (++i >= sp->typecnt) {
+ i = 0;
+ break;
+ }
+ } else {
+ register int lo = 1;
+ register int hi = sp->timecnt;
+
+ while (lo < hi) {
+ register int mid = (lo + hi) >> 1;
+
+ if (t < sp->ats[mid])
+ hi = mid;
+ else lo = mid + 1;
+ }
+ i = (int) sp->types[lo - 1];
+ }
+ ttisp = &sp->ttis[i];
+ /*
+ ** To get (wrong) behavior that's compatible with System V Release 2.0
+ ** you'd replace the statement below with
+ ** t += ttisp->tt_gmtoff;
+ ** timesub(&t, 0L, sp, tmp);
+ */
+ result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
+ tmp->tm_isdst = ttisp->tt_isdst;
+#ifdef HAVE_TM_GMTOFF
+ tmp->tm_gmtoff = ttisp->tt_gmtoff;
+#endif
+ tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
+#ifdef TM_ZONE
+ tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
+#endif /* defined TM_ZONE */
+ return result;
+}
+
+
+// ============================================================================
+#if 0
+struct tm *
+localtime(timep)
+const time_t * const timep;
+{
+ tzset();
+ return localsub(timep, 0L, &tm);
+}
+#endif
+
+/*
+** Re-entrant version of localtime.
+*/
+
+// ============================================================================
+void
+localtime_tz(const time_t * const timep, struct tm * tmp, const char* tz)
+{
+ struct state st;
+ if (tzload(tz, &st, TRUE) != 0) {
+ // not sure what's best here, but for now, we fall back to gmt
+ gmtload(&st);
+ }
+
+ localsub(timep, 0L, tmp, &st);
+}
+
+/*
+** gmtsub is to gmtime as localsub is to localtime.
+*/
+
+static struct tm *
+gmtsub(timep, offset, tmp)
+const time_t * const timep;
+const long offset;
+struct tm * const tmp;
+{
+ register struct tm * result;
+
+ if (!gmt_is_set) {
+ gmt_is_set = TRUE;
+#ifdef ALL_STATE
+ gmtptr = (struct state *) malloc(sizeof *gmtptr);
+ if (gmtptr != NULL)
+#endif /* defined ALL_STATE */
+ gmtload(gmtptr);
+ }
+ result = timesub(timep, offset, gmtptr, tmp);
+#ifdef TM_ZONE
+ /*
+ ** Could get fancy here and deliver something such as
+ ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
+ ** but this is no time for a treasure hunt.
+ */
+ if (offset != 0)
+ tmp->TM_ZONE = wildabbr;
+ else {
+#ifdef ALL_STATE
+ if (gmtptr == NULL)
+ tmp->TM_ZONE = gmt;
+ else tmp->TM_ZONE = gmtptr->chars;
+#endif /* defined ALL_STATE */
+#ifndef ALL_STATE
+ tmp->TM_ZONE = gmtptr->chars;
+#endif /* State Farm */
+ }
+#endif /* defined TM_ZONE */
+ return result;
+}
+
+// ============================================================================
+#if 0
+struct tm *
+gmtime(timep)
+const time_t * const timep;
+{
+ return gmtsub(timep, 0L, &tm);
+}
+#endif
+
+/*
+* Re-entrant version of gmtime.
+*/
+
+// ============================================================================
+#if 0
+struct tm *
+gmtime_r(timep, tmp)
+const time_t * const timep;
+struct tm * tmp;
+{
+ return gmtsub(timep, 0L, tmp);
+}
+#endif
+
+#ifdef STD_INSPIRED
+
+// ============================================================================
+#if 0
+struct tm *
+offtime(timep, offset)
+const time_t * const timep;
+const long offset;
+{
+ return gmtsub(timep, offset, &tm);
+}
+#endif
+
+#endif /* defined STD_INSPIRED */
+
+/*
+** Return the number of leap years through the end of the given year
+** where, to make the math easy, the answer for year zero is defined as zero.
+*/
+
+static int
+leaps_thru_end_of(y)
+register const int y;
+{
+ return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
+ -(leaps_thru_end_of(-(y + 1)) + 1);
+}
+
+static struct tm *
+timesub(timep, offset, sp, tmp)
+const time_t * const timep;
+const long offset;
+register const struct state * const sp;
+register struct tm * const tmp;
+{
+ register const struct lsinfo * lp;
+ register time_t tdays;
+ register int idays; /* unsigned would be so 2003 */
+ register long rem;
+ int y;
+ register const int * ip;
+ register long corr;
+ register int hit;
+ register int i;
+
+ corr = 0;
+ hit = 0;
+#ifdef ALL_STATE
+ i = (sp == NULL) ? 0 : sp->leapcnt;
+#endif /* defined ALL_STATE */
+#ifndef ALL_STATE
+ i = sp->leapcnt;
+#endif /* State Farm */
+ while (--i >= 0) {
+ lp = &sp->lsis[i];
+ if (*timep >= lp->ls_trans) {
+ if (*timep == lp->ls_trans) {
+ hit = ((i == 0 && lp->ls_corr > 0) ||
+ lp->ls_corr > sp->lsis[i - 1].ls_corr);
+ if (hit)
+ while (i > 0 &&
+ sp->lsis[i].ls_trans ==
+ sp->lsis[i - 1].ls_trans + 1 &&
+ sp->lsis[i].ls_corr ==
+ sp->lsis[i - 1].ls_corr + 1) {
+ ++hit;
+ --i;
+ }
+ }
+ corr = lp->ls_corr;
+ break;
+ }
+ }
+ y = EPOCH_YEAR;
+ tdays = *timep / SECSPERDAY;
+ rem = *timep - tdays * SECSPERDAY;
+ while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
+ int newy;
+ register time_t tdelta;
+ register int idelta;
+ register int leapdays;
+
+ tdelta = tdays / DAYSPERLYEAR;
+ idelta = tdelta;
+ if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
+ return NULL;
+ if (idelta == 0)
+ idelta = (tdays < 0) ? -1 : 1;
+ newy = y;
+ if (increment_overflow(&newy, idelta))
+ return NULL;
+ leapdays = leaps_thru_end_of(newy - 1) -
+ leaps_thru_end_of(y - 1);
+ tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
+ tdays -= leapdays;
+ y = newy;
+ }
+ {
+ register long seconds;
+
+ seconds = tdays * SECSPERDAY + 0.5;
+ tdays = seconds / SECSPERDAY;
+ rem += seconds - tdays * SECSPERDAY;
+ }
+ /*
+ ** Given the range, we can now fearlessly cast...
+ */
+ idays = tdays;
+ rem += offset - corr;
+ while (rem < 0) {
+ rem += SECSPERDAY;
+ --idays;
+ }
+ while (rem >= SECSPERDAY) {
+ rem -= SECSPERDAY;
+ ++idays;
+ }
+ while (idays < 0) {
+ if (increment_overflow(&y, -1))
+ return NULL;
+ idays += year_lengths[isleap(y)];
+ }
+ while (idays >= year_lengths[isleap(y)]) {
+ idays -= year_lengths[isleap(y)];
+ if (increment_overflow(&y, 1))
+ return NULL;
+ }
+ tmp->tm_year = y;
+ if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
+ return NULL;
+ tmp->tm_yday = idays;
+ /*
+ ** The "extra" mods below avoid overflow problems.
+ */
+ tmp->tm_wday = EPOCH_WDAY +
+ ((y - EPOCH_YEAR) % DAYSPERWEEK) *
+ (DAYSPERNYEAR % DAYSPERWEEK) +
+ leaps_thru_end_of(y - 1) -
+ leaps_thru_end_of(EPOCH_YEAR - 1) +
+ idays;
+ tmp->tm_wday %= DAYSPERWEEK;
+ if (tmp->tm_wday < 0)
+ tmp->tm_wday += DAYSPERWEEK;
+ tmp->tm_hour = (int) (rem / SECSPERHOUR);
+ rem %= SECSPERHOUR;
+ tmp->tm_min = (int) (rem / SECSPERMIN);
+ /*
+ ** A positive leap second requires a special
+ ** representation. This uses "... ??:59:60" et seq.
+ */
+ tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
+ ip = mon_lengths[isleap(y)];
+ for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
+ idays -= ip[tmp->tm_mon];
+ tmp->tm_mday = (int) (idays + 1);
+ tmp->tm_isdst = 0;
+#ifdef TM_GMTOFF
+ tmp->TM_GMTOFF = offset;
+#endif /* defined TM_GMTOFF */
+ return tmp;
+}
+
+// ============================================================================
+#if 0
+char *
+ctime(timep)
+const time_t * const timep;
+{
+/*
+** Section 4.12.3.2 of X3.159-1989 requires that
+** The ctime function converts the calendar time pointed to by timer
+** to local time in the form of a string. It is equivalent to
+** asctime(localtime(timer))
+*/
+ return asctime(localtime(timep));
+}
+#endif
+
+// ============================================================================
+#if 0
+char *
+ctime_r(timep, buf)
+const time_t * const timep;
+char * buf;
+{
+ struct tm mytm;
+
+ return asctime_r(localtime_r(timep, &mytm), buf);
+}
+#endif
+
+/*
+** Adapted from code provided by Robert Elz, who writes:
+** The "best" way to do mktime I think is based on an idea of Bob
+** Kridle's (so its said...) from a long time ago.
+** It does a binary search of the time_t space. Since time_t's are
+** just 32 bits, its a max of 32 iterations (even at 64 bits it
+** would still be very reasonable).
+*/
+
+#ifndef WRONG
+#define WRONG (-1)
+#endif /* !defined WRONG */
+
+/*
+** Simplified normalize logic courtesy Paul Eggert.
+*/
+
+static int
+increment_overflow(number, delta)
+int * number;
+int delta;
+{
+ unsigned number0 = (unsigned)*number;
+ unsigned number1 = (unsigned)(number0 + delta);
+
+ *number = (int)number1;
+
+ if (delta >= 0) {
+ return ((int)number1 < (int)number0);
+ } else {
+ return ((int)number1 > (int)number0);
+ }
+}
+
+static int
+long_increment_overflow(number, delta)
+long * number;
+int delta;
+{
+ unsigned long number0 = (unsigned long)*number;
+ unsigned long number1 = (unsigned long)(number0 + delta);
+
+ *number = (long)number1;
+
+ if (delta >= 0) {
+ return ((long)number1 < (long)number0);
+ } else {
+ return ((long)number1 > (long)number0);
+ }
+}
+
+static int
+normalize_overflow(tensptr, unitsptr, base)
+int * const tensptr;
+int * const unitsptr;
+const int base;
+{
+ register int tensdelta;
+
+ tensdelta = (*unitsptr >= 0) ?
+ (*unitsptr / base) :
+ (-1 - (-1 - *unitsptr) / base);
+ *unitsptr -= tensdelta * base;
+ return increment_overflow(tensptr, tensdelta);
+}
+
+static int
+long_normalize_overflow(tensptr, unitsptr, base)
+long * const tensptr;
+int * const unitsptr;
+const int base;
+{
+ register int tensdelta;
+
+ tensdelta = (*unitsptr >= 0) ?
+ (*unitsptr / base) :
+ (-1 - (-1 - *unitsptr) / base);
+ *unitsptr -= tensdelta * base;
+ return long_increment_overflow(tensptr, tensdelta);
+}
+
+static int
+tmcomp(atmp, btmp)
+register const struct tm * const atmp;
+register const struct tm * const btmp;
+{
+ register int result;
+
+ if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
+ (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
+ (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
+ (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
+ (result = (atmp->tm_min - btmp->tm_min)) == 0)
+ result = atmp->tm_sec - btmp->tm_sec;
+ return result;
+}
+
+static time_t
+time2sub(tmp, funcp, offset, okayp, do_norm_secs, sp)
+struct tm * const tmp;
+struct tm * (* const funcp) P((const time_t*, long, struct tm*,const struct state *sp));
+const long offset;
+int * const okayp;
+const int do_norm_secs;
+const struct state * sp;
+{
+ register int dir;
+ register int i, j;
+ register int saved_seconds;
+ register long li;
+ register time_t lo;
+ register time_t hi;
+ long y;
+ time_t newt;
+ time_t t;
+ struct tm yourtm, mytm;
+
+ *okayp = FALSE;
+ yourtm = *tmp;
+ if (do_norm_secs) {
+ if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
+ SECSPERMIN))
+ return WRONG;
+ }
+ if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
+ return WRONG;
+ if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
+ return WRONG;
+ y = yourtm.tm_year;
+ if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
+ return WRONG;
+ /*
+ ** Turn y into an actual year number for now.
+ ** It is converted back to an offset from TM_YEAR_BASE later.
+ */
+ if (long_increment_overflow(&y, TM_YEAR_BASE))
+ return WRONG;
+ while (yourtm.tm_mday <= 0) {
+ if (long_increment_overflow(&y, -1))
+ return WRONG;
+ li = y + (1 < yourtm.tm_mon);
+ yourtm.tm_mday += year_lengths[isleap(li)];
+ }
+ while (yourtm.tm_mday > DAYSPERLYEAR) {
+ li = y + (1 < yourtm.tm_mon);
+ yourtm.tm_mday -= year_lengths[isleap(li)];
+ if (long_increment_overflow(&y, 1))
+ return WRONG;
+ }
+ for ( ; ; ) {
+ i = mon_lengths[isleap(y)][yourtm.tm_mon];
+ if (yourtm.tm_mday <= i)
+ break;
+ yourtm.tm_mday -= i;
+ if (++yourtm.tm_mon >= MONSPERYEAR) {
+ yourtm.tm_mon = 0;
+ if (long_increment_overflow(&y, 1))
+ return WRONG;
+ }
+ }
+ if (long_increment_overflow(&y, -TM_YEAR_BASE))
+ return WRONG;
+ yourtm.tm_year = y;
+ if (yourtm.tm_year != y)
+ return WRONG;
+ if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
+ saved_seconds = 0;
+ else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
+ /*
+ ** We can't set tm_sec to 0, because that might push the
+ ** time below the minimum representable time.
+ ** Set tm_sec to 59 instead.
+ ** This assumes that the minimum representable time is
+ ** not in the same minute that a leap second was deleted from,
+ ** which is a safer assumption than using 58 would be.
+ */
+ if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
+ return WRONG;
+ saved_seconds = yourtm.tm_sec;
+ yourtm.tm_sec = SECSPERMIN - 1;
+ } else {
+ saved_seconds = yourtm.tm_sec;
+ yourtm.tm_sec = 0;
+ }
+ /*
+ ** Do a binary search (this works whatever time_t's type is).
+ */
+ if (!TYPE_SIGNED(time_t)) {
+ lo = 0;
+ hi = lo - 1;
+ } else if (!TYPE_INTEGRAL(time_t)) {
+ if (sizeof(time_t) > sizeof(float))
+ hi = (time_t) DBL_MAX;
+ else hi = (time_t) FLT_MAX;
+ lo = -hi;
+ } else {
+ lo = 1;
+ for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
+ lo *= 2;
+ hi = -(lo + 1);
+ }
+ for ( ; ; ) {
+ t = lo / 2 + hi / 2;
+ if (t < lo)
+ t = lo;
+ else if (t > hi)
+ t = hi;
+ if ((*funcp)(&t, offset, &mytm, sp) == NULL) {
+ /*
+ ** Assume that t is too extreme to be represented in
+ ** a struct tm; arrange things so that it is less
+ ** extreme on the next pass.
+ */
+ dir = (t > 0) ? 1 : -1;
+ } else dir = tmcomp(&mytm, &yourtm);
+ if (dir != 0) {
+ if (t == lo) {
+ if (t == TIME_T_MAX)
+ return WRONG;
+ ++t;
+ ++lo;
+ } else if (t == hi) {
+ if (t == TIME_T_MIN)
+ return WRONG;
+ --t;
+ --hi;
+ }
+ if (lo > hi)
+ return WRONG;
+ if (dir > 0)
+ hi = t;
+ else lo = t;
+ continue;
+ }
+ if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
+ break;
+ /*
+ ** Right time, wrong type.
+ ** Hunt for right time, right type.
+ ** It's okay to guess wrong since the guess
+ ** gets checked.
+ */
+ /*
+ ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
+ */
+#ifdef ALL_STATE
+ if (sp == NULL)
+ return WRONG;
+#endif /* defined ALL_STATE */
+ for (i = sp->typecnt - 1; i >= 0; --i) {
+ if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
+ continue;
+ for (j = sp->typecnt - 1; j >= 0; --j) {
+ if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
+ continue;
+ newt = t + sp->ttis[j].tt_gmtoff -
+ sp->ttis[i].tt_gmtoff;
+ if ((*funcp)(&newt, offset, &mytm, sp) == NULL)
+ continue;
+ if (tmcomp(&mytm, &yourtm) != 0)
+ continue;
+ if (mytm.tm_isdst != yourtm.tm_isdst)
+ continue;
+ /*
+ ** We have a match.
+ */
+ t = newt;
+ goto label;
+ }
+ }
+ return WRONG;
+ }
+label:
+ newt = t + saved_seconds;
+ if ((newt < t) != (saved_seconds < 0))
+ return WRONG;
+ t = newt;
+ if ((*funcp)(&t, offset, tmp, sp))
+ *okayp = TRUE;
+ return t;
+}
+
+static time_t
+time2(tmp, funcp, offset, okayp, sp)
+struct tm * const tmp;
+struct tm * (* const funcp) P((const time_t*, long, struct tm*,
+ const struct state* sp));
+const long offset;
+int * const okayp;
+const struct state * sp;
+{
+ time_t t;
+
+ /*
+ ** First try without normalization of seconds
+ ** (in case tm_sec contains a value associated with a leap second).
+ ** If that fails, try with normalization of seconds.
+ */
+ t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
+ return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
+}
+
+static time_t
+time1(tmp, funcp, offset, sp)
+struct tm * const tmp;
+struct tm * (* const funcp) P((const time_t *, long, struct tm *, const struct state* sp));
+const long offset;
+const struct state * sp;
+{
+ register time_t t;
+ register int samei, otheri;
+ register int sameind, otherind;
+ register int i;
+ register int nseen;
+ int seen[TZ_MAX_TYPES];
+ int types[TZ_MAX_TYPES];
+ int okay;
+
+ if (tmp->tm_isdst > 1)
+ tmp->tm_isdst = 1;
+ t = time2(tmp, funcp, offset, &okay, sp);
+#define PCTS 1
+#ifdef PCTS
+ /*
+ ** PCTS code courtesy Grant Sullivan.
+ */
+ if (okay)
+ return t;
+ if (tmp->tm_isdst < 0)
+ tmp->tm_isdst = 0; /* reset to std and try again */
+#endif /* defined PCTS */
+#ifndef PCTS
+ if (okay || tmp->tm_isdst < 0)
+ return t;
+#endif /* !defined PCTS */
+ /*
+ ** We're supposed to assume that somebody took a time of one type
+ ** and did some math on it that yielded a "struct tm" that's bad.
+ ** We try to divine the type they started from and adjust to the
+ ** type they need.
+ */
+ /*
+ ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
+ */
+#ifdef ALL_STATE
+ if (sp == NULL)
+ return WRONG;
+#endif /* defined ALL_STATE */
+ for (i = 0; i < sp->typecnt; ++i)
+ seen[i] = FALSE;
+ nseen = 0;
+ for (i = sp->timecnt - 1; i >= 0; --i)
+ if (!seen[sp->types[i]]) {
+ seen[sp->types[i]] = TRUE;
+ types[nseen++] = sp->types[i];
+ }
+ for (sameind = 0; sameind < nseen; ++sameind) {
+ samei = types[sameind];
+ if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
+ continue;
+ for (otherind = 0; otherind < nseen; ++otherind) {
+ otheri = types[otherind];
+ if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
+ continue;
+ tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
+ sp->ttis[samei].tt_gmtoff;
+ tmp->tm_isdst = !tmp->tm_isdst;
+ t = time2(tmp, funcp, offset, &okay, sp);
+ if (okay)
+ return t;
+ tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
+ sp->ttis[samei].tt_gmtoff;
+ tmp->tm_isdst = !tmp->tm_isdst;
+ }
+ }
+ return WRONG;
+}
+
+// ============================================================================
+time_t
+mktime_tz(struct tm * const tmp, char const * tz)
+{
+ struct state st;
+ if (tzload(tz, &st, TRUE) != 0) {
+ // not sure what's best here, but for now, we fall back to gmt
+ gmtload(&st);
+ }
+ return time1(tmp, localsub, 0L, &st);
+}
diff --git a/libion/ion.c b/libion/ion.c
index dbeac23..020c35b 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -54,13 +54,14 @@
return ret;
}
-int ion_alloc(int fd, size_t len, size_t align, unsigned int flags,
- struct ion_handle **handle)
+int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask,
+ unsigned int flags, struct ion_handle **handle)
{
int ret;
struct ion_allocation_data data = {
.len = len,
.align = align,
+ .heap_mask = heap_mask,
.flags = flags,
};
@@ -120,6 +121,19 @@
return ret;
}
+int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask,
+ unsigned int flags, int *handle_fd) {
+ struct ion_handle *handle;
+ int ret;
+
+ ret = ion_alloc(fd, len, align, heap_mask, flags, &handle);
+ if (ret < 0)
+ return ret;
+ ret = ion_share(fd, handle, handle_fd);
+ ion_free(fd, handle);
+ return ret;
+}
+
int ion_import(int fd, int share_fd, struct ion_handle **handle)
{
struct ion_fd_data data = {
@@ -132,3 +146,11 @@
*handle = data.handle;
return ret;
}
+
+int ion_sync_fd(int fd, int handle_fd)
+{
+ struct ion_fd_data data = {
+ .fd = handle_fd,
+ };
+ return ion_ioctl(fd, ION_IOC_SYNC, &data);
+}
diff --git a/libion/ion_test.c b/libion/ion_test.c
index 3f2d7cc..0caaa2a 100644
--- a/libion/ion_test.c
+++ b/libion/ion_test.c
@@ -19,8 +19,8 @@
int prot = PROT_READ | PROT_WRITE;
int map_flags = MAP_SHARED;
int alloc_flags = 0;
+int heap_mask = 1;
int test = -1;
-size_t width = 1024*1024, height = 1024*1024;
size_t stride;
int _ion_alloc_test(int *fd, struct ion_handle **handle)
@@ -31,7 +31,7 @@
if (*fd < 0)
return *fd;
- ret = ion_alloc(*fd, len, align, alloc_flags, handle);
+ ret = ion_alloc(*fd, len, align, heap_mask, alloc_flags, handle);
if (ret)
printf("%s failed: %s\n", __func__, strerror(ret));
@@ -203,17 +203,16 @@
static struct option opts[] = {
{"alloc", no_argument, 0, 'a'},
{"alloc_flags", required_argument, 0, 'f'},
+ {"heap_mask", required_argument, 0, 'h'},
{"map", no_argument, 0, 'm'},
{"share", no_argument, 0, 's'},
{"len", required_argument, 0, 'l'},
{"align", required_argument, 0, 'g'},
{"map_flags", required_argument, 0, 'z'},
{"prot", required_argument, 0, 'p'},
- {"width", required_argument, 0, 'w'},
- {"height", required_argument, 0, 'h'},
};
int i = 0;
- c = getopt_long(argc, argv, "af:h:l:mr:stw:", opts, &i);
+ c = getopt_long(argc, argv, "af:h:l:mr:st", opts, &i);
if (c == -1)
break;
@@ -245,6 +244,9 @@
case 'f':
alloc_flags = atol(optarg);
break;
+ case 'h':
+ heap_mask = atol(optarg);
+ break;
case 'a':
test = ALLOC_TEST;
break;
@@ -254,17 +256,11 @@
case 's':
test = SHARE_TEST;
break;
- case 'w':
- width = atol(optarg);
- break;
- case 'h':
- height = atol(optarg);
- break;
}
}
- printf("test %d, len %u, width %u, height %u align %u, "
- "map_flags %d, prot %d, alloc_flags %d\n", test, len, width,
- height, align, map_flags, prot, alloc_flags);
+ printf("test %d, len %u, align %u, map_flags %d, prot %d, heap_mask %d,"
+ " alloc_flags %d\n", test, len, align, map_flags, prot,
+ heap_mask, alloc_flags);
switch (test) {
case ALLOC_TEST:
ion_alloc_test();
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index a0a753b..b91de52 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -141,6 +141,7 @@
/* XXX: This needs to go! */
if (!strcmp(tag, "HTC_RIL") ||
!strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
+ !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
!strcmp(tag, "AT") ||
!strcmp(tag, "GSM") ||
!strcmp(tag, "STK") ||
@@ -169,6 +170,7 @@
/* XXX: This needs to go! */
if (!strcmp(tag, "HTC_RIL") ||
!strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
+ !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
!strcmp(tag, "AT") ||
!strcmp(tag, "GSM") ||
!strcmp(tag, "STK") ||
diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk
index b09a941..f58eab9 100644
--- a/libmincrypt/Android.mk
+++ b/libmincrypt/Android.mk
@@ -4,13 +4,13 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libmincrypt
-LOCAL_SRC_FILES := rsa.c sha.c
+LOCAL_SRC_FILES := rsa.c rsa_e_3.c rsa_e_f4.c sha.c
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libmincrypt
-LOCAL_SRC_FILES := rsa.c sha.c
+LOCAL_SRC_FILES := rsa.c rsa_e_3.c rsa_e_f4.c sha.c
include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libmincrypt/rsa.c b/libmincrypt/rsa.c
index d7124fb..b4ee6af 100644
--- a/libmincrypt/rsa.c
+++ b/libmincrypt/rsa.c
@@ -1,6 +1,6 @@
/* rsa.c
**
-** Copyright 2008, The Android Open Source Project
+** Copyright 2012, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
@@ -13,186 +13,42 @@
** be used to endorse or promote products derived from this software
** without specific prior written permission.
**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+** THIS SOFTWARE IS PROVIDED BY Google Inc. ``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
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
** EVENT SHALL Google Inc. 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
+** 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 "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
-/* a[] -= mod */
-static void subM(const RSAPublicKey *key, uint32_t *a) {
- int64_t A = 0;
- int i;
- for (i = 0; i < key->len; ++i) {
- A += (uint64_t)a[i] - key->n[i];
- a[i] = (uint32_t)A;
- A >>= 32;
- }
-}
+int RSA_e_f4_verify(const RSAPublicKey* key,
+ const uint8_t* signature,
+ const int len,
+ const uint8_t* sha);
-/* return a[] >= mod */
-static int geM(const RSAPublicKey *key, const uint32_t *a) {
- int i;
- for (i = key->len; i;) {
- --i;
- if (a[i] < key->n[i]) return 0;
- if (a[i] > key->n[i]) return 1;
- }
- return 1; /* equal */
-}
+int RSA_e_3_verify(const RSAPublicKey *key,
+ const uint8_t *signature,
+ const int len,
+ const uint8_t *sha);
-/* montgomery c[] += a * b[] / R % mod */
-static void montMulAdd(const RSAPublicKey *key,
- uint32_t* c,
- const uint32_t a,
- const uint32_t* b) {
- uint64_t A = (uint64_t)a * b[0] + c[0];
- uint32_t d0 = (uint32_t)A * key->n0inv;
- uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
- int i;
-
- for (i = 1; i < key->len; ++i) {
- A = (A >> 32) + (uint64_t)a * b[i] + c[i];
- B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
- c[i - 1] = (uint32_t)B;
- }
-
- A = (A >> 32) + (B >> 32);
-
- c[i - 1] = (uint32_t)A;
-
- if (A >> 32) {
- subM(key, c);
- }
-}
-
-/* montgomery c[] = a[] * b[] / R % mod */
-static void montMul(const RSAPublicKey *key,
- uint32_t* c,
- const uint32_t* a,
- const uint32_t* b) {
- int i;
- for (i = 0; i < key->len; ++i) {
- c[i] = 0;
- }
- for (i = 0; i < key->len; ++i) {
- montMulAdd(key, c, a[i], b);
- }
-}
-
-/* In-place public exponentiation.
-** Input and output big-endian byte array in inout.
-*/
-static void modpow3(const RSAPublicKey *key,
- uint8_t* inout) {
- uint32_t a[RSANUMWORDS];
- uint32_t aR[RSANUMWORDS];
- uint32_t aaR[RSANUMWORDS];
- uint32_t *aaa = aR; /* Re-use location. */
- int i;
-
- /* Convert from big endian byte array to little endian word array. */
- for (i = 0; i < key->len; ++i) {
- uint32_t tmp =
- (inout[((key->len - 1 - i) * 4) + 0] << 24) |
- (inout[((key->len - 1 - i) * 4) + 1] << 16) |
- (inout[((key->len - 1 - i) * 4) + 2] << 8) |
- (inout[((key->len - 1 - i) * 4) + 3] << 0);
- a[i] = tmp;
- }
-
- montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */
- montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */
- montMul(key, aaa, aaR, a); /* aaa = aaR * a / R mod M */
-
- /* Make sure aaa < mod; aaa is at most 1x mod too large. */
- if (geM(key, aaa)) {
- subM(key, aaa);
- }
-
- /* Convert to bigendian byte array */
- for (i = key->len - 1; i >= 0; --i) {
- uint32_t tmp = aaa[i];
- *inout++ = tmp >> 24;
- *inout++ = tmp >> 16;
- *inout++ = tmp >> 8;
- *inout++ = tmp >> 0;
- }
-}
-
-/* Expected PKCS1.5 signature padding bytes, for a keytool RSA signature.
-** Has the 0-length optional parameter encoded in the ASN1 (as opposed to the
-** other flavor which omits the optional parameter entirely). This code does not
-** accept signatures without the optional parameter.
-*/
-static const uint8_t padding[RSANUMBYTES - SHA_DIGEST_SIZE] = {
- 0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
- 0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,
- 0x04,0x14
-};
-
-/* Verify a 2048 bit RSA PKCS1.5 signature against an expected SHA-1 hash.
-** Returns 0 on failure, 1 on success.
-*/
int RSA_verify(const RSAPublicKey *key,
const uint8_t *signature,
const int len,
const uint8_t *sha) {
- uint8_t buf[RSANUMBYTES];
- int i;
-
- if (key->len != RSANUMWORDS) {
- return 0; /* Wrong key passed in. */
- }
-
- if (len != sizeof(buf)) {
- return 0; /* Wrong input length. */
- }
-
- for (i = 0; i < len; ++i) {
- buf[i] = signature[i];
- }
-
- modpow3(key, buf);
-
- /* Check pkcs1.5 padding bytes. */
- for (i = 0; i < (int) sizeof(padding); ++i) {
- if (buf[i] != padding[i]) {
+ switch (key->exponent) {
+ case 3:
+ return RSA_e_3_verify(key, signature, len, sha);
+ break;
+ case 65537:
+ return RSA_e_f4_verify(key, signature, len, sha);
+ break;
+ default:
return 0;
- }
}
-
- /* Check sha digest matches. */
- for (; i < len; ++i) {
- if (buf[i] != *sha++) {
- return 0;
- }
- }
-
- return 1;
}
diff --git a/libmincrypt/rsa_e_3.c b/libmincrypt/rsa_e_3.c
new file mode 100644
index 0000000..c8c02c4
--- /dev/null
+++ b/libmincrypt/rsa_e_3.c
@@ -0,0 +1,202 @@
+/* rsa_e_3.c
+**
+** Copyright 2008, The Android Open Source Project
+**
+** 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 Google Inc. ``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 Google Inc. 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 "mincrypt/rsa.h"
+#include "mincrypt/sha.h"
+
+/* a[] -= mod */
+static void subM(const RSAPublicKey *key, uint32_t *a) {
+ int64_t A = 0;
+ int i;
+ for (i = 0; i < key->len; ++i) {
+ A += (uint64_t)a[i] - key->n[i];
+ a[i] = (uint32_t)A;
+ A >>= 32;
+ }
+}
+
+/* return a[] >= mod */
+static int geM(const RSAPublicKey *key, const uint32_t *a) {
+ int i;
+ for (i = key->len; i;) {
+ --i;
+ if (a[i] < key->n[i]) return 0;
+ if (a[i] > key->n[i]) return 1;
+ }
+ return 1; /* equal */
+}
+
+/* montgomery c[] += a * b[] / R % mod */
+static void montMulAdd(const RSAPublicKey *key,
+ uint32_t* c,
+ const uint32_t a,
+ const uint32_t* b) {
+ uint64_t A = (uint64_t)a * b[0] + c[0];
+ uint32_t d0 = (uint32_t)A * key->n0inv;
+ uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
+ int i;
+
+ for (i = 1; i < key->len; ++i) {
+ A = (A >> 32) + (uint64_t)a * b[i] + c[i];
+ B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
+ c[i - 1] = (uint32_t)B;
+ }
+
+ A = (A >> 32) + (B >> 32);
+
+ c[i - 1] = (uint32_t)A;
+
+ if (A >> 32) {
+ subM(key, c);
+ }
+}
+
+/* montgomery c[] = a[] * b[] / R % mod */
+static void montMul(const RSAPublicKey *key,
+ uint32_t* c,
+ const uint32_t* a,
+ const uint32_t* b) {
+ int i;
+ for (i = 0; i < key->len; ++i) {
+ c[i] = 0;
+ }
+ for (i = 0; i < key->len; ++i) {
+ montMulAdd(key, c, a[i], b);
+ }
+}
+
+/* In-place public exponentiation.
+** Input and output big-endian byte array in inout.
+*/
+static void modpow3(const RSAPublicKey *key,
+ uint8_t* inout) {
+ uint32_t a[RSANUMWORDS];
+ uint32_t aR[RSANUMWORDS];
+ uint32_t aaR[RSANUMWORDS];
+ uint32_t *aaa = aR; /* Re-use location. */
+ int i;
+
+ /* Convert from big endian byte array to little endian word array. */
+ for (i = 0; i < key->len; ++i) {
+ uint32_t tmp =
+ (inout[((key->len - 1 - i) * 4) + 0] << 24) |
+ (inout[((key->len - 1 - i) * 4) + 1] << 16) |
+ (inout[((key->len - 1 - i) * 4) + 2] << 8) |
+ (inout[((key->len - 1 - i) * 4) + 3] << 0);
+ a[i] = tmp;
+ }
+
+ montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */
+ montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */
+ montMul(key, aaa, aaR, a); /* aaa = aaR * a / R mod M */
+
+ /* Make sure aaa < mod; aaa is at most 1x mod too large. */
+ if (geM(key, aaa)) {
+ subM(key, aaa);
+ }
+
+ /* Convert to bigendian byte array */
+ for (i = key->len - 1; i >= 0; --i) {
+ uint32_t tmp = aaa[i];
+ *inout++ = tmp >> 24;
+ *inout++ = tmp >> 16;
+ *inout++ = tmp >> 8;
+ *inout++ = tmp >> 0;
+ }
+}
+
+/* Expected PKCS1.5 signature padding bytes, for a keytool RSA signature.
+** Has the 0-length optional parameter encoded in the ASN1 (as opposed to the
+** other flavor which omits the optional parameter entirely). This code does not
+** accept signatures without the optional parameter.
+*/
+static const uint8_t padding[RSANUMBYTES - SHA_DIGEST_SIZE] = {
+ 0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
+ 0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,
+ 0x04,0x14
+};
+
+/* Verify a 2048 bit RSA e=3 PKCS1.5 signature against an expected SHA-1 hash.
+** Returns 0 on failure, 1 on success.
+*/
+int RSA_e_3_verify(const RSAPublicKey *key,
+ const uint8_t *signature,
+ const int len,
+ const uint8_t *sha) {
+ uint8_t buf[RSANUMBYTES];
+ int i;
+
+ if (key->len != RSANUMWORDS) {
+ return 0; /* Wrong key passed in. */
+ }
+
+ if (len != sizeof(buf)) {
+ return 0; /* Wrong input length. */
+ }
+
+ if (key->exponent != 3) {
+ return 0; // Wrong exponent.
+ }
+
+ for (i = 0; i < len; ++i) {
+ buf[i] = signature[i];
+ }
+
+ modpow3(key, buf);
+
+ /* Check pkcs1.5 padding bytes. */
+ for (i = 0; i < (int) sizeof(padding); ++i) {
+ if (buf[i] != padding[i]) {
+ return 0;
+ }
+ }
+
+ /* Check sha digest matches. */
+ for (; i < len; ++i) {
+ if (buf[i] != *sha++) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
diff --git a/libmincrypt/rsa_e_f4.c b/libmincrypt/rsa_e_f4.c
new file mode 100644
index 0000000..6701bcc
--- /dev/null
+++ b/libmincrypt/rsa_e_f4.c
@@ -0,0 +1,196 @@
+/* rsa_e_f4.c
+**
+** Copyright 2012, The Android Open Source Project
+**
+** 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 Google Inc. ``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 Google Inc. 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 "mincrypt/rsa.h"
+#include "mincrypt/sha.h"
+
+// a[] -= mod
+static void subM(const RSAPublicKey* key,
+ uint32_t* a) {
+ int64_t A = 0;
+ int i;
+ for (i = 0; i < key->len; ++i) {
+ A += (uint64_t)a[i] - key->n[i];
+ a[i] = (uint32_t)A;
+ A >>= 32;
+ }
+}
+
+// return a[] >= mod
+static int geM(const RSAPublicKey* key,
+ const uint32_t* a) {
+ int i;
+ for (i = key->len; i;) {
+ --i;
+ if (a[i] < key->n[i]) return 0;
+ if (a[i] > key->n[i]) return 1;
+ }
+ return 1; // equal
+}
+
+// montgomery c[] += a * b[] / R % mod
+static void montMulAdd(const RSAPublicKey* key,
+ uint32_t* c,
+ const uint32_t a,
+ const uint32_t* b) {
+ uint64_t A = (uint64_t)a * b[0] + c[0];
+ uint32_t d0 = (uint32_t)A * key->n0inv;
+ uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
+ int i;
+
+ for (i = 1; i < key->len; ++i) {
+ A = (A >> 32) + (uint64_t)a * b[i] + c[i];
+ B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
+ c[i - 1] = (uint32_t)B;
+ }
+
+ A = (A >> 32) + (B >> 32);
+
+ c[i - 1] = (uint32_t)A;
+
+ if (A >> 32) {
+ subM(key, c);
+ }
+}
+
+// montgomery c[] = a[] * b[] / R % mod
+static void montMul(const RSAPublicKey* key,
+ uint32_t* c,
+ const uint32_t* a,
+ const uint32_t* b) {
+ int i;
+ for (i = 0; i < key->len; ++i) {
+ c[i] = 0;
+ }
+ for (i = 0; i < key->len; ++i) {
+ montMulAdd(key, c, a[i], b);
+ }
+}
+
+// In-place public exponentiation.
+// Input and output big-endian byte array in inout.
+static void modpowF4(const RSAPublicKey* key,
+ uint8_t* inout) {
+ uint32_t a[RSANUMWORDS];
+ uint32_t aR[RSANUMWORDS];
+ uint32_t aaR[RSANUMWORDS];
+ uint32_t* aaa = aaR; // Re-use location.
+ int i;
+
+ // Convert from big endian byte array to little endian word array.
+ for (i = 0; i < key->len; ++i) {
+ uint32_t tmp =
+ (inout[((key->len - 1 - i) * 4) + 0] << 24) |
+ (inout[((key->len - 1 - i) * 4) + 1] << 16) |
+ (inout[((key->len - 1 - i) * 4) + 2] << 8) |
+ (inout[((key->len - 1 - i) * 4) + 3] << 0);
+ a[i] = tmp;
+ }
+
+ montMul(key, aR, a, key->rr); // aR = a * RR / R mod M
+ for (i = 0; i < 16; i += 2) {
+ montMul(key, aaR, aR, aR); // aaR = aR * aR / R mod M
+ montMul(key, aR, aaR, aaR); // aR = aaR * aaR / R mod M
+ }
+ montMul(key, aaa, aR, a); // aaa = aR * a / R mod M
+
+ // Make sure aaa < mod; aaa is at most 1x mod too large.
+ if (geM(key, aaa)) {
+ subM(key, aaa);
+ }
+
+ // Convert to bigendian byte array
+ for (i = key->len - 1; i >= 0; --i) {
+ uint32_t tmp = aaa[i];
+ *inout++ = tmp >> 24;
+ *inout++ = tmp >> 16;
+ *inout++ = tmp >> 8;
+ *inout++ = tmp >> 0;
+ }
+}
+
+// Expected PKCS1.5 signature padding bytes, for a keytool RSA signature.
+// Has the 0-length optional parameter encoded in the ASN1 (as opposed to the
+// other flavor which omits the optional parameter entirely). This code does not
+// accept signatures without the optional parameter.
+/*
+static const uint8_t padding[RSANUMBYTES] = {
+0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
+*/
+
+// SHA-1 of PKCS1.5 signature padding for 2048 bit, as above.
+// At the location of the bytes of the hash all 00 are hashed.
+static const uint8_t kExpectedPadShaRsa2048[SHA_DIGEST_SIZE] = {
+ 0xdc, 0xbd, 0xbe, 0x42, 0xd5, 0xf5, 0xa7, 0x2e, 0x6e, 0xfc,
+ 0xf5, 0x5d, 0xaf, 0x9d, 0xea, 0x68, 0x7c, 0xfb, 0xf1, 0x67
+};
+
+// Verify a 2048 bit RSA e=65537 PKCS1.5 signature against an expected
+// SHA-1 hash. Returns 0 on failure, 1 on success.
+int RSA_e_f4_verify(const RSAPublicKey* key,
+ const uint8_t* signature,
+ const int len,
+ const uint8_t* sha) {
+ uint8_t buf[RSANUMBYTES];
+ int i;
+
+ if (key->len != RSANUMWORDS) {
+ return 0; // Wrong key passed in.
+ }
+
+ if (len != sizeof(buf)) {
+ return 0; // Wrong input length.
+ }
+
+ if (key->exponent != 65537) {
+ return 0; // Wrong exponent.
+ }
+
+ for (i = 0; i < len; ++i) { // Copy input to local workspace.
+ buf[i] = signature[i];
+ }
+
+ modpowF4(key, buf); // In-place exponentiation.
+
+ // Xor sha portion, so it all becomes 00 iff equal.
+ for (i = len - SHA_DIGEST_SIZE; i < len; ++i) {
+ buf[i] ^= *sha++;
+ }
+
+ // Hash resulting buf, in-place.
+ SHA(buf, len, buf);
+
+ // Compare against expected hash value.
+ for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
+ if (buf[i] != kExpectedPadShaRsa2048[i]) {
+ return 0;
+ }
+ }
+
+ return 1; // All checked out OK.
+}
diff --git a/libmincrypt/tools/DumpPublicKey.java b/libmincrypt/tools/DumpPublicKey.java
index d2935e0..12b4f56 100644
--- a/libmincrypt/tools/DumpPublicKey.java
+++ b/libmincrypt/tools/DumpPublicKey.java
@@ -24,7 +24,6 @@
import java.security.Key;
import java.security.PublicKey;
import java.security.interfaces.RSAPublicKey;
-import sun.misc.BASE64Encoder;
/**
* Command line tool to extract RSA public keys from X.509 certificates
@@ -34,27 +33,42 @@
class DumpPublicKey {
/**
* @param key to perform sanity checks on
+ * @return version number of key. Supported versions are:
+ * 1: 2048-bit key with e=3
+ * 2: 2048-bit key with e=65537
* @throws Exception if the key has the wrong size or public exponent
+
*/
- static void check(RSAPublicKey key) throws Exception {
+ static int check(RSAPublicKey key) throws Exception {
BigInteger pubexp = key.getPublicExponent();
BigInteger modulus = key.getModulus();
+ int version;
- if (!pubexp.equals(BigInteger.valueOf(3)))
- throw new Exception("Public exponent should be 3 but is " +
- pubexp.toString(10) + ".");
+ if (pubexp.equals(BigInteger.valueOf(3))) {
+ version = 1;
+ } else if (pubexp.equals(BigInteger.valueOf(65537))) {
+ version = 2;
+ } else {
+ throw new Exception("Public exponent should be 3 or 65537 but is " +
+ pubexp.toString(10) + ".");
+ }
- if (modulus.bitLength() != 2048)
+ if (modulus.bitLength() != 2048) {
throw new Exception("Modulus should be 2048 bits long but is " +
modulus.bitLength() + " bits.");
+ }
+
+ return version;
}
/**
* @param key to output
- * @return a C initializer representing this public key.
+ * @return a String representing this public key. If the key is a
+ * version 1 key, the string will be a C initializer; this is
+ * not true for newer key versions.
*/
static String print(RSAPublicKey key) throws Exception {
- check(key);
+ int version = check(key);
BigInteger N = key.getModulus();
@@ -62,6 +76,12 @@
int nwords = N.bitLength() / 32; // # of 32 bit integers in modulus
+ if (version > 1) {
+ result.append("v");
+ result.append(Integer.toString(version));
+ result.append(" ");
+ }
+
result.append("{");
result.append(nwords);
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index 903a1db..d0ca90a 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -29,6 +29,7 @@
static const char DAEMON_PROP_NAME[] = "init.svc.dhcpcd";
static const char HOSTNAME_PROP_NAME[] = "net.hostname";
static const char DHCP_PROP_NAME_PREFIX[] = "dhcp";
+static const char DHCP_CONFIG_PATH[] = "/system/etc/dhcpcd/dhcpcd.conf";
static const int NAP_TIME = 200; /* wait for 200ms at a time */
/* when polling for property values */
static const char DAEMON_NAME_RENEW[] = "iprenew";
@@ -170,7 +171,7 @@
* The device init.rc file needs a corresponding entry for this work.
*
* Example:
- * service dhcpcd_<interface> /system/bin/dhcpcd -ABKL
+ * service dhcpcd_<interface> /system/bin/dhcpcd -ABKL -f dhcpcd.conf
*/
int dhcp_do_request(const char *interface,
char *ipaddr,
@@ -185,7 +186,7 @@
char result_prop_name[PROPERTY_KEY_MAX];
char daemon_prop_name[PROPERTY_KEY_MAX];
char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
- char daemon_cmd[PROPERTY_VALUE_MAX * 2];
+ char daemon_cmd[PROPERTY_VALUE_MAX * 2 + sizeof(DHCP_CONFIG_PATH)];
const char *ctrl_prop = "ctl.start";
const char *desired_status = "running";
/* Interface name after converting p2p0-p2p0-X to p2p to reuse system properties */
@@ -206,10 +207,11 @@
/* Start the daemon and wait until it's ready */
if (property_get(HOSTNAME_PROP_NAME, prop_value, NULL) && (prop_value[0] != '\0'))
- snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-h %s %s", DAEMON_NAME, p2p_interface,
- prop_value, interface);
+ snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s -h %s %s", DAEMON_NAME,
+ p2p_interface, DHCP_CONFIG_PATH, prop_value, interface);
else
- snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:%s", DAEMON_NAME, p2p_interface, interface);
+ snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s %s", DAEMON_NAME,
+ DHCP_CONFIG_PATH, p2p_interface, interface);
memset(prop_value, '\0', PROPERTY_VALUE_MAX);
property_set(ctrl_prop, daemon_cmd);
if (wait_for_property(daemon_prop_name, desired_status, 10) < 0) {
diff --git a/libnl_2/Android.mk b/libnl_2/Android.mk
index 1745f5a..deac9de 100644
--- a/libnl_2/Android.mk
+++ b/libnl_2/Android.mk
@@ -1,5 +1,11 @@
+#######################################
+# * Netlink cache not implemented
+# * Library is not thread safe
+#######################################
+
LOCAL_PATH := $(call my-dir)
+
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
@@ -22,9 +28,10 @@
LOCAL_MODULE_TAGS := optional
include $(BUILD_STATIC_LIBRARY)
-#######################################
-# Shared library currently unavailiable
-# * Netlink cache not implemented
-# * Library is not thread safe
-#######################################
-
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES :=
+LOCAL_WHOLE_STATIC_LIBRARIES:= libnl_2
+LOCAL_SHARED_LIBRARIES:= liblog
+LOCAL_MODULE := libnl_2
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libnl_2/attr.c b/libnl_2/attr.c
index f3a2b58..2ef7590 100644
--- a/libnl_2/attr.c
+++ b/libnl_2/attr.c
@@ -160,9 +160,31 @@
}
return -EINVAL;
-
}
+/* Add 8 bit integer attribute to netlink message. */
+int nla_put_u8(struct nl_msg *msg, int attrtype, uint8_t value)
+{
+ return nla_put(msg, attrtype, sizeof(uint8_t), &value);
+}
+
+/* Add 16 bit integer attribute to netlink message. */
+int nla_put_u16(struct nl_msg *msg, int attrtype, uint16_t value)
+{
+ return nla_put(msg, attrtype, sizeof(uint16_t), &value);
+}
+
+/* Add 32 bit integer attribute to netlink message. */
+int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value)
+{
+ return nla_put(msg, attrtype, sizeof(uint32_t), &value);
+}
+
+/* Add 64 bit integer attribute to netlink message. */
+int nla_put_u64(struct nl_msg *msg, int attrtype, uint64_t value)
+{
+ return nla_put(msg, attrtype, sizeof(uint64_t), &value);
+}
/* Add nested attributes to netlink message. */
/* Takes the attributes found in the nested message and appends them
diff --git a/libnl_2/genl/genl.c b/libnl_2/genl/genl.c
index 1e127af..1a39c6a 100644
--- a/libnl_2/genl/genl.c
+++ b/libnl_2/genl/genl.c
@@ -22,6 +22,8 @@
#include <sys/time.h>
#include <sys/socket.h>
#include <linux/netlink.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/genl/family.h>
#include "netlink-types.h"
/* Get head of attribute data. */
@@ -251,7 +253,6 @@
struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache, \
const char *name)
{
- /* TODO: When will we release this memory ? */
struct genl_family *gf = (struct genl_family *) \
malloc(sizeof(struct genl_family));
if (!gf)
@@ -263,7 +264,7 @@
/* Overriding cache pointer as family id for now */
gf->gf_id = (uint16_t) ((uint32_t) cache);
- strcpy(gf->gf_name, "nl80211");
+ strncpy(gf->gf_name, name, GENL_NAMSIZ);
return gf;
fail:
@@ -273,15 +274,29 @@
int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
{
+ struct nl_cache *cache = NULL;
+ struct genl_family *gf = NULL;
+ int id = -1;
+
/* Hack to support wpa_supplicant */
if (strcmp(name, "nlctrl") == 0)
return NETLINK_GENERIC;
- else {
- int errsv = errno;
- fprintf(stderr, \
- "Only nlctrl supported by genl_ctrl_resolve!\n");
- return -errsv;
+
+ if (strcmp(name, "nl80211") != 0) {
+ fprintf(stderr, "%s is not supported\n", name);
+ return id;
}
-}
+ if (!genl_ctrl_alloc_cache(sk, &cache)) {
+ gf = genl_ctrl_search_by_name(cache, name);
+ if (gf)
+ id = genl_family_get_id(gf);
+ }
+ if (gf)
+ genl_family_put(gf);
+ if (cache)
+ nl_cache_free(cache);
+
+ return id;
+}
diff --git a/libnl_2/socket.c b/libnl_2/socket.c
index d906cac..e94eb9e 100644
--- a/libnl_2/socket.c
+++ b/libnl_2/socket.c
@@ -127,3 +127,15 @@
{
return sk->s_fd;
}
+
+void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb)
+{
+ nl_cb_put(sk->s_cb);
+ sk->s_cb = cb;
+ nl_cb_get(cb);
+}
+
+struct nl_cb *nl_socket_get_cb(struct nl_sock *sk)
+{
+ return nl_cb_get(sk->s_cb);
+}
diff --git a/libsuspend/autosuspend_autosleep.c b/libsuspend/autosuspend_autosleep.c
index dd0dfef..5451615 100644
--- a/libsuspend/autosuspend_autosleep.c
+++ b/libsuspend/autosuspend_autosleep.c
@@ -95,5 +95,8 @@
}
ALOGI("Selected autosleep\n");
+
+ autosuspend_autosleep_disable();
+
return &autosuspend_autosleep_ops;
}
diff --git a/libsuspend/autosuspend_earlysuspend.c b/libsuspend/autosuspend_earlysuspend.c
index 2c2aa36..1df8c6a 100644
--- a/libsuspend/autosuspend_earlysuspend.c
+++ b/libsuspend/autosuspend_earlysuspend.c
@@ -16,6 +16,8 @@
#include <errno.h>
#include <fcntl.h>
+#include <pthread.h>
+#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
@@ -31,11 +33,75 @@
#define EARLYSUSPEND_WAIT_FOR_FB_SLEEP "/sys/power/wait_for_fb_sleep"
#define EARLYSUSPEND_WAIT_FOR_FB_WAKE "/sys/power/wait_for_fb_wake"
-
static int sPowerStatefd;
static const char *pwr_state_mem = "mem";
static const char *pwr_state_on = "on";
+static pthread_t earlysuspend_thread;
+static pthread_mutex_t earlysuspend_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t earlysuspend_cond = PTHREAD_COND_INITIALIZER;
+static bool wait_for_earlysuspend;
+static enum {
+ EARLYSUSPEND_ON,
+ EARLYSUSPEND_MEM,
+} earlysuspend_state = EARLYSUSPEND_ON;
+int wait_for_fb_wake(void)
+{
+ int err = 0;
+ char buf;
+ int fd = open(EARLYSUSPEND_WAIT_FOR_FB_WAKE, O_RDONLY, 0);
+ // if the file doesn't exist, the error will be caught in read() below
+ do {
+ err = read(fd, &buf, 1);
+ } while (err < 0 && errno == EINTR);
+ ALOGE_IF(err < 0,
+ "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
+ close(fd);
+ return err < 0 ? err : 0;
+}
+
+static int wait_for_fb_sleep(void)
+{
+ int err = 0;
+ char buf;
+ int fd = open(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, O_RDONLY, 0);
+ // if the file doesn't exist, the error will be caught in read() below
+ do {
+ err = read(fd, &buf, 1);
+ } while (err < 0 && errno == EINTR);
+ ALOGE_IF(err < 0,
+ "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
+ close(fd);
+ return err < 0 ? err : 0;
+}
+
+static void *earlysuspend_thread_func(void *arg)
+{
+ char buf[80];
+ char wakeup_count[20];
+ int wakeup_count_len;
+ int ret;
+
+ while (1) {
+ if (wait_for_fb_sleep()) {
+ ALOGE("Failed reading wait_for_fb_sleep, exiting earlysuspend thread\n");
+ return NULL;
+ }
+ pthread_mutex_lock(&earlysuspend_mutex);
+ earlysuspend_state = EARLYSUSPEND_MEM;
+ pthread_cond_signal(&earlysuspend_cond);
+ pthread_mutex_unlock(&earlysuspend_mutex);
+
+ if (wait_for_fb_wake()) {
+ ALOGE("Failed reading wait_for_fb_wake, exiting earlysuspend thread\n");
+ return NULL;
+ }
+ pthread_mutex_lock(&earlysuspend_mutex);
+ earlysuspend_state = EARLYSUSPEND_ON;
+ pthread_cond_signal(&earlysuspend_cond);
+ pthread_mutex_unlock(&earlysuspend_mutex);
+ }
+}
static int autosuspend_earlysuspend_enable(void)
{
char buf[80];
@@ -50,6 +116,14 @@
goto err;
}
+ if (wait_for_earlysuspend) {
+ pthread_mutex_lock(&earlysuspend_mutex);
+ while (earlysuspend_state != EARLYSUSPEND_MEM) {
+ pthread_cond_wait(&earlysuspend_cond, &earlysuspend_mutex);
+ }
+ pthread_mutex_unlock(&earlysuspend_mutex);
+ }
+
ALOGV("autosuspend_earlysuspend_enable done\n");
return 0;
@@ -72,6 +146,14 @@
goto err;
}
+ if (wait_for_earlysuspend) {
+ pthread_mutex_lock(&earlysuspend_mutex);
+ while (earlysuspend_state != EARLYSUSPEND_ON) {
+ pthread_cond_wait(&earlysuspend_cond, &earlysuspend_mutex);
+ }
+ pthread_mutex_unlock(&earlysuspend_mutex);
+ }
+
ALOGV("autosuspend_earlysuspend_disable done\n");
return 0;
@@ -85,29 +167,61 @@
.disable = autosuspend_earlysuspend_disable,
};
-struct autosuspend_ops *autosuspend_earlysuspend_init(void)
+void start_earlysuspend_thread(void)
{
char buf[80];
int ret;
ret = access(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, F_OK);
if (ret < 0) {
- return NULL;
+ return;
}
ret = access(EARLYSUSPEND_WAIT_FOR_FB_WAKE, F_OK);
if (ret < 0) {
- return NULL;
+ return;
}
+ wait_for_fb_wake();
+
+ ALOGI("Starting early suspend unblocker thread\n");
+ ret = pthread_create(&earlysuspend_thread, NULL, earlysuspend_thread_func, NULL);
+ if (ret) {
+ strerror_r(errno, buf, sizeof(buf));
+ ALOGE("Error creating thread: %s\n", buf);
+ return;
+ }
+
+ wait_for_earlysuspend = true;
+}
+
+struct autosuspend_ops *autosuspend_earlysuspend_init(void)
+{
+ char buf[80];
+ int ret;
+
sPowerStatefd = open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR);
if (sPowerStatefd < 0) {
strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error opening %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
+ ALOGW("Error opening %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
return NULL;
}
+ ret = write(sPowerStatefd, "on", 2);
+ if (ret < 0) {
+ strerror_r(errno, buf, sizeof(buf));
+ ALOGW("Error writing 'on' to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
+ goto err_write;
+ }
+
ALOGI("Selected early suspend\n");
+
+ start_earlysuspend_thread();
+
return &autosuspend_earlysuspend_ops;
+
+err_write:
+ close(sPowerStatefd);
+ return NULL;
}
diff --git a/libsync/sync.c b/libsync/sync.c
index 311da14..4892866 100644
--- a/libsync/sync.c
+++ b/libsync/sync.c
@@ -20,15 +20,16 @@
#include <stdint.h>
#include <string.h>
+#include <linux/sync.h>
+#include <linux/sw_sync.h>
+
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sync/sync.h>
-
-int sync_wait(int fd, unsigned int timeout)
+int sync_wait(int fd, int timeout)
{
- __u32 to = timeout;
+ __s32 to = timeout;
return ioctl(fd, SYNC_IOC_WAIT, &to);
}
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 5d261cd..c059b89 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -49,7 +49,8 @@
#include "usbhost/usbhost.h"
-#define USB_FS_DIR "/dev/bus/usb"
+#define DEV_DIR "/dev"
+#define USB_FS_DIR "/dev/bus/usb"
#define USB_FS_ID_SCANNER "/dev/bus/usb/%d/%d"
#define USB_FS_ID_FORMAT "/dev/bus/usb/%03d/%03d"
@@ -77,39 +78,72 @@
return 0;
}
+static int find_existing_devices_bus(char *busname,
+ usb_device_added_cb added_cb,
+ void *client_data)
+{
+ char devname[32];
+ DIR *devdir;
+ struct dirent *de;
+ int done = 0;
+
+ devdir = opendir(busname);
+ if(devdir == 0) return 0;
+
+ while ((de = readdir(devdir)) && !done) {
+ if(badname(de->d_name)) continue;
+
+ snprintf(devname, sizeof(devname), "%s/%s", busname, de->d_name);
+ done = added_cb(devname, client_data);
+ } // end of devdir while
+ closedir(devdir);
+
+ return done;
+}
+
/* returns true if one of the callbacks indicates we are done */
static int find_existing_devices(usb_device_added_cb added_cb,
- usb_device_removed_cb removed_cb,
void *client_data)
{
- char busname[32], devname[32];
- DIR *busdir , *devdir ;
+ char busname[32];
+ DIR *busdir;
struct dirent *de;
int done = 0;
busdir = opendir(USB_FS_DIR);
- if(busdir == 0) return 1;
+ if(busdir == 0) return 0;
while ((de = readdir(busdir)) != 0 && !done) {
if(badname(de->d_name)) continue;
- snprintf(busname, sizeof busname, "%s/%s", USB_FS_DIR, de->d_name);
- devdir = opendir(busname);
- if(devdir == 0) continue;
-
- while ((de = readdir(devdir)) && !done) {
- if(badname(de->d_name)) continue;
-
- snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name);
- done = added_cb(devname, client_data);
- } // end of devdir while
- closedir(devdir);
- } //end of busdir while
+ snprintf(busname, sizeof(busname), "%s/%s", USB_FS_DIR, de->d_name);
+ done = find_existing_devices_bus(busname, added_cb,
+ client_data);
+ }
closedir(busdir);
return done;
}
+static void watch_existing_subdirs(struct usb_host_context *context,
+ int *wds, int wd_count)
+{
+ char path[100];
+ int i, ret;
+
+ wds[0] = inotify_add_watch(context->fd, USB_FS_DIR, IN_CREATE | IN_DELETE);
+ if (wds[0] < 0)
+ return;
+
+ /* watch existing subdirectories of USB_FS_DIR */
+ for (i = 1; i < wd_count; i++) {
+ snprintf(path, sizeof(path), "%s/%03d", USB_FS_DIR, i);
+ ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE);
+ if (ret >= 0)
+ wds[i] = ret;
+ }
+}
+
struct usb_host_context *usb_host_init()
{
struct usb_host_context *context = calloc(1, sizeof(struct usb_host_context));
@@ -142,32 +176,28 @@
char event_buf[512];
char path[100];
int i, ret, done = 0;
- int wd, wds[10];
+ int wd, wdd, wds[10];
int wd_count = sizeof(wds) / sizeof(wds[0]);
D("Created device discovery thread\n");
/* watch for files added and deleted within USB_FS_DIR */
- memset(wds, 0, sizeof(wds));
+ for (i = 0; i < wd_count; i++)
+ wds[i] = -1;
+
/* watch the root for new subdirectories */
- wds[0] = inotify_add_watch(context->fd, USB_FS_DIR, IN_CREATE | IN_DELETE);
- if (wds[0] < 0) {
+ wdd = inotify_add_watch(context->fd, DEV_DIR, IN_CREATE | IN_DELETE);
+ if (wdd < 0) {
fprintf(stderr, "inotify_add_watch failed\n");
if (discovery_done_cb)
discovery_done_cb(client_data);
return;
}
- /* watch existing subdirectories of USB_FS_DIR */
- for (i = 1; i < wd_count; i++) {
- snprintf(path, sizeof(path), "%s/%03d", USB_FS_DIR, i);
- ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE);
- if (ret > 0)
- wds[i] = ret;
- }
+ watch_existing_subdirs(context, wds, wd_count);
/* check for existing devices first, after we have inotify set up */
- done = find_existing_devices(added_cb, removed_cb, client_data);
+ done = find_existing_devices(added_cb, client_data);
if (discovery_done_cb)
done |= discovery_done_cb(client_data);
@@ -176,14 +206,35 @@
if (ret >= (int)sizeof(struct inotify_event)) {
event = (struct inotify_event *)event_buf;
wd = event->wd;
- if (wd == wds[0]) {
+ if (wd == wdd) {
+ if ((event->mask & IN_CREATE) && !strcmp(event->name, "bus")) {
+ watch_existing_subdirs(context, wds, wd_count);
+ done = find_existing_devices(added_cb, client_data);
+ } else if ((event->mask & IN_DELETE) && !strcmp(event->name, "bus")) {
+ for (i = 0; i < wd_count; i++) {
+ if (wds[i] >= 0) {
+ inotify_rm_watch(context->fd, wds[i]);
+ wds[i] = -1;
+ }
+ }
+ }
+ } else if (wd == wds[0]) {
i = atoi(event->name);
snprintf(path, sizeof(path), "%s/%s", USB_FS_DIR, event->name);
- D("new subdirectory %s: index: %d\n", path, i);
+ D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ?
+ "new" : "gone", path, i);
if (i > 0 && i < wd_count) {
- ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE);
- if (ret > 0)
- wds[i] = ret;
+ if (event->mask & IN_CREATE) {
+ ret = inotify_add_watch(context->fd, path,
+ IN_CREATE | IN_DELETE);
+ if (ret >= 0)
+ wds[i] = ret;
+ done = find_existing_devices_bus(path, added_cb,
+ client_data);
+ } else if (event->mask & IN_DELETE) {
+ inotify_rm_watch(context->fd, wds[i]);
+ wds[i] = -1;
+ }
}
} else {
for (i = 1; i < wd_count && !done; i++) {
diff --git a/logcat/event.logtags b/logcat/event.logtags
index 2e814ff..6040bd9 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -134,5 +134,24 @@
70200 aggregation (aggregation time|2|3)
70201 aggregation_test (field1|1|2),(field2|1|2),(field3|1|2),(field4|1|2),(field5|1|2)
+# libc failure logging
+80100 bionic_event_memcpy_buffer_overflow (uid|1)
+80105 bionic_event_strcat_buffer_overflow (uid|1)
+80110 bionic_event_memmov_buffer_overflow (uid|1)
+80115 bionic_event_strncat_buffer_overflow (uid|1)
+80120 bionic_event_strncpy_buffer_overflow (uid|1)
+80125 bionic_event_memset_buffer_overflow (uid|1)
+80130 bionic_event_strcpy_buffer_overflow (uid|1)
+
+80200 bionic_event_strcat_integer_overflow (uid|1)
+80205 bionic_event_strncat_integer_overflow (uid|1)
+
+80300 bionic_event_resolver_old_response (uid|1)
+80305 bionic_event_resolver_wrong_server (uid|1)
+80310 bionic_event_resolver_wrong_query (uid|1)
+
+# libcore failure logging
+90100 cert_pin_failure (certs|4)
+
# 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/rootdir/init.rc b/rootdir/init.rc
index 0d9f779..af42223 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -4,8 +4,8 @@
# This is a common source of Android security bugs.
#
-import /init.${ro.hardware}.rc
import /init.usb.rc
+import /init.${ro.hardware}.rc
import /init.trace.rc
on early-init
@@ -34,6 +34,7 @@
export ANDROID_ROOT /system
export ANDROID_ASSETS /system/app
export ANDROID_DATA /data
+ export ANDROID_STORAGE /storage
export ASEC_MOUNTPOINT /mnt/asec
export LOOP_MOUNTPOINT /mnt/obb
export BOOTCLASSPATH /system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar
@@ -56,8 +57,14 @@
mkdir /cache 0770 system cache
mkdir /config 0500 root root
+ # See storage config details at http://source.android.com/tech/storage/
+ mkdir /mnt/shell 0700 shell shell
+ mkdir /storage 0050 root sdcard_r
+
# Directory for putting things only root should see.
mkdir /mnt/secure 0700 root root
+ # Create private mountpoint so we can MS_MOVE from staging
+ mount tmpfs tmpfs /mnt/secure mode=0700,uid=0,gid=0
# Directory for staging bindmounts
mkdir /mnt/secure/staging 0700 root root
@@ -128,6 +135,9 @@
on post-fs
# once everything is setup, no need to modify /
mount rootfs rootfs / ro remount
+ # mount shared so changes propagate into child namespaces
+ mount rootfs rootfs / shared rec
+ mount tmpfs tmpfs /mnt/secure private rec
# We chown/chmod /cache again so because mount is run as root + defaults
chown system cache /cache
@@ -145,11 +155,16 @@
chown root log /proc/vmallocinfo
chmod 0440 /proc/vmallocinfo
+ chown root log /proc/slabinfo
+ chmod 0440 /proc/slabinfo
+
#change permissions on kmsg & sysrq-trigger so bugreports can grab kthread stacks
chown root system /proc/kmsg
chmod 0440 /proc/kmsg
chown root system /proc/sysrq-trigger
chmod 0220 /proc/sysrq-trigger
+ chown system log /proc/last_kmsg
+ chmod 0440 /proc/last_kmsg
# create the lost+found directories, so as to enforce our permissions
mkdir /cache/lost+found 0770 root root
@@ -179,10 +194,12 @@
# create basic filesystem structure
mkdir /data/misc 01771 system misc
- mkdir /data/misc/bluetoothd 0770 bluetooth bluetooth
+ mkdir /data/misc/adb 02750 system shell
+ mkdir /data/misc/bluedroid 0770 bluetooth net_bt_stack
mkdir /data/misc/bluetooth 0770 system system
mkdir /data/misc/keystore 0700 keystore keystore
mkdir /data/misc/keychain 0771 system system
+ mkdir /data/misc/sms 0770 system radio
mkdir /data/misc/zoneinfo 0775 system system
mkdir /data/misc/vpn 0770 system vpn
mkdir /data/misc/systemkeys 0700 system system
@@ -197,6 +214,7 @@
mkdir /data/data 0771 system system
mkdir /data/app-private 0771 system system
mkdir /data/app-asec 0700 root root
+ mkdir /data/app-lib 0771 system system
mkdir /data/app 0771 system system
mkdir /data/property 0700 root root
mkdir /data/ssh 0750 root shell
@@ -252,6 +270,7 @@
chown radio system /sys/android_power/acquire_full_wake_lock
chown radio system /sys/android_power/acquire_partial_wake_lock
chown radio system /sys/android_power/release_wake_lock
+ chown system system /sys/power/autosleep
chown system system /sys/power/state
chown system system /sys/power/wakeup_count
chown radio system /sys/power/wake_lock
@@ -377,6 +396,7 @@
# adbd is controlled via property triggers in init.<platform>.usb.rc
service adbd /sbin/adbd
class core
+ socket adbd stream 660 system system
disabled
seclabel u:r:adbd:s0
@@ -413,12 +433,12 @@
socket rild stream 660 root radio
socket rild-debug stream 660 radio system
user root
- group radio cache inet misc audio sdcard_r sdcard_rw log
+ group radio cache inet misc audio log
service surfaceflinger /system/bin/surfaceflinger
class main
user system
- group graphics
+ group graphics drmrpc
onrestart restart zygote
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
@@ -432,7 +452,7 @@
service drm /system/bin/drmserver
class main
user drm
- group drm system inet drmrpc sdcard_r
+ group drm system inet drmrpc
service media /system/bin/mediaserver
class main
@@ -447,21 +467,6 @@
disabled
oneshot
-service dbus /system/bin/dbus-daemon --system --nofork
- class main
- socket dbus stream 660 bluetooth bluetooth
- user bluetooth
- group bluetooth net_bt_admin
-
-service bluetoothd /system/bin/bluetoothd -n
- class main
- socket bluetooth stream 660 bluetooth bluetooth
- socket dbus_bluetooth stream 660 bluetooth bluetooth
- # init.rc does not yet support applying capabilities, so run as root and
- # let bluetoothd drop uid to bluetooth with the right linux capabilities
- group bluetooth net_bt_admin misc
- disabled
-
service installd /system/bin/installd
class main
socket installd stream 600 system system
diff --git a/rootdir/init.trace.rc b/rootdir/init.trace.rc
index 1d114f5..8a05fd0 100644
--- a/rootdir/init.trace.rc
+++ b/rootdir/init.trace.rc
@@ -13,6 +13,7 @@
chown root shell /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
chown root shell /sys/kernel/debug/tracing/events/power/cpu_idle/enable
+ chown root shell /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
chown root shell /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
chown root shell /sys/kernel/debug/tracing/tracing_on
@@ -23,6 +24,7 @@
chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_idle/enable
+ chmod 0664 /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
chmod 0664 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
chmod 0664 /sys/kernel/debug/tracing/tracing_on
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index c1fca00..2cf0265 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -27,7 +27,8 @@
/dev/android_adb 0660 adb adb
/dev/android_adb_enable 0660 adb adb
/dev/ttyMSM0 0600 bluetooth bluetooth
-/dev/uinput 0660 system bluetooth
+/dev/uhid 0660 system net_bt_stack
+/dev/uinput 0660 system net_bt_stack
/dev/alarm 0664 system radio
/dev/tty0 0660 root system
/dev/graphics/* 0660 root graphics
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
index c430ac8..fb04d6d 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -4,6 +4,7 @@
LOCAL_SRC_FILES:= sdcard.c
LOCAL_MODULE:= sdcard
+LOCAL_CFLAGS := -Wall -Wno-unused-parameter
LOCAL_SHARED_LIBRARIES := libc
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index ad2f2ab..8d87ee9 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -25,7 +25,9 @@
#include <sys/statfs.h>
#include <sys/uio.h>
#include <dirent.h>
+#include <limits.h>
#include <ctype.h>
+#include <pthread.h>
#include <private/android_filesystem_config.h>
@@ -40,12 +42,10 @@
* permissions at creation, owner, group, and permissions are not
* changeable, symlinks and hardlinks are not createable, etc.
*
- * usage: sdcard <path> <uid> <gid>
+ * See usage() for command line options.
*
- * It must be run as root, but will change to uid/gid as soon as it
- * mounts a filesystem on /storage/sdcard. It will refuse to run if uid or
- * gid are zero.
- *
+ * It must be run as root, but will drop to requested UID/GID as soon as it
+ * mounts a filesystem. It will refuse to run if requested UID/GID are zero.
*
* Things I believe to be true:
*
@@ -55,7 +55,6 @@
* - if an op that returns a fuse_entry fails writing the reply to the
* kernel, you must rollback the refcount to reflect the reference the
* kernel did not actually acquire
- *
*/
#define FUSE_TRACE 0
@@ -70,30 +69,42 @@
#define FUSE_UNKNOWN_INO 0xffffffff
-#define MOUNT_POINT "/storage/sdcard0"
+/* Maximum number of bytes to write in one request. */
+#define MAX_WRITE (256 * 1024)
+
+/* Maximum number of bytes to read in one request. */
+#define MAX_READ (128 * 1024)
+
+/* Largest possible request.
+ * The request size is bounded by the maximum size of a FUSE_WRITE request because it has
+ * the largest possible data payload. */
+#define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE)
+
+/* Default number of threads. */
+#define DEFAULT_NUM_THREADS 2
+
+/* Pseudo-error constant used to indicate that no fuse status is needed
+ * or that a reply has already been written. */
+#define NO_STATUS 1
struct handle {
- struct node *node;
int fd;
};
struct dirhandle {
- struct node *node;
DIR *d;
};
struct node {
+ __u32 refcount;
__u64 nid;
__u64 gen;
struct node *next; /* per-dir sibling list */
struct node *child; /* first contained file by this dir */
- struct node *all; /* global node list */
struct node *parent; /* containing directory */
- __u32 refcount;
- __u32 namelen;
-
+ size_t namelen;
char *name;
/* If non-null, this is the real name of the file in the underlying storage.
* This may differ from the field "name" only by case.
@@ -103,95 +114,166 @@
char *actual_name;
};
+/* Global data structure shared by all fuse handlers. */
struct fuse {
+ pthread_mutex_t lock;
+
__u64 next_generation;
- __u64 next_node_id;
-
int fd;
-
- struct node *all;
-
struct node root;
- char rootpath[1024];
+ char rootpath[PATH_MAX];
};
-#define PATH_BUFFER_SIZE 1024
+/* Private data used by a single fuse handler. */
+struct fuse_handler {
+ struct fuse* fuse;
+ int token;
-#define NO_CASE_SENSITIVE_MATCH 0
-#define CASE_SENSITIVE_MATCH 1
+ /* To save memory, we never use the contents of the request buffer and the read
+ * buffer at the same time. This allows us to share the underlying storage. */
+ union {
+ __u8 request_buffer[MAX_REQUEST_SIZE];
+ __u8 read_buffer[MAX_READ];
+ };
+};
-/*
- * Get the real-life absolute path to a node.
- * node: start at this node
- * buf: storage for returned string
- * name: append this string to path if set
- */
-char *do_node_get_path(struct node *node, char *buf, const char *name, int match_case_insensitive)
+static inline void *id_to_ptr(__u64 nid)
{
- struct node *in_node = node;
- const char *in_name = name;
- char *out = buf + PATH_BUFFER_SIZE - 1;
- int len;
- out[0] = 0;
+ return (void *) (uintptr_t) nid;
+}
- if (name) {
- len = strlen(name);
- goto start;
- }
+static inline __u64 ptr_to_id(void *ptr)
+{
+ return (__u64) (uintptr_t) ptr;
+}
- while (node) {
- name = (node->actual_name ? node->actual_name : node->name);
- len = node->namelen;
- node = node->parent;
- start:
- if ((len + 1) > (out - buf))
- return 0;
- out -= len;
- memcpy(out, name, len);
- /* avoid double slash at beginning of path */
- if (out[0] != '/') {
- out --;
- out[0] = '/';
+static void acquire_node_locked(struct node* node)
+{
+ node->refcount++;
+ TRACE("ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount);
+}
+
+static void remove_node_from_parent_locked(struct node* node);
+
+static void release_node_locked(struct node* node)
+{
+ TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount);
+ if (node->refcount > 0) {
+ node->refcount--;
+ if (!node->refcount) {
+ TRACE("DESTROY %p (%s)\n", node, node->name);
+ remove_node_from_parent_locked(node);
+
+ /* TODO: remove debugging - poison memory */
+ memset(node->name, 0xef, node->namelen);
+ free(node->name);
+ free(node->actual_name);
+ memset(node, 0xfc, sizeof(*node));
+ free(node);
}
+ } else {
+ ERROR("Zero refcnt %p\n", node);
+ }
+}
+
+static void add_node_to_parent_locked(struct node *node, struct node *parent) {
+ node->parent = parent;
+ node->next = parent->child;
+ parent->child = node;
+ acquire_node_locked(parent);
+}
+
+static void remove_node_from_parent_locked(struct node* node)
+{
+ if (node->parent) {
+ if (node->parent->child == node) {
+ node->parent->child = node->parent->child->next;
+ } else {
+ struct node *node2;
+ node2 = node->parent->child;
+ while (node2->next != node)
+ node2 = node2->next;
+ node2->next = node->next;
+ }
+ release_node_locked(node->parent);
+ node->parent = NULL;
+ node->next = NULL;
+ }
+}
+
+/* Gets the absolute path to a node into the provided buffer.
+ *
+ * Populates 'buf' with the path and returns the length of the path on success,
+ * or returns -1 if the path is too long for the provided buffer.
+ */
+static ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize)
+{
+ size_t namelen = node->namelen;
+ if (bufsize < namelen + 1) {
+ return -1;
}
- /* If we are searching for a file within node (rather than computing node's path)
- * and fail, then we need to look for a case insensitive match.
- */
- if (in_name && match_case_insensitive && access(out, F_OK) != 0) {
- char *path, buffer[PATH_BUFFER_SIZE];
- DIR* dir;
+ ssize_t pathlen = 0;
+ if (node->parent) {
+ pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 2);
+ if (pathlen < 0) {
+ return -1;
+ }
+ buf[pathlen++] = '/';
+ }
+
+ const char* name = node->actual_name ? node->actual_name : node->name;
+ memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
+ return pathlen + namelen;
+}
+
+/* Finds the absolute path of a file within a given directory.
+ * Performs a case-insensitive search for the file and sets the buffer to the path
+ * of the first matching file. If 'search' is zero or if no match is found, sets
+ * the buffer to the path that the file would have, assuming the name were case-sensitive.
+ *
+ * Populates 'buf' with the path and returns the actual name (within 'buf') on success,
+ * or returns NULL if the path is too long for the provided buffer.
+ */
+static char* find_file_within(const char* path, const char* name,
+ char* buf, size_t bufsize, int search)
+{
+ size_t pathlen = strlen(path);
+ size_t namelen = strlen(name);
+ size_t childlen = pathlen + namelen + 1;
+ char* actual;
+
+ if (bufsize <= childlen) {
+ return NULL;
+ }
+
+ memcpy(buf, path, pathlen);
+ buf[pathlen] = '/';
+ actual = buf + pathlen + 1;
+ memcpy(actual, name, namelen + 1);
+
+ if (search && access(buf, F_OK)) {
struct dirent* entry;
- path = do_node_get_path(in_node, buffer, NULL, NO_CASE_SENSITIVE_MATCH);
- dir = opendir(path);
+ DIR* dir = opendir(path);
if (!dir) {
ERROR("opendir %s failed: %s", path, strerror(errno));
- return out;
+ return actual;
}
-
while ((entry = readdir(dir))) {
- if (!strcasecmp(entry->d_name, in_name)) {
- /* we have a match - replace the name */
- len = strlen(in_name);
- memcpy(buf + PATH_BUFFER_SIZE - len - 1, entry->d_name, len);
+ if (!strcasecmp(entry->d_name, name)) {
+ /* we have a match - replace the name, don't need to copy the null again */
+ memcpy(actual, entry->d_name, namelen);
break;
}
}
closedir(dir);
}
-
- return out;
+ return actual;
}
-char *node_get_path(struct node *node, char *buf, const char *name)
+static void attr_from_stat(struct fuse_attr *attr, const struct stat *s, __u64 nid)
{
- /* We look for case insensitive matches by default */
- return do_node_get_path(node, buf, name, CASE_SENSITIVE_MATCH);
-}
-
-void attr_from_stat(struct fuse_attr *attr, struct stat *s)
-{
- attr->ino = s->st_ino;
+ attr->ino = nid;
attr->size = s->st_size;
attr->blocks = s->st_blocks;
attr->atime = s->st_atime;
@@ -218,129 +300,81 @@
attr->gid = AID_SDCARD_RW;
}
-int node_get_attr(struct node *node, struct fuse_attr *attr)
-{
- int res;
- struct stat s;
- char *path, buffer[PATH_BUFFER_SIZE];
-
- path = node_get_path(node, buffer, 0);
- res = lstat(path, &s);
- if (res < 0) {
- ERROR("lstat('%s') errno %d\n", path, errno);
- return -1;
- }
-
- attr_from_stat(attr, &s);
- attr->ino = node->nid;
-
- return 0;
-}
-
-static void add_node_to_parent(struct node *node, struct node *parent) {
- node->parent = parent;
- node->next = parent->child;
- parent->child = node;
- parent->refcount++;
-}
-
-/* Check to see if our parent directory already has a file with a name
- * that differs only by case. If we find one, store it in the actual_name
- * field so node_get_path will map it to this file in the underlying storage.
- */
-static void node_find_actual_name(struct node *node)
-{
- char *path, buffer[PATH_BUFFER_SIZE];
- const char *node_name = node->name;
- DIR* dir;
- struct dirent* entry;
-
- if (!node->parent) return;
-
- path = node_get_path(node->parent, buffer, 0);
- dir = opendir(path);
- if (!dir) {
- ERROR("opendir %s failed: %s", path, strerror(errno));
- return;
- }
-
- while ((entry = readdir(dir))) {
- const char *test_name = entry->d_name;
- if (strcmp(test_name, node_name) && !strcasecmp(test_name, node_name)) {
- /* we have a match - differs but only by case */
- node->actual_name = strdup(test_name);
- if (!node->actual_name) {
- ERROR("strdup failed - out of memory\n");
- exit(1);
- }
- break;
- }
- }
- closedir(dir);
-}
-
-struct node *node_create(struct node *parent, const char *name, __u64 nid, __u64 gen)
+struct node *create_node_locked(struct fuse* fuse,
+ struct node *parent, const char *name, const char* actual_name)
{
struct node *node;
- int namelen = strlen(name);
+ size_t namelen = strlen(name);
node = calloc(1, sizeof(struct node));
- if (node == 0) {
- return 0;
+ if (!node) {
+ return NULL;
}
node->name = malloc(namelen + 1);
- if (node->name == 0) {
+ if (!node->name) {
free(node);
- return 0;
+ return NULL;
}
-
- node->nid = nid;
- node->gen = gen;
- add_node_to_parent(node, parent);
memcpy(node->name, name, namelen + 1);
+ if (strcmp(name, actual_name)) {
+ node->actual_name = malloc(namelen + 1);
+ if (!node->actual_name) {
+ free(node->name);
+ free(node);
+ return NULL;
+ }
+ memcpy(node->actual_name, actual_name, namelen + 1);
+ }
node->namelen = namelen;
- node_find_actual_name(node);
+ node->nid = ptr_to_id(node);
+ node->gen = fuse->next_generation++;
+ acquire_node_locked(node);
+ add_node_to_parent_locked(node, parent);
return node;
}
-static char *rename_node(struct node *node, const char *name)
+static int rename_node_locked(struct node *node, const char *name,
+ const char* actual_name)
{
- node->namelen = strlen(name);
- char *newname = realloc(node->name, node->namelen + 1);
- if (newname == 0)
- return 0;
- node->name = newname;
- memcpy(node->name, name, node->namelen + 1);
- node_find_actual_name(node);
- return node->name;
+ size_t namelen = strlen(name);
+ int need_actual_name = strcmp(name, actual_name);
+
+ /* make the storage bigger without actually changing the name
+ * in case an error occurs part way */
+ if (namelen > node->namelen) {
+ char* new_name = realloc(node->name, namelen + 1);
+ if (!new_name) {
+ return -ENOMEM;
+ }
+ node->name = new_name;
+ if (need_actual_name && node->actual_name) {
+ char* new_actual_name = realloc(node->actual_name, namelen + 1);
+ if (!new_actual_name) {
+ return -ENOMEM;
+ }
+ node->actual_name = new_actual_name;
+ }
+ }
+
+ /* update the name, taking care to allocate storage before overwriting the old name */
+ if (need_actual_name) {
+ if (!node->actual_name) {
+ node->actual_name = malloc(namelen + 1);
+ if (!node->actual_name) {
+ return -ENOMEM;
+ }
+ }
+ memcpy(node->actual_name, actual_name, namelen + 1);
+ } else {
+ free(node->actual_name);
+ node->actual_name = NULL;
+ }
+ memcpy(node->name, name, namelen + 1);
+ node->namelen = namelen;
+ return 0;
}
-void fuse_init(struct fuse *fuse, int fd, const char *path)
-{
- fuse->fd = fd;
- fuse->next_node_id = 2;
- fuse->next_generation = 0;
-
- fuse->all = &fuse->root;
-
- memset(&fuse->root, 0, sizeof(fuse->root));
- fuse->root.nid = FUSE_ROOT_ID; /* 1 */
- fuse->root.refcount = 2;
- rename_node(&fuse->root, path);
-}
-
-static inline void *id_to_ptr(__u64 nid)
-{
- return (void *) nid;
-}
-
-static inline __u64 ptr_to_id(void *ptr)
-{
- return (__u64) ptr;
-}
-
-
-struct node *lookup_by_inode(struct fuse *fuse, __u64 nid)
+static struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
{
if (nid == FUSE_ROOT_ID) {
return &fuse->root;
@@ -349,9 +383,23 @@
}
}
-struct node *lookup_child_by_name(struct node *node, const char *name)
+static struct node* lookup_node_and_path_by_id_locked(struct fuse* fuse, __u64 nid,
+ char* buf, size_t bufsize)
+{
+ struct node* node = lookup_node_by_id_locked(fuse, nid);
+ if (node && get_node_path_locked(node, buf, bufsize) < 0) {
+ node = NULL;
+ }
+ return node;
+}
+
+static struct node *lookup_child_by_name_locked(struct node *node, const char *name)
{
for (node = node->child; node; node = node->next) {
+ /* use exact string comparison, nodes that differ by case
+ * must be considered distinct even if they refer to the same
+ * underlying file as otherwise operations such as "mv x x"
+ * will not work because the source and target nodes are the same. */
if (!strcmp(name, node->name)) {
return node;
}
@@ -359,123 +407,43 @@
return 0;
}
-struct node *lookup_child_by_inode(struct node *node, __u64 nid)
+static struct node* acquire_or_create_child_locked(
+ struct fuse* fuse, struct node* parent,
+ const char* name, const char* actual_name)
{
- for (node = node->child; node; node = node->next) {
- if (node->nid == nid) {
- return node;
- }
- }
- return 0;
-}
-
-static void dec_refcount(struct node *node) {
- if (node->refcount > 0) {
- node->refcount--;
- TRACE("dec_refcount %p(%s) -> %d\n", node, node->name, node->refcount);
+ struct node* child = lookup_child_by_name_locked(parent, name);
+ if (child) {
+ acquire_node_locked(child);
} else {
- ERROR("Zero refcnt %p\n", node);
+ child = create_node_locked(fuse, parent, name, actual_name);
}
- }
-
-static struct node *remove_child(struct node *parent, __u64 nid)
-{
- struct node *prev = 0;
- struct node *node;
-
- for (node = parent->child; node; node = node->next) {
- if (node->nid == nid) {
- if (prev) {
- prev->next = node->next;
- } else {
- parent->child = node->next;
- }
- node->next = 0;
- node->parent = 0;
- dec_refcount(parent);
- return node;
- }
- prev = node;
- }
- return 0;
+ return child;
}
-struct node *node_lookup(struct fuse *fuse, struct node *parent, const char *name,
- struct fuse_attr *attr)
+static void fuse_init(struct fuse *fuse, int fd, const char *source_path)
{
- int res;
- struct stat s;
- char *path, buffer[PATH_BUFFER_SIZE];
- struct node *node;
+ pthread_mutex_init(&fuse->lock, NULL);
- path = node_get_path(parent, buffer, name);
- /* XXX error? */
+ fuse->fd = fd;
+ fuse->next_generation = 0;
- res = lstat(path, &s);
- if (res < 0)
- return 0;
-
- node = lookup_child_by_name(parent, name);
- if (!node) {
- node = node_create(parent, name, fuse->next_node_id++, fuse->next_generation++);
- if (!node)
- return 0;
- node->nid = ptr_to_id(node);
- node->all = fuse->all;
- fuse->all = node;
- }
-
- attr_from_stat(attr, &s);
- attr->ino = node->nid;
-
- return node;
+ memset(&fuse->root, 0, sizeof(fuse->root));
+ fuse->root.nid = FUSE_ROOT_ID; /* 1 */
+ fuse->root.refcount = 2;
+ fuse->root.namelen = strlen(source_path);
+ fuse->root.name = strdup(source_path);
}
-void node_release(struct node *node)
-{
- TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount);
- dec_refcount(node);
- if (node->refcount == 0) {
- if (node->parent->child == node) {
- node->parent->child = node->parent->child->next;
- } else {
- struct node *node2;
-
- node2 = node->parent->child;
- while (node2->next != node)
- node2 = node2->next;
- node2->next = node->next;
- }
-
- TRACE("DESTROY %p (%s)\n", node, node->name);
-
- node_release(node->parent);
-
- node->parent = 0;
- node->next = 0;
-
- /* TODO: remove debugging - poison memory */
- memset(node->name, 0xef, node->namelen);
- free(node->name);
- free(node->actual_name);
- memset(node, 0xfc, sizeof(*node));
- free(node);
- }
-}
-
-void fuse_status(struct fuse *fuse, __u64 unique, int err)
+static void fuse_status(struct fuse *fuse, __u64 unique, int err)
{
struct fuse_out_header hdr;
hdr.len = sizeof(hdr);
hdr.error = err;
hdr.unique = unique;
- if (err) {
-// ERROR("*** %d ***\n", err);
- }
write(fuse->fd, &hdr, sizeof(hdr));
}
-void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
+static void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
{
struct fuse_out_header hdr;
struct iovec vec[2];
@@ -496,530 +464,895 @@
}
}
-void lookup_entry(struct fuse *fuse, struct node *node,
- const char *name, __u64 unique)
+static int fuse_reply_entry(struct fuse* fuse, __u64 unique,
+ struct node* parent, const char* name, const char* actual_name,
+ const char* path)
{
+ struct node* node;
struct fuse_entry_out out;
-
- memset(&out, 0, sizeof(out));
+ struct stat s;
- node = node_lookup(fuse, node, name, &out.attr);
- if (!node) {
- fuse_status(fuse, unique, -ENOENT);
- return;
+ if (lstat(path, &s) < 0) {
+ return -errno;
}
-
- node->refcount++;
-// fprintf(stderr,"ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount);
+
+ pthread_mutex_lock(&fuse->lock);
+ node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
+ if (!node) {
+ pthread_mutex_unlock(&fuse->lock);
+ return -ENOMEM;
+ }
+ memset(&out, 0, sizeof(out));
+ attr_from_stat(&out.attr, &s, node->nid);
+ out.attr_valid = 10;
+ out.entry_valid = 10;
out.nodeid = node->nid;
out.generation = node->gen;
- out.entry_valid = 10;
- out.attr_valid = 10;
-
+ pthread_mutex_unlock(&fuse->lock);
fuse_reply(fuse, unique, &out, sizeof(out));
+ return NO_STATUS;
}
-void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *data, unsigned len)
+static int fuse_reply_attr(struct fuse* fuse, __u64 unique, __u64 nid,
+ const char* path)
{
- struct node *node;
+ struct fuse_attr_out out;
+ struct stat s;
- if ((len < sizeof(*hdr)) || (hdr->len != len)) {
- ERROR("malformed header\n");
- return;
+ if (lstat(path, &s) < 0) {
+ return -errno;
}
+ memset(&out, 0, sizeof(out));
+ attr_from_stat(&out.attr, &s, nid);
+ out.attr_valid = 10;
+ fuse_reply(fuse, unique, &out, sizeof(out));
+ return NO_STATUS;
+}
- len -= hdr->len;
+static int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header *hdr, const char* name)
+{
+ struct node* parent_node;
+ char parent_path[PATH_MAX];
+ char child_path[PATH_MAX];
+ const char* actual_name;
- if (hdr->nodeid) {
- node = lookup_by_inode(fuse, hdr->nodeid);
- if (!node) {
- fuse_status(fuse, hdr->unique, -ENOENT);
- return;
+ pthread_mutex_lock(&fuse->lock);
+ parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+ parent_path, sizeof(parent_path));
+ TRACE("[%d] LOOKUP %s @ %llx (%s)\n", handler->token, name, hdr->nodeid,
+ parent_node ? parent_node->name : "?");
+ pthread_mutex_unlock(&fuse->lock);
+
+ if (!parent_node || !(actual_name = find_file_within(parent_path, name,
+ child_path, sizeof(child_path), 1))) {
+ return -ENOENT;
+ }
+ return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
+}
+
+static int handle_forget(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header *hdr, const struct fuse_forget_in *req)
+{
+ struct node* node;
+
+ pthread_mutex_lock(&fuse->lock);
+ node = lookup_node_by_id_locked(fuse, hdr->nodeid);
+ TRACE("[%d] FORGET #%lld @ %llx (%s)\n", handler->token, req->nlookup,
+ hdr->nodeid, node ? node->name : "?");
+ if (node) {
+ __u64 n = req->nlookup;
+ while (n--) {
+ release_node_locked(node);
}
- } else {
- node = 0;
+ }
+ pthread_mutex_unlock(&fuse->lock);
+ return NO_STATUS; /* no reply */
+}
+
+static int handle_getattr(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header *hdr, const struct fuse_getattr_in *req)
+{
+ struct node* node;
+ char path[PATH_MAX];
+
+ pthread_mutex_lock(&fuse->lock);
+ node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
+ TRACE("[%d] GETATTR flags=%x fh=%llx @ %llx (%s)\n", handler->token,
+ req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
+ pthread_mutex_unlock(&fuse->lock);
+
+ if (!node) {
+ return -ENOENT;
+ }
+ return fuse_reply_attr(fuse, hdr->unique, hdr->nodeid, path);
+}
+
+static int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
+{
+ struct node* node;
+ char path[PATH_MAX];
+ struct timespec times[2];
+
+ pthread_mutex_lock(&fuse->lock);
+ node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
+ TRACE("[%d] SETATTR fh=%llx valid=%x @ %llx (%s)\n", handler->token,
+ req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
+ pthread_mutex_unlock(&fuse->lock);
+
+ if (!node) {
+ return -ENOENT;
}
+ /* XXX: incomplete implementation on purpose.
+ * chmod/chown should NEVER be implemented.*/
+
+ if ((req->valid & FATTR_SIZE) && truncate(path, req->size) < 0) {
+ return -errno;
+ }
+
+ /* Handle changing atime and mtime. If FATTR_ATIME_and FATTR_ATIME_NOW
+ * are both set, then set it to the current time. Else, set it to the
+ * time specified in the request. Same goes for mtime. Use utimensat(2)
+ * as it allows ATIME and MTIME to be changed independently, and has
+ * nanosecond resolution which fuse also has.
+ */
+ if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
+ times[0].tv_nsec = UTIME_OMIT;
+ times[1].tv_nsec = UTIME_OMIT;
+ if (req->valid & FATTR_ATIME) {
+ if (req->valid & FATTR_ATIME_NOW) {
+ times[0].tv_nsec = UTIME_NOW;
+ } else {
+ times[0].tv_sec = req->atime;
+ times[0].tv_nsec = req->atimensec;
+ }
+ }
+ if (req->valid & FATTR_MTIME) {
+ if (req->valid & FATTR_MTIME_NOW) {
+ times[1].tv_nsec = UTIME_NOW;
+ } else {
+ times[1].tv_sec = req->mtime;
+ times[1].tv_nsec = req->mtimensec;
+ }
+ }
+ TRACE("[%d] Calling utimensat on %s with atime %ld, mtime=%ld\n",
+ handler->token, path, times[0].tv_sec, times[1].tv_sec);
+ if (utimensat(-1, path, times, 0) < 0) {
+ return -errno;
+ }
+ }
+ return fuse_reply_attr(fuse, hdr->unique, hdr->nodeid, path);
+}
+
+static int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
+{
+ struct node* parent_node;
+ char parent_path[PATH_MAX];
+ char child_path[PATH_MAX];
+ const char* actual_name;
+
+ pthread_mutex_lock(&fuse->lock);
+ parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+ parent_path, sizeof(parent_path));
+ TRACE("[%d] MKNOD %s 0%o @ %llx (%s)\n", handler->token,
+ name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
+ pthread_mutex_unlock(&fuse->lock);
+
+ if (!parent_node || !(actual_name = find_file_within(parent_path, name,
+ child_path, sizeof(child_path), 1))) {
+ return -ENOENT;
+ }
+ __u32 mode = (req->mode & (~0777)) | 0664;
+ if (mknod(child_path, mode, req->rdev) < 0) {
+ return -errno;
+ }
+ return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
+}
+
+static int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
+{
+ struct node* parent_node;
+ char parent_path[PATH_MAX];
+ char child_path[PATH_MAX];
+ const char* actual_name;
+
+ pthread_mutex_lock(&fuse->lock);
+ parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+ parent_path, sizeof(parent_path));
+ TRACE("[%d] MKDIR %s 0%o @ %llx (%s)\n", handler->token,
+ name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
+ pthread_mutex_unlock(&fuse->lock);
+
+ if (!parent_node || !(actual_name = find_file_within(parent_path, name,
+ child_path, sizeof(child_path), 1))) {
+ return -ENOENT;
+ }
+ __u32 mode = (req->mode & (~0777)) | 0775;
+ if (mkdir(child_path, mode) < 0) {
+ return -errno;
+ }
+ return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
+}
+
+static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const char* name)
+{
+ struct node* parent_node;
+ char parent_path[PATH_MAX];
+ char child_path[PATH_MAX];
+
+ pthread_mutex_lock(&fuse->lock);
+ parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+ parent_path, sizeof(parent_path));
+ TRACE("[%d] UNLINK %s @ %llx (%s)\n", handler->token,
+ name, hdr->nodeid, parent_node ? parent_node->name : "?");
+ pthread_mutex_unlock(&fuse->lock);
+
+ if (!parent_node || !find_file_within(parent_path, name,
+ child_path, sizeof(child_path), 1)) {
+ return -ENOENT;
+ }
+ if (unlink(child_path) < 0) {
+ return -errno;
+ }
+ return 0;
+}
+
+static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const char* name)
+{
+ struct node* parent_node;
+ char parent_path[PATH_MAX];
+ char child_path[PATH_MAX];
+
+ pthread_mutex_lock(&fuse->lock);
+ parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+ parent_path, sizeof(parent_path));
+ TRACE("[%d] RMDIR %s @ %llx (%s)\n", handler->token,
+ name, hdr->nodeid, parent_node ? parent_node->name : "?");
+ pthread_mutex_unlock(&fuse->lock);
+
+ if (!parent_node || !find_file_within(parent_path, name,
+ child_path, sizeof(child_path), 1)) {
+ return -ENOENT;
+ }
+ if (rmdir(child_path) < 0) {
+ return -errno;
+ }
+ return 0;
+}
+
+static int handle_rename(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
+ const char* old_name, const char* new_name)
+{
+ struct node* old_parent_node;
+ struct node* new_parent_node;
+ struct node* child_node;
+ char old_parent_path[PATH_MAX];
+ char new_parent_path[PATH_MAX];
+ char old_child_path[PATH_MAX];
+ char new_child_path[PATH_MAX];
+ const char* new_actual_name;
+ int res;
+
+ pthread_mutex_lock(&fuse->lock);
+ old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+ old_parent_path, sizeof(old_parent_path));
+ new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
+ new_parent_path, sizeof(new_parent_path));
+ TRACE("[%d] RENAME %s->%s @ %llx (%s) -> %llx (%s)\n", handler->token,
+ old_name, new_name,
+ hdr->nodeid, old_parent_node ? old_parent_node->name : "?",
+ req->newdir, new_parent_node ? new_parent_node->name : "?");
+ if (!old_parent_node || !new_parent_node) {
+ res = -ENOENT;
+ goto lookup_error;
+ }
+ child_node = lookup_child_by_name_locked(old_parent_node, old_name);
+ if (!child_node || get_node_path_locked(child_node,
+ old_child_path, sizeof(old_child_path)) < 0) {
+ res = -ENOENT;
+ goto lookup_error;
+ }
+ acquire_node_locked(child_node);
+ pthread_mutex_unlock(&fuse->lock);
+
+ /* Special case for renaming a file where destination is same path
+ * differing only by case. In this case we don't want to look for a case
+ * insensitive match. This allows commands like "mv foo FOO" to work as expected.
+ */
+ int search = old_parent_node != new_parent_node
+ || strcasecmp(old_name, new_name);
+ if (!(new_actual_name = find_file_within(new_parent_path, new_name,
+ new_child_path, sizeof(new_child_path), search))) {
+ res = -ENOENT;
+ goto io_error;
+ }
+
+ TRACE("[%d] RENAME %s->%s\n", handler->token, old_child_path, new_child_path);
+ res = rename(old_child_path, new_child_path);
+ if (res < 0) {
+ res = -errno;
+ goto io_error;
+ }
+
+ pthread_mutex_lock(&fuse->lock);
+ res = rename_node_locked(child_node, new_name, new_actual_name);
+ if (!res) {
+ remove_node_from_parent_locked(child_node);
+ add_node_to_parent_locked(child_node, new_parent_node);
+ }
+ goto done;
+
+io_error:
+ pthread_mutex_lock(&fuse->lock);
+done:
+ release_node_locked(child_node);
+lookup_error:
+ pthread_mutex_unlock(&fuse->lock);
+ return res;
+}
+
+static int handle_open(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_open_in* req)
+{
+ struct node* node;
+ char path[PATH_MAX];
+ struct fuse_open_out out;
+ struct handle *h;
+
+ pthread_mutex_lock(&fuse->lock);
+ node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
+ TRACE("[%d] OPEN 0%o @ %llx (%s)\n", handler->token,
+ req->flags, hdr->nodeid, node ? node->name : "?");
+ pthread_mutex_unlock(&fuse->lock);
+
+ if (!node) {
+ return -ENOENT;
+ }
+ h = malloc(sizeof(*h));
+ if (!h) {
+ return -ENOMEM;
+ }
+ TRACE("[%d] OPEN %s\n", handler->token, path);
+ h->fd = open(path, req->flags);
+ if (h->fd < 0) {
+ free(h);
+ return -errno;
+ }
+ out.fh = ptr_to_id(h);
+ out.open_flags = 0;
+ out.padding = 0;
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ return NO_STATUS;
+}
+
+static int handle_read(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_read_in* req)
+{
+ struct handle *h = id_to_ptr(req->fh);
+ __u64 unique = hdr->unique;
+ __u32 size = req->size;
+ __u64 offset = req->offset;
+ int res;
+
+ /* Don't access any other fields of hdr or req beyond this point, the read buffer
+ * overlaps the request buffer and will clobber data in the request. This
+ * saves us 128KB per request handler thread at the cost of this scary comment. */
+
+ TRACE("[%d] READ %p(%d) %u@%llu\n", handler->token,
+ h, h->fd, size, offset);
+ if (size > sizeof(handler->read_buffer)) {
+ return -EINVAL;
+ }
+ res = pread64(h->fd, handler->read_buffer, size, offset);
+ if (res < 0) {
+ return -errno;
+ }
+ fuse_reply(fuse, unique, handler->read_buffer, res);
+ return NO_STATUS;
+}
+
+static int handle_write(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_write_in* req,
+ const void* buffer)
+{
+ struct fuse_write_out out;
+ struct handle *h = id_to_ptr(req->fh);
+ int res;
+
+ TRACE("[%d] WRITE %p(%d) %u@%llu\n", handler->token,
+ h, h->fd, req->size, req->offset);
+ res = pwrite64(h->fd, buffer, req->size, req->offset);
+ if (res < 0) {
+ return -errno;
+ }
+ out.size = res;
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ return NO_STATUS;
+}
+
+static int handle_statfs(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr)
+{
+ char path[PATH_MAX];
+ struct statfs stat;
+ struct fuse_statfs_out out;
+ int res;
+
+ pthread_mutex_lock(&fuse->lock);
+ TRACE("[%d] STATFS\n", handler->token);
+ res = get_node_path_locked(&fuse->root, path, sizeof(path));
+ pthread_mutex_unlock(&fuse->lock);
+ if (res < 0) {
+ return -ENOENT;
+ }
+ if (statfs(fuse->root.name, &stat) < 0) {
+ return -errno;
+ }
+ memset(&out, 0, sizeof(out));
+ out.st.blocks = stat.f_blocks;
+ out.st.bfree = stat.f_bfree;
+ out.st.bavail = stat.f_bavail;
+ out.st.files = stat.f_files;
+ out.st.ffree = stat.f_ffree;
+ out.st.bsize = stat.f_bsize;
+ out.st.namelen = stat.f_namelen;
+ out.st.frsize = stat.f_frsize;
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ return NO_STATUS;
+}
+
+static int handle_release(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_release_in* req)
+{
+ struct handle *h = id_to_ptr(req->fh);
+
+ TRACE("[%d] RELEASE %p(%d)\n", handler->token, h, h->fd);
+ close(h->fd);
+ free(h);
+ return 0;
+}
+
+static int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
+{
+ int is_data_sync = req->fsync_flags & 1;
+ struct handle *h = id_to_ptr(req->fh);
+ int res;
+
+ TRACE("[%d] FSYNC %p(%d) is_data_sync=%d\n", handler->token,
+ h, h->fd, is_data_sync);
+ res = is_data_sync ? fdatasync(h->fd) : fsync(h->fd);
+ if (res < 0) {
+ return -errno;
+ }
+ return 0;
+}
+
+static int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr)
+{
+ TRACE("[%d] FLUSH\n", handler->token);
+ return 0;
+}
+
+static int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_open_in* req)
+{
+ struct node* node;
+ char path[PATH_MAX];
+ struct fuse_open_out out;
+ struct dirhandle *h;
+
+ pthread_mutex_lock(&fuse->lock);
+ node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
+ TRACE("[%d] OPENDIR @ %llx (%s)\n", handler->token,
+ hdr->nodeid, node ? node->name : "?");
+ pthread_mutex_unlock(&fuse->lock);
+
+ if (!node) {
+ return -ENOENT;
+ }
+ h = malloc(sizeof(*h));
+ if (!h) {
+ return -ENOMEM;
+ }
+ TRACE("[%d] OPENDIR %s\n", handler->token, path);
+ h->d = opendir(path);
+ if (!h->d) {
+ free(h);
+ return -errno;
+ }
+ out.fh = ptr_to_id(h);
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ return NO_STATUS;
+}
+
+static int handle_readdir(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_read_in* req)
+{
+ char buffer[8192];
+ struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
+ struct dirent *de;
+ struct dirhandle *h = id_to_ptr(req->fh);
+
+ TRACE("[%d] READDIR %p\n", handler->token, h);
+ if (req->offset == 0) {
+ /* rewinddir() might have been called above us, so rewind here too */
+ TRACE("[%d] calling rewinddir()\n", handler->token);
+ rewinddir(h->d);
+ }
+ de = readdir(h->d);
+ if (!de) {
+ return 0;
+ }
+ fde->ino = FUSE_UNKNOWN_INO;
+ /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
+ fde->off = req->offset + 1;
+ fde->type = de->d_type;
+ fde->namelen = strlen(de->d_name);
+ memcpy(fde->name, de->d_name, fde->namelen + 1);
+ fuse_reply(fuse, hdr->unique, fde,
+ FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
+ return NO_STATUS;
+}
+
+static int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_release_in* req)
+{
+ struct dirhandle *h = id_to_ptr(req->fh);
+
+ TRACE("[%d] RELEASEDIR %p\n", handler->token, h);
+ closedir(h->d);
+ free(h);
+ return 0;
+}
+
+static int handle_init(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_init_in* req)
+{
+ struct fuse_init_out out;
+
+ TRACE("[%d] INIT ver=%d.%d maxread=%d flags=%x\n",
+ handler->token, req->major, req->minor, req->max_readahead, req->flags);
+ out.major = FUSE_KERNEL_VERSION;
+ out.minor = FUSE_KERNEL_MINOR_VERSION;
+ out.max_readahead = req->max_readahead;
+ out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
+ out.max_background = 32;
+ out.congestion_threshold = 32;
+ out.max_write = MAX_WRITE;
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ return NO_STATUS;
+}
+
+static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
+ const struct fuse_in_header *hdr, const void *data, size_t data_len)
+{
switch (hdr->opcode) {
case FUSE_LOOKUP: { /* bytez[] -> entry_out */
- TRACE("LOOKUP %llx %s\n", hdr->nodeid, (char*) data);
- lookup_entry(fuse, node, (char*) data, hdr->unique);
- return;
+ const char* name = data;
+ return handle_lookup(fuse, handler, hdr, name);
}
+
case FUSE_FORGET: {
- struct fuse_forget_in *req = data;
- TRACE("FORGET %llx (%s) #%lld\n", hdr->nodeid, node->name, req->nlookup);
- /* no reply */
- while (req->nlookup--)
- node_release(node);
- return;
+ const struct fuse_forget_in *req = data;
+ return handle_forget(fuse, handler, hdr, req);
}
+
case FUSE_GETATTR: { /* getattr_in -> attr_out */
- struct fuse_getattr_in *req = data;
- struct fuse_attr_out out;
-
- TRACE("GETATTR flags=%x fh=%llx\n", req->getattr_flags, req->fh);
-
- memset(&out, 0, sizeof(out));
- node_get_attr(node, &out.attr);
- out.attr_valid = 10;
-
- fuse_reply(fuse, hdr->unique, &out, sizeof(out));
- return;
+ const struct fuse_getattr_in *req = data;
+ return handle_getattr(fuse, handler, hdr, req);
}
+
case FUSE_SETATTR: { /* setattr_in -> attr_out */
- struct fuse_setattr_in *req = data;
- struct fuse_attr_out out;
- char *path, buffer[PATH_BUFFER_SIZE];
- int res = 0;
- struct timespec times[2];
-
- TRACE("SETATTR fh=%llx id=%llx valid=%x\n",
- req->fh, hdr->nodeid, req->valid);
-
- /* XXX: incomplete implementation on purpose. chmod/chown
- * should NEVER be implemented.*/
-
- path = node_get_path(node, buffer, 0);
- if (req->valid & FATTR_SIZE)
- res = truncate(path, req->size);
- if (res)
- goto getout;
-
- /* Handle changing atime and mtime. If FATTR_ATIME_and FATTR_ATIME_NOW
- * are both set, then set it to the current time. Else, set it to the
- * time specified in the request. Same goes for mtime. Use utimensat(2)
- * as it allows ATIME and MTIME to be changed independently, and has
- * nanosecond resolution which fuse also has.
- */
- if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
- times[0].tv_nsec = UTIME_OMIT;
- times[1].tv_nsec = UTIME_OMIT;
- if (req->valid & FATTR_ATIME) {
- if (req->valid & FATTR_ATIME_NOW) {
- times[0].tv_nsec = UTIME_NOW;
- } else {
- times[0].tv_sec = req->atime;
- times[0].tv_nsec = req->atimensec;
- }
- }
- if (req->valid & FATTR_MTIME) {
- if (req->valid & FATTR_MTIME_NOW) {
- times[1].tv_nsec = UTIME_NOW;
- } else {
- times[1].tv_sec = req->mtime;
- times[1].tv_nsec = req->mtimensec;
- }
- }
- TRACE("Calling utimensat on %s with atime %ld, mtime=%ld\n", path, times[0].tv_sec, times[1].tv_sec);
- res = utimensat(-1, path, times, 0);
- }
-
- getout:
- memset(&out, 0, sizeof(out));
- node_get_attr(node, &out.attr);
- out.attr_valid = 10;
-
- if (res)
- fuse_status(fuse, hdr->unique, -errno);
- else
- fuse_reply(fuse, hdr->unique, &out, sizeof(out));
- return;
+ const struct fuse_setattr_in *req = data;
+ return handle_setattr(fuse, handler, hdr, req);
}
+
// case FUSE_READLINK:
// case FUSE_SYMLINK:
case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
- struct fuse_mknod_in *req = data;
- char *path, buffer[PATH_BUFFER_SIZE];
- char *name = ((char*) data) + sizeof(*req);
- int res;
-
- TRACE("MKNOD %s @ %llx\n", name, hdr->nodeid);
- path = node_get_path(node, buffer, name);
-
- req->mode = (req->mode & (~0777)) | 0664;
- res = mknod(path, req->mode, req->rdev); /* XXX perm?*/
- if (res < 0) {
- fuse_status(fuse, hdr->unique, -errno);
- } else {
- lookup_entry(fuse, node, name, hdr->unique);
- }
- return;
+ const struct fuse_mknod_in *req = data;
+ const char *name = ((const char*) data) + sizeof(*req);
+ return handle_mknod(fuse, handler, hdr, req, name);
}
+
case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
- struct fuse_mkdir_in *req = data;
- struct fuse_entry_out out;
- char *path, buffer[PATH_BUFFER_SIZE];
- char *name = ((char*) data) + sizeof(*req);
- int res;
-
- TRACE("MKDIR %s @ %llx 0%o\n", name, hdr->nodeid, req->mode);
- path = node_get_path(node, buffer, name);
-
- req->mode = (req->mode & (~0777)) | 0775;
- res = mkdir(path, req->mode);
- if (res < 0) {
- fuse_status(fuse, hdr->unique, -errno);
- } else {
- lookup_entry(fuse, node, name, hdr->unique);
- }
- return;
+ const struct fuse_mkdir_in *req = data;
+ const char *name = ((const char*) data) + sizeof(*req);
+ return handle_mkdir(fuse, handler, hdr, req, name);
}
+
case FUSE_UNLINK: { /* bytez[] -> */
- char *path, buffer[PATH_BUFFER_SIZE];
- int res;
- TRACE("UNLINK %s @ %llx\n", (char*) data, hdr->nodeid);
- path = node_get_path(node, buffer, (char*) data);
- res = unlink(path);
- fuse_status(fuse, hdr->unique, res ? -errno : 0);
- return;
+ const char* name = data;
+ return handle_unlink(fuse, handler, hdr, name);
}
+
case FUSE_RMDIR: { /* bytez[] -> */
- char *path, buffer[PATH_BUFFER_SIZE];
- int res;
- TRACE("RMDIR %s @ %llx\n", (char*) data, hdr->nodeid);
- path = node_get_path(node, buffer, (char*) data);
- res = rmdir(path);
- fuse_status(fuse, hdr->unique, res ? -errno : 0);
- return;
+ const char* name = data;
+ return handle_rmdir(fuse, handler, hdr, name);
}
+
case FUSE_RENAME: { /* rename_in, oldname, newname -> */
- struct fuse_rename_in *req = data;
- char *oldname = ((char*) data) + sizeof(*req);
- char *newname = oldname + strlen(oldname) + 1;
- char *oldpath, oldbuffer[PATH_BUFFER_SIZE];
- char *newpath, newbuffer[PATH_BUFFER_SIZE];
- struct node *target;
- struct node *newparent;
- int res;
-
- TRACE("RENAME %s->%s @ %llx\n", oldname, newname, hdr->nodeid);
-
- target = lookup_child_by_name(node, oldname);
- if (!target) {
- fuse_status(fuse, hdr->unique, -ENOENT);
- return;
- }
- oldpath = node_get_path(node, oldbuffer, oldname);
-
- newparent = lookup_by_inode(fuse, req->newdir);
- if (!newparent) {
- fuse_status(fuse, hdr->unique, -ENOENT);
- return;
- }
- if (newparent == node) {
- /* Special case for renaming a file where destination
- * is same path differing only by case.
- * In this case we don't want to look for a case insensitive match.
- * This allows commands like "mv foo FOO" to work as expected.
- */
- newpath = do_node_get_path(newparent, newbuffer, newname, NO_CASE_SENSITIVE_MATCH);
- } else {
- newpath = node_get_path(newparent, newbuffer, newname);
- }
-
- if (!remove_child(node, target->nid)) {
- ERROR("RENAME remove_child not found");
- fuse_status(fuse, hdr->unique, -ENOENT);
- return;
- }
- if (!rename_node(target, newname)) {
- fuse_status(fuse, hdr->unique, -ENOMEM);
- return;
- }
- add_node_to_parent(target, newparent);
-
- res = rename(oldpath, newpath);
- TRACE("RENAME result %d\n", res);
-
- fuse_status(fuse, hdr->unique, res ? -errno : 0);
- return;
+ const struct fuse_rename_in *req = data;
+ const char *old_name = ((const char*) data) + sizeof(*req);
+ const char *new_name = old_name + strlen(old_name) + 1;
+ return handle_rename(fuse, handler, hdr, req, old_name, new_name);
}
-// case FUSE_LINK:
+
+// case FUSE_LINK:
case FUSE_OPEN: { /* open_in -> open_out */
- struct fuse_open_in *req = data;
- struct fuse_open_out out;
- char *path, buffer[PATH_BUFFER_SIZE];
- struct handle *h;
-
- h = malloc(sizeof(*h));
- if (!h) {
- fuse_status(fuse, hdr->unique, -ENOMEM);
- return;
- }
-
- path = node_get_path(node, buffer, 0);
- TRACE("OPEN %llx '%s' 0%o fh=%p\n", hdr->nodeid, path, req->flags, h);
- h->fd = open(path, req->flags);
- if (h->fd < 0) {
- ERROR("ERROR\n");
- fuse_status(fuse, hdr->unique, -errno);
- free(h);
- return;
- }
- out.fh = ptr_to_id(h);
- out.open_flags = 0;
- out.padding = 0;
- fuse_reply(fuse, hdr->unique, &out, sizeof(out));
- return;
+ const struct fuse_open_in *req = data;
+ return handle_open(fuse, handler, hdr, req);
}
+
case FUSE_READ: { /* read_in -> byte[] */
- char buffer[128 * 1024];
- struct fuse_read_in *req = data;
- struct handle *h = id_to_ptr(req->fh);
- int res;
- TRACE("READ %p(%d) %u@%llu\n", h, h->fd, req->size, req->offset);
- if (req->size > sizeof(buffer)) {
- fuse_status(fuse, hdr->unique, -EINVAL);
- return;
- }
- res = pread64(h->fd, buffer, req->size, req->offset);
- if (res < 0) {
- fuse_status(fuse, hdr->unique, -errno);
- return;
- }
- fuse_reply(fuse, hdr->unique, buffer, res);
- return;
+ const struct fuse_read_in *req = data;
+ return handle_read(fuse, handler, hdr, req);
}
+
case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
- struct fuse_write_in *req = data;
- struct fuse_write_out out;
- struct handle *h = id_to_ptr(req->fh);
- int res;
- TRACE("WRITE %p(%d) %u@%llu\n", h, h->fd, req->size, req->offset);
- res = pwrite64(h->fd, ((char*) data) + sizeof(*req), req->size, req->offset);
- if (res < 0) {
- fuse_status(fuse, hdr->unique, -errno);
- return;
- }
- out.size = res;
- fuse_reply(fuse, hdr->unique, &out, sizeof(out));
- goto oops;
+ const struct fuse_write_in *req = data;
+ const void* buffer = (const __u8*)data + sizeof(*req);
+ return handle_write(fuse, handler, hdr, req, buffer);
}
+
case FUSE_STATFS: { /* getattr_in -> attr_out */
- struct statfs stat;
- struct fuse_statfs_out out;
- int res;
-
- TRACE("STATFS\n");
-
- if (statfs(fuse->root.name, &stat)) {
- fuse_status(fuse, hdr->unique, -errno);
- return;
- }
-
- memset(&out, 0, sizeof(out));
- out.st.blocks = stat.f_blocks;
- out.st.bfree = stat.f_bfree;
- out.st.bavail = stat.f_bavail;
- out.st.files = stat.f_files;
- out.st.ffree = stat.f_ffree;
- out.st.bsize = stat.f_bsize;
- out.st.namelen = stat.f_namelen;
- out.st.frsize = stat.f_frsize;
- fuse_reply(fuse, hdr->unique, &out, sizeof(out));
- return;
+ return handle_statfs(fuse, handler, hdr);
}
+
case FUSE_RELEASE: { /* release_in -> */
- struct fuse_release_in *req = data;
- struct handle *h = id_to_ptr(req->fh);
- TRACE("RELEASE %p(%d)\n", h, h->fd);
- close(h->fd);
- free(h);
- fuse_status(fuse, hdr->unique, 0);
- return;
+ const struct fuse_release_in *req = data;
+ return handle_release(fuse, handler, hdr, req);
}
-// case FUSE_FSYNC:
+
+ case FUSE_FSYNC: {
+ const struct fuse_fsync_in *req = data;
+ return handle_fsync(fuse, handler, hdr, req);
+ }
+
// case FUSE_SETXATTR:
// case FUSE_GETXATTR:
// case FUSE_LISTXATTR:
// case FUSE_REMOVEXATTR:
- case FUSE_FLUSH:
- fuse_status(fuse, hdr->unique, 0);
- return;
+ case FUSE_FLUSH: {
+ return handle_flush(fuse, handler, hdr);
+ }
+
case FUSE_OPENDIR: { /* open_in -> open_out */
- struct fuse_open_in *req = data;
- struct fuse_open_out out;
- char *path, buffer[PATH_BUFFER_SIZE];
- struct dirhandle *h;
-
- h = malloc(sizeof(*h));
- if (!h) {
- fuse_status(fuse, hdr->unique, -ENOMEM);
- return;
- }
-
- path = node_get_path(node, buffer, 0);
- TRACE("OPENDIR %llx '%s'\n", hdr->nodeid, path);
- h->d = opendir(path);
- if (h->d == 0) {
- ERROR("ERROR\n");
- fuse_status(fuse, hdr->unique, -errno);
- free(h);
- return;
- }
- out.fh = ptr_to_id(h);
- fuse_reply(fuse, hdr->unique, &out, sizeof(out));
- return;
+ const struct fuse_open_in *req = data;
+ return handle_opendir(fuse, handler, hdr, req);
}
+
case FUSE_READDIR: {
- struct fuse_read_in *req = data;
- char buffer[8192];
- struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
- struct dirent *de;
- struct dirhandle *h = id_to_ptr(req->fh);
- TRACE("READDIR %p\n", h);
- if (req->offset == 0) {
- /* rewinddir() might have been called above us, so rewind here too */
- TRACE("calling rewinddir()\n");
- rewinddir(h->d);
- }
- de = readdir(h->d);
- if (!de) {
- fuse_status(fuse, hdr->unique, 0);
- return;
- }
- fde->ino = FUSE_UNKNOWN_INO;
- /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
- fde->off = req->offset + 1;
- fde->type = de->d_type;
- fde->namelen = strlen(de->d_name);
- memcpy(fde->name, de->d_name, fde->namelen + 1);
- fuse_reply(fuse, hdr->unique, fde,
- FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
- return;
+ const struct fuse_read_in *req = data;
+ return handle_readdir(fuse, handler, hdr, req);
}
+
case FUSE_RELEASEDIR: { /* release_in -> */
- struct fuse_release_in *req = data;
- struct dirhandle *h = id_to_ptr(req->fh);
- TRACE("RELEASEDIR %p\n",h);
- closedir(h->d);
- free(h);
- fuse_status(fuse, hdr->unique, 0);
- return;
+ const struct fuse_release_in *req = data;
+ return handle_releasedir(fuse, handler, hdr, req);
}
+
// case FUSE_FSYNCDIR:
case FUSE_INIT: { /* init_in -> init_out */
- struct fuse_init_in *req = data;
- struct fuse_init_out out;
-
- TRACE("INIT ver=%d.%d maxread=%d flags=%x\n",
- req->major, req->minor, req->max_readahead, req->flags);
-
- out.major = FUSE_KERNEL_VERSION;
- out.minor = FUSE_KERNEL_MINOR_VERSION;
- out.max_readahead = req->max_readahead;
- out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
- out.max_background = 32;
- out.congestion_threshold = 32;
- out.max_write = 256 * 1024;
-
- fuse_reply(fuse, hdr->unique, &out, sizeof(out));
- return;
+ const struct fuse_init_in *req = data;
+ return handle_init(fuse, handler, hdr, req);
}
+
default: {
- struct fuse_out_header h;
- ERROR("NOTIMPL op=%d uniq=%llx nid=%llx\n",
- hdr->opcode, hdr->unique, hdr->nodeid);
-
- oops:
- h.len = sizeof(h);
- h.error = -ENOSYS;
- h.unique = hdr->unique;
- write(fuse->fd, &h, sizeof(h));
- break;
+ TRACE("[%d] NOTIMPL op=%d uniq=%llx nid=%llx\n",
+ handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
+ return -ENOSYS;
}
- }
+ }
}
-void handle_fuse_requests(struct fuse *fuse)
+static void handle_fuse_requests(struct fuse_handler* handler)
{
- unsigned char req[256 * 1024 + 128];
- int len;
-
+ struct fuse* fuse = handler->fuse;
for (;;) {
- len = read(fuse->fd, req, sizeof(req));
+ ssize_t len = read(fuse->fd,
+ handler->request_buffer, sizeof(handler->request_buffer));
if (len < 0) {
- if (errno == EINTR)
- continue;
- ERROR("handle_fuse_requests: errno=%d\n", errno);
- return;
+ if (errno != EINTR) {
+ ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);
+ }
+ continue;
}
- handle_fuse_request(fuse, (void*) req, (void*) (req + sizeof(struct fuse_in_header)), len);
+
+ if ((size_t)len < sizeof(struct fuse_in_header)) {
+ ERROR("[%d] request too short: len=%zu\n", handler->token, (size_t)len);
+ continue;
+ }
+
+ const struct fuse_in_header *hdr = (void*)handler->request_buffer;
+ if (hdr->len != (size_t)len) {
+ ERROR("[%d] malformed header: len=%zu, hdr->len=%u\n",
+ handler->token, (size_t)len, hdr->len);
+ continue;
+ }
+
+ const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
+ size_t data_len = len - sizeof(struct fuse_in_header);
+ __u64 unique = hdr->unique;
+ int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
+
+ /* We do not access the request again after this point because the underlying
+ * buffer storage may have been reused while processing the request. */
+
+ if (res != NO_STATUS) {
+ if (res) {
+ TRACE("[%d] ERROR %d\n", handler->token, res);
+ }
+ fuse_status(fuse, unique, res);
+ }
}
}
+static void* start_handler(void* data)
+{
+ struct fuse_handler* handler = data;
+ handle_fuse_requests(handler);
+ return NULL;
+}
+
+static int ignite_fuse(struct fuse* fuse, int num_threads)
+{
+ struct fuse_handler* handlers;
+ int i;
+
+ handlers = malloc(num_threads * sizeof(struct fuse_handler));
+ if (!handlers) {
+ ERROR("cannot allocate storage for threads");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < num_threads; i++) {
+ handlers[i].fuse = fuse;
+ handlers[i].token = i;
+ }
+
+ for (i = 1; i < num_threads; i++) {
+ pthread_t thread;
+ int res = pthread_create(&thread, NULL, start_handler, &handlers[i]);
+ if (res) {
+ ERROR("failed to start thread #%d, error=%d", i, res);
+ goto quit;
+ }
+ }
+ handle_fuse_requests(&handlers[0]);
+ ERROR("terminated prematurely");
+
+ /* don't bother killing all of the other threads or freeing anything,
+ * should never get here anyhow */
+quit:
+ exit(1);
+}
+
static int usage()
{
- ERROR("usage: sdcard <path> <uid> <gid>\n");
- return -1;
+ ERROR("usage: sdcard [-t<threads>] <source_path> <dest_path> <uid> <gid>\n"
+ " -t<threads>: specify number of threads to use, default -t%d\n"
+ "\n", DEFAULT_NUM_THREADS);
+ return 1;
+}
+
+static int run(const char* source_path, const char* dest_path, uid_t uid, gid_t gid,
+ int num_threads) {
+ int fd;
+ char opts[256];
+ int res;
+ struct fuse fuse;
+
+ /* cleanup from previous instance, if necessary */
+ umount2(dest_path, 2);
+
+ fd = open("/dev/fuse", O_RDWR);
+ if (fd < 0){
+ ERROR("cannot open fuse device (error %d)\n", errno);
+ return -1;
+ }
+
+ snprintf(opts, sizeof(opts),
+ "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
+ fd, uid, gid);
+
+ res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV, opts);
+ if (res < 0) {
+ ERROR("cannot mount fuse filesystem (error %d)\n", errno);
+ goto error;
+ }
+
+ res = setgid(gid);
+ if (res < 0) {
+ ERROR("cannot setgid (error %d)\n", errno);
+ goto error;
+ }
+
+ res = setuid(uid);
+ if (res < 0) {
+ ERROR("cannot setuid (error %d)\n", errno);
+ goto error;
+ }
+
+ fuse_init(&fuse, fd, source_path);
+
+ umask(0);
+ res = ignite_fuse(&fuse, num_threads);
+
+ /* we do not attempt to umount the file system here because we are no longer
+ * running as the root user */
+
+error:
+ close(fd);
+ return res;
}
int main(int argc, char **argv)
{
- struct fuse fuse;
- char opts[256];
- int fd;
int res;
- const char *path = NULL;
+ const char *source_path = NULL;
+ const char *dest_path = NULL;
+ uid_t uid = 0;
+ gid_t gid = 0;
+ int num_threads = DEFAULT_NUM_THREADS;
int i;
- unsigned int uid = 0;
- unsigned int gid = 0;
-
- if (argc != 4) {
- return usage();
+ for (i = 1; i < argc; i++) {
+ char* arg = argv[i];
+ if (!strncmp(arg, "-t", 2))
+ num_threads = strtoul(arg + 2, 0, 10);
+ else if (!source_path)
+ source_path = arg;
+ else if (!dest_path)
+ dest_path = arg;
+ else if (!uid) {
+ char* endptr = NULL;
+ errno = 0;
+ uid = strtoul(arg, &endptr, 10);
+ if (*endptr != '\0' || errno != 0) {
+ ERROR("Invalid uid");
+ return usage();
+ }
+ } else if (!gid) {
+ char* endptr = NULL;
+ errno = 0;
+ gid = strtoul(arg, &endptr, 10);
+ if (*endptr != '\0' || errno != 0) {
+ ERROR("Invalid gid");
+ return usage();
+ }
+ } else {
+ ERROR("too many arguments\n");
+ return usage();
+ }
}
- path = argv[1];
-
- char* endptr = NULL;
- errno = 0;
- uid = strtoul(argv[2], &endptr, 10);
- if (*endptr != '\0' || errno != 0) {
- ERROR("Invalid uid");
- return usage();
+ if (!source_path) {
+ ERROR("no source path specified\n");
+ return usage();
+ }
+ if (!dest_path) {
+ ERROR("no dest path specified\n");
+ return usage();
+ }
+ if (!uid || !gid) {
+ ERROR("uid and gid must be nonzero\n");
+ return usage();
+ }
+ if (num_threads < 1) {
+ ERROR("number of threads must be at least 1\n");
+ return usage();
}
- endptr = NULL;
- errno = 0;
- gid = strtoul(argv[3], &endptr, 10);
- if (*endptr != '\0' || errno != 0) {
- ERROR("Invalid gid");
- return usage();
- }
-
- /* cleanup from previous instance, if necessary */
- umount2(MOUNT_POINT, 2);
-
- fd = open("/dev/fuse", O_RDWR);
- if (fd < 0){
- ERROR("cannot open fuse device (%d)\n", errno);
- return -1;
- }
-
- sprintf(opts, "fd=%i,rootmode=40000,default_permissions,allow_other,"
- "user_id=%d,group_id=%d", fd, uid, gid);
-
- res = mount("/dev/fuse", MOUNT_POINT, "fuse", MS_NOSUID | MS_NODEV, opts);
- if (res < 0) {
- ERROR("cannot mount fuse filesystem (%d)\n", errno);
- return -1;
- }
-
- if (setgid(gid) < 0) {
- ERROR("cannot setgid!\n");
- return -1;
- }
- if (setuid(uid) < 0) {
- ERROR("cannot setuid!\n");
- return -1;
- }
-
- fuse_init(&fuse, fd, path);
-
- umask(0);
- handle_fuse_requests(&fuse);
-
- return 0;
+ res = run(source_path, dest_path, uid, gid, num_threads);
+ return res < 0 ? 1 : 0;
}
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 2c1ba42..dbbce06 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -56,6 +56,7 @@
ionice \
touch \
lsof \
+ du \
md5 \
getenforce \
setenforce \
@@ -70,10 +71,17 @@
TOOLS += r
endif
-LOCAL_SRC_FILES:= \
+ALL_TOOLS = $(TOOLS)
+ALL_TOOLS += \
+ cp \
+ grep
+
+LOCAL_SRC_FILES := \
dynarray.c \
toolbox.c \
- $(patsubst %,%.c,$(TOOLS))
+ $(patsubst %,%.c,$(TOOLS)) \
+ cp/cp.c cp/utils.c \
+ grep/grep.c grep/fastgrep.c grep/file.c grep/queue.c grep/util.c
LOCAL_C_INCLUDES := bionic/libc/bionic
@@ -83,7 +91,7 @@
libusbhost \
libselinux
-LOCAL_MODULE:= toolbox
+LOCAL_MODULE := toolbox
# Including this will define $(intermediates).
#
@@ -92,7 +100,7 @@
$(LOCAL_PATH)/toolbox.c: $(intermediates)/tools.h
TOOLS_H := $(intermediates)/tools.h
-$(TOOLS_H): PRIVATE_TOOLS := $(TOOLS)
+$(TOOLS_H): PRIVATE_TOOLS := $(ALL_TOOLS)
$(TOOLS_H): PRIVATE_CUSTOM_TOOL = echo "/* file generated automatically */" > $@ ; for t in $(PRIVATE_TOOLS) ; do echo "TOOL($$t)" >> $@ ; done
$(TOOLS_H): $(LOCAL_PATH)/Android.mk
$(TOOLS_H):
@@ -100,7 +108,7 @@
# Make #!/system/bin/toolbox launchers for each tool.
#
-SYMLINKS := $(addprefix $(TARGET_OUT)/bin/,$(TOOLS))
+SYMLINKS := $(addprefix $(TARGET_OUT)/bin/,$(ALL_TOOLS))
$(SYMLINKS): TOOLBOX_BINARY := $(LOCAL_MODULE)
$(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk
@echo "Symlink: $@ -> $(TOOLBOX_BINARY)"
diff --git a/toolbox/cp/cp.c b/toolbox/cp/cp.c
new file mode 100644
index 0000000..bd3c70e
--- /dev/null
+++ b/toolbox/cp/cp.c
@@ -0,0 +1,552 @@
+/* $NetBSD: cp.c,v 1.58 2012/01/04 15:58:37 christos Exp $ */
+
+/*
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * David Hitz of Auspex Systems Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT(
+"@(#) Copyright (c) 1988, 1993, 1994\
+ The Regents of the University of California. All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cp.c 8.5 (Berkeley) 4/29/95";
+#else
+__RCSID("$NetBSD: cp.c,v 1.58 2012/01/04 15:58:37 christos Exp $");
+#endif
+#endif /* not lint */
+
+/*
+ * Cp copies source files to target files.
+ *
+ * The global PATH_T structure "to" always contains the path to the
+ * current target file. Since fts(3) does not change directories,
+ * this path can be either absolute or dot-relative.
+ *
+ * The basic algorithm is to initialize "to" and use fts(3) to traverse
+ * the file hierarchy rooted in the argument list. A trivial case is the
+ * case of 'cp file1 file2'. The more interesting case is the case of
+ * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the
+ * path (relative to the root of the traversal) is appended to dir (stored
+ * in "to") to form the final target path.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <locale.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+#define STRIP_TRAILING_SLASH(p) { \
+ while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \
+ *--(p).p_end = '\0'; \
+}
+
+static char empty[] = "";
+PATH_T to = { .p_end = to.p_path, .target_end = empty };
+
+uid_t myuid;
+int Hflag, Lflag, Rflag, Pflag, fflag, iflag, lflag, pflag, rflag, vflag, Nflag;
+mode_t myumask;
+sig_atomic_t pinfo;
+
+enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
+
+static int copy(char *[], enum op, int);
+
+static void
+progress(int sig __unused)
+{
+
+ pinfo++;
+}
+
+int
+cp_main(int argc, char *argv[])
+{
+ struct stat to_stat, tmp_stat;
+ enum op type;
+ int ch, fts_options, r, have_trailing_slash;
+ char *target, **src;
+
+#ifndef ANDROID
+ setprogname(argv[0]);
+#endif
+ (void)setlocale(LC_ALL, "");
+
+ Hflag = Lflag = Pflag = Rflag = 0;
+ while ((ch = getopt(argc, argv, "HLNPRfailprv")) != -1)
+ switch (ch) {
+ case 'H':
+ Hflag = 1;
+ Lflag = Pflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ Hflag = Pflag = 0;
+ break;
+ case 'N':
+ Nflag = 1;
+ break;
+ case 'P':
+ Pflag = 1;
+ Hflag = Lflag = 0;
+ break;
+ case 'R':
+ Rflag = 1;
+ break;
+ case 'a':
+ Pflag = 1;
+ pflag = 1;
+ Rflag = 1;
+ Hflag = Lflag = 0;
+ break;
+ case 'f':
+ fflag = 1;
+ iflag = 0;
+ break;
+ case 'i':
+ iflag = isatty(fileno(stdin));
+ fflag = 0;
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ case '?':
+ default:
+ cp_usage();
+ /* NOTREACHED */
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2)
+ cp_usage();
+
+ fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
+ if (rflag) {
+ if (Rflag) {
+ errx(EXIT_FAILURE,
+ "the -R and -r options may not be specified together.");
+ /* NOTREACHED */
+ }
+ if (Hflag || Lflag || Pflag) {
+ errx(EXIT_FAILURE,
+ "the -H, -L, and -P options may not be specified with the -r option.");
+ /* NOTREACHED */
+ }
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL;
+ }
+
+ if (Rflag) {
+ if (Hflag)
+ fts_options |= FTS_COMFOLLOW;
+ if (Lflag) {
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL;
+ }
+ } else if (!Pflag) {
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL | FTS_COMFOLLOW;
+ }
+
+ myuid = getuid();
+
+ /* Copy the umask for explicit mode setting. */
+ myumask = umask(0);
+ (void)umask(myumask);
+
+ /* Save the target base in "to". */
+ target = argv[--argc];
+ if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path))
+ errx(EXIT_FAILURE, "%s: name too long", target);
+ to.p_end = to.p_path + strlen(to.p_path);
+ have_trailing_slash = (to.p_end[-1] == '/');
+ if (have_trailing_slash)
+ STRIP_TRAILING_SLASH(to);
+ to.target_end = to.p_end;
+
+ /* Set end of argument list for fts(3). */
+ argv[argc] = NULL;
+
+#ifndef ANDROID
+ (void)signal(SIGINFO, progress);
+#endif
+
+ /*
+ * Cp has two distinct cases:
+ *
+ * cp [-R] source target
+ * cp [-R] source1 ... sourceN directory
+ *
+ * In both cases, source can be either a file or a directory.
+ *
+ * In (1), the target becomes a copy of the source. That is, if the
+ * source is a file, the target will be a file, and likewise for
+ * directories.
+ *
+ * In (2), the real target is not directory, but "directory/source".
+ */
+ if (Pflag)
+ r = lstat(to.p_path, &to_stat);
+ else
+ r = stat(to.p_path, &to_stat);
+ if (r == -1 && errno != ENOENT) {
+ err(EXIT_FAILURE, "%s", to.p_path);
+ /* NOTREACHED */
+ }
+ if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
+ /*
+ * Case (1). Target is not a directory.
+ */
+ if (argc > 1)
+ cp_usage();
+ /*
+ * Need to detect the case:
+ * cp -R dir foo
+ * Where dir is a directory and foo does not exist, where
+ * we want pathname concatenations turned on but not for
+ * the initial mkdir().
+ */
+ if (r == -1) {
+ if (rflag || (Rflag && (Lflag || Hflag)))
+ r = stat(*argv, &tmp_stat);
+ else
+ r = lstat(*argv, &tmp_stat);
+ if (r == -1) {
+ err(EXIT_FAILURE, "%s", *argv);
+ /* NOTREACHED */
+ }
+
+ if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag))
+ type = DIR_TO_DNE;
+ else
+ type = FILE_TO_FILE;
+ } else
+ type = FILE_TO_FILE;
+
+ if (have_trailing_slash && type == FILE_TO_FILE) {
+ if (r == -1)
+ errx(1, "directory %s does not exist",
+ to.p_path);
+ else
+ errx(1, "%s is not a directory", to.p_path);
+ }
+ } else {
+ /*
+ * Case (2). Target is a directory.
+ */
+ type = FILE_TO_DIR;
+ }
+
+ /*
+ * make "cp -rp src/ dst" behave like "cp -rp src dst" not
+ * like "cp -rp src/. dst"
+ */
+ for (src = argv; *src; src++) {
+ size_t len = strlen(*src);
+ while (len-- > 1 && (*src)[len] == '/')
+ (*src)[len] = '\0';
+ }
+
+ exit(copy(argv, type, fts_options));
+ /* NOTREACHED */
+}
+
+static int dnestack[MAXPATHLEN]; /* unlikely we'll have more nested dirs */
+static ssize_t dnesp;
+static void
+pushdne(int dne)
+{
+
+ dnestack[dnesp++] = dne;
+ assert(dnesp < MAXPATHLEN);
+}
+
+static int
+popdne(void)
+{
+ int rv;
+
+ rv = dnestack[--dnesp];
+ assert(dnesp >= 0);
+ return rv;
+}
+
+static int
+copy(char *argv[], enum op type, int fts_options)
+{
+ struct stat to_stat;
+ FTS *ftsp;
+ FTSENT *curr;
+ int base, dne, sval;
+ int this_failed, any_failed;
+ size_t nlen;
+ char *p, *target_mid;
+
+ base = 0; /* XXX gcc -Wuninitialized (see comment below) */
+
+ if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL)
+ err(EXIT_FAILURE, "%s", argv[0]);
+ /* NOTREACHED */
+ for (any_failed = 0; (curr = fts_read(ftsp)) != NULL;) {
+ this_failed = 0;
+ switch (curr->fts_info) {
+ case FTS_NS:
+ case FTS_DNR:
+ case FTS_ERR:
+ warnx("%s: %s", curr->fts_path,
+ strerror(curr->fts_errno));
+ this_failed = any_failed = 1;
+ continue;
+ case FTS_DC: /* Warn, continue. */
+ warnx("%s: directory causes a cycle", curr->fts_path);
+ this_failed = any_failed = 1;
+ continue;
+ }
+
+ /*
+ * If we are in case (2) or (3) above, we need to append the
+ * source name to the target name.
+ */
+ if (type != FILE_TO_FILE) {
+ if ((curr->fts_namelen +
+ to.target_end - to.p_path + 1) > MAXPATHLEN) {
+ warnx("%s/%s: name too long (not copied)",
+ to.p_path, curr->fts_name);
+ this_failed = any_failed = 1;
+ continue;
+ }
+
+ /*
+ * Need to remember the roots of traversals to create
+ * correct pathnames. If there's a directory being
+ * copied to a non-existent directory, e.g.
+ * cp -R a/dir noexist
+ * the resulting path name should be noexist/foo, not
+ * noexist/dir/foo (where foo is a file in dir), which
+ * is the case where the target exists.
+ *
+ * Also, check for "..". This is for correct path
+ * concatentation for paths ending in "..", e.g.
+ * cp -R .. /tmp
+ * Paths ending in ".." are changed to ".". This is
+ * tricky, but seems the easiest way to fix the problem.
+ *
+ * XXX
+ * Since the first level MUST be FTS_ROOTLEVEL, base
+ * is always initialized.
+ */
+ if (curr->fts_level == FTS_ROOTLEVEL) {
+ if (type != DIR_TO_DNE) {
+ p = strrchr(curr->fts_path, '/');
+ base = (p == NULL) ? 0 :
+ (int)(p - curr->fts_path + 1);
+
+ if (!strcmp(&curr->fts_path[base],
+ ".."))
+ base += 1;
+ } else
+ base = curr->fts_pathlen;
+ }
+
+ p = &curr->fts_path[base];
+ nlen = curr->fts_pathlen - base;
+ target_mid = to.target_end;
+ if (*p != '/' && target_mid[-1] != '/')
+ *target_mid++ = '/';
+ *target_mid = 0;
+
+ if (target_mid - to.p_path + nlen >= PATH_MAX) {
+ warnx("%s%s: name too long (not copied)",
+ to.p_path, p);
+ this_failed = any_failed = 1;
+ continue;
+ }
+ (void)strncat(target_mid, p, nlen);
+ to.p_end = target_mid + nlen;
+ *to.p_end = 0;
+ STRIP_TRAILING_SLASH(to);
+ }
+
+ sval = Pflag ? lstat(to.p_path, &to_stat) : stat(to.p_path, &to_stat);
+ /* Not an error but need to remember it happened */
+ if (sval == -1)
+ dne = 1;
+ else {
+ if (to_stat.st_dev == curr->fts_statp->st_dev &&
+ to_stat.st_ino == curr->fts_statp->st_ino) {
+ warnx("%s and %s are identical (not copied).",
+ to.p_path, curr->fts_path);
+ this_failed = any_failed = 1;
+ if (S_ISDIR(curr->fts_statp->st_mode))
+ (void)fts_set(ftsp, curr, FTS_SKIP);
+ continue;
+ }
+ if (!S_ISDIR(curr->fts_statp->st_mode) &&
+ S_ISDIR(to_stat.st_mode)) {
+ warnx("cannot overwrite directory %s with non-directory %s",
+ to.p_path, curr->fts_path);
+ this_failed = any_failed = 1;
+ continue;
+ }
+ dne = 0;
+ }
+
+ switch (curr->fts_statp->st_mode & S_IFMT) {
+ case S_IFLNK:
+ /* Catch special case of a non dangling symlink */
+ if((fts_options & FTS_LOGICAL) ||
+ ((fts_options & FTS_COMFOLLOW) && curr->fts_level == 0)) {
+ if (copy_file(curr, dne))
+ this_failed = any_failed = 1;
+ } else {
+ if (copy_link(curr, !dne))
+ this_failed = any_failed = 1;
+ }
+ break;
+ case S_IFDIR:
+ if (!Rflag && !rflag) {
+ if (curr->fts_info == FTS_D)
+ warnx("%s is a directory (not copied).",
+ curr->fts_path);
+ (void)fts_set(ftsp, curr, FTS_SKIP);
+ this_failed = any_failed = 1;
+ break;
+ }
+
+ /*
+ * Directories get noticed twice:
+ * In the first pass, create it if needed.
+ * In the second pass, after the children have been copied, set the permissions.
+ */
+ if (curr->fts_info == FTS_D) /* First pass */
+ {
+ /*
+ * If the directory doesn't exist, create the new
+ * one with the from file mode plus owner RWX bits,
+ * modified by the umask. Trade-off between being
+ * able to write the directory (if from directory is
+ * 555) and not causing a permissions race. If the
+ * umask blocks owner writes, we fail..
+ */
+ pushdne(dne);
+ if (dne) {
+ if (mkdir(to.p_path,
+ curr->fts_statp->st_mode | S_IRWXU) < 0)
+ err(EXIT_FAILURE, "%s",
+ to.p_path);
+ /* NOTREACHED */
+ } else if (!S_ISDIR(to_stat.st_mode)) {
+ errno = ENOTDIR;
+ err(EXIT_FAILURE, "%s",
+ to.p_path);
+ /* NOTREACHED */
+ }
+ }
+ else if (curr->fts_info == FTS_DP) /* Second pass */
+ {
+ /*
+ * If not -p and directory didn't exist, set it to be
+ * the same as the from directory, umodified by the
+ * umask; arguably wrong, but it's been that way
+ * forever.
+ */
+ if (pflag && setfile(curr->fts_statp, 0))
+ this_failed = any_failed = 1;
+ else if ((dne = popdne()))
+ (void)chmod(to.p_path,
+ curr->fts_statp->st_mode);
+ }
+ else
+ {
+ warnx("directory %s encountered when not expected.",
+ curr->fts_path);
+ this_failed = any_failed = 1;
+ break;
+ }
+
+ break;
+ case S_IFBLK:
+ case S_IFCHR:
+ if (Rflag) {
+ if (copy_special(curr->fts_statp, !dne))
+ this_failed = any_failed = 1;
+ } else
+ if (copy_file(curr, dne))
+ this_failed = any_failed = 1;
+ break;
+ case S_IFIFO:
+ if (Rflag) {
+ if (copy_fifo(curr->fts_statp, !dne))
+ this_failed = any_failed = 1;
+ } else
+ if (copy_file(curr, dne))
+ this_failed = any_failed = 1;
+ break;
+ default:
+ if (copy_file(curr, dne))
+ this_failed = any_failed = 1;
+ break;
+ }
+ if (vflag && !this_failed)
+ (void)printf("%s -> %s\n", curr->fts_path, to.p_path);
+ }
+ if (errno) {
+ err(EXIT_FAILURE, "fts_read");
+ /* NOTREACHED */
+ }
+ (void)fts_close(ftsp);
+ return (any_failed);
+}
diff --git a/toolbox/cp/extern.h b/toolbox/cp/extern.h
new file mode 100644
index 0000000..ffbadf7
--- /dev/null
+++ b/toolbox/cp/extern.h
@@ -0,0 +1,61 @@
+/* $NetBSD: extern.h,v 1.17 2012/01/04 15:58:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.2 (Berkeley) 4/1/94
+ */
+
+#ifndef _EXTERN_H_
+#define _EXTERN_H_
+
+typedef struct {
+ char *p_end; /* pointer to NULL at end of path */
+ char *target_end; /* pointer to end of target base */
+ char p_path[MAXPATHLEN + 1]; /* pointer to the start of a path */
+} PATH_T;
+
+extern PATH_T to;
+extern uid_t myuid;
+extern int Rflag, rflag, Hflag, Lflag, Pflag, fflag, iflag, lflag, pflag, Nflag;
+extern mode_t myumask;
+extern sig_atomic_t pinfo;
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int copy_fifo(struct stat *, int);
+int copy_file(FTSENT *, int);
+int copy_link(FTSENT *, int);
+int copy_special(struct stat *, int);
+int set_utimes(const char *, struct stat *);
+int setfile(struct stat *, int);
+void cp_usage(void) __attribute__((__noreturn__));
+__END_DECLS
+
+#endif /* !_EXTERN_H_ */
diff --git a/toolbox/cp/utils.c b/toolbox/cp/utils.c
new file mode 100644
index 0000000..b682bbe
--- /dev/null
+++ b/toolbox/cp/utils.c
@@ -0,0 +1,446 @@
+/* $NetBSD: utils.c,v 1.41 2012/01/04 15:58:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94";
+#else
+__RCSID("$NetBSD: utils.c,v 1.41 2012/01/04 15:58:37 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#ifndef ANDROID
+#include <sys/extattr.h>
+#endif
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+#ifdef ANDROID
+#define MAXBSIZE 65536
+#endif
+
+#define MMAP_MAX_SIZE (8 * 1048576)
+#define MMAP_MAX_WRITE (64 * 1024)
+
+int
+set_utimes(const char *file, struct stat *fs)
+{
+ static struct timeval tv[2];
+
+#ifdef ANDROID
+ tv[0].tv_sec = fs->st_atime;
+ tv[0].tv_usec = 0;
+ tv[1].tv_sec = fs->st_mtime;
+ tv[1].tv_usec = 0;
+
+ if (utimes(file, tv)) {
+ warn("utimes: %s", file);
+ return 1;
+ }
+#else
+ TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
+ TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
+
+ if (lutimes(file, tv)) {
+ warn("lutimes: %s", file);
+ return (1);
+ }
+#endif
+ return (0);
+}
+
+struct finfo {
+ const char *from;
+ const char *to;
+ size_t size;
+};
+
+static void
+progress(const struct finfo *fi, size_t written)
+{
+ int pcent = (int)((100.0 * written) / fi->size);
+
+ pinfo = 0;
+ (void)fprintf(stderr, "%s => %s %zu/%zu bytes %d%% written\n",
+ fi->from, fi->to, written, fi->size, pcent);
+}
+
+int
+copy_file(FTSENT *entp, int dne)
+{
+ static char buf[MAXBSIZE];
+ struct stat to_stat, *fs;
+ int ch, checkch, from_fd, rcount, rval, to_fd, tolnk, wcount;
+ char *p;
+ size_t ptotal = 0;
+
+ if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
+ warn("%s", entp->fts_path);
+ return (1);
+ }
+
+ to_fd = -1;
+ fs = entp->fts_statp;
+ tolnk = ((Rflag && !(Lflag || Hflag)) || Pflag);
+
+ /*
+ * If the file exists and we're interactive, verify with the user.
+ * If the file DNE, set the mode to be the from file, minus setuid
+ * bits, modified by the umask; arguably wrong, but it makes copying
+ * executables work right and it's been that way forever. (The
+ * other choice is 666 or'ed with the execute bits on the from file
+ * modified by the umask.)
+ */
+ if (!dne) {
+ struct stat sb;
+ int sval;
+
+ if (iflag) {
+ (void)fprintf(stderr, "overwrite %s? ", to.p_path);
+ checkch = ch = getchar();
+ while (ch != '\n' && ch != EOF)
+ ch = getchar();
+ if (checkch != 'y' && checkch != 'Y') {
+ (void)close(from_fd);
+ return (0);
+ }
+ }
+
+ sval = tolnk ?
+ lstat(to.p_path, &sb) : stat(to.p_path, &sb);
+ if (sval == -1) {
+ warn("stat: %s", to.p_path);
+ (void)close(from_fd);
+ return (1);
+ }
+
+ if (!(tolnk && S_ISLNK(sb.st_mode)))
+ to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
+ } else
+ to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+ fs->st_mode & ~(S_ISUID | S_ISGID));
+
+ if (to_fd == -1 && (fflag || tolnk)) {
+ /*
+ * attempt to remove existing destination file name and
+ * create a new file
+ */
+ (void)unlink(to.p_path);
+ to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+ fs->st_mode & ~(S_ISUID | S_ISGID));
+ }
+
+ if (to_fd == -1) {
+ warn("%s", to.p_path);
+ (void)close(from_fd);
+ return (1);
+ }
+
+ rval = 0;
+
+ /* if hard linking then simply close the open fds, link and return */
+ if (lflag) {
+ (void)close(from_fd);
+ (void)close(to_fd);
+ (void)unlink(to.p_path);
+ if (link(entp->fts_path, to.p_path)) {
+ warn("%s", to.p_path);
+ return (1);
+ }
+ return (0);
+ }
+ /* NOTREACHED */
+
+ /*
+ * There's no reason to do anything other than close the file
+ * now if it's empty, so let's not bother.
+ */
+ if (fs->st_size > 0) {
+ struct finfo fi;
+
+ fi.from = entp->fts_path;
+ fi.to = to.p_path;
+ fi.size = (size_t)fs->st_size;
+
+ /*
+ * Mmap and write if less than 8M (the limit is so
+ * we don't totally trash memory on big files).
+ * This is really a minor hack, but it wins some CPU back.
+ */
+ bool use_read;
+
+ use_read = true;
+ if (fs->st_size <= MMAP_MAX_SIZE) {
+ size_t fsize = (size_t)fs->st_size;
+ p = mmap(NULL, fsize, PROT_READ, MAP_FILE|MAP_SHARED,
+ from_fd, (off_t)0);
+ if (p != MAP_FAILED) {
+ size_t remainder;
+
+ use_read = false;
+
+ (void) madvise(p, (size_t)fs->st_size,
+ MADV_SEQUENTIAL);
+
+ /*
+ * Write out the data in small chunks to
+ * avoid locking the output file for a
+ * long time if the reading the data from
+ * the source is slow.
+ */
+ remainder = fsize;
+ do {
+ ssize_t chunk;
+
+ chunk = (remainder > MMAP_MAX_WRITE) ?
+ MMAP_MAX_WRITE : remainder;
+ if (write(to_fd, &p[fsize - remainder],
+ chunk) != chunk) {
+ warn("%s", to.p_path);
+ rval = 1;
+ break;
+ }
+ remainder -= chunk;
+ ptotal += chunk;
+ if (pinfo)
+ progress(&fi, ptotal);
+ } while (remainder > 0);
+
+ if (munmap(p, fsize) < 0) {
+ warn("%s", entp->fts_path);
+ rval = 1;
+ }
+ }
+ }
+
+ if (use_read) {
+ while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
+ wcount = write(to_fd, buf, (size_t)rcount);
+ if (rcount != wcount || wcount == -1) {
+ warn("%s", to.p_path);
+ rval = 1;
+ break;
+ }
+ ptotal += wcount;
+ if (pinfo)
+ progress(&fi, ptotal);
+ }
+ if (rcount < 0) {
+ warn("%s", entp->fts_path);
+ rval = 1;
+ }
+ }
+ }
+
+#ifndef ANDROID
+ if (pflag && (fcpxattr(from_fd, to_fd) != 0))
+ warn("%s: error copying extended attributes", to.p_path);
+#endif
+
+ (void)close(from_fd);
+
+ if (rval == 1) {
+ (void)close(to_fd);
+ return (1);
+ }
+
+ if (pflag && setfile(fs, to_fd))
+ rval = 1;
+ /*
+ * If the source was setuid or setgid, lose the bits unless the
+ * copy is owned by the same user and group.
+ */
+#define RETAINBITS \
+ (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
+ if (!pflag && dne
+ && fs->st_mode & (S_ISUID | S_ISGID) && fs->st_uid == myuid) {
+ if (fstat(to_fd, &to_stat)) {
+ warn("%s", to.p_path);
+ rval = 1;
+ } else if (fs->st_gid == to_stat.st_gid &&
+ fchmod(to_fd, fs->st_mode & RETAINBITS & ~myumask)) {
+ warn("%s", to.p_path);
+ rval = 1;
+ }
+ }
+ if (close(to_fd)) {
+ warn("%s", to.p_path);
+ rval = 1;
+ }
+ /* set the mod/access times now after close of the fd */
+ if (pflag && set_utimes(to.p_path, fs)) {
+ rval = 1;
+ }
+ return (rval);
+}
+
+int
+copy_link(FTSENT *p, int exists)
+{
+ int len;
+ char target[MAXPATHLEN];
+
+ if ((len = readlink(p->fts_path, target, sizeof(target)-1)) == -1) {
+ warn("readlink: %s", p->fts_path);
+ return (1);
+ }
+ target[len] = '\0';
+ if (exists && unlink(to.p_path)) {
+ warn("unlink: %s", to.p_path);
+ return (1);
+ }
+ if (symlink(target, to.p_path)) {
+ warn("symlink: %s", target);
+ return (1);
+ }
+ return (pflag ? setfile(p->fts_statp, 0) : 0);
+}
+
+int
+copy_fifo(struct stat *from_stat, int exists)
+{
+ if (exists && unlink(to.p_path)) {
+ warn("unlink: %s", to.p_path);
+ return (1);
+ }
+ if (mkfifo(to.p_path, from_stat->st_mode)) {
+ warn("mkfifo: %s", to.p_path);
+ return (1);
+ }
+ return (pflag ? setfile(from_stat, 0) : 0);
+}
+
+int
+copy_special(struct stat *from_stat, int exists)
+{
+ if (exists && unlink(to.p_path)) {
+ warn("unlink: %s", to.p_path);
+ return (1);
+ }
+ if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) {
+ warn("mknod: %s", to.p_path);
+ return (1);
+ }
+ return (pflag ? setfile(from_stat, 0) : 0);
+}
+
+
+/*
+ * Function: setfile
+ *
+ * Purpose:
+ * Set the owner/group/permissions for the "to" file to the information
+ * in the stat structure. If fd is zero, also call set_utimes() to set
+ * the mod/access times. If fd is non-zero, the caller must do a utimes
+ * itself after close(fd).
+ */
+int
+setfile(struct stat *fs, int fd)
+{
+ int rval, islink;
+
+ rval = 0;
+ islink = S_ISLNK(fs->st_mode);
+ fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
+
+ /*
+ * Changing the ownership probably won't succeed, unless we're root
+ * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting
+ * the mode; current BSD behavior is to remove all setuid bits on
+ * chown. If chown fails, lose setuid/setgid bits.
+ */
+ if (fd ? fchown(fd, fs->st_uid, fs->st_gid) :
+ lchown(to.p_path, fs->st_uid, fs->st_gid)) {
+ if (errno != EPERM) {
+ warn("chown: %s", to.p_path);
+ rval = 1;
+ }
+ fs->st_mode &= ~(S_ISUID | S_ISGID);
+ }
+#ifdef ANDROID
+ if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
+#else
+ if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
+#endif
+ warn("chmod: %s", to.p_path);
+ rval = 1;
+ }
+
+#ifndef ANDROID
+ if (!islink && !Nflag) {
+ unsigned long fflags = fs->st_flags;
+ /*
+ * XXX
+ * NFS doesn't support chflags; ignore errors unless
+ * there's reason to believe we're losing bits.
+ * (Note, this still won't be right if the server
+ * supports flags and we were trying to *remove* flags
+ * on a file that we copied, i.e., that we didn't create.)
+ */
+ errno = 0;
+ if ((fd ? fchflags(fd, fflags) :
+ chflags(to.p_path, fflags)) == -1)
+ if (errno != EOPNOTSUPP || fs->st_flags != 0) {
+ warn("chflags: %s", to.p_path);
+ rval = 1;
+ }
+ }
+#endif
+ /* if fd is non-zero, caller must call set_utimes() after close() */
+ if (fd == 0 && set_utimes(to.p_path, fs))
+ rval = 1;
+ return (rval);
+}
+
+void
+cp_usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src target\n"
+ " cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src1 ... srcN directory\n");
+ exit(1);
+ /* NOTREACHED */
+}
diff --git a/toolbox/dd.c b/toolbox/dd.c
index c6af3ea..350f1d2 100644
--- a/toolbox/dd.c
+++ b/toolbox/dd.c
@@ -64,7 +64,7 @@
#include "dd.h"
-#define NO_CONV
+//#define NO_CONV
//#include "extern.h"
void block(void);
@@ -91,13 +91,11 @@
extern u_int files_cnt;
extern int progress;
extern const u_char *ctab;
-extern const u_char a2e_32V[], a2e_POSIX[];
-extern const u_char e2a_32V[], e2a_POSIX[];
-extern const u_char a2ibm_32V[], a2ibm_POSIX[];
-extern u_char casetab[];
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define DEFFILEMODE (S_IRUSR | S_IWUSR)
static void dd_close(void);
static void dd_in(void);
@@ -188,14 +186,14 @@
} else {
#define OFLAGS \
(O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
- out.fd = open(out.name, O_RDWR | OFLAGS /*, DEFFILEMODE */);
+ out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE);
/*
* May not have read access, so try again with write only.
* Without read we may have a problem if output also does
* not support seeks.
*/
if (out.fd < 0) {
- out.fd = open(out.name, O_WRONLY | OFLAGS /*, DEFFILEMODE */);
+ out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
out.flags |= NOREAD;
}
if (out.fd < 0) {
@@ -243,42 +241,6 @@
if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
(void)ftruncate(out.fd, (off_t)out.offset * out.dbsz);
- /*
- * If converting case at the same time as another conversion, build a
- * table that does both at once. If just converting case, use the
- * built-in tables.
- */
- if (ddflags & (C_LCASE|C_UCASE)) {
-#ifdef NO_CONV
- /* Should not get here, but just in case... */
- fprintf(stderr, "case conv and -DNO_CONV\n");
- exit(1);
- /* NOTREACHED */
-#else /* NO_CONV */
- u_int cnt;
-
- if (ddflags & C_ASCII || ddflags & C_EBCDIC) {
- if (ddflags & C_LCASE) {
- for (cnt = 0; cnt < 0377; ++cnt)
- casetab[cnt] = tolower(ctab[cnt]);
- } else {
- for (cnt = 0; cnt < 0377; ++cnt)
- casetab[cnt] = toupper(ctab[cnt]);
- }
- } else {
- if (ddflags & C_LCASE) {
- for (cnt = 0; cnt < 0377; ++cnt)
- casetab[cnt] = tolower(cnt);
- } else {
- for (cnt = 0; cnt < 0377; ++cnt)
- casetab[cnt] = toupper(cnt);
- }
- }
-
- ctab = casetab;
-#endif /* NO_CONV */
- }
-
(void)gettimeofday(&st.start, NULL); /* Statistics timestamp. */
}
@@ -796,6 +758,9 @@
void
def_close(void)
{
+ if (ddflags & C_FDATASYNC) {
+ fdatasync(out.fd);
+ }
/* Just update the count, everything is already in the buffer. */
if (in.dbcnt)
@@ -1301,21 +1266,14 @@
u_int set, noset;
const u_char *ctab;
} clist[] = {
- { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX },
{ "block", C_BLOCK, C_UNBLOCK, NULL },
- { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX },
- { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX },
- { "lcase", C_LCASE, C_UCASE, NULL },
+ { "fdatasync", C_FDATASYNC, 0, NULL },
{ "noerror", C_NOERROR, 0, NULL },
{ "notrunc", C_NOTRUNC, 0, NULL },
- { "oldascii", C_ASCII, C_EBCDIC, e2a_32V },
- { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V },
- { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V },
{ "osync", C_OSYNC, C_BS, NULL },
{ "sparse", C_SPARSE, 0, NULL },
{ "swab", C_SWAB, 0, NULL },
{ "sync", C_SYNC, 0, NULL },
- { "ucase", C_UCASE, C_LCASE, NULL },
{ "unblock", C_UNBLOCK, C_BLOCK, NULL },
/* If you add items to this table, be sure to add the
* conversions to the C_BS check in the jcl routine above.
diff --git a/toolbox/dd.h b/toolbox/dd.h
index cca1024..89f2833 100644
--- a/toolbox/dd.h
+++ b/toolbox/dd.h
@@ -91,3 +91,4 @@
#define C_UNBLOCK 0x80000
#define C_OSYNC 0x100000
#define C_SPARSE 0x200000
+#define C_FDATASYNC 0x400000
diff --git a/toolbox/du.c b/toolbox/du.c
new file mode 100644
index 0000000..06374a4
--- /dev/null
+++ b/toolbox/du.c
@@ -0,0 +1,322 @@
+/* $NetBSD: du.c,v 1.33 2008/07/30 22:03:40 dsl Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Newcomb.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\
+ The Regents of the University of California. All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)du.c 8.5 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: du.c,v 1.33 2008/07/30 22:03:40 dsl Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <util.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+int linkchk(dev_t, ino_t);
+void prstat(const char *, int64_t);
+void usage(void);
+
+long blocksize;
+
+#define howmany(x, y) (((x)+((y)-1))/(y))
+
+int
+du_main(int argc, char *argv[])
+{
+ FTS *fts;
+ FTSENT *p;
+ int64_t totalblocks;
+ int ftsoptions, listfiles;
+ int depth;
+ int Hflag, Lflag, aflag, ch, cflag, dflag, gkmflag, nflag, rval, sflag;
+ const char *noargv[2];
+
+ Hflag = Lflag = aflag = cflag = dflag = gkmflag = sflag = 0;
+ totalblocks = 0;
+ ftsoptions = FTS_PHYSICAL;
+ depth = INT_MAX;
+ while ((ch = getopt(argc, argv, "HLPacd:ghkmnrsx")) != -1)
+ switch (ch) {
+ case 'H':
+ Hflag = 1;
+ Lflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ Hflag = 0;
+ break;
+ case 'P':
+ Hflag = Lflag = 0;
+ break;
+ case 'a':
+ aflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ depth = atoi(optarg);
+ if (depth < 0 || depth > SHRT_MAX) {
+ warnx("invalid argument to option d: %s",
+ optarg);
+ usage();
+ }
+ break;
+ case 'g':
+ blocksize = 1024 * 1024 * 1024;
+ gkmflag = 1;
+ break;
+ case 'k':
+ blocksize = 1024;
+ gkmflag = 1;
+ break;
+ case 'm':
+ blocksize = 1024 * 1024;
+ gkmflag = 1;
+ break;
+ case 'r':
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 'x':
+ ftsoptions |= FTS_XDEV;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * XXX
+ * Because of the way that fts(3) works, logical walks will not count
+ * the blocks actually used by symbolic links. We rationalize this by
+ * noting that users computing logical sizes are likely to do logical
+ * copies, so not counting the links is correct. The real reason is
+ * that we'd have to re-implement the kernel's symbolic link traversing
+ * algorithm to get this right. If, for example, you have relative
+ * symbolic links referencing other relative symbolic links, it gets
+ * very nasty, very fast. The bottom line is that it's documented in
+ * the man page, so it's a feature.
+ */
+ if (Hflag)
+ ftsoptions |= FTS_COMFOLLOW;
+ if (Lflag) {
+ ftsoptions &= ~FTS_PHYSICAL;
+ ftsoptions |= FTS_LOGICAL;
+ }
+
+ listfiles = 0;
+ if (aflag) {
+ if (sflag || dflag)
+ usage();
+ listfiles = 1;
+ } else if (sflag) {
+ if (dflag)
+ usage();
+ depth = 0;
+ }
+
+ if (!*argv) {
+ noargv[0] = ".";
+ noargv[1] = NULL;
+ argv = __UNCONST(noargv);
+ }
+
+ if (!gkmflag)
+ blocksize = 512;
+ blocksize /= 512;
+
+ if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
+ err(1, "fts_open `%s'", *argv);
+
+ for (rval = 0; (p = fts_read(fts)) != NULL;) {
+ switch (p->fts_info) {
+ case FTS_D: /* Ignore. */
+ break;
+ case FTS_DP:
+ p->fts_parent->fts_number +=
+ p->fts_number += p->fts_statp->st_blocks;
+ if (cflag)
+ totalblocks += p->fts_statp->st_blocks;
+ /*
+ * If listing each directory, or not listing files
+ * or directories and this is post-order of the
+ * root of a traversal, display the total.
+ */
+ if (p->fts_level <= depth
+ || (!listfiles && !p->fts_level))
+ prstat(p->fts_path, p->fts_number);
+ break;
+ case FTS_DC: /* Ignore. */
+ break;
+ case FTS_DNR: /* Warn, continue. */
+ case FTS_ERR:
+ case FTS_NS:
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ rval = 1;
+ break;
+ default:
+ if (p->fts_statp->st_nlink > 1 &&
+ linkchk(p->fts_statp->st_dev, p->fts_statp->st_ino))
+ break;
+ /*
+ * If listing each file, or a non-directory file was
+ * the root of a traversal, display the total.
+ */
+ if (listfiles || !p->fts_level)
+ prstat(p->fts_path, p->fts_statp->st_blocks);
+ p->fts_parent->fts_number += p->fts_statp->st_blocks;
+ if (cflag)
+ totalblocks += p->fts_statp->st_blocks;
+ }
+ }
+ if (errno)
+ err(1, "fts_read");
+ if (cflag)
+ prstat("total", totalblocks);
+ exit(rval);
+}
+
+void
+prstat(const char *fname, int64_t blocks)
+{
+ (void)printf("%lld\t%s\n",
+ (long long)howmany(blocks, (int64_t)blocksize),
+ fname);
+}
+
+int
+linkchk(dev_t dev, ino_t ino)
+{
+ static struct entry {
+ dev_t dev;
+ ino_t ino;
+ } *htable;
+ static int htshift; /* log(allocated size) */
+ static int htmask; /* allocated size - 1 */
+ static int htused; /* 2*number of insertions */
+ static int sawzero; /* Whether zero is in table or not */
+ int h, h2;
+ uint64_t tmp;
+ /* this constant is (1<<64)/((1+sqrt(5))/2)
+ * aka (word size)/(golden ratio)
+ */
+ const uint64_t HTCONST = 11400714819323198485ULL;
+ const int HTBITS = CHAR_BIT * sizeof(tmp);
+
+ /* Never store zero in hashtable */
+ if (dev == 0 && ino == 0) {
+ h = sawzero;
+ sawzero = 1;
+ return h;
+ }
+
+ /* Extend hash table if necessary, keep load under 0.5 */
+ if (htused<<1 >= htmask) {
+ struct entry *ohtable;
+
+ if (!htable)
+ htshift = 10; /* starting hashtable size */
+ else
+ htshift++; /* exponential hashtable growth */
+
+ htmask = (1 << htshift) - 1;
+ htused = 0;
+
+ ohtable = htable;
+ htable = calloc(htmask+1, sizeof(*htable));
+ if (!htable)
+ err(1, "calloc");
+
+ /* populate newly allocated hashtable */
+ if (ohtable) {
+ int i;
+ for (i = 0; i <= htmask>>1; i++)
+ if (ohtable[i].ino || ohtable[i].dev)
+ linkchk(ohtable[i].dev, ohtable[i].ino);
+ free(ohtable);
+ }
+ }
+
+ /* multiplicative hashing */
+ tmp = dev;
+ tmp <<= HTBITS>>1;
+ tmp |= ino;
+ tmp *= HTCONST;
+ h = tmp >> (HTBITS - htshift);
+ h2 = 1 | ( tmp >> (HTBITS - (htshift<<1) - 1)); /* must be odd */
+
+ /* open address hashtable search with double hash probing */
+ while (htable[h].ino || htable[h].dev) {
+ if ((htable[h].ino == ino) && (htable[h].dev == dev))
+ return 1;
+ h = (h + h2) & htmask;
+ }
+
+ /* Insert the current entry into hashtable */
+ htable[h].dev = dev;
+ htable[h].ino = ino;
+ htused++;
+ return 0;
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr,
+ "usage: du [-H | -L | -P] [-a | -d depth | -s] [-cgkmrx] [file ...]\n");
+ exit(1);
+}
diff --git a/toolbox/grep/fastgrep.c b/toolbox/grep/fastgrep.c
new file mode 100644
index 0000000..2fcd864
--- /dev/null
+++ b/toolbox/grep/fastgrep.c
@@ -0,0 +1,336 @@
+/* $OpenBSD: util.c,v 1.36 2007/10/02 17:59:18 otto Exp $ */
+/* $FreeBSD: head/usr.bin/grep/fastgrep.c 211496 2010-08-19 09:28:59Z des $ */
+
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * Copyright (C) 2008 Gabor Kovesdan <gabor@FreeBSD.org>
+ * 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 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 AUTHOR 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.
+ */
+
+/*
+ * XXX: This file is a speed up for grep to cover the defects of the
+ * regex library. These optimizations should practically be implemented
+ * there keeping this code clean. This is a future TODO, but for the
+ * meantime, we need to use this workaround.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: fastgrep.c,v 1.5 2011/04/18 03:27:40 joerg Exp $");
+
+#include <limits.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "grep.h"
+
+static inline int grep_cmp(const unsigned char *, const unsigned char *, size_t);
+static inline void grep_revstr(unsigned char *, int);
+
+void
+fgrepcomp(fastgrep_t *fg, const char *pat)
+{
+ unsigned int i;
+
+ /* Initialize. */
+ fg->len = strlen(pat);
+ fg->bol = false;
+ fg->eol = false;
+ fg->reversed = false;
+
+ fg->pattern = (unsigned char *)grep_strdup(pat);
+
+ /* Preprocess pattern. */
+ for (i = 0; i <= UCHAR_MAX; i++)
+ fg->qsBc[i] = fg->len;
+ for (i = 1; i < fg->len; i++)
+ fg->qsBc[fg->pattern[i]] = fg->len - i;
+}
+
+/*
+ * Returns: -1 on failure, 0 on success
+ */
+int
+fastcomp(fastgrep_t *fg, const char *pat)
+{
+ unsigned int i;
+ int firstHalfDot = -1;
+ int firstLastHalfDot = -1;
+ int hasDot = 0;
+ int lastHalfDot = 0;
+ int shiftPatternLen;
+
+ /* Initialize. */
+ fg->len = strlen(pat);
+ fg->bol = false;
+ fg->eol = false;
+ fg->reversed = false;
+ fg->word = wflag;
+
+ /* Remove end-of-line character ('$'). */
+ if (fg->len > 0 && pat[fg->len - 1] == '$') {
+ fg->eol = true;
+ fg->len--;
+ }
+
+ /* Remove beginning-of-line character ('^'). */
+ if (pat[0] == '^') {
+ fg->bol = true;
+ fg->len--;
+ pat++;
+ }
+
+ if (fg->len >= 14 &&
+ memcmp(pat, "[[:<:]]", 7) == 0 &&
+ memcmp(pat + fg->len - 7, "[[:>:]]", 7) == 0) {
+ fg->len -= 14;
+ pat += 7;
+ /* Word boundary is handled separately in util.c */
+ fg->word = true;
+ }
+
+ /*
+ * pat has been adjusted earlier to not include '^', '$' or
+ * the word match character classes at the beginning and ending
+ * of the string respectively.
+ */
+ fg->pattern = grep_malloc(fg->len + 1);
+ memcpy(fg->pattern, pat, fg->len);
+ fg->pattern[fg->len] = '\0';
+
+ /* Look for ways to cheat...er...avoid the full regex engine. */
+ for (i = 0; i < fg->len; i++) {
+ /* Can still cheat? */
+ if (fg->pattern[i] == '.') {
+ hasDot = i;
+ if (i < fg->len / 2) {
+ if (firstHalfDot < 0)
+ /* Closest dot to the beginning */
+ firstHalfDot = i;
+ } else {
+ /* Closest dot to the end of the pattern. */
+ lastHalfDot = i;
+ if (firstLastHalfDot < 0)
+ firstLastHalfDot = i;
+ }
+ } else {
+ /* Free memory and let others know this is empty. */
+ free(fg->pattern);
+ fg->pattern = NULL;
+ return (-1);
+ }
+ }
+
+ /*
+ * Determine if a reverse search would be faster based on the placement
+ * of the dots.
+ */
+ if ((!(lflag || cflag)) && ((!(fg->bol || fg->eol)) &&
+ ((lastHalfDot) && ((firstHalfDot < 0) ||
+ ((fg->len - (lastHalfDot + 1)) < (size_t)firstHalfDot)))) &&
+ !oflag && !color) {
+ fg->reversed = true;
+ hasDot = fg->len - (firstHalfDot < 0 ?
+ firstLastHalfDot : firstHalfDot) - 1;
+ grep_revstr(fg->pattern, fg->len);
+ }
+
+ /*
+ * Normal Quick Search would require a shift based on the position the
+ * next character after the comparison is within the pattern. With
+ * wildcards, the position of the last dot effects the maximum shift
+ * distance.
+ * The closer to the end the wild card is the slower the search. A
+ * reverse version of this algorithm would be useful for wildcards near
+ * the end of the string.
+ *
+ * Examples:
+ * Pattern Max shift
+ * ------- ---------
+ * this 5
+ * .his 4
+ * t.is 3
+ * th.s 2
+ * thi. 1
+ */
+
+ /* Adjust the shift based on location of the last dot ('.'). */
+ shiftPatternLen = fg->len - hasDot;
+
+ /* Preprocess pattern. */
+ for (i = 0; i <= (signed)UCHAR_MAX; i++)
+ fg->qsBc[i] = shiftPatternLen;
+ for (i = hasDot + 1; i < fg->len; i++) {
+ fg->qsBc[fg->pattern[i]] = fg->len - i;
+ }
+
+ /*
+ * Put pattern back to normal after pre-processing to allow for easy
+ * comparisons later.
+ */
+ if (fg->reversed)
+ grep_revstr(fg->pattern, fg->len);
+
+ return (0);
+}
+
+int
+grep_search(fastgrep_t *fg, const unsigned char *data, size_t len, regmatch_t *pmatch)
+{
+ unsigned int j;
+ int ret = REG_NOMATCH;
+
+ if (pmatch->rm_so == (ssize_t)len)
+ return (ret);
+
+ if (fg->bol && pmatch->rm_so != 0) {
+ pmatch->rm_so = len;
+ pmatch->rm_eo = len;
+ return (ret);
+ }
+
+ /* No point in going farther if we do not have enough data. */
+ if (len < fg->len)
+ return (ret);
+
+ /* Only try once at the beginning or ending of the line. */
+ if (fg->bol || fg->eol) {
+ /* Simple text comparison. */
+ /* Verify data is >= pattern length before searching on it. */
+ if (len >= fg->len) {
+ /* Determine where in data to start search at. */
+ j = fg->eol ? len - fg->len : 0;
+ if (!((fg->bol && fg->eol) && (len != fg->len)))
+ if (grep_cmp(fg->pattern, data + j,
+ fg->len) == -1) {
+ pmatch->rm_so = j;
+ pmatch->rm_eo = j + fg->len;
+ ret = 0;
+ }
+ }
+ } else if (fg->reversed) {
+ /* Quick Search algorithm. */
+ j = len;
+ do {
+ if (grep_cmp(fg->pattern, data + j - fg->len,
+ fg->len) == -1) {
+ pmatch->rm_so = j - fg->len;
+ pmatch->rm_eo = j;
+ ret = 0;
+ break;
+ }
+ /* Shift if within bounds, otherwise, we are done. */
+ if (j == fg->len)
+ break;
+ j -= fg->qsBc[data[j - fg->len - 1]];
+ } while (j >= fg->len);
+ } else {
+ /* Quick Search algorithm. */
+ j = pmatch->rm_so;
+ do {
+ if (grep_cmp(fg->pattern, data + j, fg->len) == -1) {
+ pmatch->rm_so = j;
+ pmatch->rm_eo = j + fg->len;
+ ret = 0;
+ break;
+ }
+
+ /* Shift if within bounds, otherwise, we are done. */
+ if (j + fg->len == len)
+ break;
+ else
+ j += fg->qsBc[data[j + fg->len]];
+ } while (j <= (len - fg->len));
+ }
+
+ return (ret);
+}
+
+/*
+ * Returns: i >= 0 on failure (position that it failed)
+ * -1 on success
+ */
+static inline int
+grep_cmp(const unsigned char *pat, const unsigned char *data, size_t len)
+{
+ size_t size;
+ wchar_t *wdata, *wpat;
+ unsigned int i;
+
+ if (iflag) {
+ if ((size = mbstowcs(NULL, (const char *)data, 0)) ==
+ ((size_t) - 1))
+ return (-1);
+
+ wdata = grep_malloc(size * sizeof(wint_t));
+
+ if (mbstowcs(wdata, (const char *)data, size) ==
+ ((size_t) - 1))
+ return (-1);
+
+ if ((size = mbstowcs(NULL, (const char *)pat, 0)) ==
+ ((size_t) - 1))
+ return (-1);
+
+ wpat = grep_malloc(size * sizeof(wint_t));
+
+ if (mbstowcs(wpat, (const char *)pat, size) == ((size_t) - 1))
+ return (-1);
+ for (i = 0; i < len; i++) {
+ if ((towlower(wpat[i]) == towlower(wdata[i])) ||
+ ((grepbehave != GREP_FIXED) && wpat[i] == L'.'))
+ continue;
+ free(wpat);
+ free(wdata);
+ return (i);
+ }
+ } else {
+ for (i = 0; i < len; i++) {
+ if ((pat[i] == data[i]) || ((grepbehave != GREP_FIXED) &&
+ pat[i] == '.'))
+ continue;
+ return (i);
+ }
+ }
+ return (-1);
+}
+
+static inline void
+grep_revstr(unsigned char *str, int len)
+{
+ int i;
+ char c;
+
+ for (i = 0; i < len / 2; i++) {
+ c = str[i];
+ str[i] = str[len - i - 1];
+ str[len - i - 1] = c;
+ }
+}
diff --git a/toolbox/grep/file.c b/toolbox/grep/file.c
new file mode 100644
index 0000000..86b7658
--- /dev/null
+++ b/toolbox/grep/file.c
@@ -0,0 +1,269 @@
+/* $NetBSD: file.c,v 1.7 2011/04/18 22:46:48 joerg Exp $ */
+/* $FreeBSD: head/usr.bin/grep/file.c 211496 2010-08-19 09:28:59Z des $ */
+/* $OpenBSD: file.c,v 1.11 2010/07/02 20:48:48 nicm Exp $ */
+
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
+ * Copyright (C) 2010 Dimitry Andric <dimitry@andric.com>
+ * 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 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 AUTHOR 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: file.c,v 1.7 2011/04/18 22:46:48 joerg Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef ANDROID
+#include <bzlib.h>
+#endif
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+#ifndef ANDROID
+#include <zlib.h>
+#endif
+
+#include "grep.h"
+
+#define MAXBUFSIZ (32 * 1024)
+#define LNBUFBUMP 80
+
+#ifndef ANDROID
+static gzFile gzbufdesc;
+static BZFILE* bzbufdesc;
+#endif
+
+static unsigned char buffer[MAXBUFSIZ];
+static unsigned char *bufpos;
+static size_t bufrem;
+
+static unsigned char *lnbuf;
+static size_t lnbuflen;
+
+static inline int
+grep_refill(struct file *f)
+{
+ ssize_t nr;
+ int bzerr;
+
+ bufpos = buffer;
+ bufrem = 0;
+
+#ifndef ANDROID
+ if (filebehave == FILE_GZIP)
+ nr = gzread(gzbufdesc, buffer, MAXBUFSIZ);
+ else if (filebehave == FILE_BZIP && bzbufdesc != NULL) {
+ nr = BZ2_bzRead(&bzerr, bzbufdesc, buffer, MAXBUFSIZ);
+ switch (bzerr) {
+ case BZ_OK:
+ case BZ_STREAM_END:
+ /* No problem, nr will be okay */
+ break;
+ case BZ_DATA_ERROR_MAGIC:
+ /*
+ * As opposed to gzread(), which simply returns the
+ * plain file data, if it is not in the correct
+ * compressed format, BZ2_bzRead() instead aborts.
+ *
+ * So, just restart at the beginning of the file again,
+ * and use plain reads from now on.
+ */
+ BZ2_bzReadClose(&bzerr, bzbufdesc);
+ bzbufdesc = NULL;
+ if (lseek(f->fd, 0, SEEK_SET) == -1)
+ return (-1);
+ nr = read(f->fd, buffer, MAXBUFSIZ);
+ break;
+ default:
+ /* Make sure we exit with an error */
+ nr = -1;
+ }
+ } else
+#endif
+ nr = read(f->fd, buffer, MAXBUFSIZ);
+
+ if (nr < 0)
+ return (-1);
+
+ bufrem = nr;
+ return (0);
+}
+
+static inline int
+grep_lnbufgrow(size_t newlen)
+{
+
+ if (lnbuflen < newlen) {
+ lnbuf = grep_realloc(lnbuf, newlen);
+ lnbuflen = newlen;
+ }
+
+ return (0);
+}
+
+char *
+grep_fgetln(struct file *f, size_t *lenp)
+{
+ unsigned char *p;
+ char *ret;
+ size_t len;
+ size_t off;
+ ptrdiff_t diff;
+
+ /* Fill the buffer, if necessary */
+ if (bufrem == 0 && grep_refill(f) != 0)
+ goto error;
+
+ if (bufrem == 0) {
+ /* Return zero length to indicate EOF */
+ *lenp = 0;
+ return ((char *)bufpos);
+ }
+
+ /* Look for a newline in the remaining part of the buffer */
+ if ((p = memchr(bufpos, line_sep, bufrem)) != NULL) {
+ ++p; /* advance over newline */
+ ret = (char *)bufpos;
+ len = p - bufpos;
+ bufrem -= len;
+ bufpos = p;
+ *lenp = len;
+ return (ret);
+ }
+
+ /* We have to copy the current buffered data to the line buffer */
+ for (len = bufrem, off = 0; ; len += bufrem) {
+ /* Make sure there is room for more data */
+ if (grep_lnbufgrow(len + LNBUFBUMP))
+ goto error;
+ memcpy(lnbuf + off, bufpos, len - off);
+ off = len;
+ if (grep_refill(f) != 0)
+ goto error;
+ if (bufrem == 0)
+ /* EOF: return partial line */
+ break;
+ if ((p = memchr(bufpos, line_sep, bufrem)) == NULL)
+ continue;
+ /* got it: finish up the line (like code above) */
+ ++p;
+ diff = p - bufpos;
+ len += diff;
+ if (grep_lnbufgrow(len))
+ goto error;
+ memcpy(lnbuf + off, bufpos, diff);
+ bufrem -= diff;
+ bufpos = p;
+ break;
+ }
+ *lenp = len;
+ return ((char *)lnbuf);
+
+error:
+ *lenp = 0;
+ return (NULL);
+}
+
+static inline struct file *
+grep_file_init(struct file *f)
+{
+
+#ifndef ANDROID
+ if (filebehave == FILE_GZIP &&
+ (gzbufdesc = gzdopen(f->fd, "r")) == NULL)
+ goto error;
+
+ if (filebehave == FILE_BZIP &&
+ (bzbufdesc = BZ2_bzdopen(f->fd, "r")) == NULL)
+ goto error;
+#endif
+
+ /* Fill read buffer, also catches errors early */
+ if (grep_refill(f) != 0)
+ goto error;
+
+ /* Check for binary stuff, if necessary */
+ if (!nulldataflag && binbehave != BINFILE_TEXT &&
+ memchr(bufpos, '\0', bufrem) != NULL)
+ f->binary = true;
+
+ return (f);
+error:
+ close(f->fd);
+ free(f);
+ return (NULL);
+}
+
+/*
+ * Opens a file for processing.
+ */
+struct file *
+grep_open(const char *path)
+{
+ struct file *f;
+
+ f = grep_malloc(sizeof *f);
+ memset(f, 0, sizeof *f);
+ if (path == NULL) {
+ /* Processing stdin implies --line-buffered. */
+ lbflag = true;
+ f->fd = STDIN_FILENO;
+ } else if ((f->fd = open(path, O_RDONLY)) == -1) {
+ free(f);
+ return (NULL);
+ }
+
+ return (grep_file_init(f));
+}
+
+/*
+ * Closes a file.
+ */
+void
+grep_close(struct file *f)
+{
+
+ close(f->fd);
+
+ /* Reset read buffer and line buffer */
+ bufpos = buffer;
+ bufrem = 0;
+
+ free(lnbuf);
+ lnbuf = NULL;
+ lnbuflen = 0;
+}
diff --git a/toolbox/grep/grep.c b/toolbox/grep/grep.c
new file mode 100644
index 0000000..b5bb2ef
--- /dev/null
+++ b/toolbox/grep/grep.c
@@ -0,0 +1,710 @@
+/* $NetBSD: grep.c,v 1.11 2012/05/06 22:27:00 joerg Exp $ */
+/* $FreeBSD: head/usr.bin/grep/grep.c 211519 2010-08-19 22:55:17Z delphij $ */
+/* $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $ */
+
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
+ * 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 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 AUTHOR 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: grep.c,v 1.11 2012/05/06 22:27:00 joerg Exp $");
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <libgen.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "grep.h"
+
+#ifndef WITHOUT_NLS
+#include <nl_types.h>
+nl_catd catalog;
+#endif
+
+/*
+ * Default messags to use when NLS is disabled or no catalogue
+ * is found.
+ */
+const char *errstr[] = {
+ "",
+/* 1*/ "(standard input)",
+/* 2*/ "cannot read bzip2 compressed file",
+/* 3*/ "unknown %s option",
+/* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]]\n",
+/* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
+/* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n",
+/* 7*/ "\t[pattern] [file ...]\n",
+/* 8*/ "Binary file %s matches\n",
+/* 9*/ "%s (BSD grep) %s\n",
+};
+
+/* Flags passed to regcomp() and regexec() */
+int cflags = 0;
+int eflags = REG_STARTEND;
+
+/* Searching patterns */
+unsigned int patterns, pattern_sz;
+char **pattern;
+regex_t *r_pattern;
+fastgrep_t *fg_pattern;
+
+/* Filename exclusion/inclusion patterns */
+unsigned int fpatterns, fpattern_sz;
+unsigned int dpatterns, dpattern_sz;
+struct epat *dpattern, *fpattern;
+
+/* For regex errors */
+char re_error[RE_ERROR_BUF + 1];
+
+/* Command-line flags */
+unsigned long long Aflag; /* -A x: print x lines trailing each match */
+unsigned long long Bflag; /* -B x: print x lines leading each match */
+bool Hflag; /* -H: always print file name */
+bool Lflag; /* -L: only show names of files with no matches */
+bool bflag; /* -b: show block numbers for each match */
+bool cflag; /* -c: only show a count of matching lines */
+bool hflag; /* -h: don't print filename headers */
+bool iflag; /* -i: ignore case */
+bool lflag; /* -l: only show names of files with matches */
+bool mflag; /* -m x: stop reading the files after x matches */
+unsigned long long mcount; /* count for -m */
+bool nflag; /* -n: show line numbers in front of matching lines */
+bool oflag; /* -o: print only matching part */
+bool qflag; /* -q: quiet mode (don't output anything) */
+bool sflag; /* -s: silent mode (ignore errors) */
+bool vflag; /* -v: only show non-matching lines */
+bool wflag; /* -w: pattern must start and end on word boundaries */
+bool xflag; /* -x: pattern must match entire line */
+bool lbflag; /* --line-buffered */
+bool nullflag; /* --null */
+bool nulldataflag; /* --null-data */
+unsigned char line_sep = '\n'; /* 0 for --null-data */
+char *label; /* --label */
+const char *color; /* --color */
+int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */
+int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */
+int filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */
+int devbehave = DEV_READ; /* -D: handling of devices */
+int dirbehave = DIR_READ; /* -dRr: handling of directories */
+int linkbehave = LINK_READ; /* -OpS: handling of symlinks */
+
+bool dexclude, dinclude; /* --exclude-dir and --include-dir */
+bool fexclude, finclude; /* --exclude and --include */
+
+enum {
+ BIN_OPT = CHAR_MAX + 1,
+ COLOR_OPT,
+ DECOMPRESS_OPT,
+ HELP_OPT,
+ MMAP_OPT,
+ LINEBUF_OPT,
+ LABEL_OPT,
+ R_EXCLUDE_OPT,
+ R_INCLUDE_OPT,
+ R_DEXCLUDE_OPT,
+ R_DINCLUDE_OPT
+};
+
+static inline const char *init_color(const char *);
+
+/* Housekeeping */
+int tail; /* lines left to print */
+bool notfound; /* file not found */
+
+extern char *__progname;
+
+/*
+ * Prints usage information and returns 2.
+ */
+__dead static void
+usage(void)
+{
+ fprintf(stderr, getstr(4), __progname);
+ fprintf(stderr, "%s", getstr(5));
+ fprintf(stderr, "%s", getstr(5));
+ fprintf(stderr, "%s", getstr(6));
+ fprintf(stderr, "%s", getstr(7));
+ exit(2);
+}
+
+static const char optstr[] =
+ "0123456789A:B:C:D:EFGHIJLOPSRUVZabcd:e:f:hilm:nopqrsuvwxyz";
+
+struct option long_options[] =
+{
+ {"binary-files", required_argument, NULL, BIN_OPT},
+ {"decompress", no_argument, NULL, DECOMPRESS_OPT},
+ {"help", no_argument, NULL, HELP_OPT},
+ {"mmap", no_argument, NULL, MMAP_OPT},
+ {"line-buffered", no_argument, NULL, LINEBUF_OPT},
+ {"label", required_argument, NULL, LABEL_OPT},
+ {"color", optional_argument, NULL, COLOR_OPT},
+ {"colour", optional_argument, NULL, COLOR_OPT},
+ {"exclude", required_argument, NULL, R_EXCLUDE_OPT},
+ {"include", required_argument, NULL, R_INCLUDE_OPT},
+ {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT},
+ {"include-dir", required_argument, NULL, R_DINCLUDE_OPT},
+ {"after-context", required_argument, NULL, 'A'},
+ {"text", no_argument, NULL, 'a'},
+ {"before-context", required_argument, NULL, 'B'},
+ {"byte-offset", no_argument, NULL, 'b'},
+ {"context", optional_argument, NULL, 'C'},
+ {"count", no_argument, NULL, 'c'},
+ {"devices", required_argument, NULL, 'D'},
+ {"directories", required_argument, NULL, 'd'},
+ {"extended-regexp", no_argument, NULL, 'E'},
+ {"regexp", required_argument, NULL, 'e'},
+ {"fixed-strings", no_argument, NULL, 'F'},
+ {"file", required_argument, NULL, 'f'},
+ {"basic-regexp", no_argument, NULL, 'G'},
+ {"no-filename", no_argument, NULL, 'h'},
+ {"with-filename", no_argument, NULL, 'H'},
+ {"ignore-case", no_argument, NULL, 'i'},
+ {"bz2decompress", no_argument, NULL, 'J'},
+ {"files-with-matches", no_argument, NULL, 'l'},
+ {"files-without-match", no_argument, NULL, 'L'},
+ {"max-count", required_argument, NULL, 'm'},
+ {"line-number", no_argument, NULL, 'n'},
+ {"only-matching", no_argument, NULL, 'o'},
+ {"quiet", no_argument, NULL, 'q'},
+ {"silent", no_argument, NULL, 'q'},
+ {"recursive", no_argument, NULL, 'r'},
+ {"no-messages", no_argument, NULL, 's'},
+ {"binary", no_argument, NULL, 'U'},
+ {"unix-byte-offsets", no_argument, NULL, 'u'},
+ {"invert-match", no_argument, NULL, 'v'},
+ {"version", no_argument, NULL, 'V'},
+ {"word-regexp", no_argument, NULL, 'w'},
+ {"line-regexp", no_argument, NULL, 'x'},
+ {"null", no_argument, NULL, 'Z'},
+ {"null-data", no_argument, NULL, 'z'},
+ {NULL, no_argument, NULL, 0}
+};
+
+/*
+ * Adds a searching pattern to the internal array.
+ */
+static void
+add_pattern(char *pat, size_t len)
+{
+
+ /* TODO: Check for empty patterns and shortcut */
+
+ /* Increase size if necessary */
+ if (patterns == pattern_sz) {
+ pattern_sz *= 2;
+ pattern = grep_realloc(pattern, ++pattern_sz *
+ sizeof(*pattern));
+ }
+ if (len > 0 && pat[len - 1] == '\n')
+ --len;
+ /* pat may not be NUL-terminated */
+ pattern[patterns] = grep_malloc(len + 1);
+ memcpy(pattern[patterns], pat, len);
+ pattern[patterns][len] = '\0';
+ ++patterns;
+}
+
+/*
+ * Adds a file include/exclude pattern to the internal array.
+ */
+static void
+add_fpattern(const char *pat, int mode)
+{
+
+ /* Increase size if necessary */
+ if (fpatterns == fpattern_sz) {
+ fpattern_sz *= 2;
+ fpattern = grep_realloc(fpattern, ++fpattern_sz *
+ sizeof(struct epat));
+ }
+ fpattern[fpatterns].pat = grep_strdup(pat);
+ fpattern[fpatterns].mode = mode;
+ ++fpatterns;
+}
+
+/*
+ * Adds a directory include/exclude pattern to the internal array.
+ */
+static void
+add_dpattern(const char *pat, int mode)
+{
+
+ /* Increase size if necessary */
+ if (dpatterns == dpattern_sz) {
+ dpattern_sz *= 2;
+ dpattern = grep_realloc(dpattern, ++dpattern_sz *
+ sizeof(struct epat));
+ }
+ dpattern[dpatterns].pat = grep_strdup(pat);
+ dpattern[dpatterns].mode = mode;
+ ++dpatterns;
+}
+
+/*
+ * Reads searching patterns from a file and adds them with add_pattern().
+ */
+static void
+read_patterns(const char *fn)
+{
+ FILE *f;
+ char *line;
+ size_t len;
+ ssize_t rlen;
+
+ if ((f = fopen(fn, "r")) == NULL)
+ err(2, "%s", fn);
+ line = NULL;
+ len = 0;
+#ifndef ANDROID
+ while ((rlen = getline(&line, &len, f)) != -1)
+ add_pattern(line, *line == '\n' ? 0 : (size_t)rlen);
+#endif
+ free(line);
+ if (ferror(f))
+ err(2, "%s", fn);
+ fclose(f);
+}
+
+static inline const char *
+init_color(const char *d)
+{
+ char *c;
+
+ c = getenv("GREP_COLOR");
+ return (c != NULL ? c : d);
+}
+
+int
+grep_main(int argc, char *argv[])
+{
+ char **aargv, **eargv, *eopts;
+ char *ep;
+ unsigned long long l;
+ unsigned int aargc, eargc, i, j;
+ int c, lastc, needpattern, newarg, prevoptind;
+
+ setlocale(LC_ALL, "");
+
+#ifndef WITHOUT_NLS
+ catalog = catopen("grep", NL_CAT_LOCALE);
+#endif
+
+ /* Check what is the program name of the binary. In this
+ way we can have all the funcionalities in one binary
+ without the need of scripting and using ugly hacks. */
+ switch (__progname[0]) {
+ case 'e':
+ grepbehave = GREP_EXTENDED;
+ break;
+ case 'f':
+ grepbehave = GREP_FIXED;
+ break;
+ case 'g':
+ grepbehave = GREP_BASIC;
+ break;
+ case 'z':
+ filebehave = FILE_GZIP;
+ switch(__progname[1]) {
+ case 'e':
+ grepbehave = GREP_EXTENDED;
+ break;
+ case 'f':
+ grepbehave = GREP_FIXED;
+ break;
+ case 'g':
+ grepbehave = GREP_BASIC;
+ break;
+ }
+ break;
+ }
+
+ lastc = '\0';
+ newarg = 1;
+ prevoptind = 1;
+ needpattern = 1;
+
+ eopts = getenv("GREP_OPTIONS");
+
+ /* support for extra arguments in GREP_OPTIONS */
+ eargc = 0;
+ if (eopts != NULL) {
+ char *str;
+
+ /* make an estimation of how many extra arguments we have */
+ for (j = 0; j < strlen(eopts); j++)
+ if (eopts[j] == ' ')
+ eargc++;
+
+ eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
+
+ eargc = 0;
+ /* parse extra arguments */
+ while ((str = strsep(&eopts, " ")) != NULL)
+ eargv[eargc++] = grep_strdup(str);
+
+ aargv = (char **)grep_calloc(eargc + argc + 1,
+ sizeof(char *));
+
+ aargv[0] = argv[0];
+ for (i = 0; i < eargc; i++)
+ aargv[i + 1] = eargv[i];
+ for (j = 1; j < (unsigned int)argc; j++, i++)
+ aargv[i + 1] = argv[j];
+
+ aargc = eargc + argc;
+ } else {
+ aargv = argv;
+ aargc = argc;
+ }
+
+ while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
+ -1)) {
+ switch (c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (newarg || !isdigit(lastc))
+ Aflag = 0;
+ else if (Aflag > LLONG_MAX / 10) {
+ errno = ERANGE;
+ err(2, NULL);
+ }
+ Aflag = Bflag = (Aflag * 10) + (c - '0');
+ break;
+ case 'C':
+ if (optarg == NULL) {
+ Aflag = Bflag = 2;
+ break;
+ }
+ /* FALLTHROUGH */
+ case 'A':
+ /* FALLTHROUGH */
+ case 'B':
+ errno = 0;
+ l = strtoull(optarg, &ep, 10);
+ if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
+ ((errno == EINVAL) && (l == 0)))
+ err(2, NULL);
+ else if (ep[0] != '\0') {
+ errno = EINVAL;
+ err(2, NULL);
+ }
+ if (c == 'A')
+ Aflag = l;
+ else if (c == 'B')
+ Bflag = l;
+ else
+ Aflag = Bflag = l;
+ break;
+ case 'a':
+ binbehave = BINFILE_TEXT;
+ break;
+ case 'b':
+ bflag = true;
+ break;
+ case 'c':
+ cflag = true;
+ break;
+ case 'D':
+ if (strcasecmp(optarg, "skip") == 0)
+ devbehave = DEV_SKIP;
+ else if (strcasecmp(optarg, "read") == 0)
+ devbehave = DEV_READ;
+ else
+ errx(2, getstr(3), "--devices");
+ break;
+ case 'd':
+ if (strcasecmp("recurse", optarg) == 0) {
+ Hflag = true;
+ dirbehave = DIR_RECURSE;
+ } else if (strcasecmp("skip", optarg) == 0)
+ dirbehave = DIR_SKIP;
+ else if (strcasecmp("read", optarg) == 0)
+ dirbehave = DIR_READ;
+ else
+ errx(2, getstr(3), "--directories");
+ break;
+ case 'E':
+ grepbehave = GREP_EXTENDED;
+ break;
+ case 'e':
+ add_pattern(optarg, strlen(optarg));
+ needpattern = 0;
+ break;
+ case 'F':
+ grepbehave = GREP_FIXED;
+ break;
+ case 'f':
+ read_patterns(optarg);
+ needpattern = 0;
+ break;
+ case 'G':
+ grepbehave = GREP_BASIC;
+ break;
+ case 'H':
+ Hflag = true;
+ break;
+ case 'h':
+ Hflag = false;
+ hflag = true;
+ break;
+ case 'I':
+ binbehave = BINFILE_SKIP;
+ break;
+ case 'i':
+ case 'y':
+ iflag = true;
+ cflags |= REG_ICASE;
+ break;
+ case 'J':
+ filebehave = FILE_BZIP;
+ break;
+ case 'L':
+ lflag = false;
+ Lflag = true;
+ break;
+ case 'l':
+ Lflag = false;
+ lflag = true;
+ break;
+ case 'm':
+ mflag = true;
+ errno = 0;
+ mcount = strtoull(optarg, &ep, 10);
+ if (((errno == ERANGE) && (mcount == ULLONG_MAX)) ||
+ ((errno == EINVAL) && (mcount == 0)))
+ err(2, NULL);
+ else if (ep[0] != '\0') {
+ errno = EINVAL;
+ err(2, NULL);
+ }
+ break;
+ case 'n':
+ nflag = true;
+ break;
+ case 'O':
+ linkbehave = LINK_EXPLICIT;
+ break;
+ case 'o':
+ oflag = true;
+ break;
+ case 'p':
+ linkbehave = LINK_SKIP;
+ break;
+ case 'q':
+ qflag = true;
+ break;
+ case 'S':
+ linkbehave = LINK_READ;
+ break;
+ case 'R':
+ case 'r':
+ dirbehave = DIR_RECURSE;
+ Hflag = true;
+ break;
+ case 's':
+ sflag = true;
+ break;
+ case 'U':
+ binbehave = BINFILE_BIN;
+ break;
+ case 'u':
+ case MMAP_OPT:
+ /* noop, compatibility */
+ break;
+ case 'V':
+ printf(getstr(9), __progname, VERSION);
+ exit(0);
+ case 'v':
+ vflag = true;
+ break;
+ case 'w':
+ wflag = true;
+ break;
+ case 'x':
+ xflag = true;
+ break;
+ case 'Z':
+ nullflag = true;
+ break;
+ case 'z':
+ nulldataflag = true;
+ line_sep = '\0';
+ break;
+ case BIN_OPT:
+ if (strcasecmp("binary", optarg) == 0)
+ binbehave = BINFILE_BIN;
+ else if (strcasecmp("without-match", optarg) == 0)
+ binbehave = BINFILE_SKIP;
+ else if (strcasecmp("text", optarg) == 0)
+ binbehave = BINFILE_TEXT;
+ else
+ errx(2, getstr(3), "--binary-files");
+ break;
+ case COLOR_OPT:
+ color = NULL;
+ if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
+ strcasecmp("tty", optarg) == 0 ||
+ strcasecmp("if-tty", optarg) == 0) {
+ char *term;
+
+ term = getenv("TERM");
+ if (isatty(STDOUT_FILENO) && term != NULL &&
+ strcasecmp(term, "dumb") != 0)
+ color = init_color("01;31");
+ } else if (strcasecmp("always", optarg) == 0 ||
+ strcasecmp("yes", optarg) == 0 ||
+ strcasecmp("force", optarg) == 0) {
+ color = init_color("01;31");
+ } else if (strcasecmp("never", optarg) != 0 &&
+ strcasecmp("none", optarg) != 0 &&
+ strcasecmp("no", optarg) != 0)
+ errx(2, getstr(3), "--color");
+ break;
+ case DECOMPRESS_OPT:
+ filebehave = FILE_GZIP;
+ break;
+ case LABEL_OPT:
+ label = optarg;
+ break;
+ case LINEBUF_OPT:
+ lbflag = true;
+ break;
+ case R_INCLUDE_OPT:
+ finclude = true;
+ add_fpattern(optarg, INCL_PAT);
+ break;
+ case R_EXCLUDE_OPT:
+ fexclude = true;
+ add_fpattern(optarg, EXCL_PAT);
+ break;
+ case R_DINCLUDE_OPT:
+ dinclude = true;
+ add_dpattern(optarg, INCL_PAT);
+ break;
+ case R_DEXCLUDE_OPT:
+ dexclude = true;
+ add_dpattern(optarg, EXCL_PAT);
+ break;
+ case HELP_OPT:
+ default:
+ usage();
+ }
+ lastc = c;
+ newarg = optind != prevoptind;
+ prevoptind = optind;
+ }
+ aargc -= optind;
+ aargv += optind;
+
+ /* Fail if we don't have any pattern */
+ if (aargc == 0 && needpattern)
+ usage();
+
+ /* Process patterns from command line */
+ if (aargc != 0 && needpattern) {
+ add_pattern(*aargv, strlen(*aargv));
+ --aargc;
+ ++aargv;
+ }
+
+ switch (grepbehave) {
+ case GREP_FIXED:
+ case GREP_BASIC:
+ break;
+ case GREP_EXTENDED:
+ cflags |= REG_EXTENDED;
+ break;
+ default:
+ /* NOTREACHED */
+ usage();
+ }
+
+ fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
+ r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
+/*
+ * XXX: fgrepcomp() and fastcomp() are workarounds for regexec() performance.
+ * Optimizations should be done there.
+ */
+ /* Check if cheating is allowed (always is for fgrep). */
+ if (grepbehave == GREP_FIXED) {
+ for (i = 0; i < patterns; ++i)
+ fgrepcomp(&fg_pattern[i], pattern[i]);
+ } else {
+ for (i = 0; i < patterns; ++i) {
+ if (fastcomp(&fg_pattern[i], pattern[i])) {
+ /* Fall back to full regex library */
+ c = regcomp(&r_pattern[i], pattern[i], cflags);
+ if (c != 0) {
+ regerror(c, &r_pattern[i], re_error,
+ RE_ERROR_BUF);
+ errx(2, "%s", re_error);
+ }
+ }
+ }
+ }
+
+ if (lbflag)
+ setlinebuf(stdout);
+
+ if ((aargc == 0 || aargc == 1) && !Hflag)
+ hflag = true;
+
+ if (aargc == 0)
+ exit(!procfile("-"));
+
+ if (dirbehave == DIR_RECURSE)
+ c = grep_tree(aargv);
+ else
+ for (c = 0; aargc--; ++aargv) {
+ if ((finclude || fexclude) && !file_matching(*aargv))
+ continue;
+ c+= procfile(*aargv);
+ }
+
+#ifndef WITHOUT_NLS
+ catclose(catalog);
+#endif
+
+ /* Find out the correct return value according to the
+ results and the command line option. */
+ exit(c ? (notfound ? (qflag ? 0 : 2) : 0) : (notfound ? 2 : 1));
+}
diff --git a/toolbox/grep/grep.h b/toolbox/grep/grep.h
new file mode 100644
index 0000000..6454f93
--- /dev/null
+++ b/toolbox/grep/grep.h
@@ -0,0 +1,166 @@
+/* $NetBSD: grep.h,v 1.8 2012/05/06 22:27:00 joerg Exp $ */
+/* $OpenBSD: grep.h,v 1.15 2010/04/05 03:03:55 tedu Exp $ */
+/* $FreeBSD: head/usr.bin/grep/grep.h 211496 2010-08-19 09:28:59Z des $ */
+
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * Copyright (c) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
+ * 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 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 AUTHOR 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.
+ */
+
+#ifdef ANDROID
+#define WITHOUT_NLS
+#endif
+
+#ifndef ANDROID
+#include <bzlib.h>
+#endif
+#include <limits.h>
+#include <regex.h>
+#include <stdbool.h>
+#include <stdio.h>
+#ifndef ANDROID
+#include <zlib.h>
+#endif
+
+#ifdef WITHOUT_NLS
+#define getstr(n) errstr[n]
+#else
+#include <nl_types.h>
+
+extern nl_catd catalog;
+#define getstr(n) catgets(catalog, 1, n, errstr[n])
+#endif
+
+extern const char *errstr[];
+
+#define VERSION "2.5.1-FreeBSD"
+
+#define GREP_FIXED 0
+#define GREP_BASIC 1
+#define GREP_EXTENDED 2
+
+#define BINFILE_BIN 0
+#define BINFILE_SKIP 1
+#define BINFILE_TEXT 2
+
+#define FILE_STDIO 0
+#define FILE_GZIP 1
+#define FILE_BZIP 2
+
+#define DIR_READ 0
+#define DIR_SKIP 1
+#define DIR_RECURSE 2
+
+#define DEV_READ 0
+#define DEV_SKIP 1
+
+#define LINK_READ 0
+#define LINK_EXPLICIT 1
+#define LINK_SKIP 2
+
+#define EXCL_PAT 0
+#define INCL_PAT 1
+
+#define MAX_LINE_MATCHES 32
+
+struct file {
+ int fd;
+ bool binary;
+};
+
+struct str {
+ off_t off;
+ size_t len;
+ char *dat;
+ char *file;
+ int line_no;
+};
+
+struct epat {
+ char *pat;
+ int mode;
+};
+
+typedef struct {
+ size_t len;
+ unsigned char *pattern;
+ int qsBc[UCHAR_MAX + 1];
+ /* flags */
+ bool bol;
+ bool eol;
+ bool reversed;
+ bool word;
+} fastgrep_t;
+
+/* Flags passed to regcomp() and regexec() */
+extern int cflags, eflags;
+
+/* Command line flags */
+extern bool Eflag, Fflag, Gflag, Hflag, Lflag,
+ bflag, cflag, hflag, iflag, lflag, mflag, nflag, oflag,
+ qflag, sflag, vflag, wflag, xflag;
+extern bool dexclude, dinclude, fexclude, finclude, lbflag, nullflag, nulldataflag;
+extern unsigned char line_sep;
+extern unsigned long long Aflag, Bflag, mcount;
+extern char *label;
+extern const char *color;
+extern int binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave;
+
+extern bool notfound;
+extern int tail;
+extern unsigned int dpatterns, fpatterns, patterns;
+extern char **pattern;
+extern struct epat *dpattern, *fpattern;
+extern regex_t *er_pattern, *r_pattern;
+extern fastgrep_t *fg_pattern;
+
+/* For regex errors */
+#define RE_ERROR_BUF 512
+extern char re_error[RE_ERROR_BUF + 1]; /* Seems big enough */
+
+/* util.c */
+bool file_matching(const char *fname);
+int procfile(const char *fn);
+int grep_tree(char **argv);
+void *grep_malloc(size_t size);
+void *grep_calloc(size_t nmemb, size_t size);
+void *grep_realloc(void *ptr, size_t size);
+char *grep_strdup(const char *str);
+void printline(struct str *line, int sep, regmatch_t *matches, int m);
+
+/* queue.c */
+void enqueue(struct str *x);
+void printqueue(void);
+void clearqueue(void);
+
+/* file.c */
+void grep_close(struct file *f);
+struct file *grep_open(const char *path);
+char *grep_fgetln(struct file *f, size_t *len);
+
+/* fastgrep.c */
+int fastcomp(fastgrep_t *, const char *);
+void fgrepcomp(fastgrep_t *, const char *);
+int grep_search(fastgrep_t *, const unsigned char *, size_t, regmatch_t *);
diff --git a/toolbox/grep/queue.c b/toolbox/grep/queue.c
new file mode 100644
index 0000000..e3c6be1
--- /dev/null
+++ b/toolbox/grep/queue.c
@@ -0,0 +1,116 @@
+/* $NetBSD: queue.c,v 1.5 2011/08/31 16:24:57 plunky Exp $ */
+/* $FreeBSD: head/usr.bin/grep/queue.c 211496 2010-08-19 09:28:59Z des $ */
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * 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 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 AUTHOR 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.
+ */
+
+/*
+ * A really poor man's queue. It does only what it has to and gets out of
+ * Dodge. It is used in place of <sys/queue.h> to get a better performance.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: queue.c,v 1.5 2011/08/31 16:24:57 plunky Exp $");
+
+#include <sys/param.h>
+#include <sys/queue.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "grep.h"
+
+struct qentry {
+ STAILQ_ENTRY(qentry) list;
+ struct str data;
+};
+
+static STAILQ_HEAD(, qentry) queue = STAILQ_HEAD_INITIALIZER(queue);
+static unsigned long long count;
+
+static struct qentry *dequeue(void);
+
+void
+enqueue(struct str *x)
+{
+ struct qentry *item;
+
+ item = grep_malloc(sizeof(struct qentry));
+ item->data.dat = grep_malloc(sizeof(char) * x->len);
+ item->data.len = x->len;
+ item->data.line_no = x->line_no;
+ item->data.off = x->off;
+ memcpy(item->data.dat, x->dat, x->len);
+ item->data.file = x->file;
+
+ STAILQ_INSERT_TAIL(&queue, item, list);
+
+ if (++count > Bflag) {
+ item = dequeue();
+ free(item->data.dat);
+ free(item);
+ }
+}
+
+static struct qentry *
+dequeue(void)
+{
+ struct qentry *item;
+
+ item = STAILQ_FIRST(&queue);
+ if (item == NULL)
+ return (NULL);
+
+ STAILQ_REMOVE_HEAD(&queue, list);
+ --count;
+ return (item);
+}
+
+void
+printqueue(void)
+{
+ struct qentry *item;
+
+ while ((item = dequeue()) != NULL) {
+ printline(&item->data, '-', NULL, 0);
+ free(item->data.dat);
+ free(item);
+ }
+}
+
+void
+clearqueue(void)
+{
+ struct qentry *item;
+
+ while ((item = dequeue()) != NULL) {
+ free(item->data.dat);
+ free(item);
+ }
+}
diff --git a/toolbox/grep/util.c b/toolbox/grep/util.c
new file mode 100644
index 0000000..497db06
--- /dev/null
+++ b/toolbox/grep/util.c
@@ -0,0 +1,498 @@
+/* $NetBSD: util.c,v 1.16 2012/05/06 22:32:05 joerg Exp $ */
+/* $FreeBSD: head/usr.bin/grep/util.c 211496 2010-08-19 09:28:59Z des $ */
+/* $OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $ */
+
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
+ * 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 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 AUTHOR 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: util.c,v 1.16 2012/05/06 22:32:05 joerg Exp $");
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <fts.h>
+#include <libgen.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "grep.h"
+
+static bool first, first_global = true;
+static unsigned long long since_printed;
+
+static int procline(struct str *l, int);
+
+bool
+file_matching(const char *fname)
+{
+ char *fname_base, *fname_copy;
+ unsigned int i;
+ bool ret;
+
+ ret = finclude ? false : true;
+ fname_copy = grep_strdup(fname);
+ fname_base = basename(fname_copy);
+
+ for (i = 0; i < fpatterns; ++i) {
+ if (fnmatch(fpattern[i].pat, fname, 0) == 0 ||
+ fnmatch(fpattern[i].pat, fname_base, 0) == 0) {
+ if (fpattern[i].mode == EXCL_PAT)
+ return (false);
+ else
+ ret = true;
+ }
+ }
+ free(fname_copy);
+ return (ret);
+}
+
+static inline bool
+dir_matching(const char *dname)
+{
+ unsigned int i;
+ bool ret;
+
+ ret = dinclude ? false : true;
+
+ for (i = 0; i < dpatterns; ++i) {
+ if (dname != NULL &&
+ fnmatch(dname, dpattern[i].pat, 0) == 0) {
+ if (dpattern[i].mode == EXCL_PAT)
+ return (false);
+ else
+ ret = true;
+ }
+ }
+ return (ret);
+}
+
+/*
+ * Processes a directory when a recursive search is performed with
+ * the -R option. Each appropriate file is passed to procfile().
+ */
+int
+grep_tree(char **argv)
+{
+ FTS *fts;
+ FTSENT *p;
+ char *d, *dir = NULL;
+ int c, fts_flags;
+ bool ok;
+
+ c = fts_flags = 0;
+
+ switch(linkbehave) {
+ case LINK_EXPLICIT:
+ fts_flags = FTS_COMFOLLOW;
+ break;
+ case LINK_SKIP:
+ fts_flags = FTS_PHYSICAL;
+ break;
+ default:
+ fts_flags = FTS_LOGICAL;
+
+ }
+
+ fts_flags |= FTS_NOSTAT | FTS_NOCHDIR;
+
+ if (!(fts = fts_open(argv, fts_flags, NULL)))
+ err(2, "fts_open");
+ while ((p = fts_read(fts)) != NULL) {
+ switch (p->fts_info) {
+ case FTS_DNR:
+ /* FALLTHROUGH */
+ case FTS_ERR:
+ errx(2, "%s: %s", p->fts_path, strerror(p->fts_errno));
+ break;
+ case FTS_D:
+ /* FALLTHROUGH */
+ case FTS_DP:
+ break;
+ case FTS_DC:
+ /* Print a warning for recursive directory loop */
+ warnx("warning: %s: recursive directory loop",
+ p->fts_path);
+ break;
+ default:
+ /* Check for file exclusion/inclusion */
+ ok = true;
+ if (dexclude || dinclude) {
+ if ((d = strrchr(p->fts_path, '/')) != NULL) {
+ dir = grep_malloc(sizeof(char) *
+ (d - p->fts_path + 1));
+ memcpy(dir, p->fts_path,
+ d - p->fts_path);
+ dir[d - p->fts_path] = '\0';
+ }
+ ok = dir_matching(dir);
+ free(dir);
+ dir = NULL;
+ }
+ if (fexclude || finclude)
+ ok &= file_matching(p->fts_path);
+
+ if (ok)
+ c += procfile(p->fts_path);
+ break;
+ }
+ }
+
+ fts_close(fts);
+ return (c);
+}
+
+/*
+ * Opens a file and processes it. Each file is processed line-by-line
+ * passing the lines to procline().
+ */
+int
+procfile(const char *fn)
+{
+ struct file *f;
+ struct stat sb;
+ struct str ln;
+ mode_t s;
+ int c, t;
+
+ if (mflag && (mcount <= 0))
+ return (0);
+
+ if (strcmp(fn, "-") == 0) {
+ fn = label != NULL ? label : getstr(1);
+ f = grep_open(NULL);
+ } else {
+ if (!stat(fn, &sb)) {
+ /* Check if we need to process the file */
+ s = sb.st_mode & S_IFMT;
+ if (s == S_IFDIR && dirbehave == DIR_SKIP)
+ return (0);
+ if ((s == S_IFIFO || s == S_IFCHR || s == S_IFBLK
+ || s == S_IFSOCK) && devbehave == DEV_SKIP)
+ return (0);
+ }
+ f = grep_open(fn);
+ }
+ if (f == NULL) {
+ if (!sflag)
+ warn("%s", fn);
+ if (errno == ENOENT)
+ notfound = true;
+ return (0);
+ }
+
+ ln.file = grep_malloc(strlen(fn) + 1);
+ strcpy(ln.file, fn);
+ ln.line_no = 0;
+ ln.len = 0;
+ tail = 0;
+ ln.off = -1;
+
+ for (first = true, c = 0; c == 0 || !(lflag || qflag); ) {
+ ln.off += ln.len + 1;
+ if ((ln.dat = grep_fgetln(f, &ln.len)) == NULL || ln.len == 0)
+ break;
+ if (ln.len > 0 && ln.dat[ln.len - 1] == line_sep)
+ --ln.len;
+ ln.line_no++;
+
+ /* Return if we need to skip a binary file */
+ if (f->binary && binbehave == BINFILE_SKIP) {
+ grep_close(f);
+ free(ln.file);
+ free(f);
+ return (0);
+ }
+ /* Process the file line-by-line */
+ t = procline(&ln, f->binary);
+ c += t;
+
+ /* Count the matches if we have a match limit */
+ if (mflag) {
+ mcount -= t;
+ if (mcount <= 0)
+ break;
+ }
+ }
+ if (Bflag > 0)
+ clearqueue();
+ grep_close(f);
+
+ if (cflag) {
+ if (!hflag)
+ printf("%s:", ln.file);
+ printf("%u%c", c, line_sep);
+ }
+ if (lflag && !qflag && c != 0)
+ printf("%s%c", fn, line_sep);
+ if (Lflag && !qflag && c == 0)
+ printf("%s%c", fn, line_sep);
+ if (c && !cflag && !lflag && !Lflag &&
+ binbehave == BINFILE_BIN && f->binary && !qflag)
+ printf(getstr(8), fn);
+
+ free(ln.file);
+ free(f);
+ return (c);
+}
+
+#define iswword(x) (iswalnum((x)) || (x) == L'_')
+
+/*
+ * Processes a line comparing it with the specified patterns. Each pattern
+ * is looped to be compared along with the full string, saving each and every
+ * match, which is necessary to colorize the output and to count the
+ * matches. The matching lines are passed to printline() to display the
+ * appropriate output.
+ */
+static int
+procline(struct str *l, int nottext)
+{
+ regmatch_t matches[MAX_LINE_MATCHES];
+ regmatch_t pmatch;
+ size_t st = 0;
+ unsigned int i;
+ int c = 0, m = 0, r = 0;
+
+ /* Loop to process the whole line */
+ while (st <= l->len) {
+ pmatch.rm_so = st;
+ pmatch.rm_eo = l->len;
+
+ /* Loop to compare with all the patterns */
+ for (i = 0; i < patterns; i++) {
+/*
+ * XXX: grep_search() is a workaround for speed up and should be
+ * removed in the future. See fastgrep.c.
+ */
+ if (fg_pattern[i].pattern) {
+ r = grep_search(&fg_pattern[i],
+ (unsigned char *)l->dat,
+ l->len, &pmatch);
+ r = (r == 0) ? 0 : REG_NOMATCH;
+ st = pmatch.rm_eo;
+ } else {
+ r = regexec(&r_pattern[i], l->dat, 1,
+ &pmatch, eflags);
+ r = (r == 0) ? 0 : REG_NOMATCH;
+ st = pmatch.rm_eo;
+ }
+ if (r == REG_NOMATCH)
+ continue;
+ /* Check for full match */
+ if (xflag &&
+ (pmatch.rm_so != 0 ||
+ (size_t)pmatch.rm_eo != l->len))
+ continue;
+ /* Check for whole word match */
+ if (fg_pattern[i].word && pmatch.rm_so != 0) {
+ wint_t wbegin, wend;
+
+ wbegin = wend = L' ';
+ if (pmatch.rm_so != 0 &&
+ sscanf(&l->dat[pmatch.rm_so - 1],
+ "%lc", &wbegin) != 1)
+ continue;
+ if ((size_t)pmatch.rm_eo != l->len &&
+ sscanf(&l->dat[pmatch.rm_eo],
+ "%lc", &wend) != 1)
+ continue;
+ if (iswword(wbegin) || iswword(wend))
+ continue;
+ }
+ c = 1;
+ if (m < MAX_LINE_MATCHES)
+ matches[m++] = pmatch;
+ /* matches - skip further patterns */
+ if ((color != NULL && !oflag) || qflag || lflag)
+ break;
+ }
+
+ if (vflag) {
+ c = !c;
+ break;
+ }
+ /* One pass if we are not recording matches */
+ if ((color != NULL && !oflag) || qflag || lflag)
+ break;
+
+ if (st == (size_t)pmatch.rm_so)
+ break; /* No matches */
+ }
+
+ if (c && binbehave == BINFILE_BIN && nottext)
+ return (c); /* Binary file */
+
+ /* Dealing with the context */
+ if ((tail || c) && !cflag && !qflag && !lflag && !Lflag) {
+ if (c) {
+ if ((Aflag || Bflag) && !first_global &&
+ (first || since_printed > Bflag))
+ printf("--\n");
+ tail = Aflag;
+ if (Bflag > 0)
+ printqueue();
+ printline(l, ':', matches, m);
+ } else {
+ printline(l, '-', matches, m);
+ tail--;
+ }
+ first = false;
+ first_global = false;
+ since_printed = 0;
+ } else {
+ if (Bflag)
+ enqueue(l);
+ since_printed++;
+ }
+ return (c);
+}
+
+/*
+ * Safe malloc() for internal use.
+ */
+void *
+grep_malloc(size_t size)
+{
+ void *ptr;
+
+ if ((ptr = malloc(size)) == NULL)
+ err(2, "malloc");
+ return (ptr);
+}
+
+/*
+ * Safe calloc() for internal use.
+ */
+void *
+grep_calloc(size_t nmemb, size_t size)
+{
+ void *ptr;
+
+ if ((ptr = calloc(nmemb, size)) == NULL)
+ err(2, "calloc");
+ return (ptr);
+}
+
+/*
+ * Safe realloc() for internal use.
+ */
+void *
+grep_realloc(void *ptr, size_t size)
+{
+
+ if ((ptr = realloc(ptr, size)) == NULL)
+ err(2, "realloc");
+ return (ptr);
+}
+
+/*
+ * Safe strdup() for internal use.
+ */
+char *
+grep_strdup(const char *str)
+{
+ char *ret;
+
+ if ((ret = strdup(str)) == NULL)
+ err(2, "strdup");
+ return (ret);
+}
+
+/*
+ * Prints a matching line according to the command line options.
+ */
+void
+printline(struct str *line, int sep, regmatch_t *matches, int m)
+{
+ size_t a = 0;
+ int i, n = 0;
+
+ if (!hflag) {
+ if (nullflag == 0)
+ fputs(line->file, stdout);
+ else {
+ printf("%s", line->file);
+ putchar(0);
+ }
+ ++n;
+ }
+ if (nflag) {
+ if (n > 0)
+ putchar(sep);
+ printf("%d", line->line_no);
+ ++n;
+ }
+ if (bflag) {
+ if (n > 0)
+ putchar(sep);
+ printf("%lld", (long long)line->off);
+ ++n;
+ }
+ if (n)
+ putchar(sep);
+ /* --color and -o */
+ if ((oflag || color) && m > 0) {
+ for (i = 0; i < m; i++) {
+ if (!oflag)
+ fwrite(line->dat + a, matches[i].rm_so - a, 1,
+ stdout);
+ if (color)
+ fprintf(stdout, "\33[%sm\33[K", color);
+
+ fwrite(line->dat + matches[i].rm_so,
+ matches[i].rm_eo - matches[i].rm_so, 1,
+ stdout);
+ if (color)
+ fprintf(stdout, "\33[m\33[K");
+ a = matches[i].rm_eo;
+ if (oflag)
+ putchar('\n');
+ }
+ if (!oflag) {
+ if (line->len - a > 0)
+ fwrite(line->dat + a, line->len - a, 1, stdout);
+ putchar(line_sep);
+ }
+ } else {
+ fwrite(line->dat, line->len, 1, stdout);
+ putchar(line_sep);
+ }
+}
diff --git a/toolbox/mount.c b/toolbox/mount.c
index 27cf3c9..b7adce2 100644
--- a/toolbox/mount.c
+++ b/toolbox/mount.c
@@ -49,12 +49,17 @@
{ "exec", MS_NOEXEC, 0, MS_NOEXEC },
{ "move", MS_TYPE, MS_MOVE, 0 },
{ "recurse", MS_REC, MS_REC, 0 },
+ { "rec", MS_REC, MS_REC, 0 },
{ "remount", MS_TYPE, MS_REMOUNT, 0 },
{ "ro", MS_RDONLY, MS_RDONLY, 0 },
{ "rw", MS_RDONLY, 0, MS_RDONLY },
{ "suid", MS_NOSUID, 0, MS_NOSUID },
{ "sync", MS_SYNCHRONOUS, MS_SYNCHRONOUS, 0 },
{ "verbose", MS_VERBOSE, MS_VERBOSE, 0 },
+ { "unbindable", MS_UNBINDABLE, MS_UNBINDABLE, 0 },
+ { "private", MS_PRIVATE, MS_PRIVATE, 0 },
+ { "slave", MS_SLAVE, MS_SLAVE, 0 },
+ { "shared", MS_SHARED, MS_SHARED, 0 },
};
static void add_extra_option(struct extra_opts *extra, char *s)